mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 16:59:35 -04:00
fix(recomp): advance ctx->pc on fallthrough functions with no terminating branch (#168)
* fix(recomp): advance ctx->pc on fallthrough functions with no terminating branch FunctionEmitter::emit only ever advances ctx->pc via the per-instruction `ctx->pc = 0x<addr>u;` assignment (overwritten by the next instruction in the same function) or via handleBranchDelaySlots when the last instruction is a branch/jump. A function whose last instruction is neither (e.g. a lone padduw/NOP-style instruction with no terminator) leaves ctx->pc pointing at its own last instruction forever after returning, since nothing ever advances it to the next function. dispatchLoop then reads ctx->pc, looks up the same function, and calls it again -- forever. No exception, no crash, just an infinite loop that silently never makes forward progress. Reproduced on SDBZ's SLUS_214.42 ELF entry point: 0x100008 is emitted as a standalone 1-instruction function (padduw $at, $zero, $zero) with no branch, causing dispatchLoop to spin on pc=0x100008 indefinitely. Fix: track whether the last processed instruction had a delay slot (i.e. was a branch/jump); if the function ends without one, emit an unconditional ctx->pc = function.end before closing the function so dispatchLoop resumes at the next function instead of spinning. * review: trim overly verbose comment per ran-j feedback
This commit is contained in:
@@ -103,9 +103,12 @@ namespace ps2recomp
|
||||
<< std::dec;
|
||||
ss << "\n";
|
||||
|
||||
bool lastInstructionWasControlFlow = false;
|
||||
|
||||
for (size_t i = 0; i < instructions.size(); ++i)
|
||||
{
|
||||
const Instruction &inst = instructions[i];
|
||||
lastInstructionWasControlFlow = inst.hasDelaySlot;
|
||||
|
||||
if (internalTargets.contains(inst.address))
|
||||
{
|
||||
@@ -223,6 +226,13 @@ namespace ps2recomp
|
||||
}
|
||||
}
|
||||
|
||||
// Fallthrough with no terminating branch: advance ctx->pc past the function so dispatchLoop doesn't re-call it forever.
|
||||
if (!instructions.empty() && !lastInstructionWasControlFlow)
|
||||
{
|
||||
ss << " ctx->pc = 0x" << std::hex << function.end << "u;\n"
|
||||
<< std::dec;
|
||||
}
|
||||
|
||||
ss << "}\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user