mirror of
https://github.com/lifting-bits/remill
synced 2026-06-21 13:56:07 +00:00
treat all pop to pc as function return (#502)
Update semantics to handle function returns and indirect jumps
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user