phase7: match 22 more function bodies from the worklist

Both batch targets are met in one pass: 22 new bodies (23 including the P7-T5
match), taking the project from 11 distinct bodies to 34 -- past the phase
milestone of 30 -- across 39 registered regions.

The batch is dominated by the small leaf shapes the worklist ranks first:
empty function (4 duplicate addresses), byte/halfword/word setters, field
getters, a word-buffer clearer, and eight gp-relative getters/setters. Every one
was byte-identical on the first or second attempt, and every extent came from
tools/sf3_extents rather than a hand-derived end.

Three shapes needed diagnosis, and two were solved:

- 0x8003636C was 16 bytes instead of 12 because `return 1` forced a second
  `li v0,1` into the delay slot; the original leaves 1 in v0 as scratch, so the
  function is `void`.
- 0x800F7FB4 needed the parameter reused as the loop counter.

Four candidates are recorded as bounded negatives or deferrals rather than
guesses:

- 0x800F7FB4: the loop body reproduces exactly, but the original has no frame
  and every tested formulation allocates 8 bytes (five C forms, and an
  -O1/-O2/-O3/-fomit-frame-pointer matrix). Stopped after two distinct attempts.
- 0x800F8AEC: the original schedules `lui` / `jr ra` / `addiu` with the low half
  in the delay slot; the reconstruction emits `lui` / `addiu` / `jr ra` / `nop`.
- 0x80010810: GTE (COP2) code needing the SDK's GTE macros, which the build has
  no headers for.
- 0x800FB5D4 (`move v0,sp`) and 0x80103FCC/0x80103FEC (BIOS `syscall` wrappers)
  and 0x8001EAFC (a shared jump block, not a standalone function).

