Files
BFM-decomp/docs/wiki/Overlays-and-modules.md
T

76 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`](../formats.md);
the extractor is [`tools/bfm_extract/`](../../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`](../../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`](../disc-completeness.md), [`docs/disc-ledger.md`](../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`](../../config/overlays.mk) and [`config/modules.mk`](../../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](The-dedup-engine.md) is the consequence.
## How the load addresses were proven
Every address in [`docs/memory-map.md`](../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).
1. **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 in [`dumps/INDEX.md`](../../dumps/INDEX.md).
2. **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 `jal` alignment.
3. **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.
4. **From their own bytes (Phase 32).** The last five payloads — never seen loaded — were placed by
[`tools/payload_base_evidence.py`](../../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
```bash
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`](../../tools/split_indicator.py), in `make tools-health`, refuses a carve that cannot build.