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