10
10
#include " core/assembler/assembler-arm.h"
11
11
#include " core/codegen/codegen-arm.h"
12
12
13
+ #include < algorithm>
14
+
13
15
using namespace zz ;
14
16
using namespace zz ::arm;
15
17
@@ -155,29 +157,26 @@ static void ARMRelocateSingleInsn(relo_ctx_t *ctx, int32_t insn) {
155
157
uint32_t P, U, o2, W, o1, Rn, Rt, imm12;
156
158
P = bit (insn, 24 );
157
159
U = bit (insn, 23 );
160
+ o2 = bit (insn, 22 );
158
161
W = bit (insn, 21 );
159
- imm12 = bits (insn, 0 , 11 );
162
+ o1 = bit (insn, 20 );
160
163
Rn = bits (insn, 16 , 19 );
161
164
Rt = bits (insn, 12 , 15 );
162
- o1 = bit (insn, 20 );
163
- o2 = bit (insn, 22 );
165
+ imm12 = bits (insn, 0 , 11 );
164
166
uint32_t P_W = (P << 1 ) | W;
165
167
do {
166
168
// LDR (literal)
167
169
DEBUG_LOG (" %d:relo <ldr_literal> at %p" , ctx->relocated_offset_map .size (), relo_cur_src_vmaddr (ctx));
168
- if (o1 == 1 && o2 == 0 && P_W != 0b01 && Rn == 0b1111 ) {
169
- goto load_literal_fix_scheme;
170
- }
171
- if (o1 == 1 && o2 == 1 && P_W != 0b01 && Rn == 0b1111 ) {
170
+ if (o1 == 1 /* && o2 == 0 */ && P_W != 0b01 && Rn == pc.code ()) {
172
171
goto load_literal_fix_scheme;
173
172
}
174
173
break ;
175
174
load_literal_fix_scheme:
176
- addr32_t dst_vmaddr = 0 ;
175
+ addr32_t dst_vmaddr = relo_cur_src_vmaddr (ctx); // origin pc
177
176
if (U == 0b1 )
178
- dst_vmaddr = relo_cur_src_vmaddr (ctx) + imm12;
177
+ dst_vmaddr += imm12;
179
178
else
180
- dst_vmaddr = relo_cur_src_vmaddr (ctx) - imm12;
179
+ dst_vmaddr -= imm12;
181
180
182
181
Register intermediateReg = Register::R (Rt == pc.code () ? VOLATILE_REGISTER.code () : Rt);
183
182
Register regRt = Register::R (Rt);
@@ -204,6 +203,74 @@ static void ARMRelocateSingleInsn(relo_ctx_t *ctx, int32_t insn) {
204
203
} while (0 );
205
204
}
206
205
206
+ // handle some kinds of pc-relative instructions
207
+ if (cond != 0b1111 && (op0 == 0b000 || op0 == 0b011 )) {
208
+ uint32_t P, U, o2, W, o1, Rn, Rt, imm5, type, Rm;
209
+ P = bit (insn, 24 );
210
+ U = bit (insn, 23 );
211
+ o2 = bit (insn, 22 );
212
+ W = bit (insn, 21 );
213
+ o1 = bit (insn, 20 );
214
+ Rn = bits (insn, 16 , 19 );
215
+ Rt = bits (insn, 12 , 15 );
216
+ imm5 = bits (insn, 7 , 11 );
217
+ type = bits (insn, 5 , 6 );
218
+ Rm = bits (insn, 0 , 3 );
219
+ uint32_t P_W = (P << 1 ) | W;
220
+ if (Rn == pc.code () || Rm == pc.code ()) {
221
+ do {
222
+ if (op0 == 0b000 && P == 0 && U == 1 && o2 == 0 && W == 0 && o1 == 0 ) {
223
+ // consecutive LDR (literal) - ADD (register, PC-relative)
224
+ // example:
225
+ // ldr r1, [pc, #8]
226
+ // add r1, pc, r1 ; <- we are here
227
+ // str r0, [r1]
228
+ // bx lr
229
+ // dcd vmaddr_offset_relative_to_pc
230
+ goto inject_insn_change_Rn;
231
+ }
232
+ if (op0 == 0b011 && o1 == 1 && o2 == 0 && P_W != 0b01 ) {
233
+ // consecutive LDR (literal) - LDR (register, PC-relative)
234
+ // example:
235
+ // ldr r0, [pc, #4]
236
+ // ldr r0, [pc, r0] ; <- we are here
237
+ // bx lr
238
+ // dcd vmaddr_offset_relative_to_pc
239
+ goto inject_insn_change_Rn;
240
+ }
241
+ break ;
242
+ inject_insn_change_Rn:
243
+ int RnOffset = 16 ;
244
+ if (Rm == pc.code ()) {
245
+ std::swap (Rm, Rn);
246
+ RnOffset = 0 ;
247
+ }
248
+ Register RmReg = Register::R (Rm);
249
+
250
+ // change Rn to something else than pc, fill it with value of origin pc
251
+ int32_t RnVal = relo_cur_src_vmaddr (ctx); // origin pc
252
+ Register RnReg = Register::R (Rm == 1 ? 0 : 1 );
253
+ RegisterList RnRegList (RnReg);
254
+ insn &= ~(0x0f << RnOffset);
255
+ insn |= RnReg.code () << RnOffset;
256
+
257
+ auto RnValLabel = RelocLabel::withData (RnVal);
258
+ _ AppendRelocLabel (RnValLabel);
259
+
260
+ if (Rn != Rt) {
261
+ _ push (RnRegList);
262
+ }
263
+ _ Ldr (RnReg, RnValLabel);
264
+ _ EmitARMInst (insn);
265
+ if (Rn != Rt) {
266
+ _ pop (RnRegList);
267
+ }
268
+
269
+ is_insn_relocated = true ;
270
+ } while (0 );
271
+ }
272
+ }
273
+
207
274
// Data-processing and miscellaneous instructions
208
275
if (cond != 0b1111 && (op0 & 0b110 ) == 0b000 ) {
209
276
uint32_t op0, op1, op2, op3, op4;
0 commit comments