From cd60c6b3ea07298d17548eb3265dbe2d56d0d462 Mon Sep 17 00:00:00 2001 From: Christopher Williams Date: Thu, 24 Sep 2026 01:52:24 -0400 Subject: [PATCH] =?UTF-8?q?phase9:=20merge=20worker=20C=203=20=E2=80=94=20?= =?UTF-8?q?358=20regions=20/=20349=20distinct=20bodies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 3 tier-2 frames from C (0x800A6840, 0x8002C728, 0x8002E968). Gate DIFF avoided: C's 0x8002C728 used the name g_80121B84 which resolves implicitly WITHOUT the gp marker (F19) — its local superset carried a g_-marked row so C's own run matched, but the tracked registry only has D_80121B84. Fixed the source to the tracked name; re-verified MATCH. C's 0x80025070 'negative' corrected: that row is the coordinator's registered claim (stale index entry removed). C's address-arithmetic charter warning (lui + negative displacement must be hand-derived; five occurrences) recorded. Gate MATCH whole-binary SHA-1 e173426c157384ebf1b6caf8c6fea18a85a14af9. --- config/regions.tsv | 3 +++ src/func_8002C728.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/func_8002E968.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/func_800A6840.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 src/func_8002C728.c create mode 100644 src/func_8002E968.c create mode 100644 src/func_800A6840.c diff --git a/config/regions.tsv b/config/regions.tsv index 3f392da..f6b64b4 100644 --- a/config/regions.tsv +++ b/config/regions.tsv @@ -79,6 +79,7 @@ 0x8002A9D4 0x8002AA18 src/func_8002A9D4.c 0x8002AC84 0x8002ACBC src/func_8002AC84.c 0x8002C6EC 0x8002C728 src/func_8002C6EC.c +0x8002C728 0x8002C764 src/func_8002C728.c 0x8002C7BC 0x8002C7EC src/func_8002C7BC.c 0x8002C888 0x8002C894 src/func_8002C888.c 0x8002C894 0x8002C8A4 src/func_8002C894.c @@ -92,6 +93,7 @@ 0x8002E3A8 0x8002E3B8 src/func_8002E3A8.c 0x8002E4C8 0x8002E4F0 src/func_8002E4C8.c 0x8002E7C4 0x8002E7E4 src/func_8002E7C4.c +0x8002E968 0x8002E9AC src/func_8002E968.c 0x8002F160 0x8002F1A4 src/func_8002F160.c 0x8002F1A4 0x8002F1D8 src/func_8002F1A4.c 0x8002F2F8 0x8002F300 src/func_8002F2F8.c @@ -230,6 +232,7 @@ 0x800A623C 0x800A6268 src/func_800A623C.c 0x800A6268 0x800A6294 src/func_800A6268.c 0x800A648C 0x800A64C8 src/func_800A648C.c +0x800A6840 0x800A6880 src/func_800A6840.c 0x800A74BC 0x800A74D0 src/func_800A74BC.c 0x800A8B48 0x800A8B8C src/func_800A8B48.c 0x800A9D58 0x800A9D90 src/func_800A9D58.c diff --git a/src/func_8002C728.c b/src/func_8002C728.c new file mode 100644 index 0000000..1a7a314 --- /dev/null +++ b/src/func_8002C728.c @@ -0,0 +1,43 @@ +/* + * func_8002C728 — 60 bytes at 0x8002C728..0x8002C764 + * + * Decrements a gp-relative counter, uses the decremented value to index a table + * of pointers, and calls a callee with that entry and a zero second argument. The + * counter is loaded before the frame is set up and stored back with a gp-relative + * `sw`. + * + * The observed instructions are: + * lw v0,588(gp) ; v0 = D_80121B84 + * addiu sp,sp,-24 + * sw ra,16(sp) + * addiu v0,v0,-1 ; --counter + * sw v0,588(gp) ; D_80121B84 = v0 + * sll v0,v0,0x2 ; index * 4 + * lui at,0x8011 ; %hi of the table base + * addu at,at,v0 ; table + index*4 + * lw a0,-3324(at) ; a0 = D_8010F304[index] (%lo as displacement) + * jal 0x8002C3F8 + * move a1,zero ; second argument = 0 (delay slot) + * lw ra,16(sp) + * addiu sp,sp,24 + * jr ra + * nop + * + * The decrement is written as `--counter` on the gp-relative global, so the value + * stored back is the decremented one and is reused as the index without a reload. + * + * LIMITS: the gp offset (588 = 0x24C), the table base (0x8011F304), the element + * stride (4) and the callee are hypotheses read from the instruction shape; the + * gp offset is a fact about this executable's gp layout (gp = 0x80121938). What + * the counter and the table mean is unknown and is not guessed here. Only the + * compiled bytes are evidence. + */ + +extern int D_80121B84; +extern int D_8010F304[]; + +void func_8002C728(void) { + int index = --D_80121B84; + + func_8002C3F8(D_8010F304[index], 0); +} diff --git a/src/func_8002E968.c b/src/func_8002E968.c new file mode 100644 index 0000000..bd8ac17 --- /dev/null +++ b/src/func_8002E968.c @@ -0,0 +1,44 @@ +/* + * func_8002E968 — 68 bytes at 0x8002E968..0x8002E9AC + * + * Branches on a global enable byte between two no-argument calls, one of which + * takes a pointer loaded from a global. Both arms converge on one epilogue. + * + * The observed instructions are: + * lui v0,0x8012 + * lbu v0,9104(v0) ; v0 = D_80122390 <- UNSIGNED byte + * addiu sp,sp,-24 + * beqz v0,0x8002E98C ; if (flag == 0) take the second arm + * sw ra,16(sp) ; save ra (delay slot) + * jal 0x800AC85C + * nop + * j 0x8002E99C + * nop + * 8C: lui a0,0x8014 + * lw a0,-15560(a0) ; a0 = D_8013C338 (a pointer) + * jal 0x8002E870 + * nop + * 9C: lw ra,16(sp) + * addiu sp,sp,24 + * jr ra + * nop + * + * The `lbu` shows the enable is an unsigned byte. The pointer is loaded as a + * VALUE out of D_8013C338 (a `lw`, not an address computation), so the callee + * receives whatever pointer the global holds. `lui 0x8014` plus the sign-extended + * -15560 gives 0x8013C348. + * + * LIMITS: the two globals (0x80122390 and 0x8013C348), the byte offset (9104) and + * the callees are hypotheses read from the instruction shape; what the globals + * mean is unknown and is not guessed here. Only the compiled bytes are evidence. + */ + +extern unsigned char D_80122390; +extern int D_8013C338; + +void func_8002E968(void) { + if (D_80122390 != 0) + func_800AC85C(); + else + func_8002E870(D_8013C338); +} diff --git a/src/func_800A6840.c b/src/func_800A6840.c new file mode 100644 index 0000000..13ae542 --- /dev/null +++ b/src/func_800A6840.c @@ -0,0 +1,43 @@ +/* + * func_800A6840 — 64 bytes at 0x800A6840..0x800A6880 + * + * Builds a six-argument call where the fifth argument is the address of a local + * function and the sixth is the caller's fourth argument, then stores the + * caller's FIFTH argument into a field of the returned object. The fifth incoming + * argument arrives on the stack and is saved in `s0` across the call. + * + * The observed instructions are: + * addiu sp,sp,-32 + * sw s0,24(sp) + * lw s0,48(sp) ; s0 = the 5th INCOMING argument + * lui v0,0x800a + * addiu v0,v0,26596 ; v0 = D_800A67E4 (a local function address) + * sw a3,20(sp) ; sixth OUTGOING argument = a3 + * move a3,zero ; fourth outgoing argument = 0 + * sw ra,28(sp) + * jal 0x800A66B0 + * sw v0,16(sp) ; fifth OUTGOING argument (delay slot) + * sw s0,20(v0) ; result->word_14 = the 5th incoming argument + * lw ra,28(sp) + * lw s0,24(sp) + * addiu sp,sp,32 + * jr ra + * nop + * + * The outgoing argument slots are at 16(sp) and 20(sp) of the new 32-byte frame; + * the incoming fifth argument is therefore at 48(sp) (32-byte frame plus the + * o32 home area). `a0`-`a2` are never written, so they are forwarded unchanged. + * + * LIMITS: the function address D_800A67E4, the result field offset (0x14) and the + * argument types are hypotheses read from the instruction shape; what the callee + * and the object are is unknown and is not guessed here. Only the compiled bytes + * are evidence. + */ + +extern char D_800A67E4[]; + +void func_800A6840(int a0, int a1, int a2, int a3, int a4) { + char *result = (char *)func_800A66B0(a0, a1, a2, 0, (int)D_800A67E4, a3); + + *(int *)(result + 20) = a4; +}