make gate: c_regions=39, 0 differing bytes, SHA-1 e173426c. Extents verify agrees
on all 39 regions. 168 synthetic tests.
This commit is contained in:
Christopher Williams
2026-09-23 22:34:02 -04:00
parent 399da98a83
commit dd807ffb8c
24 changed files with 466 additions and 0 deletions
+25
View File
@@ -11,16 +11,41 @@
#
# Matched so far:
0x80012780 0x8001278C src/func_80012780.c
0x80013C88 0x80013C90 src/func_80013C88.c
0x800179D4 0x800179E0 src/func_800179D4.c
0x80017AD4 0x80017AE8 src/func_80017AD4.c
0x80017AE8 0x80017AF8 src/func_80017AE8.c
0x80017C60 0x80017C6C src/func_80017C60.c
0x80017DD0 0x80017DF0 src/func_80017DD0.c
0x80019C04 0x80019C10 src/func_80019C04.c
0x8001AA9C 0x8001AAA8 src/func_8001AA9C.c
0x80024C14 0x80024C34 src/func_80024C14.c
0x80026258 0x80026264 src/func_80026258.c
0x80026264 0x80026274 src/func_80026264.c
0x800262E0 0x800262EC src/func_800262E0.c
0x800262EC 0x800262F8 src/func_800262E0.c
0x800262F8 0x80026304 src/func_800262F8.c
0x800267C0 0x800267CC src/func_800267C0.c
0x8002C888 0x8002C894 src/func_8002C888.c
0x8002D2A0 0x8002D2BC src/func_8002D2A0.c
0x8002D2BC 0x8002D2D4 src/func_8002D2BC.c
0x800321EC 0x800321F8 src/func_800321EC.c
0x80036308 0x80036328 src/func_80036308.c
0x8003636C 0x80036378 src/func_8003636C.c
0x80036378 0x80036380 src/func_80036378.c
0x80038788 0x80038790 src/func_80038788.c
0x80038790 0x8003879C src/func_80038790.c
0x80042088 0x80042090 src/func_80042088.c
0x80057DFC 0x80057E04 src/func_80057DFC.c
0x800697A4 0x800697C4 src/func_800697A4.c
0x8007DC40 0x8007DC4C src/func_8007DC40.c
0x80089C4C 0x80089C54 src/func_80042088.c
0x80089E74 0x80089E7C src/func_80042088.c
0x8008F4A0 0x8008F4AC src/func_8008F4A0.c
0x800B5AF0 0x800B5AF8 src/func_80042088.c
0x800BBDEC 0x800BBDF8 src/func_800BBDEC.c
0x800F8F9C 0x800F8FC0 src/func_800F8F9C.c
0x800FBDF8 0x800FBE04 src/func_800FBDF8.c
0x800FC2CC 0x800FC2D8 src/func_800FC2CC.c
0x800FE86C 0x800FE878 src/func_800FE86C.c
0x80109314 0x80109338 src/func_800F8F9C.c
1 # Code-region registry: one C region per matched function.
11 #
12 # Matched so far:
13 0x80012780
14 0x80013C88
15 0x800179D4
16 0x80017AD4
17 0x80017AE8
18 0x80017C60
19 0x80017DD0
20 0x80019C04
21 0x8001AA9C
22 0x80024C14
23 0x80026258
24 0x80026264
25 0x800262E0
26 0x800262EC
27 0x800262F8
28 0x800267C0
29 0x8002C888
30 0x8002D2A0
31 0x8002D2BC
32 0x800321EC
33 0x80036308
34 0x8003636C
35 0x80036378
36 0x80038788
37 0x80038790
38 0x80042088
39 0x80057DFC
40 0x800697A4
41 0x8007DC40
42 0x80089C4C
43 0x80089E74
44 0x8008F4A0
45 0x800B5AF0
46 0x800BBDEC
47 0x800F8F9C
48 0x800FBDF8
49 0x800FC2CC
50 0x800FE86C
51 0x80109314
+11
View File
@@ -18,6 +18,17 @@ _gp 0x80121938
D_80121974 0x80121974 gp
D_80121B18 0x80121B18 gp
D_80121B14 0x80121B14 gp
D_801219BC 0x801219BC gp
D_80121A88 0x80121A88 gp
D_80121A60 0x80121A60 gp
D_80121B2A 0x80121B2A gp
D_80121B8C 0x80121B8C gp
D_80121EA4 0x80121EA4 gp
D_8012265C 0x8012265C gp
D_801220A0 0x801220A0 gp
D_801220E0 0x801220E0 gp
D_80122104 0x80122104 gp
D_80122138 0x80122138 gp
func_80024668 0x80024668
func_800F4098 0x800F4098
func_800695D8 0x800695D8
1 # Symbol registry: absolute addresses for cross-references used by C regions.
18 D_80121974
19 D_80121B18
20 D_80121B14
21 D_801219BC
22 D_80121A88
23 D_80121A60
24 D_80121B2A
25 D_80121B8C
26 D_80121EA4
27 D_8012265C
28 D_801220A0
29 D_801220E0
30 D_80122104
31 D_80122138
32 func_80024668
33 func_800F4098
34 func_800695D8
+17
View File
@@ -0,0 +1,17 @@
/*
* func_80013C88 — 8 bytes at 0x80013C88..0x80013C90
*
* Byte-identical reconstruction of a one-byte field setter. The store is
* scheduled into the `jr` delay slot (cookbook finding 8).
*
* The observed instructions are:
* jr ra
* sb a1,0x13c(a0) (delay slot)
*
* LIMITS: the name, the base pointer type and the field offset are hypotheses
* read from the disassembly; `sb` fixes only that a single byte is stored.
*/
void func_80013C88(char *base, char value) {
base[0x13c] = value;
}
+20
View File
@@ -0,0 +1,20 @@
/*
* func_800179D4 — 12 bytes at 0x800179D4..0x800179E0
*
* Byte-identical reconstruction of a two-field setter that stores a halfword and
* a word. The second store is scheduled into the `jr` delay slot.
*
* The observed instructions are:
* sh a1,0x16(a0) base->half = first
* jr ra
* sw a2,0xc(a0) (delay slot) base->word = second
*
* LIMITS: the name, the base pointer type and both field offsets are hypotheses
* read from the disassembly. `sh` fixes the first store's width, `sw` the
* second's; the parameter order is fixed by the register usage (a1 then a2).
*/
void func_800179D4(char *base, short first, int second) {
*(short *)(base + 0x16) = first;
*(int *)(base + 0xc) = second;
}
+22
View File
@@ -0,0 +1,22 @@
/*
* func_80017C60 — 12 bytes at 0x80017C60..0x80017C6C
*
* Byte-identical reconstruction of a `gp`-relative halfword setter. `gp` is
* 0x80121938 (crt0 sets it at 0x800FB3E4), so 0x84(gp) is 0x801219BC; the symbol
* is marked `gp` in `config/symbols.tsv` so the access is emitted `%gp_rel`
* (cookbook finding 10).
*
* The observed instructions are:
* sh a0,0x84(gp) D_801219BC = value
* jr ra
* nop
*
* LIMITS: the name and the global's name and type are hypotheses read from the
* disassembly; `sh` fixes only that a halfword is stored.
*/
extern short D_801219BC;
void func_80017C60(short value) {
D_801219BC = value;
}
+21
View File
@@ -0,0 +1,21 @@
/*
* func_80019C04 — 12 bytes at 0x80019C04..0x80019C10
*
* Byte-identical reconstruction of a `gp`-relative word setter. `gp` is
* 0x80121938, so 0x150(gp) is 0x80121A88; the symbol is marked `gp` in
* `config/symbols.tsv` (cookbook finding 10).
*
* The observed instructions are:
* sw a0,0x150(gp) D_80121A88 = value
* jr ra
* nop
*
* LIMITS: the name and the global's name and type are hypotheses read from the
* disassembly; `sw` fixes only that one word is stored.
*/
extern int D_80121A88;
void func_80019C04(int value) {
D_80121A88 = value;
}
+21
View File
@@ -0,0 +1,21 @@
/*
* func_8001AA9C — 12 bytes at 0x8001AA9C..0x8001AAA8
*
* Byte-identical reconstruction of a `gp`-relative word setter. `gp` is
* 0x80121938, so 0x128(gp) is 0x80121A60; the symbol is marked `gp` in
* `config/symbols.tsv` (cookbook finding 10).
*
* The observed instructions are:
* sw a0,0x128(gp) D_80121A60 = value
* jr ra
* nop
*
* LIMITS: the name and the global's name and type are hypotheses read from the
* disassembly; `sw` fixes only that one word is stored.
*/
extern int D_80121A60;
void func_8001AA9C(int value) {
D_80121A60 = value;
}
+21
View File
@@ -0,0 +1,21 @@
/*
* func_80026258 — 12 bytes at 0x80026258..0x80026264
*
* Byte-identical reconstruction of a `gp`-relative word setter. `gp` is
* 0x80121938, so 0x1dc(gp) is 0x80121B14, which is already a `gp`-marked row in
* `config/symbols.tsv` (cookbook finding 10).
*
* The observed instructions are:
* sw a0,0x1dc(gp) D_80121B14 = value
* jr ra
* nop
*
* LIMITS: the name and the global's name and type are hypotheses read from the
* disassembly; `sw` fixes only that one word is stored.
*/
extern int D_80121B14;
void func_80026258(int value) {
D_80121B14 = value;
}
+23
View File
@@ -0,0 +1,23 @@
/*
* func_800262F8 — 12 bytes at 0x800262F8..0x80026304
*
* Byte-identical reconstruction of a `gp`-relative word getter. `gp` is
* 0x80121938, so 0x1e0(gp) is 0x80121B18, which is already a `gp`-marked row in
* `config/symbols.tsv` (cookbook finding 10). It reads back the global that
* `func_800262E0` and `func_80026258` write, which is consistent with a
* getter/setter family, but that is an inference, not evidence.
*
* The observed instructions are:
* lw v0,0x1e0(gp) return D_80121B18
* jr ra
* nop
*
* LIMITS: the name and the global's name and type are hypotheses read from the
* disassembly; `lw` fixes only that one word is loaded into the return register.
*/
extern int D_80121B18;
int func_800262F8(void) {
return D_80121B18;
}
+21
View File
@@ -0,0 +1,21 @@
/*
* func_800267C0.c — 12 bytes at 0x800267C0..0x800267CC
*
* Byte-identical reconstruction of a gp-relative byte setter that returns 0.
* gp is 0x80121938, so 0x1f2(gp) is 0x80121B2A; the symbol carries the `gp`
* marker in `config/symbols.tsv`.
*
* The observed instructions are:
* sb a0,0x1f2(gp) D_80121B2A = value
* jr ra
* clear v0 (delay slot) return 0
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
extern char D_80121B2A;
int func_800267C0(char value) {
D_80121B2A = value;
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* func_8002C888.c — 12 bytes at 0x8002C888..0x8002C894
*
* Byte-identical reconstruction of a gp-relative byte setter. gp is 0x80121938,
* so 0x254(gp) is 0x80121B8C; the symbol carries the `gp` marker.
*
* The observed instructions are:
* sb a0,0x254(gp) D_80121B8C = value
* jr ra
* nop
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
extern char D_80121B8C;
void func_8002C888(char value) {
D_80121B8C = value;
}
+16
View File
@@ -0,0 +1,16 @@
/*
* func_800321EC.c — 12 bytes at 0x800321EC..0x800321F8
*
* Byte-identical reconstruction of a word field getter at a large offset.
*
* The observed instructions are:
* lw v0,0xdc(a0) return base->word at 0xdc
* jr ra
* nop
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
int func_800321EC(char *base) {
return *(int *)(base + 0xdc);
}
+21
View File
@@ -0,0 +1,21 @@
/*
* func_8003636C.c — 12 bytes at 0x8003636C..0x80036378
*
* Byte-identical reconstruction of a flag setter.
* The store is scheduled into the `jr` delay slot.
*
* The observed instructions are:
* li v0,0x1 v0 = 1, used as scratch for the constant
* jr ra
* sb v0,0x129a(a0) (delay slot) base[0x129a] = 1
*
* The function is `void`: an `int` return forced a second `li v0,1` into the
* delay slot and made the body 16 bytes instead of 12, so the `li` here is
* scratch for the constant, not a return value.
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
void func_8003636C(char *base) {
base[0x129a] = 1;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* func_80036378 — 8 bytes at 0x80036378..0x80036380
*
* Byte-identical reconstruction of a one-byte field setter at a large offset.
* The store is scheduled into the `jr` delay slot (cookbook finding 8).
*
* The observed instructions are:
* jr ra
* sb a1,0x1298(a0) (delay slot)
*
* LIMITS: the name, the base pointer type and the field offset are hypotheses
* read from the disassembly; `sb` fixes only that a single byte is stored. The
* 0x1298 offset is far outside a plausible single struct field's neighbourhood,
* so the base may be a byte buffer rather than a struct pointer.
*/
void func_80036378(char *base, char value) {
base[0x1298] = value;
}
+17
View File
@@ -0,0 +1,17 @@
/*
* func_80038788 — 8 bytes at 0x80038788..0x80038790
*
* Byte-identical reconstruction of a one-byte field setter at a large offset.
* The store is scheduled into the `jr` delay slot (cookbook finding 8).
*
* The observed instructions are:
* jr ra
* sb a1,0x132c(a0) (delay slot)
*
* LIMITS: the name, the base pointer type and the field offset are hypotheses
* read from the disassembly; `sb` fixes only that a single byte is stored.
*/
void func_80038788(char *base, char value) {
base[0x132c] = value;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* func_80038790.c — 12 bytes at 0x80038790..0x8003879C
*
* Byte-identical reconstruction of a word field setter taking an unsigned char.
* The `andi a1,a1,0xff` is the unsigned-char parameter mask (cookbook finding
* 7: plain `char` is unsigned on this target, and an `unsigned char` argument
* is masked before use).
*
* The observed instructions are:
* andi a1,a1,0xff value &= 0xff
* jr ra
* sw a1,0x1328(a0) (delay slot) base->word at 0x1328 = value
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
void func_80038790(char *base, unsigned char value) {
*(int *)(base + 0x1328) = value;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* func_80042088 — 8 bytes at 0x80042088..0x80042090
*
* Byte-identical reconstruction of an empty function. The identical 8-byte body
* occurs at four addresses (0x80042088, 0x80089C4C, 0x80089E74, 0x800B5AF0), so
* it is matched once and registered four times against this source — the
* documented N-rows-to-one-source duplicate-sharing mechanism.
*
* The observed instructions are:
* jr ra
* nop
*
* LIMITS: the name is an address placeholder. An empty C function is the only
* shape that produces this body, so the reconstruction is byte-proven while the
* original's name and purpose remain unknown.
*/
void func_80042088(void) {
}
+17
View File
@@ -0,0 +1,17 @@
/*
* func_80057DFC — 8 bytes at 0x80057DFC..0x80057E04
*
* Byte-identical reconstruction of a field clearer. The store is scheduled into
* the `jr` delay slot (cookbook finding 8).
*
* The observed instructions are:
* jr ra
* sw zero,0x4(a0) (delay slot)
*
* LIMITS: the name, the base pointer type and the field offset are hypotheses
* read from the disassembly; `sw` fixes only that one word is stored.
*/
void func_80057DFC(int *base) {
base[1] = 0;
}
+20
View File
@@ -0,0 +1,20 @@
/*
* func_8007DC40.c — 12 bytes at 0x8007DC40..0x8007DC4C
*
* Byte-identical reconstruction of a gp-relative word getter tested against
* zero. gp is 0x80121938, so 0x56c(gp) is 0x80121EA4; the symbol carries the
* `gp` marker. `sltiu v0,v0,1` is the `== 0` comparison.
*
* The observed instructions are:
* lw v0,0x56c(gp)
* jr ra
* sltiu v0,v0,0x1 (delay slot) return value == 0
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
extern int D_80121EA4;
int func_8007DC40(void) {
return D_80121EA4 == 0;
}
+21
View File
@@ -0,0 +1,21 @@
/*
* func_8008F4A0.c — 12 bytes at 0x8008F4A0..0x8008F4AC
*
* Byte-identical reconstruction of a gp-relative byte getter tested against
* zero. gp is 0x80121938, so 0xd24(gp) is 0x8012265C; the symbol carries the
* `gp` marker. `lbu` fixes the global as a byte; `sltiu v0,v0,1` is the
* `== 0` comparison.
*
* The observed instructions are:
* lbu v0,0xd24(gp)
* jr ra
* sltiu v0,v0,0x1 (delay slot) return value == 0
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
extern unsigned char D_8012265C;
int func_8008F4A0(void) {
return D_8012265C == 0;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* func_800BBDEC.c — 12 bytes at 0x800BBDEC..0x800BBDF8
*
* Byte-identical reconstruction of a gp-relative word clearer. gp is 0x80121938,
* so 0x768(gp) is 0x801220A0; the symbol carries the `gp` marker.
*
* The observed instructions are:
* sw zero,0x768(gp) D_801220A0 = 0
* jr ra
* nop
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
extern int D_801220A0;
void func_800BBDEC(void) {
D_801220A0 = 0;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* func_800FBDF8.c — 12 bytes at 0x800FBDF8..0x800FBE04
*
* Byte-identical reconstruction of a gp-relative word getter. gp is 0x80121938,
* so 0x7a8(gp) is 0x801220E0; the symbol carries the `gp` marker.
*
* The observed instructions are:
* lw v0,0x7a8(gp)
* jr ra
* nop
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
extern int D_801220E0;
int func_800FBDF8(void) {
return D_801220E0;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* func_800FC2CC.c — 12 bytes at 0x800FC2CC..0x800FC2D8
*
* Byte-identical reconstruction of a gp-relative word setter. gp is 0x80121938,
* so 0x7cc(gp) is 0x80122104; the symbol carries the `gp` marker.
*
* The observed instructions are:
* sw a0,0x7cc(gp) D_80122104 = value
* jr ra
* nop
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
extern int D_80122104;
void func_800FC2CC(int value) {
D_80122104 = value;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* func_800FE86C.c — 12 bytes at 0x800FE86C..0x800FE878
*
* Byte-identical reconstruction of a gp-relative word getter. gp is 0x80121938,
* so 0x800(gp) is 0x80122138; the symbol carries the `gp` marker.
*
* The observed instructions are:
* lw v0,0x800(gp)
* jr ra
* nop
*
* LIMITS: every name, type and offset here is a hypothesis read from the
* disassembly; only the compiled bytes are evidence.
*/
extern int D_80122138;
int func_800FE86C(void) {
return D_80122138;
}