phase9: merge C 3 — 361 regions / 352 distinct bodies

Worker C closed 0x80031F2C (a row the coordinator had recorded as a
negative) via the F23 struct-assignment lever (second confirmation) —
stale negative removed. Also 0x800129C8, 0x8009132C (F22: unsigned char
local re-masks an already-zero-extended lbu — width-of-DESTINATION tell).
C's link-error finding recorded: 'small-data section too large' on a
region that built fine = a duplicate gp symbol (name mismatch), not a -G
problem. New negative 0x80042E68 pairs with 0x80042DD4; named pointer
lever untried. Gate MATCH whole-binary SHA-1
e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
Christopher Williams
2026-09-24 01:57:36 -04:00
parent 8300f855a5
commit e407d5d2f2
5 changed files with 156 additions and 1 deletions
-1
View File
@@ -28,7 +28,6 @@
0x800266A8 68 near-match byte-replication alloc (first sll register; fresh-context re-spelling 3B; named-locals regresses)
0x8002D014 - near-match -
0x8002D060 72 near-match -
0x80031F2C 76 near-match cross-join/load-hoist (3 coordinator spellings: 92/92/68; original loads 4 words then stores, shared a3=a1 delay binding; finding-F6 family)
0x80039308 - near-match -
0x80042DD4 - near-match -
0x80042E10 - near-match -
1 # Syphon Filter 3 (USA) open negatives index.
28 0x800266A8
29 0x8002D014
30 0x8002D060
0x80031F2C
31 0x80039308
32 0x80042DD4
33 0x80042E10
+3
View File
@@ -15,6 +15,7 @@
0x8001281C 0x80012834 src/func_8001281C.c
0x8001289C 0x800128E4 src/func_8001289C.c
0x800128E4 0x80012918 src/func_800128E4.c
0x800129C8 0x80012A10 src/func_800129C8.c
0x80012D8C 0x80012DBC src/func_80012D8C.c
0x80012DBC 0x80012DE8 src/func_80012DBC.c
0x80013C88 0x80013C90 src/func_80013C88.c
@@ -100,6 +101,7 @@
0x8002F404 0x8002F450 src/func_8002F404.c
0x800301FC 0x8003022C src/func_800301FC.c
0x80030358 0x80030390 src/func_80030358.c
0x80031F2C 0x80031F78 src/func_80031F2C.c
0x80031F78 0x80031FC4 src/func_80031F78.c
0x800321EC 0x800321F8 src/func_800321EC.c
0x80034A80 0x80034ABC src/func_80034A80.c
@@ -209,6 +211,7 @@
0x8009107C 0x800910B0 src/func_8009107C.c
0x800912D4 0x800912FC src/func_800912D4.c
0x800912FC 0x8009132C src/func_800912FC.c
0x8009132C 0x80091370 src/func_8009132C.c
0x80092068 0x80092088 src/func_80092068.c
0x80092088 0x800920BC src/func_80092088.c
0x800920BC 0x800920DC src/func_800920BC.c
1 # Code-region registry: one C region per matched function.
15 0x8001281C
16 0x8001289C
17 0x800128E4
18 0x800129C8
19 0x80012D8C
20 0x80012DBC
21 0x80013C88
101 0x8002F404
102 0x800301FC
103 0x80030358
104 0x80031F2C
105 0x80031F78
106 0x800321EC
107 0x80034A80
211 0x8009107C
212 0x800912D4
213 0x800912FC
214 0x8009132C
215 0x80092068
216 0x80092088
217 0x800920BC
+48
View File
@@ -0,0 +1,48 @@
/*
* func_800129C8 — 72 bytes at 0x800129C8..0x80012A10
*
* Calls a teardown routine with a fixed displacement from the first argument and
* a value read through the second, then clears that value. Both null cases return
* zero through the SAME epilogue, so the source uses guarded blocks rather than
* early returns.
*
* The observed instructions are:
* addiu sp,sp,-24
* sw s0,16(sp)
* move s0,a1 ; s0 = flag pointer
* beqz s0,0x800129F8 ; if (flag == 0) goto return-zero
* sw ra,20(sp) ; save ra (delay slot)
* lw a1,0(s0) ; a1 = *flag
* nop
* beqz a1,0x800129FC ; if (*flag == 0) return 0
* move v0,zero ; return value (delay slot)
* jal 0x80026560
* addiu a0,a0,152 ; first argument = p + 152 (delay slot)
* sw zero,0(s0) ; *flag = 0
* F8: move v0,zero ; return 0
* FC: lw ra,20(sp)
* lw s0,16(sp)
* addiu sp,sp,24
* jr ra
* nop
*
* The second argument is kept in `s0` across the call, which is why the frame
* saves both `ra` and `s0`. The value read through the pointer is passed as the
* callee's second argument and the pointer is cleared afterwards.
*
* LIMITS: the displacement (152) and the parameter types are hypotheses read from
* the instruction shape; what the pointer and the callee mean is unknown and is
* not guessed here. Only the compiled bytes are evidence.
*/
int func_800129C8(char *p, int *flag) {
if (flag == 0)
return 0;
if (*flag != 0) {
func_80026560(p + 152, *flag);
*flag = 0;
}
return 0;
}
+52
View File
@@ -0,0 +1,52 @@
/*
* func_80031F2C — 76 bytes at 0x80031F2C..0x80031F78
*
* Copies either one word or four words out of a structure reached through the
* first argument, depending on a flag word: the single-word case jumps over the
* four-word case, and both converge on one epilogue.
*
* The observed instructions are:
* lw a2,164(a0) ; q = p->ptr_a4
* nop
* lw v0,1300(a2) ; q->word_514 (the flag)
* nop
* bnez v0,0x80031F50 ; if (flag != 0) take the four-word arm
* move a3,a1 ; out = a1 (delay slot)
* lw v0,1308(a2) ; q->word_51c
* j 0x80031F70
* sw v0,0(a3) ; out[0] = v0 (delay slot)
* 50: lw v0,1308(a2)
* lw v1,1312(a2)
* lw a0,1316(a2)
* lw a1,1320(a2)
* sw v0,0(a3) ; out[0..3] = four words
* sw v1,4(a3)
* sw a0,8(a3)
* sw a1,12(a3)
* 70: jr ra
* nop
*
* Note the four-word arm re-reads the SAME first field that the one-word arm
* reads (offset 0x51c), so the two arms differ only in how many words follow.
*
* LIMITS: the pointer offset (0xa4) and the five field offsets (0x514, 0x51c,
* 0x520, 0x524, 0x528) are hypotheses read from the instruction shape; what the
* structure holds is unknown and is not guessed here. Only the compiled bytes are
* evidence.
*/
typedef struct {
int word_00;
int word_04;
int word_08;
int word_0c;
} func_80031F2C_block;
void func_80031F2C(char *p, int *out) {
char *q = *(char **)(p + 164);
if (*(int *)(q + 1300) == 0)
out[0] = *(int *)(q + 1308);
else
*(func_80031F2C_block *)out = *(func_80031F2C_block *)(q + 1308);
}
+53
View File
@@ -0,0 +1,53 @@
/*
* func_8009132C — 68 bytes at 0x8009132C..0x80091370
*
* Reads a gp-relative mode byte, clears a gp-relative state word to -1, and when
* the mode is exactly 1 makes a two-argument call before a final no-argument call.
* The mode byte is read BEFORE the state word is cleared.
*
* The observed instructions are:
* addiu sp,sp,-24
* lbu v1,3388(gp) ; mode = D_80122674 <- UNSIGNED byte
* li v0,-1
* sw v0,1468(gp) ; D_80121EF4 = -1
* li v0,1
* bne v1,v0,0x80091358 ; if (mode != 1) skip the first call
* sw ra,16(sp) ; save ra (delay slot)
* lw a0,3368(gp) ; D_80122660
* lw a1,3384(gp) ; D_80122670
* jal 0x8008FCD8
* nop
* 58: jal 0x800912D4
* nop
* lw ra,16(sp)
* addiu sp,sp,24
* jr ra
* nop
*
* Two source-shape requirements: the mode byte must be loaded before the state
* store (reading it inline in the condition lets cc1 sink the load below the
* store), and the local it is read into must be an `int`, not an `unsigned char`
* — an `unsigned char` local makes cc1 re-mask the already-zero-extended `lbu`
* result with `andi v0,v0,0xff`, costing 4 bytes.
*
* LIMITS: the four gp offsets (3388 = 0xD3C, 1468 = 0x5BC, 3368 = 0xD28,
* 3384 = 0xD38) and the two callees are hypotheses read from the instruction
* shape; the offsets are facts about this executable's gp layout (gp =
* 0x80121938). What the mode and the state mean is unknown and is not guessed
* here. The `lbu` shows the mode is an unsigned byte. Only the compiled bytes are
* evidence.
*/
extern unsigned char D_80122674;
extern int D_80121EF4;
extern int D_80122660;
extern int D_80122670;
void func_8009132C(void) {
int mode = D_80122674;
D_80121EF4 = -1;
if (mode == 1)
func_8008FCD8(D_80122660, D_80122670);
func_800912D4();
}