mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-05-15 07:29:46 -05:00
recomp: SectionAbsolute guard + reloc filter + runtime-fragment decl
Three engine fixes uncovered by Stadium fragment dispatch: 1. recompilation.cpp: SectionAbsolute guard in print_func_call_by_address. Stadium's .fragmentN sections JAL into SHN_ABS symbols (e.g. osGbpakReadWrite); resolve_jal indexed context.sections[] at 65534 and segfaulted on first dispatch. Skip reloc resolution when reloc_section >= context.sections.size(). 2. main.cpp (overlay table emit): filter unsupported MIPS reloc types before indexing reloc_names[]. Stadium's .rel.fragmentN includes R_MIPS_PC16 (type 10) which the recompiler doesn't model; the OOB read embedded a NUL byte in the .type field and broke the C compile. 3. main.cpp: bounds-check inversion in the static-funcs scan (read section_funcs[size] before checking i < size). Latent bug exposed by .fragment1's larger CreateStatic surface. 4. recomp.h: forward-declare recomp_register_runtime_fragment so funcs files can call it from inlined hook text generated by [[patches.hook]] on Memmap_RelocateFragment. (NOTE: original local commit de76241 also added a recomp_unhandled_* forward-decl family; those declarations are dropped from this PR — they violate the no-stubs principle and depend on a runtime API not yet in upstream N64ModernRuntime.) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
81213c1831
commit
5fe2c734a5
|
|
@ -468,6 +468,16 @@ void recomp_syscall_handler(uint8_t* rdram, recomp_context* ctx, int32_t instruc
|
|||
|
||||
void pause_self(uint8_t *rdram);
|
||||
|
||||
/* Runtime fragment registrar — invoked from a Memmap_RelocateFragment
|
||||
* hook (see Stadium's game.toml). Translates Stadium's encoded fragment
|
||||
* id to the matching section in the recompiled section_table and
|
||||
* registers all of that section's FuncEntry rows in func_map at
|
||||
* (fragment_ptr + offset). Also runs the trampoline scanner over the
|
||||
* fragment's textbin region. Implemented in
|
||||
* librecomp/src/overlays.cpp. */
|
||||
void recomp_register_runtime_fragment(uint8_t *rdram, uint32_t id,
|
||||
int32_t fragment_ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
19
src/main.cpp
19
src/main.cpp
|
|
@ -792,7 +792,12 @@ int main(int argc, char** argv) {
|
|||
// Determine the end of this static function
|
||||
uint32_t cur_func_end = static_cast<uint32_t>(section.size + section.ram_addr);
|
||||
|
||||
// Search for the closest function
|
||||
// Search for the closest function. The bounds check must come
|
||||
// first — the previous order read section_funcs[size] before
|
||||
// exiting, which is OOB and segfaults for static funcs whose
|
||||
// address lies past the last known function in the section
|
||||
// (observed in Stadium's .fragment1 once it was marked
|
||||
// relocatable, which exposes more CreateStatic targets).
|
||||
size_t closest_func_index = 0;
|
||||
while (closest_func_index < section_funcs.size() && section_funcs[closest_func_index] < static_func_addr) {
|
||||
closest_func_index++;
|
||||
|
|
@ -951,6 +956,18 @@ int main(int argc, char** argv) {
|
|||
for (const N64Recomp::Reloc& reloc : section_relocs) {
|
||||
bool emit_reloc = false;
|
||||
uint16_t target_section = reloc.target_section;
|
||||
// Skip relocs whose type the runtime doesn't understand
|
||||
// (e.g. R_MIPS_PC16, R_MIPS_GOT16) — these come through
|
||||
// the ELF parser as raw cast values and would index
|
||||
// reloc_names out of bounds, producing a NUL byte in
|
||||
// the .type field of the emitted RelocEntry. Stadium's
|
||||
// .rel.fragment* sections include R_MIPS_PC16 (type
|
||||
// 10) for branches; the recompiler resolves those
|
||||
// statically already, so dropping them here is safe.
|
||||
size_t type_idx = static_cast<size_t>(reloc.type);
|
||||
if (type_idx >= reloc_names.size()) {
|
||||
continue;
|
||||
}
|
||||
// In reference symbol mode, only emit relocations into the table that point to
|
||||
// non-absolute reference symbols, events, or manual patch symbols.
|
||||
if (reference_symbol_mode) {
|
||||
|
|
|
|||
|
|
@ -297,8 +297,16 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con
|
|||
}
|
||||
else {
|
||||
uint32_t target_section = func.section_index;
|
||||
// If this instruction has a reloc and the target section is a normal section, use the section of the reloc when searching for a matching target function.
|
||||
if (has_reloc && reloc_section < 65500) {
|
||||
// Only override target_section when the reloc points at a real
|
||||
// section. SectionAbsolute / SectionImport / SectionEvent are
|
||||
// special sentinels (negative when interpreted signed) and
|
||||
// would index context.sections out of bounds — observed when
|
||||
// marking Stadium's .fragment1 relocatable, which surfaces
|
||||
// R_MIPS_26 relocs whose ELF symbol lives in SHN_ABS (the
|
||||
// absolute address is already encoded in the JAL immediate,
|
||||
// so the in-section function lookup against the caller's
|
||||
// section is the right fallback).
|
||||
if (has_reloc && reloc_section < context.sections.size()) {
|
||||
target_section = reloc_section;
|
||||
}
|
||||
JalResolutionResult jal_result = resolve_jal(context, target_section, target_func_vram, matched_func_index);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user