phase9: merge 6 more — 281 regions / 272 distinct bodies
Worker A batch 9: if-conversion demo, pre-increment append, negate-magnitude, guarded call pairs, epilogue-order-variant NEGATIVE 0x80100334 (finding 11's '13 CRT sites' scoping corrected — this site is outside the CRT; recorded as a third epilogue class data point), sched-tiebreak 0x8002515C. New symbol D_80122160 (gp). Gate MATCH whole-binary SHA-1 e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
@@ -64,6 +64,7 @@
|
||||
0x800276B0 0x800276D4 src/func_800276B0.c
|
||||
0x800290D0 0x800290F0 src/func_800290D0.c
|
||||
0x800290F0 0x80029118 src/func_800290F0.c
|
||||
0x8002C6EC 0x8002C728 src/func_8002C6EC.c
|
||||
0x8002C7BC 0x8002C7EC src/func_8002C7BC.c
|
||||
0x8002C888 0x8002C894 src/func_8002C888.c
|
||||
0x8002C894 0x8002C8A4 src/func_8002C894.c
|
||||
@@ -95,6 +96,7 @@
|
||||
0x80042D64 0x80042D88 src/func_80042D64.c
|
||||
0x80043D8C 0x80043DC4 src/func_80043D8C.c
|
||||
0x80044F58 0x80044FA4 src/func_80044F58.c gp=-D_80121BFC
|
||||
0x80045388 0x800453C0 src/func_80045388.c
|
||||
0x800453C0 0x800453F8 src/func_800453C0.c
|
||||
0x8004C060 0x8004C090 src/func_8004C060.c
|
||||
0x8004C090 0x8004C0AC src/func_8004C090.c
|
||||
@@ -126,6 +128,7 @@
|
||||
0x8006FA78 0x8006FAA0 src/func_8006FA78.c
|
||||
0x8007049C 0x800704BC src/func_8007049C.c
|
||||
0x80072BA8 0x80072BDC src/func_80072BA8.c
|
||||
0x800734A4 0x800734DC src/func_800734A4.c
|
||||
0x8007A404 0x8007A428 src/func_8007A404.c
|
||||
0x8007C4EC 0x8007C524 src/func_8007C4EC.c
|
||||
0x8007DC40 0x8007DC4C src/func_8007DC40.c
|
||||
@@ -164,6 +167,7 @@
|
||||
0x80099A94 0x80099AE4 src/func_80099A94.c
|
||||
0x80099E14 0x80099E34 src/func_80099E14.c
|
||||
0x8009AC08 0x8009AC28 src/func_8009AC08.c
|
||||
0x8009B464 0x8009B4A0 src/func_8009B464.c
|
||||
0x8009D8A0 0x8009D8E0 src/func_8009D8A0.c
|
||||
0x8009E8D0 0x8009E95C src/func_8009E8D0.c
|
||||
0x8009F0E8 0x8009F120 src/func_8009F0E8.c
|
||||
@@ -172,6 +176,7 @@
|
||||
0x800A6268 0x800A6294 src/func_800A6268.c
|
||||
0x800A74BC 0x800A74D0 src/func_800A74BC.c
|
||||
0x800A8B48 0x800A8B8C src/func_800A8B48.c
|
||||
0x800A9D58 0x800A9D90 src/func_800A9D58.c
|
||||
0x800AA56C 0x800AA59C src/func_800AA56C.c
|
||||
0x800AC818 0x800AC85C src/func_800AC818.c
|
||||
0x800AC85C 0x800AC884 src/func_800AC85C.c
|
||||
@@ -222,6 +227,7 @@
|
||||
0x800F8F9C 0x800F8FC0 src/func_800F8F9C.c
|
||||
0x800F8FE4 0x800F8FF8 src/func_800F8FE4.c maspsx=off
|
||||
0x800F8FF8 0x800F9008 src/func_800F8FF8.c
|
||||
0x800F9344 0x800F9380 src/func_800F9344.c
|
||||
0x800FA960 0x800FA980 src/func_800FA960.c
|
||||
0x800FB13C 0x800FB1BC src/func_800FB13C.c
|
||||
0x800FB5D4 0x800FB5DC src/func_800FB5D4.c
|
||||
|
||||
|
@@ -179,6 +179,7 @@ D_80122150 0x80122150 gp
|
||||
D_80122154 0x80122154 gp
|
||||
D_80122158 0x80122158 gp
|
||||
D_8012215C 0x8012215C gp
|
||||
D_80122160 0x80122160 gp
|
||||
D_80122164 0x80122164 gp
|
||||
D_80122170 0x80122170 gp
|
||||
D_80122174 0x80122174 gp
|
||||
|
||||
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* func_8002C6EC — 60 bytes at 0x8002C6EC..0x8002C728
|
||||
*
|
||||
* Framed routine: appends its argument to a global array indexed by an incrementing
|
||||
* `gp`-relative counter, then calls a routine.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* lw v0,0x24c(gp) 8f82024c v0 = *(int *)(gp + 0x24c)
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* addiu v0,v0,0x1 24420001 v0 += 1
|
||||
* sw v0,0x24c(gp) af82024c *(int *)(gp + 0x24c) = v0
|
||||
* sll v0,v0,0x2 00021080 v0 *= 4
|
||||
* lui at,0x8011 3c018011 \
|
||||
* addu at,at,v0 00220821 / at = 0x80110000 + index * 4
|
||||
* sw a0,-0xcfc(at) ac24f304 *(int *)(at - 0xcfc) = a0
|
||||
* jal 0x8002c3f8 0c00b0fe call func_8002C3F8
|
||||
* li a1,0x1 24050001 a1 = 1 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* `0x24c(gp)` is a `gp`-relative access off gp 0x80121938, i.e. 0x80121B84, which the registry
|
||||
* already carries as `D_80121B84` with the `gp` marker. The counter is **incremented first**
|
||||
* and the array is then indexed by the incremented value, so this is a pre-increment append.
|
||||
*
|
||||
* The array store is the explicit indexed symbol form (`lui at,%hi` / `addu at,at,index` /
|
||||
* `sw rt,%lo(at)`), and the address arithmetic carries: `lui 0x8011` with the signed
|
||||
* displacement -0xcfc gives **0x8010F304**, not 0x8011F304.
|
||||
*
|
||||
* LIMITS: the function name, the callee, the array and the counter's meaning are hypotheses;
|
||||
* only the bytes are evidence. The array elements and the counter are 32-bit. The second
|
||||
* argument to the callee is the literal 1, materialised in the `jal` delay slot.
|
||||
*/
|
||||
|
||||
extern int D_80121B84;
|
||||
extern int D_8010F304[];
|
||||
extern void func_8002C3F8(int a0, int a1);
|
||||
|
||||
void func_8002C6EC(int a0)
|
||||
{
|
||||
D_80121B84++;
|
||||
D_8010F304[D_80121B84] = a0;
|
||||
func_8002C3F8(a0, 1);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* func_80045388 — 56 bytes at 0x80045388..0x800453C0
|
||||
*
|
||||
* Framed routine guarded by a byte flag: when the flag is clear it calls one routine with a
|
||||
* global pointer and its own argument.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* lui v0,0x8012 3c028012 \
|
||||
* lbu v0,0x2374(v0) 90422374 / v0 = *(unsigned char *)0x80122374
|
||||
* move a1,a0 00802821 a1 = a0
|
||||
* bne v0,zero,0x800453b0 14400004 if (v0 != 0) goto epilogue
|
||||
* sw ra,0x10(sp) afbf0010 save ra (delay slot)
|
||||
* lui a0,0x8013 3c048013 \
|
||||
* lw a0,-0x2774(a0) 8c84d88c / a0 = *(int *)0x8012D88C
|
||||
* jal 0x8005a78c 0c0169e3 call func_8005A78C
|
||||
* nop 00000000 (delay slot)
|
||||
* 0x800453b0:
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* Byte-for-byte the same shape as func_800453C0 except for the callee (func_8005A78C here,
|
||||
* func_8005A81C there) — the pair is one guard reached through two different routines. The
|
||||
* difference between the two is only scheduling: here the frame is established **first** and
|
||||
* the flag load second, in func_800453C0 the flag load is hoisted above the frame. Both come
|
||||
* from the same C and are cc1's scheduling choice.
|
||||
*
|
||||
* The guard's `sw ra` sits in the branch delay slot, so `ra` is only saved on the path that
|
||||
* reaches the call. The argument moves to a1 before a0 is overwritten with the global, so the
|
||||
* call is `f(global, arg)`. The address arithmetic carries: `lui 0x8013` with the signed
|
||||
* displacement -0x2774 gives **0x8012D88C**.
|
||||
*
|
||||
* LIMITS: the function name, the flag's meaning, the global's type and the callee are
|
||||
* hypotheses; only the bytes are evidence. The flag is a byte (`lbu`) and the global is read
|
||||
* as a 32-bit pointer. The routine sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern unsigned char D_80122374;
|
||||
extern int D_8012D88C;
|
||||
extern void func_8005A78C(int a0, int a1);
|
||||
|
||||
void func_80045388(int a0)
|
||||
{
|
||||
unsigned char v0 = D_80122374;
|
||||
|
||||
if (v0 == 0)
|
||||
func_8005A78C(D_8012D88C, a0);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* func_800734A4 — 56 bytes at 0x800734A4..0x800734DC
|
||||
*
|
||||
* Framed routine: sets one bit of a 16-bit value, passes it on, and if the result is
|
||||
* non-null passes that on too.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* ori a0,a0,0x4000 34844000 a0 |= 0x4000
|
||||
* sll a0,a0,0x10 00042400 a0 <<= 16
|
||||
* jal 0x80072d0c 0c01cb43 call func_80072D0C
|
||||
* sra a0,a0,0x10 00042403 a0 = (short)a0 (delay slot)
|
||||
* beq v0,zero,0x800734cc 10400003 if (v0 == 0) goto epilogue
|
||||
* nop 00000000 (delay slot)
|
||||
* jal 0x8006f28c 0c01bcA3 call func_8006F28C
|
||||
* move a0,v0 00402021 a0 = v0 (delay slot)
|
||||
* 0x800734cc:
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The `ori`/`sll`/`sra` triple is the mask-and-sign-extend this ABI applies to a `short`
|
||||
* argument: bit 14 is set on the incoming value and the result is narrowed back to 16 bits
|
||||
* before the call, so both the parameter and the callee's parameter are `short`. The
|
||||
* narrowing is scheduled into the `jal` delay slot.
|
||||
*
|
||||
* The second call is guarded and receives the first call's result; nothing touches v0 after
|
||||
* it, so the wrapper sets no result of its own and is `void`.
|
||||
*
|
||||
* LIMITS: the function names, the callees and the meaning of bit 14 are hypotheses; only the
|
||||
* bytes are evidence. The `nop` in the first branch's delay slot means nothing was available
|
||||
* to fill it.
|
||||
*/
|
||||
|
||||
extern int func_80072D0C(short a0);
|
||||
extern void func_8006F28C(int a0);
|
||||
|
||||
void func_800734A4(short a0)
|
||||
{
|
||||
int v0 = func_80072D0C(a0 | 0x4000);
|
||||
|
||||
if (v0 != 0)
|
||||
func_8006F28C(v0);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* func_8009B464 — 60 bytes at 0x8009B464..0x8009B4A0
|
||||
*
|
||||
* Framed routine: calls one routine with an advanced pointer, its own argument, a value
|
||||
* selected by one bit of a field, and a zero.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* move a1,a0 00802821 a1 = a0
|
||||
* addiu a0,a1,0x30 24a40030 a0 = a1 + 0x30
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* lw a2,0x28(a1) 8ca20028 a2 = *(int *)(a1 + 0x28)
|
||||
* addu a3,zero,zero 00003821 a3 = 0
|
||||
* andi a2,a2,0x8000 30428000 a2 &= 0x8000
|
||||
* sltu a2,zero,a2 0002102b a2 = (0 < a2)
|
||||
* subu a2,zero,a2 00021023 a2 = -a2 (0 or -1)
|
||||
* jal 0x8009b074 0c026c1d call func_8009B074
|
||||
* andi a2,a2,0x29a 3042029a a2 &= 0x29a (delay slot) (0 or 0x29a)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The four-instruction `andi`/`sltu`/`subu`/`andi` sequence is cc1's **if-conversion** of a
|
||||
* two-constant conditional: `(field & 0x8000) ? 0x29a : 0` becomes
|
||||
* `-((field & 0x8000) != 0) & 0x29a`, with the final `andi` scheduled into the `jal` delay
|
||||
* slot. That is the same mechanism cookbook finding 26's neighbours show, and it is why the
|
||||
* source is written as a ternary: an `if`/`else` assigning the same variable produces the same
|
||||
* code.
|
||||
*
|
||||
* The first argument is the incoming pointer advanced by 0x30 (computed in a register copy, so
|
||||
* the original value survives as the second argument), and a3 is zeroed with
|
||||
* `addu rd,zero,zero`.
|
||||
*
|
||||
* LIMITS: the function name, the callee, the field at +0x28, the bit 15 test and the constant
|
||||
* 0x29a are hypotheses; only the bytes are evidence. The field load is 32-bit.
|
||||
*/
|
||||
|
||||
extern void func_8009B074(int a0, int a1, int a2, int a3);
|
||||
|
||||
void func_8009B464(int a0)
|
||||
{
|
||||
func_8009B074(a0 + 0x30, a0, (*(int *)(a0 + 0x28) & 0x8000) ? 0x29a : 0, 0);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* func_800A9D58 — 56 bytes at 0x800A9D58..0x800A9D90
|
||||
*
|
||||
* Framed routine: calls one routine, and if it returns non-null passes the result on and
|
||||
* then calls a second routine.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x800a82d0 0c02a0b4 call func_800A82D0
|
||||
* nop 00000000 (delay slot)
|
||||
* beq v0,zero,0x800a9d80 10400005 if (v0 == 0) goto epilogue
|
||||
* nop 00000000 (delay slot)
|
||||
* jal 0x800a9d90 0c02a764 call func_800A9D90
|
||||
* move a0,v0 00402021 a0 = v0 (delay slot)
|
||||
* jal 0x800a8224 0c02a089 call func_800A8224
|
||||
* nop 00000000 (delay slot)
|
||||
* 0x800a9d80:
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* Both calls are inside the guard: the first takes the tested result as its argument (moved
|
||||
* into a0 in the `jal` delay slot), the second takes none. Nothing touches v0 after the
|
||||
* second call, so the wrapper sets no result and is `void`.
|
||||
*
|
||||
* The first callee, 0x800A82D0, is one of the project's recorded open negatives
|
||||
* (`near_match_negatives.tsv`, class `-`); it is referenced here as an unresolved symbol, not
|
||||
* as a matched region. The second callee, 0x800A9D90, is the address immediately after this
|
||||
* function's end.
|
||||
*
|
||||
* LIMITS: the function names and the callees' purposes are hypotheses; only the bytes are
|
||||
* evidence. The guard tests v0 for zero (`beq v0,zero`), so the source condition is `!= 0`.
|
||||
*/
|
||||
|
||||
extern int func_800A82D0(void);
|
||||
extern void func_800A9D90(int a0);
|
||||
extern void func_800A8224(void);
|
||||
|
||||
void func_800A9D58(void)
|
||||
{
|
||||
int v0 = func_800A82D0();
|
||||
|
||||
if (v0 != 0) {
|
||||
func_800A9D90(v0);
|
||||
func_800A8224();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* func_800F9344 — 60 bytes at 0x800F9344..0x800F9380
|
||||
*
|
||||
* Framed routine: applies a routine to a 12-bit field of its argument, negating both the
|
||||
* argument and the result when the argument is negative.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* bltz a0,0x800f9360 04800006 if (a0 < 0) goto the negative path
|
||||
* sw ra,0x10(sp) afbf0010 save ra (delay slot)
|
||||
* jal 0x800f9380 0c03e4e0 call func_800F9380
|
||||
* andi a0,a0,0xfff 30840fff a0 &= 0xfff (delay slot)
|
||||
* j 0x800f9370 081003dc goto epilogue
|
||||
* nop 00000000 (delay slot)
|
||||
* 0x800f9360:
|
||||
* subu a0,zero,a0 00042023 a0 = -a0
|
||||
* jal 0x800f9380 0c03e4e0 call func_800F9380
|
||||
* andi a0,a0,0xfff 30840fff a0 &= 0xfff (delay slot)
|
||||
* subu v0,zero,v0 00021023 v0 = -v0
|
||||
* 0x800f9370:
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The two arms each call the same routine with the argument masked to 12 bits; the negative
|
||||
* arm negates the argument first and the result afterwards. The positive arm ends with a `j`
|
||||
* over the negative block, so the source is the early `return` for the negative case followed
|
||||
* by the positive one — the layout is the branch target being the later block, which is the
|
||||
* shape the `if (a0 < 0) return ...;` spelling produces here.
|
||||
*
|
||||
* Both masks are scheduled into their `jal` delay slots, and the guard's `sw ra` is in the
|
||||
* `bltz` delay slot.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the claim that the mask is a 12-bit field are
|
||||
* hypotheses; only the bytes are evidence. The negation implies a signed result.
|
||||
*/
|
||||
|
||||
extern int func_800F9380(int a0);
|
||||
|
||||
int func_800F9344(int a0)
|
||||
{
|
||||
if (a0 < 0)
|
||||
return -func_800F9380((-a0) & 0xfff);
|
||||
|
||||
return func_800F9380(a0 & 0xfff);
|
||||
}
|
||||
Reference in New Issue
Block a user