phase11: merge 61 — worker E's 0x8007F9B0 -> 602 bodies / 611 regions

This commit is contained in:
Christopher Williams
2026-09-24 11:43:43 -04:00
parent b0ed17d494
commit 6141079f9b
2 changed files with 60 additions and 0 deletions
+1
View File
@@ -327,6 +327,7 @@
0x8007E8B8 0x8007E904 src/func_8007E8B8.c
0x8007EB8C 0x8007EBEC src/func_8007EB8C.c
0x8007ED4C 0x8007ED8C src/func_8007ED4C.c
0x8007F9B0 0x8007FA1C src/func_8007F9B0.c
0x80082750 0x800827A8 src/func_80082750.c
0x800827A8 0x800827C4 src/func_800827A8.c
0x800827C4 0x80082868 src/func_800827C4.c
1 # Code-region registry: one C region per matched function.
327 0x8007E8B8
328 0x8007EB8C
329 0x8007ED4C
330 0x8007F9B0
331 0x80082750
332 0x800827A8
333 0x800827C4
+59
View File
@@ -0,0 +1,59 @@
/*
* func_8007F9B0 — 108 bytes at 0x8007F9B0..0x8007FA1C
*
* Gate on a three-level dereference, then set two fields and call a helper. No frame beyond the
* return address. **Second spelling, default toolchain.**
*
* addiu sp,sp,-0x18 / sw ra,16(sp) frame 24, ra at 0x10, no other save.
* lw v0,12(a0) / nop v0 = *(int *)(a0 + 12)
* lw v0,344(v0) / nop v0 = *(int *)(v0 + 344)
* lw v1,56(v0) v1 = *(int *)(v0 + 56) <-- THE THIRD LEVEL
* li v0,6 / bne v1,v0,END / nop if (that != 6) return;
* lw v0,28(a0) / nop the a0->f28 chain is RE-READ for each statement
* lw v1,8(v0) / li v0,62
* sw v0,48(v1) *(int *)(*(int *)(a0+28)+8)+48) = 62; WORD store
* lw v0,28(a0) / nop / lw v1,8(v0) ... re-read for the SECOND statement
* li v0,20 / sb v0,52(v1) *(... +52) = 20; BYTE store
* lh a0,2(a0) the call's first argument is a SIGNED HALFWORD
* jal 0x80043DC4 / li a1,62 func_80043DC4(*(short *)(a0 + 2), 62);
*
* FOUR THINGS ARE BYTE-REQUIRED:
*
* 1. **THE GATE IS THREE DEREFERENCES, NOT TWO.** `a0->f12 -> f344 -> f56`, and the innermost
* load is easy to drop when transcribing from a disassembly: writing
* `*(int *)(*(int *)(a0 + 12) + 344) != 6` compiles to a body **two instructions SHORT**
* (100 vs 108) because the missing load and its load-delay `nop` are exactly the deficit.
* **Diagnostic (cookbook 49's family): a body exactly two instructions short where the
* original has one more `lw` in a pointer chain means a MISSING DEREFERENCE LEVEL, not a
* missing statement -- recompute the chain from the displacements rather than eyeballing it.**
* 2. **THE a0->f28 CHAIN IS RE-READ PER STATEMENT** (cookbook 105's per-statement setting): the
* original loads `28(a0)` and `8(v0)` TWICE, once for each of the two stores. Binding either
* to a local would collapse one of the pairs.
* 3. **THE STORE WIDTHS ARE THE LAYOUT** (cookbook 93): `sw` for the field at 48 and `sb` for the
* field at 52 -- there is no other evidence for these two fields' types.
* 4. **THE CALL'S FIRST ARGUMENT IS A SIGNED HALFWORD**: `lh a0,2(a0)`, not `lw`. The `lh` is the
* only reason to call it `short`, and it is the same parameter register being reused.
*
* The gate's chained loads keep the SAME register (`lw v0,12(a0)` then `lw v0,344(v0)`), which is
* why the body carries a load-delay `nop` after each of the first two loads: the next instruction
* loads FROM the register just loaded, which is exactly maspsx's nop predicate (cookbook 27).
*
* LIMITS: func_80043DC4 is a cross-reference by address only and its purpose is not established.
* The object at a0 and the two objects reached through the chains are typed by their access widths
* and displacements only -- offsets 12, 344, 56, 28, 8, 48, 52 and 2, and the `short` at +2 is the
* one type claim, earned from the `lh`. The field names and the meaning of the `!= 6` gate are not
* recovered. The function returns nothing (`void`): the epilogue sets no value in v0.
*/
extern void func_80043DC4(int a0, int a1);
void func_8007F9B0(int a0)
{
if (*(int *)(*(int *)(*(int *)(a0 + 12) + 344) + 56) != 6)
return;
*(int *)(*(int *)(*(int *)(a0 + 28) + 8) + 48) = 62;
*(char *)(*(int *)(*(int *)(a0 + 28) + 8) + 52) = 20;
func_80043DC4(*(short *)(a0 + 2), 62);
}