Skip to content

Commit 8efbe33

Browse files
handle consecutive PC-relative instructions
change Rn to something else than pc, fill it with value of origin pc example1: ldr r0, [pc, #4] ldr r0, [pc, r0] ; <- we are here bx lr dcd vmaddr_offset_relative_to_pc example2: ldr r1, [pc, #8] add r1, pc, r1 ; <- we are here str r0, [r1] bx lr dcd vmaddr_offset_relative_to_pc
1 parent ebb3541 commit 8efbe33

File tree

1 file changed

+77
-10
lines changed

1 file changed

+77
-10
lines changed

source/InstructionRelocation/arm/InstructionRelocationARM.cc

+77-10
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "core/assembler/assembler-arm.h"
1111
#include "core/codegen/codegen-arm.h"
1212

13+
#include <algorithm>
14+
1315
using namespace zz;
1416
using namespace zz::arm;
1517

@@ -155,29 +157,26 @@ static void ARMRelocateSingleInsn(relo_ctx_t *ctx, int32_t insn) {
155157
uint32_t P, U, o2, W, o1, Rn, Rt, imm12;
156158
P = bit(insn, 24);
157159
U = bit(insn, 23);
160+
o2 = bit(insn, 22);
158161
W = bit(insn, 21);
159-
imm12 = bits(insn, 0, 11);
162+
o1 = bit(insn, 20);
160163
Rn = bits(insn, 16, 19);
161164
Rt = bits(insn, 12, 15);
162-
o1 = bit(insn, 20);
163-
o2 = bit(insn, 22);
165+
imm12 = bits(insn, 0, 11);
164166
uint32_t P_W = (P << 1) | W;
165167
do {
166168
// LDR (literal)
167169
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()) {
172171
goto load_literal_fix_scheme;
173172
}
174173
break;
175174
load_literal_fix_scheme:
176-
addr32_t dst_vmaddr = 0;
175+
addr32_t dst_vmaddr = relo_cur_src_vmaddr(ctx); // origin pc
177176
if (U == 0b1)
178-
dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm12;
177+
dst_vmaddr += imm12;
179178
else
180-
dst_vmaddr = relo_cur_src_vmaddr(ctx) - imm12;
179+
dst_vmaddr -= imm12;
181180

182181
Register intermediateReg = Register::R(Rt == pc.code() ? VOLATILE_REGISTER.code() : Rt);
183182
Register regRt = Register::R(Rt);
@@ -204,6 +203,74 @@ static void ARMRelocateSingleInsn(relo_ctx_t *ctx, int32_t insn) {
204203
} while (0);
205204
}
206205

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+
207274
// Data-processing and miscellaneous instructions
208275
if (cond != 0b1111 && (op0 & 0b110) == 0b000) {
209276
uint32_t op0, op1, op2, op3, op4;

0 commit comments

Comments
 (0)