From e2f64a7c621555dddfa745eb67398026d5fa467e Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Mon, 31 Aug 2026 19:46:10 -0600 Subject: [PATCH] =?UTF-8?q?feat(o0):=20md=5FMAIN=5F003=20second=20carve=20?= =?UTF-8?q?=E2=80=94=20func=5F800D12D0=20(657=20ins)=20banked=20as=20real?= =?UTF-8?q?=20-O0=20C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MY HYPOTHESIS WAS WRONG AND THE AGENT SAID SO. I predicted the ownership oracle was blind to verbatim-asm owners. It is not. 0x800cedf8 is the §154-A LEADING RODATA ISLAND (the module-id header + jtbl/ptr table at segment offset 0), which rodata_carves already exempts via 'off == 0 and sub == ov'. The S68 first carve legitimately renamed that subseg to md_MAIN_003_jr_800D12D0 (§371: spimdisasm rodata migration is same-subseg-only), so the 'sub == ov' conjunct stopped firing and offset 0 leaked in as a 'carve'. The island has NO single owner BY DESIGN -- which is why the exemption exists -- so widening owner kinds could never have restored 1:1. The fix drops one conjunct: offset 0 alone is the honest structural key, because a carve is a table LIFTED OUT OF THE DATA TAIL and can never sit at the segment's own offset 0. Verified across all 213 configs: every offset-0 .rodata piece is an md_* leading island; ov_*/main have none. The R32 hard abort is UNTOUCHED -- this widens the recognised-island set, it does not soften the refusal. NEGATIVE CONTROL (R39) over all 184 binaries with .rodata pieces: OK 182 -> 183, ABORT 2 -> 1, and exactly ONE verdict moved (md_MAIN_003). The remaining us.exe abort (UNOWNED 0x80073238, the LZSS jtbl carve whose owner LzssDecodeSector does not live under src/us.exe/*.c) is byte-identical before and after -- PRE-EXISTING, not newly hidden, and logged rather than silently absorbed. Carve byte-neutral and bank byte-identical, both re-verified by my own rebuild: sha1 dd1b32ecf1103c6f7cf1943d25546a3046e17b14 == config/check.md_MAIN_003.sha. md_MAIN_003 12 -> 11 stubs. THREE o0_subsplit GAPS surfaced and hand-finished, and they must be fixed before the remaining 7 -O0 stubs here are carved: build_new_config drops a cut at the object start so region 0 kept the -O2 name while the tool PRINTED the _o0 name; parse_overlay_c folds pre-anchor text into the FOLLOWING anchor, so a verbatim body inside region 0 attached to region 1; and the island .rodata piece needs repointing to whichever TU ends up holding its emitters. --- config/splat.md_MAIN_003.yaml | 5 +- ...r_800D12D0.c => md_MAIN_003_jr_800D1E18.c} | 82 +--- src/md_MAIN_003/md_MAIN_003_o0d.c | 447 ++++++++++++++++++ tools/jr_isolate_all.py | 18 +- 4 files changed, 468 insertions(+), 84 deletions(-) rename src/md_MAIN_003/{md_MAIN_003_jr_800D12D0.c => md_MAIN_003_jr_800D1E18.c} (92%) create mode 100644 src/md_MAIN_003/md_MAIN_003_o0d.c diff --git a/config/splat.md_MAIN_003.yaml b/config/splat.md_MAIN_003.yaml index ec665af36..2f7a657dc 100644 --- a/config/splat.md_MAIN_003.yaml +++ b/config/splat.md_MAIN_003.yaml @@ -95,10 +95,11 @@ segments: # shift the code start. Mark it `rodata` (section_order places .rodata first) so it lands at # 0x800CEDF8 ahead of the code, a 1-word analogue of main's rodata-island (no ld_interleave). # - [0x0, rodata, head] - - [0x0, .rodata, md_MAIN_003_jr_800D12D0] # module-id header (+jtbl/ptr table) — §154-A; renamed to the jr TU by the S68 o0 carve: ALL island emitters (D_800CEDF8 include, D_800CEE1C asm, MDEC literals, func_800D30D0 with its migrated strings) live there, and spimdisasm rodata-migration is same-subseg-only + - [0x0, .rodata, md_MAIN_003_jr_800D1E18] # module-id header (+jtbl/ptr table) — §154-A; named for the TU holding ALL island emitters (D_800CEDF8 include, D_800CEE1C asm, MDEC literals, func_800D30D0 with its migrated strings): spimdisasm rodata-migration is same-subseg-only. Renamed _jr_800D12D0 -> _jr_800D1E18 by the S68 func_800D12D0 o0 carve (region0 became md_MAIN_003_o0d; the emitters live in the post region) - [0xd8, c, md_MAIN_003] - [0x1f74, c, md_MAIN_003_o0c] - - [0x24d8, c, md_MAIN_003_jr_800D12D0] + - [0x24d8, c, md_MAIN_003_o0d] + - [0x3020, c, md_MAIN_003_jr_800D1E18] - [0x477C, data, tail] # data tail: pointer tables + packed data (split iterated) - [0x1DC1C] # EOF marker = the 0.4.dec byte length # @TRAILING@ (above) is replaced by tools/new_overlay.sh: for a non-4-aligned overlay it becomes diff --git a/src/md_MAIN_003/md_MAIN_003_jr_800D12D0.c b/src/md_MAIN_003/md_MAIN_003_jr_800D1E18.c similarity index 92% rename from src/md_MAIN_003/md_MAIN_003_jr_800D12D0.c rename to src/md_MAIN_003/md_MAIN_003_jr_800D1E18.c index c640d92fc..8e15f08c9 100644 --- a/src/md_MAIN_003/md_MAIN_003_jr_800D12D0.c +++ b/src/md_MAIN_003/md_MAIN_003_jr_800D1E18.c @@ -71,79 +71,6 @@ extern u8 D_800AF6DC; extern u8 D_800AF680; /* ==== end §8b carried decl layer ==== */ -INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003_jr_800D12D0", func_800D12D0); - -__asm__(".text\n.align 2\n.globl func_800D1D14\n.ent\tfunc_800D1D14\n" -"func_800D1D14:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -32\n" -"sw $ra, 28($sp)\n" -"sw $fp, 24($sp)\n" -"addu $fp, $sp, $zero\n" -"sw $a0, 32($fp)\n" -"sw $a1, 36($fp)\n" -"lw $v0, 36($fp)\n" -"nop\n" -"bnez $v0, .L800D1D88\n" -"nop\n" -"lw $v0, 32($fp)\n" -"nop\n" -"addu $v1, $v0, $zero\n" -"sll $v0, $v1, 2\n" -"lui $a0, %hi(D_800D3630)\n" -"addiu $a0, $a0, %lo(D_800D3630)\n" -"addu $v1, $v0, $a0\n" -"lh $v0, 0($v1)\n" -"sw $zero, 16($sp)\n" -"sw $zero, 20($sp)\n" -"addu $a0, $v0, $zero\n" -"lui $a1, %hi(D_800D3618)\n" -"addiu $a1, $a1, %lo(D_800D3618)\n" -"addu $a2, $zero, $zero\n" -"addu $a3, $zero, $zero\n" -"jal func_8001534C\n" -"nop\n" -"j .L800D1E00\n" -"nop\n" -".L800D1D88:\n" -"lw $v0, 32($fp)\n" -"nop\n" -"addu $v1, $v0, $zero\n" -"sll $v0, $v1, 2\n" -"lui $a0, %hi(D_800D3630)\n" -"addiu $a0, $a0, %lo(D_800D3630)\n" -"addu $v1, $v0, $a0\n" -"lh $v0, 0($v1)\n" -"lw $v1, 32($fp)\n" -"nop\n" -"addu $a0, $v1, $zero\n" -"sll $v1, $a0, 2\n" -"lui $a0, %hi(D_800D3624)\n" -"addiu $a0, $a0, %lo(D_800D3624)\n" -"addu $v1, $v1, $a0\n" -"lw $a0, 32($fp)\n" -"lui $a1, %hi(D_800D3620)\n" -"addiu $a1, $a1, %lo(D_800D3620)\n" -"addu $a0, $a0, $a1\n" -"lbu $a1, 0($a0)\n" -"nop\n" -"sll $a0, $a1, 16\n" -"sra $a3, $a0, 16\n" -"sw $zero, 16($sp)\n" -"sw $zero, 20($sp)\n" -"addu $a0, $v0, $zero\n" -"lw $a1, 0($v1)\n" -"addiu $a2, $zero, 80\n" -"jal func_8001534C\n" -"nop\n" -".L800D1E00:\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 28($sp)\n" -"lw $fp, 24($sp)\n" -"addiu $sp, $sp, 32\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D1D14\n"); typedef struct { @@ -419,7 +346,7 @@ void func_800D2454(s32 a0, s32 a1, s32 *a2) { } -INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003_jr_800D12D0", func_800D24D0); +INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003_jr_800D1E18", func_800D24D0); extern s32 func_800D27A0(); extern void func_800D3234(s32 a0, s32 a1); @@ -735,7 +662,7 @@ void func_800D2D44(s32 arg0) { } -INCLUDE_RODATA("asm/md_MAIN_003/nonmatchings/md_MAIN_003_jr_800D12D0", D_800CEDF8); +INCLUDE_RODATA("asm/md_MAIN_003/nonmatchings/md_MAIN_003_jr_800D1E18", D_800CEDF8); __asm__( ".section .rodata\n" @@ -863,9 +790,9 @@ s32 func_800D30B8(void) { } -INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003_jr_800D12D0", func_800D30D0); +INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003_jr_800D1E18", func_800D30D0); -INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003_jr_800D12D0", D_800D3200); +INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003_jr_800D1E18", D_800D3200); extern s32 D_800D3200; /* dup-def demoted: a sibling .s still emits it (S61) */ @@ -1134,3 +1061,4 @@ __asm__( ); + diff --git a/src/md_MAIN_003/md_MAIN_003_o0d.c b/src/md_MAIN_003/md_MAIN_003_o0d.c new file mode 100644 index 000000000..c1f14c4a3 --- /dev/null +++ b/src/md_MAIN_003/md_MAIN_003_o0d.c @@ -0,0 +1,447 @@ +#include "common.h" + +/* ==== Phase-26 §8b carried decl layer (jr_isolate_all.py) =================== + * The file-scope decl environment from earlier code regions of this object — + * file-local types, col-0 decls, DEFINE_func macro externs, and each earlier + * definition's implied prototype (types first, then decls in original order). + * Decls emit no code => byte-neutral. See cookbook §8c. */ +extern void (*D_800D3598[])(void); +extern void func_800CEED0(void); +extern u8 D_800B9A11; +extern s32 D_800EC694; +extern s32 D_800EC68C; +extern s16 D_800EC678; +extern s32 D_800EC67C; +extern s32 D_800EC680; +extern s32 D_800EC690; +extern s32 D_800EC698; +extern s32 D_800EC688; +extern s32 D_800EC684; +extern u8 D_800DA48C[]; +extern void func_8001C044(void); +extern void func_80015310(void); +extern void func_8002D858(void); +extern s32 func_800D1E18(void); +extern void func_800CFB3C(); +extern void func_800118AC(void); +extern void func_800CEF04(void); +extern void func_8001A9F8(s32 a0); +extern s32 CdReadRequest(s32 *a0, void *a1, s32 a2, s32 a3); +extern s32 D_800AE858; +extern void func_800CEFBC(void); +extern s32 D_800B9A18; +extern s32 D_800EC6A0; +extern s32 D_800EC6A4; +extern unsigned char D_800DA48C[]; +extern void func_800D1E58(void); +extern void func_800CFFEC(void); +extern void func_800CF010(void); +extern void func_800CF3E8(void); +extern s32 func_800CFC1C(); +extern void func_800CF078(void); +extern s32 func_800149E0(s32); +extern s32 func_80014B10(s32); +extern void func_8002D4C8(s32, s32); +extern void func_800CFE00(void); +extern void func_800CF104(void); +extern void func_80059888(void *a0, s32 a1, s32 a2, s32 a3); +extern void func_800CF300(void); +extern void func_800146B0(s32); +extern void func_800118AC(); +extern void func_800CF370(void); +extern s8 D_800D52BC[]; +extern u16 D_800B99E6; +extern u16 D_800B99E8; +extern void func_800183E0(s32 a0); +extern void func_800CF3A4(void); +extern s32 D_800EC69C; +extern void func_800599B8(); +extern void func_800CFB3C(u16 *arg0); +extern s32 func_800CFC1C(u16 *param_1); +extern void func_800599B8(u16 *, u16 *); +extern u16 D_800AF7BC; +extern u16 D_800AF7BE; +extern u16 D_800AF7C0; +extern void GsInitGraph2(s32 w, s32 h, s32 mode, s32 a3, s32 st); +extern void func_80053EEC(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_80059234(s32 a0); +extern void func_80053218(void); +extern void func_800147B8(void); +extern u8 D_800AF6DC; +extern u8 D_800AF680; +/* ==== end §8b carried decl layer ==== */ + +/* func_800D12D0 -- md_MAIN_003, -O0 (frame-pointer prologue: sw $fp / addu $fp,$sp,$zero). + * Direct sibling of func_800D0D6C (src/md_MAIN_003/md_MAIN_003_o0c.c): eight 0x18-byte + * SPRT-with-own-tpage prims at fixed addresses, addPrim()'d onto OT word[0] of the frame's + * ordering table (D_800AA60C + gameFrame*0x4000), linked in the order 944, 98C, 92C, 914, + * 8FC, 8E4, 8CC, 8B4. + * + * BANKING NOTE: the subseg md_MAIN_003_jr_800D12D0 builds -O2. This MATCH cannot bank until + * the function lives in an -O0 object (tools/o0_subsplit.py plus the Makefile "_o0?" glob at + * Makefile:724, which already covers the md module dirs). Cookbook 362 trap class. + * + * -O0 spellings that are load-bearing (inherited from the byte-proven func_800D0D6C, cookbook + * 261a ADDENDA (b)/(c)/(d)); one NEW one found here: + * - "register u8 *base = D_800AF630;" lands in $v0 (caller-saved, no calls), and the + * >0x7FFF member access assembles to lui $at,1 + addu $at,$v0,$at + lhu -0x5C2E($at). + * - "0x4000" and "20" are MULTIPLIES, not shifts: expand_mult's copy_to_mode_reg emits the + * "addu $a0,$v1,$zero" copy of the index before the sll. + * - the OT address is index * 0x4000 + (u32)D_800AA60C, base CAST TO AN INTEGER and written + * SECOND (a pointer-typed spelling routes through pointer_int_sum and swaps the operands). + * - the 24-bit "addr" bitfield reproduces libgpu setaddr()/getaddr() AND fixes the operand + * order of the final "or". + * - every sh destination is s16, not u16 (a u16 lvalue turns -0x140/-0xF0/-0xA0/-0xBE into + * "ori $v1,$zero,imm" instead of the target's "addiu $v1,$zero,-imm"). + * - NEW HERE: the three colour bytes come from ONE "lbu D_800EC890" feeding THREE "sb"s, so + * they are a CHAINED assignment "B+8 = B+9 = B+10 = D_800EC890;" -- gcc expands innermost + * first, which produces the target's B+10, B+9, B+8 store order. Three separate statements + * would emit three loads (+16 instructions). + */ + +extern u8 D_800AF630[]; +extern u8 D_800AA60C[]; + +extern u8 D_800EC890; +extern s16 D_800EC894; + +extern u32 D_800EC8B4; +extern u8 D_800EC8B7; +extern u32 D_800EC8B8; +extern u8 D_800EC8BC; +extern u8 D_800EC8BD; +extern u8 D_800EC8BE; +extern u8 D_800EC8BF; +extern s16 D_800EC8C0; +extern s16 D_800EC8C2; +extern u8 D_800EC8C4; +extern u8 D_800EC8C5; +extern s16 D_800EC8C6; +extern s16 D_800EC8C8; +extern s16 D_800EC8CA; + +extern u32 D_800EC8CC; +extern u8 D_800EC8CF; +extern u32 D_800EC8D0; +extern u8 D_800EC8D4; +extern u8 D_800EC8D5; +extern u8 D_800EC8D6; +extern u8 D_800EC8D7; +extern s16 D_800EC8D8; +extern s16 D_800EC8DA; +extern u8 D_800EC8DC; +extern u8 D_800EC8DD; +extern s16 D_800EC8DE; +extern s16 D_800EC8E0; +extern s16 D_800EC8E2; + +extern u32 D_800EC8E4; +extern u8 D_800EC8E7; +extern u32 D_800EC8E8; +extern u8 D_800EC8EC; +extern u8 D_800EC8ED; +extern u8 D_800EC8EE; +extern u8 D_800EC8EF; +extern s16 D_800EC8F0; +extern s16 D_800EC8F2; +extern u8 D_800EC8F4; +extern u8 D_800EC8F5; +extern s16 D_800EC8F6; +extern s16 D_800EC8F8; +extern s16 D_800EC8FA; + +extern u32 D_800EC8FC; +extern u8 D_800EC8FF; +extern u32 D_800EC900; +extern u8 D_800EC904; +extern u8 D_800EC905; +extern u8 D_800EC906; +extern u8 D_800EC907; +extern s16 D_800EC908; +extern s16 D_800EC90A; +extern u8 D_800EC90C; +extern u8 D_800EC90D; +extern s16 D_800EC90E; +extern s16 D_800EC910; +extern s16 D_800EC912; + +extern u32 D_800EC914; +extern u8 D_800EC917; +extern u32 D_800EC918; +extern u8 D_800EC91C; +extern u8 D_800EC91D; +extern u8 D_800EC91E; +extern u8 D_800EC91F; +extern s16 D_800EC920; +extern s16 D_800EC922; +extern u8 D_800EC924; +extern u8 D_800EC925; +extern s16 D_800EC926; +extern s16 D_800EC928; +extern s16 D_800EC92A; + +extern u32 D_800EC92C; +extern u8 D_800EC92F; +extern u32 D_800EC930; +extern u8 D_800EC934; +extern u8 D_800EC935; +extern u8 D_800EC936; +extern u8 D_800EC937; +extern s16 D_800EC938; +extern s16 D_800EC93A; +extern u8 D_800EC93C; +extern u8 D_800EC93D; +extern s16 D_800EC93E; +extern s16 D_800EC940; +extern s16 D_800EC942; + +extern u32 D_800EC944; +extern u8 D_800EC947; +extern u32 D_800EC948; +extern u8 D_800EC94C; +extern u8 D_800EC94D; +extern u8 D_800EC94E; +extern u8 D_800EC94F; +extern s16 D_800EC950; +extern s16 D_800EC952; +extern u8 D_800EC954; +extern u8 D_800EC955; +extern s16 D_800EC956; +extern s16 D_800EC958; +extern s16 D_800EC95A; + +extern u32 D_800EC98C; +extern u8 D_800EC98F; +extern u32 D_800EC990; +extern u8 D_800EC994; +extern u8 D_800EC995; +extern u8 D_800EC996; +extern u8 D_800EC997; +extern s16 D_800EC998; +extern s16 D_800EC99A; +extern u8 D_800EC99C; +extern u8 D_800EC99D; +extern s16 D_800EC99E; +extern s16 D_800EC9A0; +extern s16 D_800EC9A2; + +void func_800D12D0(void) { + typedef struct { + unsigned int addr : 24; + unsigned int len : 8; + } PrimTag; + + register u8 *base = D_800AF630; + + D_800EC8B7 = 5; + D_800EC8B8 = 0xE100008A; + D_800EC8BF = 0x64; + D_800EC8BC = D_800EC8BD = D_800EC8BE = D_800EC890; + D_800EC8C0 = -0x140; + D_800EC8C2 = -0xF0; + D_800EC8C4 = 0; + D_800EC8C5 = 0x10; + D_800EC8C6 = 0x7800; + D_800EC8C8 = 0x100; + D_800EC8CA = 0xF0; + + D_800EC8CF = 5; + D_800EC8D0 = 0xE100008C; + D_800EC8D7 = 0x64; + D_800EC8D4 = D_800EC8D5 = D_800EC8D6 = D_800EC890; + D_800EC8D8 = -0x40; + D_800EC8DA = -0xF0; + D_800EC8DC = 0; + D_800EC8DD = 0x10; + D_800EC8DE = 0x7800; + D_800EC8E0 = 0x100; + D_800EC8E2 = 0xF0; + + D_800EC8E7 = 5; + D_800EC8E8 = 0xE100008E; + D_800EC8EF = 0x64; + D_800EC8EC = D_800EC8ED = D_800EC8EE = D_800EC890; + D_800EC8F0 = 0xC0; + D_800EC8F2 = -0xF0; + D_800EC8F4 = 0; + D_800EC8F5 = 0x10; + D_800EC8F6 = 0x7800; + D_800EC8F8 = 0x80; + D_800EC8FA = 0xF0; + + D_800EC8FF = 5; + D_800EC900 = 0xE100009A; + D_800EC907 = 0x64; + D_800EC904 = D_800EC905 = D_800EC906 = D_800EC890; + D_800EC908 = -0x140; + D_800EC90A = 0; + D_800EC90C = 0; + D_800EC90D = 0; + D_800EC90E = 0x7800; + D_800EC910 = 0x100; + D_800EC912 = 0xF0; + + D_800EC917 = 5; + D_800EC918 = 0xE100009C; + D_800EC91F = 0x64; + D_800EC91C = D_800EC91D = D_800EC91E = D_800EC890; + D_800EC920 = -0x40; + D_800EC922 = 0; + D_800EC924 = 0; + D_800EC925 = 0; + D_800EC926 = 0x7800; + D_800EC928 = 0x100; + D_800EC92A = 0xF0; + + D_800EC92F = 5; + D_800EC930 = 0xE100009E; + D_800EC937 = 0x64; + D_800EC934 = D_800EC935 = D_800EC936 = D_800EC890; + D_800EC938 = 0xC0; + D_800EC93A = 0; + D_800EC93C = 0; + D_800EC93D = 0; + D_800EC93E = 0x7800; + D_800EC940 = 0x80; + D_800EC942 = 0xF0; + + D_800EC947 = 5; + D_800EC948 = 0xE100000F; + D_800EC94F = 0x64; + D_800EC94C = D_800EC94D = D_800EC94E = D_800EC890; + D_800EC950 = -0xA0; + D_800EC952 = 0x64; + D_800EC954 = 0; + D_800EC955 = 0; + D_800EC956 = 0x7800; + D_800EC958 = 0x78; + D_800EC95A = 0x3C; + D_800EC956 = 0x7A00; + + ((PrimTag *)&D_800EC944)->addr = + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr; + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr = + (u32)&D_800EC944; + + D_800EC98F = 5; + D_800EC990 = 0xE100000F; + D_800EC997 = 0x64; + D_800EC994 = D_800EC995 = D_800EC996 = D_800EC890; + D_800EC998 = -0xBE; + D_800EC99A = D_800EC894 * 20 + 0x64; + D_800EC99C = 0; + D_800EC99D = 0x3C; + D_800EC99E = 0x7800; + D_800EC9A0 = 0x1E; + D_800EC9A2 = 0x14; + D_800EC99E = 0x7A00; + + ((PrimTag *)&D_800EC98C)->addr = + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr; + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr = + (u32)&D_800EC98C; + + ((PrimTag *)&D_800EC92C)->addr = + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr; + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr = + (u32)&D_800EC92C; + + ((PrimTag *)&D_800EC914)->addr = + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr; + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr = + (u32)&D_800EC914; + + ((PrimTag *)&D_800EC8FC)->addr = + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr; + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr = + (u32)&D_800EC8FC; + + ((PrimTag *)&D_800EC8E4)->addr = + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr; + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr = + (u32)&D_800EC8E4; + + ((PrimTag *)&D_800EC8CC)->addr = + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr; + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr = + (u32)&D_800EC8CC; + + ((PrimTag *)&D_800EC8B4)->addr = + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr; + ((PrimTag *)(*(u16 *)(base + 0xA3D2) * 0x4000 + (u32)D_800AA60C))->addr = + (u32)&D_800EC8B4; +} + + +__asm__(".text\n.align 2\n.globl func_800D1D14\n.ent\tfunc_800D1D14\n" +"func_800D1D14:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -32\n" +"sw $ra, 28($sp)\n" +"sw $fp, 24($sp)\n" +"addu $fp, $sp, $zero\n" +"sw $a0, 32($fp)\n" +"sw $a1, 36($fp)\n" +"lw $v0, 36($fp)\n" +"nop\n" +"bnez $v0, .L800D1D88\n" +"nop\n" +"lw $v0, 32($fp)\n" +"nop\n" +"addu $v1, $v0, $zero\n" +"sll $v0, $v1, 2\n" +"lui $a0, %hi(D_800D3630)\n" +"addiu $a0, $a0, %lo(D_800D3630)\n" +"addu $v1, $v0, $a0\n" +"lh $v0, 0($v1)\n" +"sw $zero, 16($sp)\n" +"sw $zero, 20($sp)\n" +"addu $a0, $v0, $zero\n" +"lui $a1, %hi(D_800D3618)\n" +"addiu $a1, $a1, %lo(D_800D3618)\n" +"addu $a2, $zero, $zero\n" +"addu $a3, $zero, $zero\n" +"jal func_8001534C\n" +"nop\n" +"j .L800D1E00\n" +"nop\n" +".L800D1D88:\n" +"lw $v0, 32($fp)\n" +"nop\n" +"addu $v1, $v0, $zero\n" +"sll $v0, $v1, 2\n" +"lui $a0, %hi(D_800D3630)\n" +"addiu $a0, $a0, %lo(D_800D3630)\n" +"addu $v1, $v0, $a0\n" +"lh $v0, 0($v1)\n" +"lw $v1, 32($fp)\n" +"nop\n" +"addu $a0, $v1, $zero\n" +"sll $v1, $a0, 2\n" +"lui $a0, %hi(D_800D3624)\n" +"addiu $a0, $a0, %lo(D_800D3624)\n" +"addu $v1, $v1, $a0\n" +"lw $a0, 32($fp)\n" +"lui $a1, %hi(D_800D3620)\n" +"addiu $a1, $a1, %lo(D_800D3620)\n" +"addu $a0, $a0, $a1\n" +"lbu $a1, 0($a0)\n" +"nop\n" +"sll $a0, $a1, 16\n" +"sra $a3, $a0, 16\n" +"sw $zero, 16($sp)\n" +"sw $zero, 20($sp)\n" +"addu $a0, $v0, $zero\n" +"lw $a1, 0($v1)\n" +"addiu $a2, $zero, 80\n" +"jal func_8001534C\n" +"nop\n" +".L800D1E00:\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 28($sp)\n" +"lw $fp, 24($sp)\n" +"addiu $sp, $sp, 32\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D1D14\n"); + diff --git a/tools/jr_isolate_all.py b/tools/jr_isolate_all.py index eb4571aeb..c01d0ff6b 100644 --- a/tools/jr_isolate_all.py +++ b/tools/jr_isolate_all.py @@ -69,16 +69,24 @@ def rodata_carves(cfg_lines, ov=None): owner, so jr_inventory's "every carve resolves to exactly one banked function" check (R32) aborted on it and md_* could not be isolated at all. - The discriminator is structural and was verified across all 213 splat configs: a `.rodata` - piece at offset 0 whose subseg is the binary's own alias exists in exactly the 42 md_* configs - and in none of the others, so passing `ov` is a no-op for every ov_*/main config.""" + The discriminator is structural: a carve is a table LIFTED OUT OF THE DATA TAIL, so it can + never sit at the segment's own offset 0 — offset 0 is where the module-id header (md_*) or the + first function (ov_*) lives. Verified across all 213 splat configs: every `.rodata` piece at + offset 0 is an md_* leading island; ov_*/main configs have none, so passing `ov` is a no-op + for them. The discriminator used to ALSO require the subseg to be the binary's own alias, but + that conjunct broke the moment a leading island was legitimately RENAMED to the code subseg + where its emitters live (S68 md_MAIN_003 → md_MAIN_003_jr_800D12D0: spimdisasm rodata-migration + is same-subseg-only, cookbook §371), which made jr_inventory read the island as an UNOWNED + carve and R32-abort every further carve on the binary. Offset 0 alone is the honest key; + negative-controlled over all 184 configs with `.rodata` pieces (only md_MAIN_003's verdict + moved, abort → OK).""" out = [] for i, ln in enumerate(cfg_lines): m = re.match(r'^\s*- \[(0x[0-9A-Fa-f]+),\s*\.rodata,\s*(\w+)\]', ln) if m: off, sub = int(m.group(1), 16), m.group(2) - if ov is not None and off == 0 and sub == ov: - continue # the leading island, not a carve + if ov is not None and off == 0: + continue # the leading island (possibly renamed), not a carve out.append((i, off, sub)) return out