Skip to content

Commit

Permalink
Fixed modifyData logic for offset values beyond +/- 1 MB.
Browse files Browse the repository at this point in the history
When the offset is <-1MB/>+1MB, the appropriate sequence of instructions
needs to be generated to keep the PC-relative data access intact. The
previous logic was using the incorrect values for loading into the
temporary registers before using those registers as indirect pointers
(in the LDR/LDRSW case). This is now fixed.
  • Loading branch information
ssunny7 committed Apr 7, 2017
1 parent 83bdf66 commit a2b9679
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 21 deletions.
1 change: 1 addition & 0 deletions common/src/arch-aarch64.h
Expand Up @@ -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
Expand Down
59 changes: 42 additions & 17 deletions dyninstAPI/src/codegen-aarch64.C
Expand Up @@ -140,7 +140,7 @@ void insnCodeGen::generateLongBranch(codeGen &gen,
generateBranchViaTrap(gen, from, to, isCall);
}

insnCodeGen::loadImmIntoReg(gen, scratch, to);
insnCodeGen::loadImmIntoReg<Address>(gen, scratch, to);

instruction branchInsn;
branchInsn.clear();
Expand Down Expand Up @@ -469,7 +469,8 @@ assert(0);
//#warning "This function is not implemented yet!"
}

void insnCodeGen::loadImmIntoReg(codeGen &gen, Register rt, unsigned long value)
template <typename T>
void insnCodeGen::loadImmIntoReg(codeGen &gen, Register rt, T value)
{
assert(value >= 0);

Expand Down Expand Up @@ -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<Address>(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<Address>(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!");
Expand Down
6 changes: 3 additions & 3 deletions dyninstAPI/src/codegen-aarch64.h
Expand Up @@ -97,6 +97,9 @@ class insnCodeGen {

static void generateMemAccessFP(codeGen &gen, LoadStore accType, Register rt, Register rn, int immd, int size, bool is128bit);

template<typename T>
static void loadImmIntoReg(codeGen &gen, Register rt, T value);

/** TODO **/
static void generateLoadReg(codeGen &gen, Register rt,
Register ra, Register rb);
Expand Down Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion dyninstAPI/src/inst-aarch64.C
Expand Up @@ -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<Offset?(gen, scratchReg, destOff);

if(!isStaticBinary) {
insnCodeGen::generateLoadReg64(gen, scratchReg, scratchReg, TOCreg);
Expand Down

0 comments on commit a2b9679

Please sign in to comment.