From d93823cd7286cfdbcc7f6f3586a3235737eb8b0d Mon Sep 17 00:00:00 2001 From: kumarak Date: Tue, 6 Apr 2021 18:26:22 -0400 Subject: [PATCH] treat all pop to pc as function return (#502) Update semantics to handle function returns and indirect jumps --- include/remill/BC/ABI.h | 1 + lib/Arch/AArch32/Arch.cpp | 5 +- lib/Arch/AArch32/Decode.cpp | 266 +++++++++++++++++++------ lib/Arch/AArch32/Semantics/BINARY.cpp | 56 ++++-- lib/Arch/AArch32/Semantics/BRANCH.cpp | 7 +- lib/Arch/AArch32/Semantics/LOGICAL.cpp | 15 +- lib/Arch/AArch32/Semantics/MEM.cpp | 137 ++++++++++--- lib/BC/ABI.cpp | 2 + lib/BC/Util.cpp | 71 +++---- 9 files changed, 409 insertions(+), 151 deletions(-) diff --git a/include/remill/BC/ABI.h b/include/remill/BC/ABI.h index 6400a545..682a5da7 100644 --- a/include/remill/BC/ABI.h +++ b/include/remill/BC/ABI.h @@ -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 diff --git a/lib/Arch/AArch32/Arch.cpp b/lib/Arch/AArch32/Arch.cpp index c44af8ec..853859d2 100644 --- a/lib/Arch/AArch32/Arch.cpp +++ b/lib/Arch/AArch32/Arch.cpp @@ -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); diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 7e007aea..853435fe 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -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(inst.pc & ~(3u)) - static_cast(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(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); diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index ebd88b94..4b780ec9 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -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 diff --git a/lib/Arch/AArch32/Semantics/BRANCH.cpp b/lib/Arch/AArch32/Semantics/BRANCH.cpp index 422de586..fce58d1f 100644 --- a/lib/Arch/AArch32/Semantics/BRANCH.cpp +++ b/lib/Arch/AArch32/Semantics/BRANCH.cpp @@ -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); diff --git a/lib/Arch/AArch32/Semantics/LOGICAL.cpp b/lib/Arch/AArch32/Semantics/LOGICAL.cpp index bdeb986c..b6c5617b 100644 --- a/lib/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/lib/Arch/AArch32/Semantics/LOGICAL.cpp @@ -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; } diff --git a/lib/Arch/AArch32/Semantics/MEM.cpp b/lib/Arch/AArch32/Semantics/MEM.cpp index d1990ef4..bfa1a446 100644 --- a/lib/Arch/AArch32/Semantics/MEM.cpp +++ b/lib/Arch/AArch32/Semantics/MEM.cpp @@ -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(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(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(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(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(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(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(Read(src2)), 32ul); auto rhs = ZExt(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(Read(src2)), 32ul); auto rhs = ZExt(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(src)); Write(dst2, TruncTo(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(src)); Write(dst2, TruncTo(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 diff --git a/lib/BC/ABI.cpp b/lib/BC/ABI.cpp index e9a353d9..f8682af7 100644 --- a/lib/BC/ABI.cpp +++ b/lib/BC/ABI.cpp @@ -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 diff --git a/lib/BC/Util.cpp b/lib/BC/Util.cpp index f5930b9d..b8c5810c 100644 --- a/lib/BC/Util.cpp +++ b/lib/BC/Util.cpp @@ -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( 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(c) && - !llvm::isa(c) && - !llvm::isa(c) && - !c->needsRelocation()) { + if (!llvm::isa(c) && !llvm::isa(c) && + !llvm::isa(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(type)); + auto ret = + llvm::ConstantPointerNull::get(llvm::cast(type)); moved_c = ret; return ret; } @@ -1170,8 +1168,8 @@ static llvm::Constant *MoveConstantIntoModule( g->getSourceElementType(), dest_context); std::vector 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(moved_var); } - const auto dest_type = llvm::dyn_cast(RecontextualizeType( - var->getType(), dest_module->getContext())); + const auto dest_type = llvm::dyn_cast( + 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(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 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(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;