phase9: merge worker C 3 — 358 regions / 349 distinct bodies

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.
This commit is contained in:
Christopher Williams
2026-09-24 01:52:24 -04:00
parent 814340cb20
commit cd60c6b3ea
4 changed files with 133 additions and 0 deletions
+3
View File
@@ -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
1 # Code-region registry: one C region per matched function.
79 0x8002A9D4
80 0x8002AC84
81 0x8002C6EC
82 0x8002C728
83 0x8002C7BC
84 0x8002C888
85 0x8002C894
93 0x8002E3A8
94 0x8002E4C8
95 0x8002E7C4
96 0x8002E968
97 0x8002F160
98 0x8002F1A4
99 0x8002F2F8
232 0x800A623C
233 0x800A6268
234 0x800A648C
235 0x800A6840
236 0x800A74BC
237 0x800A8B48
238 0x800A9D58
+43
View File
@@ -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);
}
+44
View File
@@ -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);
}
+43
View File
@@ -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;
}