6.1 KiB
Overlays and modules — the 218 binaries and the disc
The disc
Brave Fencer Musashi (USA) is a 4-track disc (Track 1 = data, Tracks 2–4 = CD audio). Track 1 holds 27 root files and
no directories: the 413,696-byte executable SLUS_007.26, SYSTEM.CNF, LIST.CD (the file-location table the loader
indexes), and the container files MAIN.CD and SC01.CD … SC07.CD (one per chapter), plus three .DA entries pointing
into the audio tracks. Each .CD is a table of contents over PAC archives; each PAC entry is a typed payload, and
type 4 is an LZSS-compressed stream with the game's own termination semantics (the reference tool's differ — the
extractor implements the game's). The full formats, verified against the bytes, are in docs/formats.md;
the extractor is tools/bfm_extract/ and its output is the 1,801-file manifest your
make disc-extract is checked against.
| PAC type | payloads | code-bearing | what |
|---|---|---|---|
| 0, 2, 3, 6, 7, 8 | 885 | 0 | graphics, blobs, structured data |
| 1 | 166 | 78 | raw (uncompressed) payloads: the resident engine, the code modules, three overlays stored uncompressed |
| 4 | 138 | 138 | LZSS location overlays |
"Code-bearing" is decided by make audit-disc (tools/disc_audit.py): whole-payload
classification at both the raw and the decompressed layer, a residue-0 partition over every byte of the disc, and
claimed-by derived from the per-binary contracts — so a code payload nobody onboarded cannot hide behind a green fleet
(the byte gate is blind to what it was never asked to build — rule R34). At the close: UNCLAIMED 0 of 220 code
payloads. The audit exists because the count was wrong twice: 4 overlays that put their code at PAC entry 1 instead of 0
were invisible for a month, and a first sweep with a 4,096-word window counted 39 hidden modules where the honest number
was 78 (docs/disc-completeness.md, docs/disc-ledger.md).
The 218 binaries
| Kind | Count | Alias | Loads at | Source |
|---|---|---|---|---|
| The executable | 1 | main |
0x80010000 (PS-X EXE header; t_size 0x64800) |
SLUS_007.26 |
| The resident engine | 1 | resident |
0x800CEDF8 (the boot slot) |
MAIN.CD/FILE_010/1.1, 365,404 B, type 1 |
| Location overlays | 141 | ov_<DISC>_<FILE> |
0x80128158 — the shared overlay slot, position-locked |
138 type-4 LZSS payloads + 3 stored uncompressed (ov_MAIN_012, ov_SC02_037, ov_SC03_107) |
| Code modules | 75 | md_<DISC>_<FILE> |
their own slots: module slot A 0x800CAE08 (MAIN/13–41), slot B 0x800CCB1C (MAIN/42–47), the boot slot 0x800CEDF8 (boot trio + the two opening-demo modules), the SC07 pair 0x801A00D8, four per-chapter script-module slots, and the five last payloads at bases derived from their own bytes |
type-1 payloads across MAIN.CD and the chapter discs |
The registries config/overlays.mk and config/modules.mk
(generated by the onboarding scripts) give each binary its payload path, load address, source and build directories;
config/splat.<alias>.yaml its split; config/check.<alias>.sha its contract. One parameterized pipeline builds any of
them (make check BINARY=<alias>). The overlays share one symbol space because they share one address space —
The dedup engine is the consequence.
How the load addresses were proven
Every address in docs/memory-map.md carries its source and its verification status (rule G5: never
a JP address assumed for US, never an overlay address treated as a static symbol until the map says so).
- Runtime proof (Phase 3). The loader was reverse-engineered — a hand-rolled CD reader driven by the location table
and a resource map, with an LZSS staging buffer at
0x80079A70— and the resident and the first overlay were proven by byte-comparing a live PCSX-Redux RAM dump against the extracted, decompressed payloads (sha1-equal prefixes of 18,788 and 389,400 bytes at the derived addresses). A finding is verified only with ≥ 3 consistent datapoints or a controlled before/after diff (R10). The 28 RAM images are catalogued indumps/INDEX.md. - Static derivation (Phase 30). For 46 of the 78 unclaimed payloads the addresses were readable without an
emulator: the executable's load-destination pointer table, the boot loaders' literal table operands, and two index
tables inside the resident that route MAIN/13–41 and MAIN/42–47 to the two module slots — corroborated by base voting
over shared code (about 500:1) and
jalalignment. - The emulator tour (Phase 30/31). The 28 per-chapter script modules and a few stragglers were captured live through the debug menu, each byte-proven at its slot.
- From their own bytes (Phase 32). The last five payloads — never seen loaded — were placed by
tools/payload_base_evidence.py: score a bounded candidate list on how many self-calls and function-pointer-table entries land exactly on the payload's own function starts (controls: seven known modules re-derive their proven bases from the payload alone). An all-assembly first build is a null oracle for fine base errors; each base was then proven by the first C bank whose body calls an internal sibling.
Working on one binary
make extract BINARY=ov_SC01_077 && make -j8 check BINARY=ov_SC01_077 # split, build, compare to check.ov_SC01_077.sha
make -j8 check BINARY=main # main: read the exit code; gate changes by a clean rebuild
Some translation units are carved: a function whose jump table sits in a rodata island between two others is split into
its own file at segmentation time, -O0 regions are carved out of -O2 files, and the carve state — the yaml and the
registry lines — belongs to the binary that owns it (a gate commit carries only its own binary's lines; R60).
tools/split_indicator.py, in make tools-health, refuses a carve that cannot build.