mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-05-15 07:29:46 -05:00
decompressed: sort section.relocs by address after parsing
The recompiler walks instructions linearly and advances
reloc_index only forward (recompilation.cpp: while
section.relocs[reloc_index].address < vram). This requires the
section's relocs to be sorted by address — out-of-order entries
are skipped silently and emitted as literal immediates instead of
RELOC_HI16/RELOC_LO16/RELOC_R_MIPS_26 macros.
Stadium's raw fragment reloc table orders entries by HI16+LO16
pair adjacency, NOT by instruction address. For stadium_models
sub-fragment 4 (variant 384, hash 0x242995EF6B92F471), the raw
table holds:
[HI16 @ off 0x50][HI16 @ off 0x30][LO16 @ off 0x60]
Both HI16 entries pair correctly via raw-list adjacency
(target_section_offset is computed before this sort). But when
the recompiler walks instruction at PC 0x8FF00030, the
already-advanced reloc_index points at the entry for offset 0x50
(seen first in raw order) and the address comparison fails. The
HI16 at 0x30 is silently skipped and emitted as the literal
`S32(0x8FF1 << 16)`.
The matching LO16 at 0x60 IS encountered in linear order, so it
emits correctly as `RELOC_LO16(384, 0xB14C)`. The asymmetric pair
produces:
ctx->r3 = S32(0x8FF1 << 16); // HI literal
ctx->r2 = ADD32(ctx->r3,
(int16_t)RELOC_LO16(384, 0xB14C)); // LO reloc'd
For section 384 with runtime base 0x8027FAB0, RELOC_LO16(384,
0xB14C) sign-extends to -0x5404, yielding `0x8FF10000 + (-0x5404)
= 0x8FF0ABFC` instead of the intended `runtime_base + 0xB14C =
0x8028ABFC`. The result lands back in the pattern bucket and
process_geo_layout walks bogus geo data → cmd_byte=0xFF →
lookup-miss 0x00000E00 → crash.
Fix: std::sort section_out.relocs by address ascending after
parsing. Pairing has already been computed via raw-list adjacency
(which is independent of address), so the sort only affects the
recompiler's lookup order. Verified: variant 384's recompiled C
now emits all three lui instructions as RELOC_HI16(384, ...),
attract demo no longer crashes on 0x8FF0ABFC.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6f9649c7e7
commit
152d463ff4
|
|
@ -1,5 +1,6 @@
|
|||
#include "decompressed.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
|
@ -239,6 +240,25 @@ bool parse_fragment_relocs(const std::vector<uint8_t>& bytes,
|
|||
}
|
||||
}
|
||||
|
||||
// The recompiler walks instructions linearly and advances
|
||||
// reloc_index only forward (recompilation.cpp: while
|
||||
// section.relocs[reloc_index].address < vram). It REQUIRES the
|
||||
// relocs to be sorted by address — out-of-order entries are
|
||||
// skipped silently and emitted as literal immediates.
|
||||
//
|
||||
// Stadium's raw reloc table is ordered by HI16+LO16 pair
|
||||
// adjacency, NOT by instruction address. For example, in
|
||||
// stadium_models sub-fragment 4 (variant 384), the table holds:
|
||||
// [HI16 @ off 0x50][HI16 @ off 0x30][LO16 @ off 0x60]
|
||||
// Pairing has already baked target_section_offset above (the
|
||||
// HI16 at 0x30 pairs with the LO16 at 0x60 via raw-list
|
||||
// adjacency, which is independent of address). Now sort by
|
||||
// address so the recompiler's linear walk hits every entry.
|
||||
std::sort(section_out.relocs.begin(), section_out.relocs.end(),
|
||||
[](const Reloc& a, const Reloc& b) {
|
||||
return a.address < b.address;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user