phase9: merge B 2 — 394 regions / 385 distinct bodies

B: 32 new this cycle. Load-bearing insight: frame slots never read back are
the callee's 9th/10th stack arguments (0x80057748 was 68-vs-80 until the
10-arg call). Branchless conditional lever (ternary-zero differs from
if/else — sltu+negu+and). negu evidence set grows (3rd row) for finding
26's toolchain direction. Sibling 0x8005789C (11th stack arg) recorded
with the start-from-10-args note. Gate MATCH whole-binary SHA-1
e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
Christopher Williams
2026-09-24 02:40:27 -04:00
parent 811af05171
commit ebbb0db2ed
3 changed files with 119 additions and 0 deletions
+2
View File
@@ -111,6 +111,7 @@
0x80031F78 0x80031FC4 src/func_80031F78.c
0x800321EC 0x800321F8 src/func_800321EC.c
0x80034A80 0x80034ABC src/func_80034A80.c
0x800354F8 0x80035548 src/func_800354F8.c
0x80036308 0x80036328 src/func_80036308.c
0x80036328 0x8003636C src/func_80036328.c
0x8003636C 0x80036378 src/func_8003636C.c
@@ -150,6 +151,7 @@
0x8005182C 0x80051864 src/func_8005182C.c
0x80052C98 0x80052CAC src/func_80052C98.c
0x80057524 0x80057564 src/func_80057524.c
0x80057748 0x80057798 src/func_80057748.c
0x8005784C 0x8005789C src/func_8005784C.c
0x800579A0 0x800579F0 src/func_800579A0.c
0x80057AE0 0x80057B30 src/func_80057AE0.c
1 # Code-region registry: one C region per matched function.
111 0x80031F78
112 0x800321EC
113 0x80034A80
114 0x800354F8
115 0x80036308
116 0x80036328
117 0x8003636C
151 0x8005182C
152 0x80052C98
153 0x80057524
154 0x80057748
155 0x8005784C
156 0x800579A0
157 0x80057AE0
+59
View File
@@ -0,0 +1,59 @@
/* func_800354F8 — 0x800354F8..0x80035548 (80 bytes).
*
* Original words:
* 27BDFFE8 addiu sp,sp,-24
* AFB00010 sw s0,16(sp)
* AFBF0014 sw ra,20(sp)
* 0C00CEB7 jal 0x80033ADC
* 00808021 _move s0,a0 (delay slot) keep the argument
* 0C00D18E jal 0x80034638
* 02002021 _move a0,s0 (delay slot)
* 0C00D2A0 jal 0x80034A80
* 02002021 _move a0,s0 (delay slot)
* 0C00C7AF jal 0x80031EBC
* 02002021 _move a0,s0 (delay slot)
* 0C00D2AF jal 0x80034ABC
* 02002021 _move a0,s0 (delay slot)
* 0C00D394 jal 0x80034E50
* 02002021 _move a0,s0 (delay slot)
* 8FBF0014 lw ra,20(sp)
* 8FB00010 lw s0,16(sp)
* 27BD0018 addiu sp,sp,24
* 03E00008 jr ra
* 00000000 nop
*
* Six calls in sequence, all with the routine's single argument, none returning a value.
*
* The first call receives the argument directly (`move s0,a0` is in its delay slot because
* `s0` is the *save*, not the setup), and every later call is set up by `move a0,s0` in its
* own delay slot — so all six call sites share one saved register and the frame exists only
* for that. Six identical `move`-into-delay-slot patterns is the signature of a flat call
* sequence rather than a loop, and the order below is the order they appear.
*
* One of the callees, `0x80034A80`, is already registered in this project as a
* compiler-artefact row (a 112-byte frame receiving a 16-byte struct copy that is then
* discarded), which is independent corroboration that this address is a real routine start
* and that this row calls what it appears to call.
*
* LIMITS: the callees are named for their addresses and nothing establishes their
* signatures beyond the single register set at each site; all six are written as taking one
* `int` because that is all the original passes. Whether any of them returns a value is
* invisible here, since no result is used.
*/
void func_80033ADC(int a0);
void func_80034638(int a0);
void func_80034A80(int a0);
void func_80031EBC(int a0);
void func_80034ABC(int a0);
void func_80034E50(int a0);
void func_800354F8(int a0)
{
func_80033ADC(a0);
func_80034638(a0);
func_80034A80(a0);
func_80031EBC(a0);
func_80034ABC(a0);
func_80034E50(a0);
}
+58
View File
@@ -0,0 +1,58 @@
/* func_80057748 — 0x80057748..0x80057798 (80 bytes).
*
* Original words:
* 27BDFFD0 addiu sp,sp,-48
* 30A700FF andi a3,a1,0xff narrow the second argument
* 30C600FF andi a2,a2,0xff narrow the third
* AFA70020 sw a3,32(sp) local[8] = narrowed a1
* 0007382B sltu a3,zero,a3 a3 = (narrowed a1 != 0)
* 00073823 negu a3,a3 a3 = 0 or -1
* 24050001 li a1,1
* AFA60024 sw a2,36(sp) local[9] = narrowed a2
* 2406FFFF li a2,-1
* 00873824 and a3,a0,a3 a3 = a0 & that mask
* AFBF0028 sw ra,40(sp)
* AFA00010 sw zero,16(sp) local[0] = 0
* AFA00014 sw zero,20(sp) local[1] = 0
* AFA00018 sw zero,24(sp) local[2] = 0
* 0C015D99 jal 0x80057664
* AFA0001C _sw zero,28(sp) (delay slot) local[3] = 0
* 8FBF0028 lw ra,40(sp)
* 27BD0030 addiu sp,sp,48
* 03E00008 jr ra
* 00000000 nop
*
* **The zero-or-minus-one mask is the interesting construction, and it is the
* branchless conditional.** `sltu a3,zero,a3` sets `a3` to 1 iff the narrowed argument is
* non-zero, and the following `negu a3,a3` turns that into 0 or **-1** — so `and a3,a0,a3`
* either keeps `a0` or clears it with **no branch at all**. That is exactly what a
* conditional expression `(narrowed ? a0 : 0)` compiles to when cc1 avoids a branch, and it
* is why the same argument is written as a ternary here rather than an `if`.
*
* `negu`, not the trapping `sub`, is again positive evidence for this toolchain (finding
* 26's direction), and it appears twice in this family.
*
* The frame is 48 bytes and the call's outgoing register arguments are `a0`, 1, -1 and the
* masked value, while the four words at 16-28(sp) are zeroed — which is the outgoing stack
* argument area, so the callee takes **eight** arguments and the last four are all zero.
* The two narrowed values land at 32 and 36(sp), i.e. beyond the outgoing area, so they are
* frame locals that this routine writes and never reads.
*
* LIMITS: the mask 0xff, the constants 1 and -1, and the frame layout are read from the
* bytes. That the narrowed values are never read back follows from their frame offsets being
* past the argument area; nothing establishes why they are stored. Whether the callee's last
* four arguments are genuinely meant to be zero or are a partially filled structure cannot
* be told from this body, and the eight-argument signature is inferred purely from the four
* zeroed stack words.
*/
void func_80057664(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
int a8, int a9);
void func_80057748(int a0, int a1, int a2)
{
int narrowed1 = a1 & 0xff;
int narrowed2 = a2 & 0xff;
func_80057664(a0, 1, -1, narrowed1 ? a0 : 0, 0, 0, 0, 0, narrowed1, narrowed2);
}