- config/splat.us.exe.yaml: splat PSX config (platform psx, compiler PSYQ, subalign 2, gp_value 0x80074750, base_path .., main segment align 4); one asm text seg [0x800] + data seg [0x531DC], header via splat's header segtype - Makefile: implement extract (splat split) / build (as -> ld(splat .ld + undefined_*_auto) -> objcopy) / check (SHA1 vs config/check.us.sha, auto-run) / expected (asm-differ baseline) / clean; check-env untouched - config/check.us.sha: committed build-check hash (validation stage 2) - config/symbols.us.txt: now hand-curated — 15 2D_* -> gfx2D_* (illegal leading digit broke as), +D_800629D4 label; header flags re-merge + Ghidra-mirror (G6) - .gitignore: ignore regenerable splat outputs (asm/, include macros, undefined_*_auto.txt); refine the earlier commit-asm/ note - docs: SETUP.md §4.5 binutils 2.42 = byte-clean (no 2.35 downgrade), §5.3 + ledger #8 RESOLVED -G0, §6.3 as-built; memory-map.md gp0 -> -G0 + text/data split - MILESTONE: make extract && make build && make check -> build/us/SLUS_007.26 SHA1 143dbb89... == original (BYTE-IDENTICAL), 100% asm, check fails on corruption - rule R15 (symbol file = curated, valid-identifier build input, Ghidra-mirrored) - bumps project version 1.4.0 -> 1.5.0
10 KiB
PhaseEnd — Phase 5: splat config + build skeleton (all-asm byte-match)
Date: 2026-06-14 · Project Version: 1.5.0 · Phase Status: Complete
Build Log
Files created/changed and complete — do not recreate:
config/splat.us.exe.yaml— new. The splat config for the main EXE. Derived from splat 0.41.0's owncreate_psx_configtemplate (platformpsx, compilerPSYQ,subalign: 2,section_orderrodata/text/ data/bss,find_file_boundaries: False,gp_value: 0x80074750).base_path: ..(the yaml lives inconfig/, so paths anchor at the repo root). Onecodesegment split into a[0x800] asmtext subsegment + a[0x531DC] datasubsegment,align: 4on the segment (see Deviations). Consumed bymake extract.config/check.us.sha— new, committed.143dbb89… SLUS_007.26— the canonical build-check hash (validation stage 2). Consumed bymake check.config/symbols.us.txt— modified (now HAND-CURATED). 152D_*→gfx2D_*renames (a leading digit is an illegal as/C identifier — it brokeas); added theD_800629D4data label (boot-code-referenced address in the text→data boundary region that splat did not auto-label). Header rewritten to flag that ExportSymbols.java overwrites this file → re-apply curations + mirror to Ghidra (G6). Consumed by splat.Makefile— modified. The five Phase-5 stub targets replaced with real implementations:extract(splat split),build(assembleasm/*.s→ldvia the splat linker script +undefined_*_auto.txt→objcopy -O binary→build/us/SLUS_007.26),check(SHA1 vsconfig/check.us.sha, auto-run bybuild),expected(snapshot a verified build →expected/build/),clean(remove all regenerable outputs). Added varsSPLAT/CPP/OUT/ELF/LD_SCRIPT/ASFLAGS/ASPSX_VERSION/OBJS.check-envuntouched..gitignore— modified. Ignore the regenerable splat outputs (/asm/, the four generatedinclude/macros,undefined_{syms,funcs}_auto.txt); the earlier "commit asm/" note refined with rationale (durable record =config/symbols.us.txt)./build/+/expected/already ignored.docs/SETUP.md— modified. §4.5 binutils VERDICT: 2.42 byte-clean (no downgrade); §5.3 + ledger #8 RESOLVED: -G0; §6.3 As-built (Phase 5) target table note; ledger #6 resolved. Original deferred-verdict text preserved (additive).docs/memory-map.md— modified. §1gp0row → -G0 CONFIRMED; added the Text→data split block (file/vram boundary, the mixed transition region,vram = fileoff + 0x8000F800).phase-ends/PhaseEnd_Phase5.md— this file.phase-ends/CURRENT_PHASE.md— absorbed into this file and deleted (P8).
Local artifacts (gitignored / regenerable — do NOT recreate; make extract rebuilds them):
asm/{header.s, 800.s, data/531DC.data.s}— the splat disassembly (header reproduced via splat's structuredheadersegtype; text + data).include/{include_asm.h, macro.inc, labels.inc, gte_macros.inc}— splat-generated assembler macros.build/us/SLUS_007.26.ld— the splat-generated linker script (_gp=0x80074750;ALIGN(.,4)).undefined_syms_auto.txt(899) +undefined_funcs_auto.txt(8) — splat-generated linker symbol defs.build/(objects,.elf, the 413,696-byte binary) +expected/build/(the asm-differ baseline).
Tools/packages installed: None — used the existing Phase-4 toolchain (splat64 0.41.0, mipsel-binutils 2.42, the cc1 candidates) entirely. (cc1/maspsx were not invoked — the build is all-assembly.)
Verification results (literal):
make extract && make build && make check→build/us/SLUS_007.26, 413,696 B, SHA1143dbb89f34491258bbc27810d0a12ec8b43a8dd== original (BYTE-IDENTICAL). Reproduced from a fullmake cleancycle.- Check is a real gate: a 1-byte corruption makes
make checkexit non-zero; a rebuild restores[ OK ]. make check-envstill exits 0 (no Phase-4 regression).- binutils 2.42 byte-clean with
as -march=r3000 -mtune=r3000 -no-pad-sections -O1 -G0— the §4.5 "≥2.38 regression" risk did not materialise; no 2.35 downgrade. - -G0 confirmed: the disassembly has 0
($gp)base accesses and 0%gp_relrelocations. git status: onlyconfig/,Makefile,.gitignore,docs/tracked;asm/ build/ expected/+ generated macros +undefined_*_auto.txtignored — zero generated/ROM bulk staged.
Milestone achieved: make build rebuilds SLUS_007.26 byte-for-byte (SHA1-identical) from
disassembly alone at 100% assembly, with the SHA1 check auto-running and provably failing on corruption —
the split, linker script, and as→ld→objcopy tooling proven end-to-end.
Next: Phase 6 — Compiler fingerprint + first matched functions. Start with selecting 3–5 medium leaf
functions as fingerprint probes (⭐⭐ Max — the highest-stakes task in Gen1 per docs/effort-map.md).
Phase 6 also introduces the c/INCLUDE_ASM scaffold (flip the code subsegment to c, wire decompile.py
- asm-differ, establish INCLUDE_ASM/NON_MATCHING headers) — the Makefile already has the dormant cpp→cc1→maspsx path and the §5.4 candidate ladder is queued.
Deviations
| Item | Plan | Actual | Reason |
|---|---|---|---|
| Code segment type | c/INCLUDE_ASM primary; asm as fallback |
asm (all-asm) |
The plan's documented fallback, and the better fit: the phase title is "all-asm byte-match" and the roadmap puts INCLUDE_ASM/NON_MATCHING setup in Phase 6. Keeps the unpinned compiler out of Phase 5. Drew-ratified. |
| Execution order | T1 split → T2 Makefile → T3 byte-match | Byte-identity proven by a manual round-trip during T1, before the Makefile | Isolated and cleared the High-risk binutils-2.42 variable first (as→ld→objcopy only); the Makefile then just transcribed the working chain. |
| binutils 2.42 verdict | possibly downgrade to 2.35 (§4.5) | No downgrade — 2.42 is byte-clean | The build is SHA1-identical with 2.42; the regression warning didn't bite our flags. |
asm/ git policy |
gitignore (my plan) vs the repo's existing "commit asm/" note | gitignored (regenerable via make extract) |
make extract deterministically regenerates it from committed yaml+symbols → build scaffolding, not durable work. .gitignore note refined; Drew-ratified. |
| Section-boundary effort | feared a fighting link (T3 Max-escalation) | The link was clean; the only real fights were 15 leading-digit symbol names + one un-labelled boundary address + an align: 4 tweak |
splat round-trips bytes, so byte-identity was robust to the imperfect text/data split (as predicted). |
config/symbols.us.txt role |
seeded Ghidra export | became the hand-curated build input | Build validity (identifiers) + a boot-referenced label had to be fixed in the splat input; ExportSymbols now a careful re-merge, not a blind overwrite (→ R15). |
Commit Message
feat(phase-5): splat config + all-asm byte-identical build of SLUS_007.26
- config/splat.us.exe.yaml: splat PSX config (platform psx, compiler PSYQ,
subalign 2, gp_value 0x80074750, base_path .., main segment align 4); one
asm text seg [0x800] + data seg [0x531DC], header via splat's header segtype
- Makefile: implement extract (splat split) / build (as -> ld(splat .ld +
undefined_*_auto) -> objcopy) / check (SHA1 vs config/check.us.sha, auto-run)
/ expected (asm-differ baseline) / clean; check-env untouched
- config/check.us.sha: committed build-check hash (validation stage 2)
- config/symbols.us.txt: now hand-curated — 15 2D_* -> gfx2D_* (illegal leading
digit broke as), +D_800629D4 label; header flags re-merge + Ghidra-mirror (G6)
- .gitignore: ignore regenerable splat outputs (asm/, include macros,
undefined_*_auto.txt); refine the earlier commit-asm/ note
- docs: SETUP.md §4.5 binutils 2.42 = byte-clean (no 2.35 downgrade), §5.3 +
ledger #8 RESOLVED -G0, §6.3 as-built; memory-map.md gp0 -> -G0 + text/data split
- MILESTONE: make extract && make build && make check -> build/us/SLUS_007.26
SHA1 143dbb89... == original (BYTE-IDENTICAL), 100% asm, check fails on corruption
- rule R15 (symbol file = curated, valid-identifier build input, Ghidra-mirrored)
- bumps project version 1.4.0 -> 1.5.0
Rules Added This Phase
| Rule | Reason |
|---|---|
R15 — config/symbols.us.txt is the curated, build-valid symbol source. It is hand-curated (seeded from ExportSymbols.java, then refined for the build); re-exporting is a careful re-merge, never a blind overwrite. Every name must be a valid as/C identifier (no leading digit, etc.). All curations — renames and added labels — are mirrored back into Ghidra so a future re-export stays valid and consistent (extends G5/G6). |
Phase 5: 2D_* names broke as (leading digit illegal); the fix lives only in this file, which ExportSymbols would silently overwrite, and Ghidra must carry the change to stay the static oracle. This recurs at scale in Gen2. |
PhaseEnd Changelog
v1.4.0 → v1.5.0 — Phase 5 complete. The repo now rebuilds SLUS_007.26 byte-for-byte (SHA1-identical)
from disassembly alone via make extract && make build && make check — splat split → mipsel-as → ld
(splat linker script) → objcopy, at 100% assembly (no C). The build is compiler-independent (no
cc1/maspsx invoked), so it is solid before the Phase-6 fingerprint. Two roadmap unknowns fell out for free:
binutils 2.42 is byte-clean (the §4.5 ≥2.38 regression risk cleared — no 2.35 downgrade) and ledger #8
= -G0 (zero $gp-relative addressing in the disassembly). The splat config uses splat's own PSX template
(PSYQ, subalign 2, gp 0x80074750) with a single align: 4 tweak (the word- but not 16-aligned text→data
boundary at vram 0x800629DC). config/symbols.us.txt became the hand-curated build input (15 2D_*→gfx2D_*
for illegal identifiers, +D_800629D4 label) → R15. Decisions (Drew-ratified): the code segment stays
all-asm (Phase 6 owns the INCLUDE_ASM/.c scaffold per the roadmap), and the regenerable splat outputs
(asm/, generated macros, undefined_*_auto.txt) are gitignored. No tools installed. One rule (R15).
🛑 Stop Here
PhaseEnd written; CURRENT_PHASE.md absorbed and removed. Drew commits AND pushes this PhaseEnd plus the
whole Phase-5 change set (R6/R8). Start a fresh session for Phase 6 — Compiler fingerprint + first matched
functions. Keep this file forever.