diff --git a/common/src/arch-aarch64.h b/common/src/arch-aarch64.h
index 120fc4d6b3..b6d2c6ff91 100644
--- a/common/src/arch-aarch64.h
+++ b/common/src/arch-aarch64.h
@@ -78,6 +78,7 @@ namespace NS_aarch64 {
#define LDRFPImmOp 0x1E2
#define STRImmUIOp 0xE4
#define LDRImmUIOp 0xE5
+#define LDRSWImmUIOp 0xE6
#define MSROp 0xD51
#define MRSOp 0xD53
diff --git a/dyninstAPI/src/codegen-aarch64.C b/dyninstAPI/src/codegen-aarch64.C
index 19a5be66fc..634838ce68 100644
--- a/dyninstAPI/src/codegen-aarch64.C
+++ b/dyninstAPI/src/codegen-aarch64.C
@@ -140,7 +140,7 @@ void insnCodeGen::generateLongBranch(codeGen &gen,
generateBranchViaTrap(gen, from, to, isCall);
}
- insnCodeGen::loadImmIntoReg(gen, scratch, to);
+ insnCodeGen::loadImmIntoReg
(gen, scratch, to);
instruction branchInsn;
branchInsn.clear();
@@ -469,7 +469,8 @@ assert(0);
//#warning "This function is not implemented yet!"
}
-void insnCodeGen::loadImmIntoReg(codeGen &gen, Register rt, unsigned long value)
+template
+void insnCodeGen::loadImmIntoReg(codeGen &gen, Register rt, T value)
{
assert(value >= 0);
@@ -630,44 +631,68 @@ bool insnCodeGen::modifyData(Address target,
int raw = insn.asInt();
bool isneg = false;
- if(target < gen.currAddr())
- isneg = true;
+ if (target < gen.currAddr())
+ isneg = true;
Address offset = !isneg ? (target - gen.currAddr()) : (gen.currAddr() - target);
- if(((raw >> 24) & 0x1F) == 0x10) {
- int shiftamt = ((raw >> 31) & 0x1) ? 12 : 0;
+ if (((raw >> 24) & 0x1F) == 0x10) {
+ int shiftamt = ((raw >> 31) & 0x1) ? 12 : 0;
+ signed long imm = isneg ? -(offset >> shiftamt) : (offset >> shiftamt);
//If offset is within +/- 1 MB, modify the instruction (ADR/ADRP) with the new offset
if (offset <= (1 << 20)) {
instruction newInsn(insn);
- signed long imm = isneg ? -(offset >> shiftamt) : (offset >> shiftamt);
-
INSN_SET(newInsn, 5, 23, ((imm >> 2) & 0x7FFFF));
INSN_SET(newInsn, 29, 30, (imm & 0x3));
generate(gen, newInsn);
}
- //Else, generate move instructions to move the value to the same register
+ //Else, generate move instructions to move the value to the same register
else {
Register rd = raw & 0x1F;
- loadImmIntoReg(gen, rd, offset);
+ loadImmIntoReg(gen, rd, target);
}
- } else if(((raw >> 24) & 0x3F) == 0x18) {
- //If offset is within +/- 1 MB, modify the instruction (LDR/LDRSW) with the new offset
- if(offset <= (1 << 20)) {
+ } else if (((raw >> 24) & 0x3F) == 0x18) {
+ //If offset is within +/- 1 MB, modify the instruction (LDR/LDRSW) with the new offset
+ signed long imm = isneg ? -(offset >> 2) : (offset >> 2);
+
+ if (offset <= (1 << 20)) {
instruction newInsn(insn);
- isneg ? (offset += 4) : (offset -= 4);
- signed long imm = isneg ? -(offset >> 2) : (offset >> 2);
+ isneg ? (offset += 4) : (offset -= 4);
INSN_SET(newInsn, 5, 23, (imm & 0x7FFFF));
generate(gen, newInsn);
}
- //Else, generate move instructions to move the value to the same register
+ //Else, generate move instructions to move the value to the same register
else {
+ //Get scratch register for loading the target address in
+ Register immReg = gen.rs()->getScratchRegister(gen, true);
+ if(immReg == REG_NULL)
+ assert(!"No scratch register available to load the target address into for a PC-relative data access using LDR/LDRSW!");
+ //Generate sequence of instructions for loading the target address in scratch register
+ loadImmIntoReg(gen, rt, target);
+
Register rt = raw & 0x1F;
- loadImmIntoReg(gen, rt, offset);
+
+ //Generate instruction for reading value at target address using unsigned-offset variant of the immediate variant of LDR/LDRSW
+ instruction newInsn;
+ newInsn.clear();
+
+ if(((raw >> 31) & 0x1) == 0) {
+ INSN_SET(newInsn, 30, 30, ((raw >> 30) & 0x1));
+ INSN_SET(newInsn, 22, 29, LDRImmUIOp);
+ } else {
+ INSN_SET(newInsn, 22, 29, LDRSWImmUIOp);
+ }
+
+ INSN_SET(newInsn, 31, 31, 0x1);
+ INSN_SET(newInsn, 10, 21, 0);
+ INSN_SET(newInsn, 5, 9, immReg);
+ INSN_SET(newInsn, 0, 4, rt);
+
+ generate(gen, newInsn);
}
} else {
assert(!"Got an instruction other than ADR/ADRP/LDR(literal)/LDRSW(literal) in PC-relative data access!");
diff --git a/dyninstAPI/src/codegen-aarch64.h b/dyninstAPI/src/codegen-aarch64.h
index c27859e208..b599691d55 100644
--- a/dyninstAPI/src/codegen-aarch64.h
+++ b/dyninstAPI/src/codegen-aarch64.h
@@ -97,6 +97,9 @@ class insnCodeGen {
static void generateMemAccessFP(codeGen &gen, LoadStore accType, Register rt, Register rn, int immd, int size, bool is128bit);
+ template
+ static void loadImmIntoReg(codeGen &gen, Register rt, T value);
+
/** TODO **/
static void generateLoadReg(codeGen &gen, Register rt,
Register ra, Register rb);
@@ -130,9 +133,6 @@ class insnCodeGen {
int mode, Register rs1,
Register rs2, Register rd);
- static void loadImmIntoReg(codeGen &gen, Register rt,
- unsigned long value);
-
static void loadPartialImmIntoReg(codeGen &gen, Register rt,
long value);
diff --git a/dyninstAPI/src/inst-aarch64.C b/dyninstAPI/src/inst-aarch64.C
index a0e9076750..fc96dfb762 100644
--- a/dyninstAPI/src/inst-aarch64.C
+++ b/dyninstAPI/src/inst-aarch64.C
@@ -973,7 +973,7 @@ bool EmitterAARCH64Stat::emitPLTCommon(func_instance *callee, bool call, codeGen
assert (stackSize == 1);
scratchReg = freeReg[0];
}
- insnCodeGen::loadImmIntoReg(gen, scratchReg, destOff);
+ insnCodeGen::loadImmIntoReg