Files
BFM-decomp/docs/psyq-worklist.md
T
Drew T ade73cce62 feat(phase-8): link libgpu EXT+PRIM byte-identical (T4); exclude SYS.o (scattered .bss)
- splat: split 800b2 into [800b2][libgpu][800c]; libgpu block = EXT.o+PRIM.o
  (vram 0x80058890-0x80059234, holds LoadClut/LoadClut2 + primitives)
- SYS.o (3109 ins) EXCLUDED — scattered-.bss commons (cookbook §9.1, the GS_001
  class): SYS references .bss by section+offset but the original linker scattered
  the commons across 0x80078xxx/0x800c5xxx, so no single NOLOAD base reproduces it.
  Stays a byte-identical INCLUDE_ASM stub in 800c; documented in docs/psyq-worklist.md
- curated dir .run/obj40/libgpu_used = {EXT,PRIM} (validates the _used mechanism for
  the later alias libraries); Makefile LIBGPU_* + gated psyq_integrate + -T
- src/800b2.c trimmed; src/libgpu.c + src/800c.c committed (stub records); the trim's
  9 "moved" items were all splat-auto empties (regenerated identically, 0 real lost)
- dual byte-gate PASS: 143dbb89 with libgpu objects AND without (stub fallback)
- LINKED 375 -> 424; REAL still 43; byte-identical 24.32%
2026-06-15 18:21:25 -06:00

7.3 KiB
Raw Blame History

PsyQ library integration worklist (Phase 8)

Byte-confirmed footprint map of the remaining PsyQ 4.0 libraries linked by SLUS_007.26. Generated by psyq_identify.py over the original EXE (extracted/retail/SLUS_007.26, text 0x80010000..0x800629DC); raw per-object placements in .run/survey/<lib>.txt (regenerable: for L in …; do python3 tools/psyq_identify.py .run/obj40/$L; done). Replaces the Phase-7 ~350-fn estimate (R14). Placement = candidate footprint; per-object byte-identity is confirmed at integration time by psyq_link_region.py --verify before wiring (the real gate, G3/P9).

DONE (Gen1/Phase 7): libcd (18 objs) + libgs (31 objs) linked byte-identical.

Footprint summary (remaining libraries)

