phase9: merge B 3 — 355 regions / 346 distinct bodies
Worker B: 3 more tier-2 frames (0x80036328, 0x800AA2B4, 0x80021FF4 — the latter with the base+offset decode and the clearest finding-13 scratch constant yet) + symbol D_80121978 (gp). 23 new bodies this cycle. GATE INCIDENT: the first candidate gate DIFFed with 4 extra bytes because src/func_80025070.c was DELETED from the working tree after my commit ( status) — the build used a stale/wrong object. Restored from git and re-gated clean. Lesson recorded: every tracked src/ file is a claim; a registry row whose source is missing breaks the whole-binary gate with a cascade, so the pre-gate 'git status src/' check must catch deletions too. Gate MATCH whole-binary SHA-1 e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
@@ -55,6 +55,7 @@
|
||||
0x80021F64 0x80021F88 src/func_80021F64.c
|
||||
0x80021F88 0x80021FA8 src/func_80021F88.c
|
||||
0x80021FA8 0x80021FF4 src/func_80021FA8.c
|
||||
0x80021FF4 0x8002203C src/func_80021FF4.c
|
||||
0x80022A60 0x80022A98 src/func_80022A60.c
|
||||
0x80022FB8 0x80022FCC src/func_80022FB8.c
|
||||
0x80022FCC 0x80022FFC src/func_80022FCC.c
|
||||
@@ -101,6 +102,7 @@
|
||||
0x800321EC 0x800321F8 src/func_800321EC.c
|
||||
0x80034A80 0x80034ABC src/func_80034A80.c
|
||||
0x80036308 0x80036328 src/func_80036308.c
|
||||
0x80036328 0x8003636C src/func_80036328.c
|
||||
0x8003636C 0x80036378 src/func_8003636C.c
|
||||
0x80036378 0x80036380 src/func_80036378.c
|
||||
0x80036380 0x80036390 src/func_80036380.c
|
||||
@@ -232,6 +234,7 @@
|
||||
0x800A8B48 0x800A8B8C src/func_800A8B48.c
|
||||
0x800A9D58 0x800A9D90 src/func_800A9D58.c
|
||||
0x800A9FD4 0x800AA01C src/func_800A9FD4.c
|
||||
0x800AA2B4 0x800AA2F8 src/func_800AA2B4.c
|
||||
0x800AA56C 0x800AA59C src/func_800AA56C.c
|
||||
0x800AC818 0x800AC85C src/func_800AC818.c
|
||||
0x800AC85C 0x800AC884 src/func_800AC85C.c
|
||||
|
||||
|
@@ -20,6 +20,7 @@ D_80121958 0x80121958 gp
|
||||
D_8012195D 0x8012195D gp
|
||||
D_80121970 0x80121970 gp
|
||||
D_80121974 0x80121974 gp
|
||||
D_80121978 0x80121978 gp
|
||||
D_8012197C 0x8012197C gp
|
||||
D_80121988 0x80121988 gp
|
||||
D_8012199C 0x8012199C gp
|
||||
|
||||
|
@@ -0,0 +1,65 @@
|
||||
/* func_80021FF4 — 0x80021FF4..0x8002203C (72 bytes).
|
||||
*
|
||||
* Original words:
|
||||
* 27BDFFE8 addiu sp,sp,-24
|
||||
* AFBF0010 sw ra,16(sp)
|
||||
* 0C052084 jal 0x80148210
|
||||
* 00002021 _move a0,zero (delay slot)
|
||||
* 3C048012 lui a0,0x8012
|
||||
* 2484622C addiu a0,a0,25132 a0 = D_8012622C
|
||||
* 0C03DFF6 jal 0x800F7FD8
|
||||
* 24850022 _addiu a1,a0,34 (delay slot) a1 = a0 + 34
|
||||
* 0C03E18E jal 0x800F8638
|
||||
* 00000000 nop
|
||||
* 0C0087EA jal 0x80021FA8
|
||||
* 00000000 nop
|
||||
* 24020001 li v0,1
|
||||
* A3820920 sb v0,2336(gp) D_80122258 = 1
|
||||
* 8FBF0010 lw ra,16(sp)
|
||||
* 00001021 move v0,zero
|
||||
* 03E00008 jr ra
|
||||
* 27BD0018 _addiu sp,sp,24 (delay slot)
|
||||
*
|
||||
* A four-call initialiser ending in a one-byte flag store. The frame exists only to
|
||||
* preserve `ra`; every argument setup is either in a delay slot or absent.
|
||||
*
|
||||
* The second call's two addresses are `0x8012622C` and that value **plus 34** —
|
||||
* `addiu a1,a0,34` reuses the register already holding the first address rather than
|
||||
* materialising a second symbol. That is the tell for a source that passed one
|
||||
* address and a displacement from it (a base and a base+34 pair), not two
|
||||
* independently named globals; two symbols would each need their own `lui`.
|
||||
*
|
||||
* The first address's `lui`/`addiu` split needs no sign adjustment (25132 = 0x622C is
|
||||
* positive as a 16-bit value), unlike the negatively-displaced cases elsewhere in
|
||||
* this batch — so here the `lui` immediate *is* the top half of the address.
|
||||
*
|
||||
* `li v0,1` then `sb v0,2336(gp)` then `move v0,zero` is a **scratch constant, not a
|
||||
* return value**: the byte written is 1 and the routine then returns 0, so the `1`
|
||||
* never reaches the caller (cookbook finding 13's rule, in its clearest form). The
|
||||
* flag store is gp-relative, so `gp` (0x80121938) + 2336 gives **0x80122258**, which
|
||||
* needs a `gp` marker row.
|
||||
*
|
||||
* LIMITS: all four callees are named for their addresses and nothing here establishes
|
||||
* what they do or what the two addresses mean. That 34 is a displacement into the
|
||||
* object at 0x8012622C rather than an unrelated constant follows from the register
|
||||
* reuse, not from the value. The returned zero is taken to be a success indicator
|
||||
* only because the body also sets a flag; that is a reading, not evidence.
|
||||
*/
|
||||
|
||||
extern char D_8012622C[];
|
||||
extern unsigned char D_80122258;
|
||||
|
||||
void func_80148210(int arg);
|
||||
void func_800F7FD8(char *from, char *to);
|
||||
void func_800F8638(void);
|
||||
void func_80021FA8(void);
|
||||
|
||||
int func_80021FF4(void)
|
||||
{
|
||||
func_80148210(0);
|
||||
func_800F7FD8(D_8012622C, D_8012622C + 34);
|
||||
func_800F8638();
|
||||
func_80021FA8();
|
||||
D_80122258 = 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/* func_80036328 — 0x80036328..0x8003636C (68 bytes).
|
||||
*
|
||||
* Original words:
|
||||
* 27BDFFE0 addiu sp,sp,-32
|
||||
* AFB10014 sw s1,20(sp)
|
||||
* 00808821 move s1,a0 keep the pointer
|
||||
* AFB00010 sw s0,16(sp)
|
||||
* 30B000FF andi s0,a1,0xff keep the narrowed second argument
|
||||
* AFBF0018 sw ra,24(sp)
|
||||
* 0C00D89E jal 0x80036278
|
||||
* 02002821 _move a1,s0 (delay slot)
|
||||
* 02202021 move a0,s1
|
||||
* 0C00D8C2 jal 0x80036308
|
||||
* 02002821 _move a1,s0 (delay slot)
|
||||
* 8FBF0018 lw ra,24(sp)
|
||||
* 8FB10014 lw s1,20(sp)
|
||||
* 8FB00010 lw s0,16(sp)
|
||||
* 27BD0020 addiu sp,sp,32
|
||||
* 03E00008 jr ra
|
||||
* 00000000 nop
|
||||
*
|
||||
* Calls two routines with the same pair of arguments, the second argument masked
|
||||
* to a byte. Both calls fill their delay slots with the second argument, so the
|
||||
* narrowed value is the one passed — the mask happens once, before either call.
|
||||
*
|
||||
* `andi s0,a1,0xff` is the whole reason the value is kept at all: without the mask
|
||||
* the argument could be forwarded straight from `a1` and no saved register would be
|
||||
* needed for it. The two saved registers exist because two calls intervene, so the
|
||||
* pointer and the masked value must survive both.
|
||||
*
|
||||
* The spill order (`sw s1`, `move s1`, `sw s0`, `andi s0`, `sw ra`) is the scheduler
|
||||
* interleaving, not source order — the frame's three saves are emitted around the
|
||||
* two register setups.
|
||||
*
|
||||
* LIMITS: the mask 0xff is read from the `andi`, so the second parameter is
|
||||
* narrowed to 8 bits, but whether the source declared it as `unsigned char` or
|
||||
* masked it explicitly cannot be told from the bytes. The frame is 32 bytes for two
|
||||
* saved registers and `ra`, which is 8 more than those need — the same round-up
|
||||
* anomaly seen at `0x80066E2C`. The two callees are named for their addresses.
|
||||
*/
|
||||
|
||||
void func_80036278(int a0, int a1);
|
||||
void func_80036308(int a0, int a1);
|
||||
|
||||
void func_80036328(int obj, int value)
|
||||
{
|
||||
int masked = value & 0xff;
|
||||
|
||||
func_80036278(obj, masked);
|
||||
func_80036308(obj, masked);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/* func_800AA2B4 — 0x800AA2B4..0x800AA2F8 (68 bytes).
|
||||
*
|
||||
* Original words:
|
||||
* 27BDFFE8 addiu sp,sp,-24
|
||||
* AFB00010 sw s0,16(sp)
|
||||
* AFBF0014 sw ra,20(sp)
|
||||
* 0C02A0B4 jal 0x800A82D0
|
||||
* 00A08021 _move s0,a1 (delay slot) keep the second argument
|
||||
* 10400005 beqz v0,0x800AA2E0
|
||||
* 00402021 _move a0,v0 (delay slot) first argument of the tail call
|
||||
* 0C02A843 jal 0x800AA10C
|
||||
* 02002821 _move a1,s0 (delay slot)
|
||||
* 0802A8B9 j 0x800AA2E4
|
||||
* 00000000 _nop (delay slot)
|
||||
* 00001021 move v0,zero <- 0x800AA2E0
|
||||
* 8FBF0014 lw ra,20(sp) <- 0x800AA2E4
|
||||
* 8FB00010 lw s0,16(sp)
|
||||
* 27BD0018 addiu sp,sp,24
|
||||
* 03E00008 jr ra
|
||||
* 00000000 nop
|
||||
*
|
||||
* A lookup-then-forward: the first callee's result is tested, a null result answers
|
||||
* zero, and a non-null one is passed as the *first* argument to a second callee
|
||||
* together with the second argument that was kept.
|
||||
*
|
||||
* Every argument setup is scheduled into a branch or call delay slot — `move s0,a1`
|
||||
* into the first `jal`, `move a0,v0` into the `beqz`, `move a1,s0` into the second
|
||||
* `jal` — so the routine has no instruction that is purely argument setup, and the
|
||||
* C below is written to match that shape rather than to read naturally.
|
||||
*
|
||||
* The two returns share one epilogue, reached by the fall-through path and by the
|
||||
* `j` from the success path, and the `move v0,zero` before it is the zero answer.
|
||||
*
|
||||
* LIMITS: the two callees are named for their addresses. That the first returns a
|
||||
* pointer or handle is inferred from its being null-tested and then forwarded as an
|
||||
* argument; nothing in this body establishes its type, and the `int` used here is a
|
||||
* width choice. The second argument is passed unchanged to both callees, so no
|
||||
* narrowing of it can be inferred.
|
||||
*/
|
||||
|
||||
int func_800A82D0(int a0, int a1);
|
||||
int func_800AA10C(int a0, int a1);
|
||||
|
||||
int func_800AA2B4(int a0, int a1)
|
||||
{
|
||||
int found = func_800A82D0(a0, a1);
|
||||
|
||||
if (found == 0)
|
||||
return 0;
|
||||
return func_800AA10C(found, a1);
|
||||
}
|
||||
Reference in New Issue
Block a user