Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ps2xRecomp/src/lib/code_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,12 @@ namespace ps2recomp
}
}

// Safety fallback: if execution reaches here, the function boundary
// was incomplete (missing jr $ra). Return via $ra to prevent ctx->pc
// from being left in a bad state, which would cascade returns up the
// entire call chain. For correctly-terminated functions this is
// unreachable dead code after the jr $ra return block.
ss << " ctx->pc = GPR_U32(ctx, 31); return;\n";
ss << "}\n";
return ss.str();
}
Expand Down
14 changes: 13 additions & 1 deletion ps2xRecomp/src/lib/ps2_recompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,10 +636,22 @@ namespace ps2recomp

const Function *containingFunction = findContainingFunction(function.start);
uint32_t sliceEndAddress = containingFunction ? containingFunction->end : function.end;
// Only clamp to boundaries OUTSIDE the containing function.
// Sub-functions inside the parent (e.g. Ghidra-detected sub_xxx)
// must not truncate sibling entry slices that share the parent range.
uint32_t parentEnd = sliceEndAddress;
auto nextIt = std::upper_bound(boundaryStarts.begin(), boundaryStarts.end(), function.start);
if (nextIt != boundaryStarts.end() && *nextIt < sliceEndAddress)
while (nextIt != boundaryStarts.end() && *nextIt < parentEnd)
{
// Skip boundaries inside the containing function — they are
// sub-functions, not real function starts that should truncate us.
if (containingFunction && *nextIt < containingFunction->end)
{
++nextIt;
continue;
}
sliceEndAddress = *nextIt;
break;
}

if (sliceEndAddress <= function.start)
Expand Down