treat all pop to pc as function return (#502)

Update semantics to handle function returns and indirect jumps
This commit is contained in:
kumarak
2021-04-06 18:26:22 -04:00
committed by GitHub
parent 142ab2f0aa
commit d93823cd72
9 changed files with 409 additions and 151 deletions
+1
View File
@@ -40,5 +40,6 @@ extern const std::string_view kBranchTakenVariableName;
extern const std::string_view kInvalidInstructionISelName;
extern const std::string_view kUnsupportedInstructionISelName;
extern const std::string_view kIgnoreNextPCVariableName;
} // namespace remill
+4 -1
View File
@@ -167,7 +167,10 @@ void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module,
const auto pc_arg = NthArgument(bb_func, kPCArgNum);
const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum);
ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, "NEXT_PC"));
ir.CreateStore(pc_arg,
ir.CreateAlloca(addr, nullptr, kNextPCVariableName.data()));
ir.CreateStore(
pc_arg, ir.CreateAlloca(addr, nullptr, kIgnoreNextPCVariableName.data()));
auto zero_c = ir.CreateAlloca(u8, nullptr, "ZERO_C");
ir.CreateStore(llvm::Constant::getNullValue(u8), zero_c);
+207 -59
View File
@@ -526,9 +526,10 @@ union SpecialRegsAndHints {
} __attribute__((packed));
static_assert(sizeof(SpecialRegsAndHints) == 4, " ");
static constexpr auto kAddressSize = 32u;
static constexpr auto kPCRegNum = 15u;
static constexpr auto kLRRegNum = 14u;
static constexpr auto kSPRegNum = 13u;
static const char *const kIntRegName[] = {
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
@@ -907,6 +908,7 @@ static void AddShiftRegImmOperand(Instruction &inst, uint32_t reg_num,
inst.operands.back().expr = inst.EmplaceBinaryOp(
llvm::Instruction::Or, inst.operands.back().expr, rrx_op);
}
if (carry_out) {
AddShiftImmCarryOperand(inst, reg_num, shift_type, shift_size, "C");
}
@@ -1151,6 +1153,8 @@ static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd,
auto src2 = EvalOperand(inst, inst.operands[4], uses_linkreg);
if (uses_linkreg) {
AddAddrRegOp(inst, kNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
// NOTE(akshayk): conditional return `movne pc, lr`
if (is_cond) {
@@ -1160,8 +1164,12 @@ static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd,
inst.category = Instruction::kCategoryFunctionReturn;
}
} else if (!src1 || !src2) {
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
inst.category = Instruction::kCategoryIndirectJump;
} else {
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
auto res = evaluator(*src1, *src2);
if (!res) {
if (is_cond) {
@@ -1181,6 +1189,8 @@ static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd,
}
}
} else {
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
inst.category = Instruction::kCategoryNormal;
}
return true;
@@ -1248,7 +1258,6 @@ static const char *const kIdpNamesRRR[] = {
static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst,
uint32_t bits) {
const IntDataProcessingRRRI enc = {bits};
inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s];
auto is_cond = DecodeCondition(inst, enc.cond);
AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite);
@@ -1274,6 +1283,8 @@ static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst,
AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite);
AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead);
AddShiftRegRegOperand(inst, enc.rm, enc.type, enc.rs, enc.s);
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
inst.category = Instruction::kCategoryNormal;
return true;
@@ -1301,15 +1312,16 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst,
inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s];
auto is_cond = DecodeCondition(inst, enc.cond);
AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite);
AddIntRegOp(inst, enc.rd, kAddressSize, Operand::kActionWrite);
// Raise the program counter to align to a multiple of 4 bytes
if (enc.rn == kPCRegNum && (enc.opc == 0b100u || enc.opc == 0b010u)) {
int64_t diff =
static_cast<int32_t>(inst.pc & ~(3u)) - static_cast<int32_t>(inst.pc);
AddAddrRegOp(inst, "PC", 32, Operand::kActionRead, diff);
AddAddrRegOp(inst, kPCVariableName.data(), kAddressSize,
Operand::kActionRead, diff);
} else {
AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead);
AddIntRegOp(inst, enc.rn, kAddressSize, Operand::kActionRead);
}
ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s);
@@ -1696,14 +1708,43 @@ static bool TryDecodeLoadStoreWordUBIL(Instruction &inst, uint32_t bits) {
disp + pc_adjust);
}
// NOTE(akshayk): Instruction updating PC register will be a branching
// instruction. A branching instruction(conditional/
// unconditional) may update PC and invalidates `next_pc`.
// The semantics for these instructions take `next_pc` as
// arguments and should update it accordingly.
if (enc.rt == kPCRegNum) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
AddAddrRegOp(inst, kNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
// NOTE(akshayk): A function can return by poping LR register to PC. Decoder
// having single view of instruction can't identify the register
// pushed on to the stack. All pop involving PC is categorized
// as function return
//
// e.g: push {r2, lr}; ....; pop {r2, pc}
//
if (enc.rn == kSPRegNum) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalFunctionReturn;
} else {
inst.category = Instruction::kCategoryFunctionReturn;
}
} else {
inst.category = Instruction::kCategoryIndirectJump;
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
} else {
inst.category = Instruction::kCategoryIndirectJump;
}
}
} else {
// Add operand to ignore any updates of the next pc if done by semantic
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
inst.category = Instruction::kCategoryNormal;
}
return true;
@@ -1781,14 +1822,43 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) {
inst.EmplaceBinaryOp(disp_op, inst.operands.back().expr, disp_expr);
}
// NOTE(akshayk): Instruction updating PC register will be a branching
// instruction. A branching instruction(conditional/
// unconditional) may update PC and invalidates `next_pc`.
// The semantics for these instructions take `next_pc` as
// arguments and should update it accordingly.
if (enc.rt == kPCRegNum) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
AddAddrRegOp(inst, kNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
// NOTE(akshayk): A function can return by poping LR register to PC. Decoder
// having single view of instruction can't identify the register
// pushed on to the stack. All pop involving PC is categorized
// as function return
//
// e.g: push {r2, lr}; ....; pop {r2, pc}
//
if (enc.rn == kSPRegNum) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalFunctionReturn;
} else {
inst.category = Instruction::kCategoryFunctionReturn;
}
} else {
inst.category = Instruction::kCategoryIndirectJump;
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
} else {
inst.category = Instruction::kCategoryIndirectJump;
}
}
} else {
// Add operand to ignore any updates of the next pc if done by semantic
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
inst.category = Instruction::kCategoryNormal;
}
return true;
@@ -1907,14 +1977,43 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst,
disp + pc_adjust);
}
// NOTE(akshayk): Instruction updating PC register will be a branching
// instruction. A branching instruction(conditional/
// unconditional) may update PC and invalidates `next_pc`.
// The semantics for these instructions take `next_pc` as
// arguments and should update it accordingly.
if (enc.rt == kPCRegNum) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
AddAddrRegOp(inst, kNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
// NOTE(akshayk): A function can return by poping LR register to PC. Decoder
// having single view of instruction can't identify the register
// pushed on to the stack. All pop involving PC is categorized
// as function return
//
// e.g: push {r2, lr}; ....; pop {r2, pc}
//
if (enc.rn == kSPRegNum) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalFunctionReturn;
} else {
inst.category = Instruction::kCategoryFunctionReturn;
}
} else {
inst.category = Instruction::kCategoryIndirectJump;
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
} else {
inst.category = Instruction::kCategoryIndirectJump;
}
}
} else {
// Add operand to ignore any updates of the next pc if done by semantic
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
inst.category = Instruction::kCategoryNormal;
}
return true;
@@ -2010,14 +2109,36 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst,
inst.EmplaceBinaryOp(disp_op, inst.operands.back().expr, disp_expr);
}
// NOTE(akshayk): Instruction updating PC register will be a branching
// instruction. A branching instruction(conditional/
// unconditional) may update PC and invalidates `next_pc`.
// The semantics for these instructions take `next_pc` as
// arguments and should update it accordingly.
if (enc.rt == kPCRegNum) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
AddAddrRegOp(inst, kNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
if (enc.rn == kSPRegNum) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalFunctionReturn;
} else {
inst.category = Instruction::kCategoryFunctionReturn;
}
} else {
inst.category = Instruction::kCategoryIndirectJump;
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
} else {
inst.category = Instruction::kCategoryIndirectJump;
}
}
} else {
// Add operand to ignore any updates of the next pc if done by semantic
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
inst.category = Instruction::kCategoryNormal;
}
return true;
@@ -2130,14 +2251,44 @@ static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) {
AddIntRegOp(inst, i, 32u, kRegAction);
}
// NOTE(akshayk): `POP` instruction updating PC can move link register
// to program counter and be alias to the return. These
// instructions should be categorized as function return.
// e.g :
// 0: e92d4004 push {r2, lr}
// ...
// 10: e8bd8004 pop {r2, pc}
//
// LR can also be moved(pop'd) to PC indirectly using
// one of scratch register. All POP updating PC is
// considered function return and lifting work-list will
// take care of identifying if its indirect jump
//
if (enc.register_list & (0b1 << 15u)) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
AddAddrRegOp(inst, kNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
if (enc.rn == kSPRegNum) {
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalFunctionReturn;
} else {
inst.category = Instruction::kCategoryFunctionReturn;
}
} else {
inst.category = Instruction::kCategoryIndirectJump;
if (is_cond) {
inst.branch_not_taken_pc = inst.next_pc;
inst.category = Instruction::kCategoryConditionalIndirectJump;
} else {
inst.category = Instruction::kCategoryIndirectJump;
}
}
} else {
// Add operand to ignore any updates of the next pc if done by semantic
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
inst.category = Instruction::kCategoryNormal;
}
return true;
@@ -2294,7 +2445,6 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) {
inst.function = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s];
auto is_cond = DecodeCondition(inst, enc.cond);
AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite);
// enc.opc == x0
@@ -2310,11 +2460,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) {
AddImmOp(inst, ~0u);
}
if (enc.type) {
AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, enc.s);
} else {
AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead);
}
AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, enc.s);
return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u],
is_cond);
@@ -2348,6 +2494,9 @@ static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) {
AddImmOp(inst, ~0u);
}
AddShiftRegRegOperand(inst, enc.rm, enc.type, enc.rs, enc.s);
AddAddrRegOp(inst, kIgnoreNextPCVariableName.data(), kAddressSize,
Operand::kActionWrite, 0);
inst.category = Instruction::kCategoryNormal;
return true;
}
@@ -2502,32 +2651,32 @@ static bool TryBranchImm(Instruction &inst, uint32_t bits) {
}
auto offset = static_cast<uint32_t>(target_pc - inst.pc);
AddAddrRegOp(inst, "PC", 32u, Operand::kActionRead, offset);
AddAddrRegOp(inst, kPCVariableName.data(), kAddressSize, Operand::kActionRead,
offset);
inst.branch_taken_pc = target_pc;
inst.branch_not_taken_pc = inst.pc + 4;
if (is_cond && is_func) {
inst.category = Instruction::kCategoryConditionalDirectFunctionCall;
AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0);
} else if (is_cond) {
inst.category = Instruction::kCategoryConditionalBranch;
AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0);
} else if (is_func) {
inst.category = Instruction::kCategoryDirectFunctionCall;
AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0);
} else {
inst.category = Instruction::kCategoryDirectJump;
}
AddAddrRegOp(inst, kNextPCVariableName.data(), kAddressSize,
Operand::kActionRead, 0);
Operand::Register reg;
reg.size = 32u;
reg.size = kAddressSize;
reg.name = remill::kNextPCVariableName;
auto &next_pc = inst.EmplaceOperand(reg);
next_pc.action = Operand::kActionWrite;
if (is_func) {
Operand::Register reg;
reg.size = 32u;
reg.size = kAddressSize;
reg.name = remill::kReturnPCVariableName;
auto &next_pc = inst.EmplaceOperand(reg);
next_pc.action = Operand::kActionWrite;
@@ -2562,38 +2711,37 @@ static bool TryDecodeBX(Instruction &inst, uint32_t bits) {
inst.function += "COND";
}
AddAddrRegOp(inst, kIntRegName[enc.Rm], 32u, Operand::kActionRead, 0);
AddAddrRegOp(inst, kIntRegName[enc.Rm], kAddressSize, Operand::kActionRead,
0);
if (enc.op1 == 0b01) {
if (is_cond && (enc.Rm == kLRRegNum)) {
inst.category = Instruction::kCategoryConditionalFunctionReturn;
AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0);
} else if (enc.Rm == kLRRegNum) {
inst.category = Instruction::kCategoryFunctionReturn;
AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0);
} else if (is_cond) {
inst.category = Instruction::kCategoryConditionalIndirectJump;
AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0);
} else if (enc.op1 == 0b01) {
inst.category = Instruction::kCategoryIndirectJump;
AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0);
}
} else if (is_cond) {
inst.category = Instruction::kCategoryConditionalDirectFunctionCall;
AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0);
} else {
inst.category = Instruction::kCategoryDirectFunctionCall;
AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0);
}
AddAddrRegOp(inst, kNextPCVariableName.data(), kAddressSize,
Operand::kActionRead, 0);
Operand::Register reg;
reg.size = 32u;
reg.size = kAddressSize;
reg.name = remill::kNextPCVariableName;
auto &next_pc = inst.EmplaceOperand(reg);
next_pc.action = Operand::kActionWrite;
if (enc.op1 == 0b11) {
Operand::Register reg;
reg.size = 32u;
reg.size = kAddressSize;
reg.name = remill::kReturnPCVariableName;
auto &next_pc = inst.EmplaceOperand(reg);
next_pc.action = Operand::kActionWrite;
@@ -2613,8 +2761,8 @@ static bool TryDecodeCLZ(Instruction &inst, uint32_t bits) {
}
DecodeCondition(inst, enc.cond);
AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite);
AddIntRegOp(inst, enc.Rm, 32u, Operand::kActionRead);
AddIntRegOp(inst, enc.Rd, kAddressSize, Operand::kActionWrite);
AddIntRegOp(inst, enc.Rm, kAddressSize, Operand::kActionRead);
inst.function = "CLZ";
inst.category = Instruction::kCategoryNormal;
@@ -2639,9 +2787,9 @@ static bool TryDecodeIntegerSaturatingArithmetic(Instruction &inst,
return false;
}
DecodeCondition(inst, enc.cond);
AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite);
AddIntRegOp(inst, enc.Rm, 32u, Operand::kActionRead);
AddIntRegOp(inst, enc.Rn, 32u, Operand::kActionRead);
AddIntRegOp(inst, enc.Rd, kAddressSize, Operand::kActionWrite);
AddIntRegOp(inst, enc.Rm, kAddressSize, Operand::kActionRead);
AddIntRegOp(inst, enc.Rn, kAddressSize, Operand::kActionRead);
inst.function = kSatArith[enc.opc];
inst.category = Instruction::kCategoryNormal;
@@ -2659,7 +2807,7 @@ static bool TryDecodeSat16(Instruction &inst, uint32_t bits) {
return false;
}
AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite);
AddIntRegOp(inst, enc.Rd, kAddressSize, Operand::kActionWrite);
if (enc.U) {
inst.function = "USAT16";
AddImmOp(inst, enc.sat_imm);
@@ -2667,7 +2815,7 @@ static bool TryDecodeSat16(Instruction &inst, uint32_t bits) {
inst.function = "SSAT16";
AddImmOp(inst, enc.sat_imm + 1);
}
AddIntRegOp(inst, enc.Rn, 32u, Operand::kActionRead);
AddIntRegOp(inst, enc.Rn, kAddressSize, Operand::kActionRead);
inst.category = Instruction::kCategoryNormal;
return true;
@@ -2684,7 +2832,7 @@ static bool TryDecodeSat32(Instruction &inst, uint32_t bits) {
return false;
}
AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite);
AddIntRegOp(inst, enc.Rd, kAddressSize, Operand::kActionWrite);
if (enc.U) {
inst.function = "USAT";
AddImmOp(inst, enc.sat_imm);
@@ -2744,13 +2892,13 @@ static bool TryExtAdd(Instruction &inst, uint32_t bits) {
}
inst.function = instruction;
AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite);
AddIntRegOp(inst, enc.Rd, kAddressSize, Operand::kActionWrite);
if (enc.Rn != kPCRegNum) {
AddIntRegOp(inst, enc.Rn, 32u, Operand::kActionRead);
AddIntRegOp(inst, enc.Rn, kAddressSize, Operand::kActionRead);
} else {
AddImmOp(inst, 0u);
}
AddIntRegOp(inst, enc.Rm, 32u, Operand::kActionRead);
AddIntRegOp(inst, enc.Rm, kAddressSize, Operand::kActionRead);
AddImmOp(inst, enc.rot << 3);
inst.category = Instruction::kCategoryNormal;
@@ -2781,8 +2929,8 @@ static bool TryBitExtract(Instruction &inst, uint32_t bits) {
return false;
}
AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite);
AddIntRegOp(inst, enc.Rn, 32u, Operand::kActionRead);
AddIntRegOp(inst, enc.Rd, kAddressSize, Operand::kActionWrite);
AddIntRegOp(inst, enc.Rn, kAddressSize, Operand::kActionRead);
AddImmOp(inst, enc.lsb);
AddImmOp(inst, enc.widthm1);
+40 -16
View File
@@ -28,13 +28,15 @@ T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) {
return result;
}
DEF_COND_SEM(AND, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(AND, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = Read(src2);
Write(dst, UAnd(Read(src1), value));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(ANDS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(ANDS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto value = Read(src2);
auto res = UAnd(Read(src1), value);
WriteZExt(dst, res);
@@ -43,16 +45,19 @@ DEF_COND_SEM(ANDS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
state.sr.c = Read(carry_out);
// PSTATE.V unchanged
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(EOR, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(EOR, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = Read(src2);
Write(dst, UXor(Read(src1), value));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(EORS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(EORS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto value = Read(src2);
auto res = UXor(Read(src1), value);
Write(dst, res);
@@ -61,90 +66,109 @@ DEF_COND_SEM(EORS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
state.sr.c = Read(carry_out);
// PSTATE.V unchanged
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(RSB, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(RSB, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = Read(src2);
Write(dst, USub(value, Read(src1)));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(RSBS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(RSBS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto rhs = Read(src2);
auto lhs = Read(src1);
auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(1));
Write(dst, res);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(SUB, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(SUB, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = Read(src2);
Write(dst, USub(Read(src1), value));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(SUBS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(SUBS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto rhs = Read(src2);
auto lhs = Read(src1);
auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(1));
Write(dst, res);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(ADD, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(ADD, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = Read(src2);
Write(dst, UAdd(Read(src1), value));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(ADDS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(ADDS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto rhs = Read(src2);
auto lhs = Read(src1);
auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(0));
Write(dst, res);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(ADC, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(ADC, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = Read(src2);
Write(dst, UAdd(UAdd(Read(src1), value), uint32_t(state.sr.c)));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(ADCS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(ADCS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto rhs = Read(src2);
auto lhs = Read(src1);
auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(state.sr.c));
Write(dst, res);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(SBC, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(SBC, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = Read(src2);
Write(dst, UAdd(UAdd(Read(src1), UNot(value)), uint32_t(state.sr.c)));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(SBCS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(SBCS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto rhs = Read(src2);
auto lhs = Read(src1);
auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(state.sr.c));
Write(dst, res);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(RSC, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(RSC, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = Read(src2);
Write(dst, UAdd(UAdd(value, UNot(Read(src1))), uint32_t(state.sr.c)));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(RSCS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(RSCS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto rhs = Read(src2);
auto lhs = Read(src1);
auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(state.sr.c));
Write(dst, res);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
} // namespace
+4 -3
View File
@@ -15,10 +15,11 @@
*/
namespace {
DEF_SEM(B, R8, R8W, I32 taken_pc, R32W next_pc_dst) {
DEF_SEM(B, R8, R8W, I32 taken_pc, PC next_pc_src, R32W next_pc_dst) {
auto new_pc = Read(taken_pc);
Write(REG_PC, new_pc);
Write(next_pc_dst, new_pc);
(void) next_pc_src;
return memory;
}
@@ -32,8 +33,8 @@ DEF_SEM(BCOND, R8 cond, R8W branch_taken, I32 taken_pc, I32 not_taken_pc,
return memory;
}
DEF_SEM(BL, R8, R8W, PC target_addr, PC ret_addr, R32W next_pc_dst,
R32W return_pc_dst) {
DEF_SEM(BL, R8, R8W, PC target_addr, PC ret_addr,
R32W next_pc_dst, R32W return_pc_dst) {
const auto return_pc = Read(ret_addr);
const auto new_pc = Read(target_addr);
Write(REG_LR, return_pc);
+11 -4
View File
@@ -15,14 +15,16 @@
*/
namespace {
DEF_COND_SEM(ORR, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(ORR, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = Read(src2);
auto result = UOr(Read(src1), value);
Write(dst, result);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(ORRS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(ORRS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto value = Read(src2);
auto result = UOr(Read(src1), value);
Write(dst, result);
@@ -32,17 +34,21 @@ DEF_COND_SEM(ORRS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
state.sr.c = Read(carry_out);
// PSTATE.V unchanged
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(BIC, R32W dst, R32 src1, I32 src2) {
DEF_COND_SEM(BIC, R32W dst, R32 src1, I32 src2, R32W maybe_next_pc_dst) {
auto value = UNot(Read(src2));
auto result = UAnd(Read(src1), value);
Write(dst, result);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(BICS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
DEF_COND_SEM(BICS, R32W dst, R32 src1, I32 src2, I8 carry_out,
R32W maybe_next_pc_dst) {
auto value = UNot(Read(src2));
auto result = UAnd(Read(src1), value);
Write(dst, result);
@@ -52,6 +58,7 @@ DEF_COND_SEM(BICS, R32W dst, R32 src1, I32 src2, I8 carry_out) {
state.sr.c = Read(carry_out);
// PSTATE.V unchanged
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
+107 -30
View File
@@ -17,105 +17,149 @@
namespace {
// Offset
DEF_COND_SEM(STR, M32W dst, R32 src1) {
DEF_COND_SEM(STR, M32W dst, R32 src1, R32W maybe_next_pc_dst) {
auto src = Read(src1);
Write(dst, src);
// ignore maybe_next_pc_dst since the semantic does not
// update program counter
(void) maybe_next_pc_dst;
return memory;
}
DEF_COND_SEM(STRB, M8W dst, R32 src1) {
DEF_COND_SEM(STRB, M8W dst, R32 src1, R32W maybe_next_pc_dst) {
auto src = Read(src1);
Write(dst, TruncTo<uint8_t>(src));
// ignore maybe_next_pc_dst since the semantic does not
// update program counter
(void) maybe_next_pc_dst;
return memory;
}
// Pre + Post
DEF_COND_SEM(STRp, M32W dst, R32 src1, R32W dst_reg, R32 src2) {
DEF_COND_SEM(STRp, M32W dst, R32 src1, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, src);
Write(dst_reg, new_val);
// update maybe_next_pc_dst with the PC; It may get ignored
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Pre + Post
DEF_COND_SEM(STRBp, M8W dst, R32 src1, R32W dst_reg, R32 src2) {
DEF_COND_SEM(STRBp, M8W dst, R32 src1, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, TruncTo<uint8_t>(src));
Write(dst_reg, new_val);
// update maybe_next_pc_dst with the PC; It may get ignored
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Offset
DEF_COND_SEM(LDR, M32 src1, R32W dst) {
DEF_COND_SEM(LDR, M32 src1, R32W dst, R32W maybe_next_pc_dst) {
auto src = Read(src1);
WriteZExt(dst, src);
// update maybe_next_pc_dst with the PC;
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Offset
DEF_COND_SEM(LDRB, M8 src1, R32W dst) {
DEF_COND_SEM(LDRB, M8 src1, R32W dst, R32W maybe_next_pc_dst) {
auto src = Read(src1);
WriteZExt(dst, src);
// update maybe_next_pc_dst with the PC;
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRp, M32 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRp, M32 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
// update maybe_next_pc_dst with the PC;
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRBp, M8 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRBp, M8 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
// update maybe_next_pc_dst with the PC;
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(STRT, M32W dst, R32 src1, R32W dst_reg, R32 src2) {
DEF_COND_SEM(STRT, M32W dst, R32 src1, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, TruncTo<uint32_t>(src));
Write(dst_reg, new_val);
// update maybe_next_pc_dst with the PC;
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(STRTB, M8W dst, R32 src1, R32W dst_reg, R32 src2) {
DEF_COND_SEM(STRTB, M8W dst, R32 src1, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, TruncTo<uint8_t>(src));
Write(dst_reg, new_val);
// update maybe_next_pc_dst with the PC;
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(LDRT, M32 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRT, M32 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
// update maybe_next_pc_dst with the PC;
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(LDRTB, M8 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRTB, M8 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
@@ -137,39 +181,49 @@ DEF_ISEL(LDRBT) = LDRTB;
namespace {
// Offset
DEF_COND_SEM(STRH, M16W dst, R32 src1) {
DEF_COND_SEM(STRH, M16W dst, R32 src1, R32W maybe_next_pc_dst) {
auto src = Read(src1);
Write(dst, TruncTo<uint16_t>(src));
// ignore maybe_next_pc_dst
(void) maybe_next_pc_dst;
return memory;
}
// Pre + Post
DEF_COND_SEM(STRHp, M16W dst, R32 src1, R32W dst_reg, R32 src2) {
DEF_COND_SEM(STRHp, M16W dst, R32 src1, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, TruncTo<uint16_t>(src));
Write(dst_reg, new_val);
// ignore maybe_next_pc_dst
(void) maybe_next_pc_dst;
return memory;
}
// Offset
DEF_COND_SEM(LDRH, M16 src1, R32W dst) {
DEF_COND_SEM(LDRH, M16 src1, R32W dst, R32W maybe_next_pc_dst) {
auto src = Read(src1);
WriteZExt(dst, src);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRHp, M16 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRHp, M16 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Offset
DEF_COND_SEM(STRD, M64W dst, R32 src1, R32 src2) {
DEF_COND_SEM(STRD, M64W dst, R32 src1, R32 src2, R32W maybe_next_pc_dst) {
auto lhs = UShl(ZExt<uint64_t>(Read(src2)), 32ul);
auto rhs = ZExt<uint64_t>(Read(src1));
auto src = UOr(lhs, rhs);
@@ -178,7 +232,8 @@ DEF_COND_SEM(STRD, M64W dst, R32 src1, R32 src2) {
}
// Pre + Post
DEF_COND_SEM(STRDp, M64W dst, R32 src1, R32 src2, R32W dst_reg, R32 src_new) {
DEF_COND_SEM(STRDp, M64W dst, R32 src1, R32 src2, R32W dst_reg, R32 src_new,
R32W maybe_next_pc_dst) {
auto lhs = UShl(ZExt<uint64_t>(Read(src2)), 32ul);
auto rhs = ZExt<uint64_t>(Read(src1));
auto src = UOr(lhs, rhs);
@@ -189,92 +244,109 @@ DEF_COND_SEM(STRDp, M64W dst, R32 src1, R32 src2, R32W dst_reg, R32 src_new) {
}
// Offset
DEF_COND_SEM(LDRD, M64 src1, R32W dst1, R32W dst2) {
DEF_COND_SEM(LDRD, M64 src1, R32W dst1, R32W dst2, R32W maybe_next_pc_dst) {
auto src = Read(src1);
Write(dst1, TruncTo<uint32_t>(src));
Write(dst2, TruncTo<uint32_t>(UShr(src, 32ul)));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRDp, M64 src1, R32W dst1, R32W dst2, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRDp, M64 src1, R32W dst1, R32W dst2, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst1, TruncTo<uint32_t>(src));
Write(dst2, TruncTo<uint32_t>(UShr(src, 32ul)));
Write(dst_reg, new_val);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Offset
DEF_COND_SEM(LDRSB, M8 src1, R32W dst) {
DEF_COND_SEM(LDRSB, M8 src1, R32W dst, R32W maybe_next_pc_dst) {
auto src = Read(src1);
WriteSExt(dst, src);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRSBp, M8 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRSBp, M8 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteSExt(dst, src);
Write(dst_reg, new_val);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Offset
DEF_COND_SEM(LDRSH, M16 src1, R32W dst) {
DEF_COND_SEM(LDRSH, M16 src1, R32W dst, R32W maybe_next_pc_dst) {
auto src = Read(src1);
WriteSExt(dst, src);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRSHp, M16 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRSHp, M16 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteSExt(dst, src);
Write(dst_reg, new_val);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(STRHT, M16W dst, R32 src1, R32W dst_reg, R32 src2) {
DEF_COND_SEM(STRHT, M16W dst, R32 src1, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteTrunc(dst, src);
Write(dst_reg, new_val);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(LDRHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRHT, M16 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(LDRSBT, M8 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRSBT, M8 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteSExt(dst, src);
Write(dst_reg, new_val);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(LDRSHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) {
DEF_COND_SEM(LDRSHT, M16 src1, R32W dst, R32W dst_reg, R32 src2,
R32W maybe_next_pc_dst) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteSExt(dst, src);
Write(dst_reg, new_val);
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
@@ -302,7 +374,8 @@ namespace {
DEF_COND_SEM(LDM, I16 reg_list, R32W dst, R32 dst_new, M32 src_mem, R32W dst0,
R32W dst1, R32W dst2, R32W dst3, R32W dst4, R32W dst5, R32W dst6,
R32W dst7, R32W dst8, R32W dst9, R32W dst10, R32W dst11,
R32W dst12, R32W dst13, R32W dst14, R32W dst15) {
R32W dst12, R32W dst13, R32W dst14, R32W dst15,
R32W maybe_next_pc_dst) {
auto regs = Read(reg_list);
uint32_t index = 0;
if (UAnd(regs, uint16_t(0b1u))) {
@@ -354,13 +427,14 @@ DEF_COND_SEM(LDM, I16 reg_list, R32W dst, R32 dst_new, M32 src_mem, R32W dst0,
Write(dst15, Read(GetElementPtr(src_mem, index++)));
}
Write(dst, Read(dst_new));
Write(maybe_next_pc_dst, Read(REG_PC));
return memory;
}
DEF_COND_SEM(STMDB, I16 reg_list, R32W dst, R32 dst_new, M32W dst_mem, R32 src0,
R32 src1, R32 src2, R32 src3, R32 src4, R32 src5, R32 src6,
R32 src7, R32 src8, R32 src9, R32 src10, R32 src11, R32 src12,
R32 src13, R32 src14, R32 src15) {
R32 src13, R32 src14, R32 src15, R32W maybe_next_pc_dst) {
auto regs = Read(reg_list);
uint32_t index = 0;
if (UAnd(regs, uint16_t(0b1u))) {
@@ -412,6 +486,9 @@ DEF_COND_SEM(STMDB, I16 reg_list, R32W dst, R32 dst_new, M32W dst_mem, R32 src0,
Write(GetElementPtr(dst_mem, index++), Read(src15));
}
Write(dst, Read(dst_new));
// ignore maybe_next_pc_dst
(void) maybe_next_pc_dst;
return memory;
}
} // namespace
+2
View File
@@ -29,4 +29,6 @@ const std::string_view kInvalidInstructionISelName = "INVALID_INSTRUCTION";
const std::string_view kUnsupportedInstructionISelName =
"UNSUPPORTED_INSTRUCTION";
const std::string_view kIgnoreNextPCVariableName = "IGNORE_NEXT_PC";
} // namespace remill
+33 -38
View File
@@ -781,9 +781,9 @@ static llvm::Constant *CloneConstant(llvm::Constant *val) {
#endif
static llvm::Function *DeclareFunctionInModule(
llvm::Function *func, llvm::Module *dest_module,
ValueMap &value_map) {
static llvm::Function *DeclareFunctionInModule(llvm::Function *func,
llvm::Module *dest_module,
ValueMap &value_map) {
auto &moved_func = value_map[func];
if (moved_func) {
@@ -792,9 +792,9 @@ static llvm::Function *DeclareFunctionInModule(
auto dest_func = dest_module->getFunction(func->getName());
if (dest_func) {
CHECK_EQ(RecontextualizeType(func->getFunctionType(),
dest_module->getContext()),
dest_func->getFunctionType());
CHECK_EQ(
RecontextualizeType(func->getFunctionType(), dest_module->getContext()),
dest_func->getFunctionType());
moved_func = dest_func;
return dest_func;
@@ -807,9 +807,8 @@ static llvm::Function *DeclareFunctionInModule(
const auto func_type = llvm::dyn_cast<llvm::FunctionType>(
RecontextualizeType(func->getFunctionType(), dest_module->getContext()));
dest_func =
llvm::Function::Create(func_type, func->getLinkage(),
func->getName(), dest_module);
dest_func = llvm::Function::Create(func_type, func->getLinkage(),
func->getName(), dest_module);
dest_func->copyAttributesFrom(func);
dest_func->setVisibility(func->getVisibility());
@@ -839,8 +838,9 @@ static void ClearMetaData(T *value) {
}
}
static llvm::Constant *MoveConstantIntoModule(
llvm::Constant *c, llvm::Module *dest_module, ValueMap &value_map) {
static llvm::Constant *MoveConstantIntoModule(llvm::Constant *c,
llvm::Module *dest_module,
ValueMap &value_map) {
auto &moved_c = value_map[c];
if (moved_c) {
@@ -855,10 +855,8 @@ static llvm::Constant *MoveConstantIntoModule(
type = ::remill::RecontextualizeType(type, dest_context);
} else {
#if LLVM_VERSION_NUMBER > LLVM_VERSION(3, 8)
if (!llvm::isa<llvm::Function>(c) &&
!llvm::isa<llvm::GlobalVariable>(c) &&
!llvm::isa<llvm::GlobalAlias>(c) &&
!c->needsRelocation()) {
if (!llvm::isa<llvm::Function>(c) && !llvm::isa<llvm::GlobalVariable>(c) &&
!llvm::isa<llvm::GlobalAlias>(c) && !c->needsRelocation()) {
moved_c = c;
return c;
}
@@ -889,8 +887,8 @@ static llvm::Constant *MoveConstantIntoModule(
moved_c = cf;
return cf;
} else {
auto ret = llvm::ConstantFP::get(
type, cf->getValueAPF().convertToDouble());
auto ret =
llvm::ConstantFP::get(type, cf->getValueAPF().convertToDouble());
moved_c = ret;
return ret;
}
@@ -908,8 +906,8 @@ static llvm::Constant *MoveConstantIntoModule(
moved_c = p;
return p;
} else {
auto ret = llvm::ConstantPointerNull::get(
llvm::cast<llvm::PointerType>(type));
auto ret =
llvm::ConstantPointerNull::get(llvm::cast<llvm::PointerType>(type));
moved_c = ret;
return ret;
}
@@ -1170,8 +1168,8 @@ static llvm::Constant *MoveConstantIntoModule(
g->getSourceElementType(), dest_context);
std::vector<llvm::Constant *> indices(ni);
for (auto i = 0u; i < ni; ++i) {
indices[i] = MoveConstantIntoModule(
ce->getOperand(i + 1u), dest_module, value_map);
indices[i] = MoveConstantIntoModule(ce->getOperand(i + 1u),
dest_module, value_map);
}
auto ret = llvm::ConstantExpr::getGetElementPtr(
source_type,
@@ -1310,8 +1308,8 @@ llvm::GlobalAlias *DeclareAliasInModule(llvm::GlobalAlias *var,
return llvm::dyn_cast<llvm::GlobalAlias>(moved_var);
}
const auto dest_type = llvm::dyn_cast<llvm::PointerType>(RecontextualizeType(
var->getType(), dest_module->getContext()));
const auto dest_type = llvm::dyn_cast<llvm::PointerType>(
RecontextualizeType(var->getType(), dest_module->getContext()));
for (auto &alias : dest_module->aliases()) {
if (alias.getName() == var->getName()) {
CHECK_EQ(dest_type, alias.getType());
@@ -1323,9 +1321,7 @@ llvm::GlobalAlias *DeclareAliasInModule(llvm::GlobalAlias *var,
const auto elem_type = dest_type->getElementType();
const auto dest_var = llvm::GlobalAlias::create(
elem_type, var->getType()->getAddressSpace(), var->getLinkage(),
var->getName(),
nullptr,
dest_module);
var->getName(), nullptr, dest_module);
moved_var = dest_var;
dest_var->setAliasee(
@@ -1338,6 +1334,7 @@ llvm::GlobalAlias *DeclareAliasInModule(llvm::GlobalAlias *var,
static void MoveInstructionIntoModule(llvm::Instruction *inst,
llvm::Module *dest_module,
ValueMap &value_map) {
// Substitute the operands.
for (auto &op : inst->operands()) {
auto new_val_it = value_map.find(op.get());
@@ -1375,8 +1372,8 @@ static void MoveInstructionIntoModule(llvm::Instruction *inst,
auto &new_callee_val = value_map[callee_val];
if (!new_callee_val) {
if (auto callee_const = llvm::dyn_cast<llvm::Constant>(callee_val)) {
new_callee_val = MoveConstantIntoModule(
callee_const, dest_module, value_map);
new_callee_val =
MoveConstantIntoModule(callee_const, dest_module, value_map);
} else {
new_callee_val = callee_val;
@@ -1477,8 +1474,7 @@ void CloneFunctionInto(llvm::Function *source_func, llvm::Function *dest_func,
// Replace all uses of a constant `old_c` with `new_c` inside of `module`.
//
// Returns the number of constant uses of `old_c`.
unsigned ReplaceAllUsesOfConstant(llvm::Constant *old_c,
llvm::Constant *new_c,
unsigned ReplaceAllUsesOfConstant(llvm::Constant *old_c, llvm::Constant *new_c,
llvm::Module *module) {
std::vector<llvm::Use *> repls;
for (auto &use : old_c->uses()) {
@@ -1493,7 +1489,7 @@ unsigned ReplaceAllUsesOfConstant(llvm::Constant *old_c,
while (!repls.empty()) {
const auto use = repls.back();
llvm::User * const user = use->getUser();
llvm::User *const user = use->getUser();
repls.pop_back();
const auto used_c = llvm::dyn_cast<llvm::Constant>(use);
@@ -1510,8 +1506,7 @@ unsigned ReplaceAllUsesOfConstant(llvm::Constant *old_c,
use->set(MoveConstantIntoModule(used_c, module, value_map));
} else {
LOG(ERROR)
<< "Unrecognized user type";
LOG(ERROR) << "Unrecognized user type";
}
}
@@ -1540,7 +1535,8 @@ void MoveFunctionIntoModule(llvm::Function *func, llvm::Module *dest_module) {
existing_decl_in_dest_module->setName(llvm::Twine::createNull());
existing_decl_in_dest_module->setLinkage(llvm::GlobalValue::PrivateLinkage);
existing_decl_in_dest_module->setVisibility(llvm::GlobalValue::DefaultVisibility);
existing_decl_in_dest_module->setVisibility(
llvm::GlobalValue::DefaultVisibility);
}
const auto in_same_context = source_context == dest_context;
@@ -1548,8 +1544,7 @@ void MoveFunctionIntoModule(llvm::Function *func, llvm::Module *dest_module) {
// We need to possibly preserve `func` as a declaration in its source module.
func->setName(llvm::Twine::createNull());
auto replacement_decl_in_source_module = llvm::Function::Create(
func->getFunctionType(), func->getLinkage(), func_name,
source_module);
func->getFunctionType(), func->getLinkage(), func_name, source_module);
replacement_decl_in_source_module->copyAttributesFrom(func);
replacement_decl_in_source_module->setVisibility(func->getVisibility());
@@ -1584,8 +1579,8 @@ void MoveFunctionIntoModule(llvm::Function *func, llvm::Module *dest_module) {
// constants that instead use `func`.
if (existing_decl_in_dest_module) {
value_map.emplace(existing_decl_in_dest_module, func);
if (!ReplaceAllUsesOfConstant(existing_decl_in_dest_module,
func, dest_module)) {
if (!ReplaceAllUsesOfConstant(existing_decl_in_dest_module, func,
dest_module)) {
existing_decl_in_dest_module->eraseFromParent();
}
existing_decl_in_dest_module = nullptr;