@@ -79,7 +79,7 @@ int16_t getLO(uint32_t v) {
79
79
80
80
void PCSX::PS1Packer::pack (IO<File> src, IO<File> dest, uint32_t addr, uint32_t pc, uint32_t gp, uint32_t sp,
81
81
const Options& options) {
82
- constexpr size_t stubSize = 8 ;
82
+ constexpr size_t stubSize = 7 * 4 ;
83
83
std::vector<uint8_t > dataIn;
84
84
dataIn.resize (src->size ());
85
85
src->read (dataIn.data (), dataIn.size ());
@@ -98,21 +98,21 @@ void PCSX::PS1Packer::pack(IO<File> src, IO<File> dest, uint32_t addr, uint32_t
98
98
if (r != UCL_E_OK) {
99
99
throw std::runtime_error (" Fatal error during data compression.\n " );
100
100
}
101
- dataOut.resize (outSize + (options.raw ? 16 : 0 ));
102
- uint32_t newPC;
103
- uint32_t compLoad;
104
-
101
+ dataOut.resize (outSize + (options.raw ? stubSize : 0 ));
105
102
while ((dataOut.size () & 3 ) != 0 ) {
106
103
dataOut.push_back (0 );
107
104
}
105
+ uint32_t newPC = dataOut.size ();
106
+ uint32_t compLoad = 0 ;
107
+
108
108
// If we're outputting a rom file, our tload will be fixed
109
109
// at 0x1f000110, after the license string.
110
- uint32_t tload = options.rom ? 0x1f000110 : options.tload ;
110
+ uint32_t tload = options.raw ? 0 : options. rom ? 0x1f000110 : options.tload ;
111
111
112
112
if (tload != 0 ) {
113
113
newPC = tload + dataOut.size ();
114
114
compLoad = tload;
115
- } else {
115
+ } else if (!options. raw ) {
116
116
// If we don't have a tload, it means we're doing
117
117
// in-place decompression. We need to make sure
118
118
// we have enough space to decompress our binary
@@ -132,10 +132,18 @@ void PCSX::PS1Packer::pack(IO<File> src, IO<File> dest, uint32_t addr, uint32_t
132
132
if (options.raw ) {
133
133
// If outputting a raw file, our start address is going
134
134
// to be the same as our tload address, so we need to inject
135
- // a jump to the start of our code.
135
+ // a jump to the start of our code. We are doing this in
136
+ // a fully position-independent way, so raw files can be
137
+ // loaded anywhere in memory.
138
+ auto offset = newPC - 4 * 4 ;
136
139
std::vector<uint8_t > stub;
137
- pushBytes (stub, j (newPC));
138
- pushBytes (stub, nop ());
140
+ pushBytes (stub, addiu (Reg::T8, Reg::RA, 0 ));
141
+ pushBytes (stub, lui (Reg::T1, getHI (offset)));
142
+ pushBytes (stub, bgezal (Reg::R0, 4 ));
143
+ pushBytes (stub, addiu (Reg::T1, Reg::T1, getLO (offset)));
144
+ pushBytes (stub, addu (Reg::T0, Reg::RA, Reg::T1));
145
+ pushBytes (stub, jr (Reg::T0));
146
+ pushBytes (stub, addiu (Reg::A0, Reg::RA, 12 ));
139
147
140
148
assert (stub.size () == stubSize);
141
149
@@ -163,7 +171,7 @@ void PCSX::PS1Packer::pack(IO<File> src, IO<File> dest, uint32_t addr, uint32_t
163
171
// binary file, and so the next instructions will
164
172
// be the very first our binary will run.
165
173
166
- if (!options.shell ) {
174
+ if (!options.shell && !options. raw ) {
167
175
// We save $ra to $t8, so we can restore it later. This breaks ABI,
168
176
// but the ucl-nrv2e decompressor won't use it. This isn't useful
169
177
// for the shell trick, since we're just going to reboot the machine.
@@ -173,8 +181,10 @@ void PCSX::PS1Packer::pack(IO<File> src, IO<File> dest, uint32_t addr, uint32_t
173
181
pushBytes (dataOut, lui (Reg::V1, 0x1f80 ));
174
182
pushBytes (dataOut, sw (Reg::R0, 0x1074 , Reg::V1));
175
183
// Calls the ucl-nrv2e decompressor.
176
- pushBytes (dataOut, lui (Reg::A0, getHI (compLoad)));
177
- pushBytes (dataOut, addiu (Reg::A0, Reg::A0, getLO (compLoad)));
184
+ if (!options.raw ) {
185
+ pushBytes (dataOut, lui (Reg::A0, getHI (compLoad)));
186
+ pushBytes (dataOut, addiu (Reg::A0, Reg::A0, getLO (compLoad)));
187
+ }
178
188
pushBytes (dataOut, lui (Reg::A1, getHI (addr)));
179
189
pushBytes (dataOut, bgezal (Reg::R0, -((int16_t )(dataOut.size () + 4 - n2estart))));
180
190
pushBytes (dataOut, addiu (Reg::A1, Reg::A1, getLO (addr)));
0 commit comments