diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index 0c8c3e1bb..727b45196 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -29707,3 +29707,26 @@ peel stays valid for already-peeled pieces (`--tu` frames them). **Controls.** Positive: the derive reproduces the hand-proven `0t1,0` and its filtered output is byte-identical to the stored-spec output. Negative: every module binary rebuilt through the derive stage must stay byte-identical (the S62 module sweep — count quoted in the phase log). + +## §304 — SELF-DEFINING RODATA: WHEN A FUNCTION'S `.s` IS THE ONLY OWNER OF THE DATA IT REFERENCES, THE C BODY MUST DEFINE IT (P31 S62 T3; byte-proven md_MAIN_011/func_800D04F4) + +**The refusal.** `PLUMBING: undefined reference to D_800CEE3C` at link, for a draft that rtu +called MATCH. The module's rodata island holds a string table (`"ON "`, `"OFF"`, `"PLAYER DMG"`, …) +that ONLY this function references, so spimdisasm migrated those blocks into the function's own +`.s` (§154-A). Banking the C body deletes the `.s` — and with it the only definition of the strings +the body still `extern`s. + +**The fix (byte-neutral by construction).** Define the blocks in the draft at FILE scope, in +address order, one per `dlabel` in the `.s`: `const char D_800CEE3C[] = "ON ";` (cc1 emits +`.section .rodata / .align 2 / label / .ascii "…\000"` — the exact shape spimdisasm wrote), a +`.word` block as `const u32 D_800CEE60[] = { … };`. The definitions land at the function's position +in the emission stream, which is where the `.s` emitted them, so the island bytes are unchanged +(§303's order law); keep `const` (drops it → `.data`), cast at a `void *` use if a prototype +demands it. The block-scope `extern`s for those symbols go away (a file-scope definition after a +block-scope extern of another type is gcc's "used prior to declaration", §302's SC04_018 lesson). + +**Tell + generalization.** Undefined-reference at link for a `D_` the target `.s` carries as a +`dlabel` block = this class; the `.s` block is the literal source of the initializer. Candidate +resolver transform (not built yet): `rodata_from_s` — for each `undefined reference to D_x` where +the fn's `.s` has `dlabel D_x`, emit the C definition from the block. One instance in the S62 +resolver stock; expect more as module drafting resumes. diff --git a/phase-ends/CURRENT_PHASE.md b/phase-ends/CURRENT_PHASE.md index 500358ee9..afaeef9da 100644 --- a/phase-ends/CURRENT_PHASE.md +++ b/phase-ends/CURRENT_PHASE.md @@ -2389,3 +2389,11 @@ gaps — fixed; md_MAIN_003's blob sizing is 34 bytes short but it has no C tabl return covers it and any future table there refuses loudly). Commits `commit:3098`, `commit:3099`, `commit:3100` + this one. NEXT: fleet sweep #3 (definitive GREEN count with the deriver live), then a fresh resolver pass to bank the 32 tail + 25 md_ island drafts through the official gate. + +**T3 progress (S62).** Fleet sweep #3: **213/213 GREEN, extract-all 212/212** (14:52, from +`make clean`, deriver live) — the honest R58 count for T2+T3a. T3b: ov_SC03_118/119 -O0 region +`o0d` (0x80183178..0x80183830, 9 stubs each) carved, byte-neutral (`commit:3102`); the five md_MAIN +"F" members are NOT -O0 (func_800D0C50's draft matches at both levels) — their rejections were +module-island/plumbing, now covered. §304: md_MAIN_011/func_800D04F4 banked by defining its own +rodata strings in the C body (the resolver's PLUMBING class). A fresh resolver pass is running to +bank the 32 tail + 25 module-island drafts through the official gate.