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
+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);
}