mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-09 01:59:26 -04:00
76 lines
6.1 KiB
Markdown
76 lines
6.1 KiB
Markdown
# 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.
|