Skip to content

Commit fcc74e6

Browse files
committed
Fix truncated function codegen: safety fallback + entry slice boundary fix
Two fixes for functions that end without jr $ra (issue #86): 1. code_generator.cpp: Emit implicit `ctx->pc = GPR_U32(ctx, 31); return;` at end of every generated function. For correct functions this is unreachable dead code. For functions with wrong TOML/CSV boundaries, it returns via $ra instead of leaving ctx->pc in a bad state that cascades returns up the entire call chain. 2. ps2_recompiler.cpp: When reslicing entry functions, skip boundary starts that fall inside the containing parent function. Ghidra sub-functions (sub_xxx) inside a parent were creating false boundaries that truncated sibling entry slices before their jr $ra.
1 parent 553a902 commit fcc74e6

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

ps2xRecomp/src/lib/code_generator.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,12 @@ namespace ps2recomp
10031003
}
10041004
}
10051005

1006+
// Safety fallback: if execution reaches here, the function boundary
1007+
// was incomplete (missing jr $ra). Return via $ra to prevent ctx->pc
1008+
// from being left in a bad state, which would cascade returns up the
1009+
// entire call chain. For correctly-terminated functions this is
1010+
// unreachable dead code after the jr $ra return block.
1011+
ss << " ctx->pc = GPR_U32(ctx, 31); return;\n";
10061012
ss << "}\n";
10071013
return ss.str();
10081014
}

ps2xRecomp/src/lib/ps2_recompiler.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,10 +636,22 @@ namespace ps2recomp
636636

637637
const Function *containingFunction = findContainingFunction(function.start);
638638
uint32_t sliceEndAddress = containingFunction ? containingFunction->end : function.end;
639+
// Only clamp to boundaries OUTSIDE the containing function.
640+
// Sub-functions inside the parent (e.g. Ghidra-detected sub_xxx)
641+
// must not truncate sibling entry slices that share the parent range.
642+
uint32_t parentEnd = sliceEndAddress;
639643
auto nextIt = std::upper_bound(boundaryStarts.begin(), boundaryStarts.end(), function.start);
640-
if (nextIt != boundaryStarts.end() && *nextIt < sliceEndAddress)
644+
while (nextIt != boundaryStarts.end() && *nextIt < parentEnd)
641645
{
646+
// Skip boundaries inside the containing function — they are
647+
// sub-functions, not real function starts that should truncate us.
648+
if (containingFunction && *nextIt < containingFunction->end)
649+
{
650+
++nextIt;
651+
continue;
652+
}
642653
sliceEndAddress = *nextIt;
654+
break;
643655
}
644656

645657
if (sliceEndAddress <= function.start)

0 commit comments

Comments
 (0)