Root cause: the per-section indexing used throughout this investigation was wrong

The verification f2d7e7e asked for. Reference case: the tool disassembles
0x2ee138 as 0x4bc00083; reading the flat overlay at 0x2ee138 - LIT_BASE gives
83 00 c0 4b, little-endian 0x4bc00083. Match. Correct mapping is
off = ram - LIT_BASE indexed into the whole overlay.bin.

What I used in every probe: off = addr - secs[6].dest indexed into secs[6].data,
and OverlaySection::data includes the 16-byte section header. Every read was
displaced.

Invalidated:
- cee17c9's addiu r17, r18, 0xc0 disassembly, the 16-byte-stride walk, and the
  'address not float' conclusion. Built on wrong bytes.
- the immediate-frequency and neighbour-enrichment numbers in 3ea5ab7 and
  a2f8c92. Scanned per-function windows, so uniformly displaced: ratios are
  probably robust, exact counts are not measured on the bytes they claim.
- e1482ab, d97e7df, f2d7e7e: the jal decoding was verified correct, so branch
  targets stand; what lives at them was read wrongly.

Survives intact: every chunk-offset measurement in the tie and overlay work,
which read core_data and the overlay flat and never went through the section
index.

Fix: never index secs[n].data by addr - secs[n].dest. Either use
overlay[addr - LIT_BASE], or add a helper that accounts for the 16-byte header so
call sites cannot forget it -- and verify it against a word the decomp pins, as
above.

This was available from the first probe and skipped sixteen times.

284 passing with the disc present, clippy clean.
This commit is contained in:
2026-10-14 06:14:14 +02:00
parent f2d7e7ecd4
commit e6b3e0b091
+50
View File
@@ -2400,3 +2400,53 @@ independently known, and only then re-read `0x2ee138`. Until that mapping is
verified, **no address in this investigation that I computed by hand is verified, **no address in this investigation that I computed by hand is
trustworthy** -- including the `0x3a8060` walk, which happened to decode but may trustworthy** -- including the `0x3a8060` walk, which happened to decode but may
have been read from the wrong bytes. have been read from the wrong bytes.
### Root cause verified: the per-section indexing used throughout was wrong
The check `f2d7e7e` asked for, finally performed.
**Reference case:** `tools/overlay-anchors` disassembles `0x2ee138` as
`0x4bc00083`. Reading the flat overlay at `0x2ee138 - LIT_BASE` gives the bytes
`83 00 c0 4b`, which is little-endian `0x4bc00083`. **Match.** The correct mapping
is
off = ram_address - LIT_BASE, indexed into the whole overlay.bin
with `LIT_BASE = 0x1A7C80`.
**What I used instead**, in every probe in this investigation:
off = addr - secs[6].dest, indexed into secs[6].data
and `OverlaySection::data` **includes the 16-byte section header** ("the 16-byte
header included, since it is the first `size` bytes of the section in the table",
`overlay_reloc.rs`). So every read was displaced, and the addresses I printed
against the bytes they actually came from were wrong.
**Scope of the invalidation, stated as precisely as I can:**
- `cee17c9` -- the `addiu r17, r18, 0xc0` disassembly, the 16-byte-stride walk,
the "it is an address not a float" conclusion. **Built on wrong bytes.**
- `3ea5ab7`, `a2f8c92` -- the immediate-frequency and neighbour-enrichment
numbers. These scanned `[off, off+size)` per function, so each window was
displaced by a constant. A uniform displacement preserves most of a function's
body and loses the first few instructions, so the counts are *approximately*
right and the ratios are probably robust -- but they are not measured on the
bytes they claim to measure, and cannot be quoted as exact.
- `e1482ab`, `d97e7df`, `f2d7e7e` -- the `jal` decoding itself was verified
correct, so the branch *targets* stand; it is what lives at them that was read
wrongly.
**The one result that survives intact** is the one that never went through the
section index at all: the chunk-offset measurements in the tie and overlay work,
which read `core_data` and the overlay flat.
**The fix, for whoever continues:** never index `secs[n].data` by
`addr - secs[n].dest`. Either use `overlay[addr - LIT_BASE]`, or add a helper that
subtracts the 16-byte header from `data` and states that it does. The second is
better -- it puts the header in one place instead of making every call site
remember.
And then: **verify it**, the way the check above verifies, against a word the
decomp already pins. I had that verification available from the first probe and
skipped it sixteen times.