Skip to content

Commit c9ddc18

Browse files
committed
Fix inline return handling for nonstandard return registers
Avoid treating LLIL_JUMP(reg) as an inline return when the inlined callee writes to that register before returning. Only suppress normal return-address setup after proving the callee actually returns through an unmodified caller-recorded return-address register Also share the call-return rewrite path with direct LLIL_JUMP forms that have call-like semantics, so nonstandard direct-call patterns get the same return, jump, and tail-call handling as LLIL_CALL
1 parent a872917 commit c9ddc18

1 file changed

Lines changed: 62 additions & 13 deletions

File tree

defaultarch.cpp

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,37 @@ static bool IsReturnAddressRegisterExpr(LowLevelILInstruction expr, const set<ui
4848
}
4949

5050

51+
static void RemoveWrittenReturnAddressRegisters(LowLevelILInstruction instr, set<uint32_t>& returnAddressRegisters)
52+
{
53+
switch (instr.operation)
54+
{
55+
case LLIL_SET_REG:
56+
returnAddressRegisters.erase(instr.GetDestRegister<LLIL_SET_REG>());
57+
break;
58+
case LLIL_SET_REG_SPLIT:
59+
returnAddressRegisters.erase(instr.GetHighRegister<LLIL_SET_REG_SPLIT>());
60+
returnAddressRegisters.erase(instr.GetLowRegister<LLIL_SET_REG_SPLIT>());
61+
break;
62+
default:
63+
break;
64+
}
65+
}
66+
67+
68+
static bool IsReturnAddressRegisterJumpOrReturn(LowLevelILInstruction instr, const set<uint32_t>& returnAddressRegisters)
69+
{
70+
switch (instr.operation)
71+
{
72+
case LLIL_JUMP:
73+
return IsReturnAddressRegisterExpr(instr.GetDestExpr<LLIL_JUMP>(), returnAddressRegisters);
74+
case LLIL_RET:
75+
return IsReturnAddressRegisterExpr(instr.GetDestExpr<LLIL_RET>(), returnAddressRegisters);
76+
default:
77+
return false;
78+
}
79+
}
80+
81+
5182
void Architecture::DefaultAnalyzeBasicBlocks(Function* function, BasicBlockAnalysisContext& context)
5283
{
5384
auto data = function->GetView();
@@ -1033,11 +1064,34 @@ void FunctionLifterContext::CheckForInlinedCall(BasicBlock* block, size_t instrC
10331064
if (IsConstantPointer(instr.GetSourceExpr<LLIL_SET_REG>(), addr))
10341065
returnAddressRegisters.insert(instr.GetDestRegister<LLIL_SET_REG>());
10351066
}
1067+
bool hasCallSemantics = lastInstr.operation == LLIL_CALL
1068+
|| (lastInstr.operation == LLIL_JUMP && !returnAddressRegisters.empty());
10361069

1037-
if (lastInstr.operation == LLIL_CALL && returnAddressRegisters.empty())
1070+
// Copy the inlined code from the target function
1071+
Ref<Architecture> callArch = block->GetArchitecture();
1072+
auto blocks = PrepareToCopyForeignFunction(targetIL);
1073+
auto unresolvedIndirectBranches = targetFunc->GetUnresolvedIndirectBranches();
1074+
auto sourceLocation = inlineDuringAnalysis == InlineUsingCallAddress ? ILSourceLocation(lastInstr) : ILSourceLocation();
1075+
set<uint32_t> unmodifiedReturnAddressRegisters = returnAddressRegisters;
1076+
bool calleeReturnsThroughCallerReturnAddressRegister = false;
1077+
for (auto& block : blocks)
1078+
{
1079+
for (size_t instrIndex = block->GetStart(); instrIndex < block->GetEnd(); instrIndex++)
1080+
RemoveWrittenReturnAddressRegisters(targetIL->GetInstruction(instrIndex), unmodifiedReturnAddressRegisters);
1081+
}
1082+
for (auto& block : blocks)
1083+
{
1084+
for (size_t instrIndex = block->GetStart(); instrIndex < block->GetEnd(); instrIndex++)
1085+
{
1086+
if (IsReturnAddressRegisterJumpOrReturn(
1087+
targetIL->GetInstruction(instrIndex), unmodifiedReturnAddressRegisters))
1088+
calleeReturnsThroughCallerReturnAddressRegister = true;
1089+
}
1090+
}
1091+
1092+
if (hasCallSemantics && !calleeReturnsThroughCallerReturnAddressRegister)
10381093
{
10391094
// Set up return address according to the architecture
1040-
// TODO: Handle architectures that use a nonstandard way of calling functions
10411095
uint32_t linkReg = m_platform->GetArchitecture()->GetLinkRegister();
10421096
if (linkReg == BN_INVALID_REGISTER)
10431097
{
@@ -1056,20 +1110,14 @@ void FunctionLifterContext::CheckForInlinedCall(BasicBlock* block, size_t instrC
10561110

10571111
uint64_t addrToSet = addr;
10581112
if (block->GetArchitecture()->GetName() == "thumb2")
1059-
addrToSet |= 1; // XXX: hack moved here from lowlevelilfunction.cpp
1113+
addrToSet |= 1;
10601114

10611115
ExprId linkExpr = m_function->SetRegister(
10621116
regInfo.size, linkReg, m_function->ConstPointer(regInfo.size, addrToSet, lastInstr), 0, lastInstr);
10631117
m_function->SetExprAttributes(linkExpr, ILAllowDeadStoreElimination);
10641118
m_function->AddInstruction(linkExpr);
10651119
}
10661120
}
1067-
1068-
// Copy the inlined code from the target function
1069-
Ref<Architecture> callArch = block->GetArchitecture();
1070-
auto blocks = PrepareToCopyForeignFunction(targetIL);
1071-
auto unresolvedIndirectBranches = targetFunc->GetUnresolvedIndirectBranches();
1072-
auto sourceLocation = inlineDuringAnalysis == InlineUsingCallAddress ? ILSourceLocation(lastInstr) : ILSourceLocation();
10731121
for (auto& block : blocks)
10741122
{
10751123
m_function->PrepareToCopyBlock(block);
@@ -1078,7 +1126,7 @@ void FunctionLifterContext::CheckForInlinedCall(BasicBlock* block, size_t instrC
10781126
LowLevelILInstruction instr = targetIL->GetInstruction(instrIndex);
10791127
ArchAndAddr loc(block->GetArchitecture(), instr.address);
10801128

1081-
if (lastInstr.operation == LLIL_CALL && instr.operation == LLIL_RET)
1129+
if (hasCallSemantics && instr.operation == LLIL_RET)
10821130
{
10831131
// If the instruction is a return, emit the computation of the target
10841132
// location (it may affect the stack pointer) but go directly to the
@@ -1089,14 +1137,15 @@ void FunctionLifterContext::CheckForInlinedCall(BasicBlock* block, size_t instrC
10891137
m_function->AddInstruction(instr.GetDestExpr<LLIL_RET>().CopyTo(m_function, sourceLocation));
10901138
m_function->AddInstruction(m_function->Goto(end, sourceLocation));
10911139
}
1092-
else if (lastInstr.operation == LLIL_CALL && instr.operation == LLIL_JUMP
1140+
else if (hasCallSemantics && instr.operation == LLIL_JUMP
10931141
&& (block->GetArchitecture() == callArch)
10941142
&& (IsConstantPointer(instr.GetDestExpr<LLIL_JUMP>(), addr)
1095-
|| IsReturnAddressRegisterExpr(instr.GetDestExpr<LLIL_JUMP>(), returnAddressRegisters)))
1143+
|| IsReturnAddressRegisterExpr(instr.GetDestExpr<LLIL_JUMP>(),
1144+
unmodifiedReturnAddressRegisters)))
10961145
{
10971146
m_function->AddInstruction(m_function->Goto(end, sourceLocation));
10981147
}
1099-
else if (lastInstr.operation == LLIL_CALL && instr.operation == LLIL_JUMP
1148+
else if (hasCallSemantics && instr.operation == LLIL_JUMP
11001149
&& block->GetOutgoingEdges().empty() && (unresolvedIndirectBranches.count(loc) == 0))
11011150
{
11021151
// Jump without outgoing edges in the graph, and it is not marked as having

0 commit comments

Comments
 (0)