Order Library Placed / total Region(s) ~banked B Difficulty notes
1 libgpu 3 / 12 800b2 (0x80058890) ~14.9k ✅ DONE (T4): EXT+PRIM linked (curated libgpu_used). SYS.o EXCLUDED — scattered-.bss (§9.1, GS_001 class; stays a stub in 800c).
2 libetc 5 / 7 800 tail (0x8004239C) ~3.3k VSYNC/INTR/INTR_VB/INTR_DMA/VMODE contiguous, ends exactly at libcd1 (0x80043088). Clean.
3 libmcrd 2 / 2 800b2 (0x8005FC68,0x80062888) ~9.0k LIBMCRD.o (2186 ins, huge, holds the 55 LIBMCRD_OBJ_*) + USERFUNC.o — 2 blocks. _card_* h_norm dups collapse inside LIBMCRD.
4 libc2 17 / 46 800b2 (0x8005C2C8–0x5CD98 + STRCAT 0x80061E90) ~3.1k C stdlib (BZERO/MEMCPY/STRCMP/PRINTF/PRNT…); contiguous run + 1 outlier. PRNT.o (418 ins) has an internal jtbl — verify NOLOAD .rodata placement (the PRNT_OBJ_24C rodata note).
5 libcard 11 / 18 800b2 (0x80061F38–0x80062808) ~0.5k 11 short objects (mostly 4–46 ins). C112.o alias with libapi (both claim 0x80061F38). Short objects → windowed placement.
6 libapi 33 / 90 800b2 (scattered 0x8005CE18–0x800626B8) ~0.5k Mostly 4-ins BIOS syscall stubs (A##/C##/L##); interleaved with libcard/libc2/libmcrd. 1 ambiguous (SEND), C112 alias. Windowed + alias disambiguation.
7 libspu 38 / 129 800 sound (0x8003A444–0x800422E8) ~12k SPU.o(741)/S_SRMP(318)/SR_SV(399)/S_SCA(229)…; interleaved with libsnd; aliases (S_R≡S_W @0x8003C438; S_GRMDT/FB/T @0x8003D424; S_IH @0x8003D94C≡libsnd UT_RON). 1 ambiguous (S_I). Windowed.
8 libsnd 32 / 163 800 (0x8003D454–0x80042374 + SSGM 0x8001BD80 isolated) ~12k SSSTART(206)/MIDIREAD(445)/VS_VH(283)/UT_KEYV(259)…; interleaved with libspu; SSINIT_C≡SSINIT_H @0x8003D518; UT_RON @0x8003D94C. 6 ambiguous (PLAY/SSNOFF/SSQUIT/UT_ROFF/VM_DOFF/VM_VIB). Windowed + isolated SSGM block.
9 libgte 58 / 381 800b (0x8004787C–0x5082C) + libgs gaps ~48k Largest. MTX/GEO/COR/PRS/F/G/T series; multiple blocks (game code interleaved in 800b, e.g. between FGO_00 and PRS_F3). Fills gsgap1=MTX_05, gsgap2≈MTX_07, gsgap4=MTX_11, gsgap5=REG03+REG11. Multi-region, do last.

SKIP — zero footprint (recorded, not linked by the EXE): libmath 0/48, libc 0/56, libsn 0/51 (2 tiny ambiguous). BFM links libc2, not libc; no libmath/libsn. (Also unbuilt/no-footprint: libcomb, libds, libgun, libsio, libtap, libpress — never converted, no symbols.)

Region map (where each library lives, relative to the current splat subsegs)

800   (0x800123F0–0x80043088)  game code + libsnd(SSGM @1BD80; 3D454–42374) + libspu(3A444–422E8) + libetc(4239C–43088, tail)
libcd (0x80043088–0x8004787C)  DONE
800b  (0x8004787C–0x80051804)  libgte(4787C–5082C, multi-block) + game-code tail
libgs (0x80051804–0x80057928)  DONE; gaps gsgap1/2/4/5 are actually libgte (MTX_05/07/11, REG03/11); gsgap3=GS_001 excluded
800b2 (0x80057928–0x800629DC)  game code + libgpu(58890–5Bxxx) + libc2(5C2C8–5CD98,+STRCAT 61E90) + libapi(5CE18–626B8 scattered) + libmcrd(5FC68 + 62888) + libcard(61F38–62808)

Integration order rationale (ascending difficulty)

  • 1–2 (libgpu, libetc): clean single contiguous blocks, minimal interleaving → re-validate the §9 mechanism end-to-end on a fresh library before the hard ones.
  • 3–4 (libmcrd, libc2): few blocks, contained in 800b2; libc2 introduces the PRNT internal-jtbl wrinkle.
  • 5–6 (libcard, libapi): short syscall stubs + cross-library aliases + scatter in 800b2 → need windowed placement + curated _used dirs.
  • 7–8 (libspu, libsnd): the interleaved sound pair in the 800 subseg (which still holds the 43 REAL game-code matches lower down) → split_src_region.py trims, windowed placement, alias disambiguation.
  • 9 (libgte): largest, multi-region (800b + 4 libgs gaps), game-code-interleaved blocks → last.

Per-library integration recipe (each = one byte-gated task, §9.3/§9.5)

  1. psyq_link_region.py .run/obj40/<lib> <lo> <hi> --verify → confirm per-object byte-identity + the block/gap structure (G1: derive blocks empirically, don't trust this table's addresses).
  2. Curate .run/obj40/<lib>_used (drop cross-library aliases / keep the variant whose .data/.rdata also matches) when aliases exist (make_libgs.sh pattern).
  3. Resegment config/splat.us.exe.yaml (one c subseg per contiguous block; non-library gaps stay stubs); split_src_region.py trim the affected game-code .c; make extract.
  4. Makefile: add LIB<X>_ELF/OBJDIR/SYMS + a gated psyq_integrate.py … <stubs> [lo hi] call + -T $(LIB<X>_SYMS) on the ld line.
  5. Add recovered SDK names to config/symbols.us.txt (mirror to Ghidra, R15/G6); update progress.py's LINKED config.
  6. Dual byte-gate: make clean && extract && build && check → 143dbb89… WITH .run/obj40/<lib> present AND with it absent (stub fallback). make report LINKED up. Commit (R20).

Cross-cutting: windowed placement is mandatory for the short-object / interleaved libraries (the libgs GS_106 precedent); cross-library address collisions (C112 libapi/libcard; UT_RON/S_IH; S_R/S_W) mean total distinct objects < the 199 summed placements — byte-verify decides ownership. Any object that won't link byte-identical after §9.1/§9.4 stays a documented honest stub (does not block exit, P9).

Excluded / deferred objects (§9.1 scattered-.bss) — honest stubs, byte-identical via asm

The standard mechanism places each object's .bss as ONE NOLOAD section at a single base. An object whose .bss commons the original linker scattered to non-contiguous addresses (referenced as .bss+offset by a single section symbol) cannot be reproduced by one base → excluded, kept as an INCLUDE_ASM stub (still byte-identical). Diagnose: psyq_link_region.py <dir> shows N words differ in the object, and its .bss references resolve to >1 base in the EXE. Curate the library's _used dir to drop these.

Object Library Evidence Status
GS_001.o libgs scattered .bss (Phase 7) excluded (gsgap3 stub)
SYS.o (3109 ins) libgpu .bss+0x150 → 0x800c551c but base recovered 0x80078830; commons scattered 0x80078xxx/0x800c5xxx excluded (T4); stub in 800c

If scattered-.bss proves prevalent across libgte/libspu/libsnd, escalate to a Max general fix (split each object's .bss into per-common NOLOAD sections at their EXE-resolved addresses); otherwise excluding the few affected objects is the GS_001-precedent decision.