phase9: merge B 3 + C 4 — 372 regions / 363 distinct bodies
Worker B: 26 new this cycle, incl. the rare-epilogue three-way model confirmed textually (sub-case b: 0x800F8928 mutual exclusion, before/after 68->64 then or-encoded moves), the discard-an-argument-outright pass-through 5th flavour, and D_80121ED8 corroboration. Worker C: 4 matched (0x80048E20, 0x8005784C, 0x800579A0, 0x80057AE0). GATE INCIDENT: C's 0x8002E3FC claimed but its source is LENGTH-MISMATCH (88 vs expected) against the tracked registry — dropped from the merge, reported back to C. Gate MATCH whole-binary SHA-1 e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
@@ -112,6 +112,7 @@
|
||||
0x80036378 0x80036380 src/func_80036378.c
|
||||
0x80036380 0x80036390 src/func_80036380.c
|
||||
0x80036A0C 0x80036A54 src/func_80036A0C.c
|
||||
0x80036A54 0x80036A9C src/func_80036A54.c
|
||||
0x80036A9C 0x80036AD8 src/func_80036A9C.c
|
||||
0x80036AD8 0x80036B14 src/func_80036AD8.c
|
||||
0x8003768C 0x800376CC src/func_8003768C.c
|
||||
@@ -130,6 +131,7 @@
|
||||
0x800450C4 0x80045110 src/func_800450C4.c gp=-D_80121BFC
|
||||
0x80045388 0x800453C0 src/func_80045388.c
|
||||
0x800453C0 0x800453F8 src/func_800453C0.c
|
||||
0x80048E20 0x80048E70 src/func_80048E20.c
|
||||
0x80049298 0x800492E4 src/func_80049298.c gp=-D_80121BFC
|
||||
0x8004C060 0x8004C090 src/func_8004C060.c
|
||||
0x8004C090 0x8004C0AC src/func_8004C090.c
|
||||
@@ -141,6 +143,9 @@
|
||||
0x8005182C 0x80051864 src/func_8005182C.c
|
||||
0x80052C98 0x80052CAC src/func_80052C98.c
|
||||
0x80057524 0x80057564 src/func_80057524.c
|
||||
0x8005784C 0x8005789C src/func_8005784C.c
|
||||
0x800579A0 0x800579F0 src/func_800579A0.c
|
||||
0x80057AE0 0x80057B30 src/func_80057AE0.c
|
||||
0x80057DFC 0x80057E04 src/func_80057DFC.c
|
||||
0x80058230 0x80058288 src/func_80058230.c
|
||||
0x80058288 0x800582AC src/func_80058288.c
|
||||
@@ -161,6 +166,7 @@
|
||||
0x80068F98 0x80068FA8 src/func_80068F98.c
|
||||
0x800697A4 0x800697C4 src/func_800697A4.c
|
||||
0x800697C4 0x800697FC src/func_800697C4.c
|
||||
0x8006B1CC 0x8006B214 src/func_8006B1CC.c
|
||||
0x8006B778 0x8006B7C0 src/func_8006B778.c
|
||||
0x8006BC08 0x8006BC34 src/func_8006BC08.c
|
||||
0x8006BC34 0x8006BC74 src/func_8006BC34.c
|
||||
@@ -200,6 +206,7 @@
|
||||
0x8008B8E4 0x8008B8F4 src/func_8008B8E4.c
|
||||
0x8008B8F4 0x8008B910 src/func_8008B8F4.c
|
||||
0x8008F4A0 0x8008F4AC src/func_8008F4A0.c
|
||||
0x8008F4AC 0x8008F4F4 src/func_8008F4AC.c
|
||||
0x8008F4F4 0x8008F508 src/func_8008F4F4.c
|
||||
0x8008F508 0x8008F530 src/func_8008F508.c
|
||||
0x8008FF58 0x8008FF84 src/func_8008FF58.c
|
||||
|
||||
|
@@ -0,0 +1,52 @@
|
||||
/* func_80036A54 — 0x80036A54..0x80036A9C (72 bytes).
|
||||
*
|
||||
* Original words:
|
||||
* 27BDFFE0 addiu sp,sp,-32
|
||||
* AFB00010 sw s0,16(sp)
|
||||
* 00808021 move s0,a0 keep the first argument
|
||||
* AFB10014 sw s1,20(sp)
|
||||
* 00C08821 move s1,a2 keep the third argument
|
||||
* AFBF0018 sw ra,24(sp)
|
||||
* 0C00C896 jal 0x80032258
|
||||
* 24050001 _li a1,1 (delay slot) second argument = 1
|
||||
* 02002021 move a0,s0
|
||||
* 00402821 move a1,v0
|
||||
* 0C00C8C0 jal 0x80032300
|
||||
* 02203021 _move a2,s1 (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 one routine with a forced second argument, then passes its result into a
|
||||
* second routine alongside the first and third arguments.
|
||||
*
|
||||
* **The routine's own second parameter is never read.** `a1` is overwritten by
|
||||
* `li a1,1` in the first call's delay slot and never restored, so whatever the
|
||||
* caller placed there is discarded — the parameter exists in the signature but the
|
||||
* body drops it (the degenerate form of the pass-through idiom: a parameter that is
|
||||
* silently discarded). It is written into the declaration here purely so the
|
||||
* argument count matches the two callees' register expectations.
|
||||
*
|
||||
* Only `a0` and `a2` need saving because both are live across the first call, and
|
||||
* the two `move`s into the second call's argument registers are scheduled into the
|
||||
* first call's exit path and the second call's delay slot.
|
||||
*
|
||||
* LIMITS: the two callees are named for their addresses and nothing establishes
|
||||
* their signatures; the `1` is read from the `li`. That the dropped parameter is a
|
||||
* real parameter of the original — rather than the source having only two
|
||||
* parameters and `a2` being something else — follows from `a2` being saved and
|
||||
* forwarded, which a two-parameter routine could not explain.
|
||||
*/
|
||||
|
||||
int func_80032258(int a0, int a1);
|
||||
void func_80032300(int a0, int a1, int a2);
|
||||
|
||||
void func_80036A54(int a0, int unused, int a2)
|
||||
{
|
||||
int result = func_80032258(a0, 1);
|
||||
|
||||
func_80032300(a0, result, a2);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* func_80048E20 — 80 bytes at 0x80048E20..0x80048E70
|
||||
*
|
||||
* Sign-extends a 16-bit second argument, fills a scratch buffer through a call,
|
||||
* then makes a five-argument call with a fixed function address, the first
|
||||
* argument saved in `s0`, and the buffer as the fourth argument.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-48
|
||||
* sw s0,40(sp)
|
||||
* move s0,a0 ; s0 = first argument
|
||||
* sll a0,a1,0x10
|
||||
* sra a0,a0,0x10 ; a0 = (short)a1 <- SIGNED 16-bit
|
||||
* sw ra,44(sp)
|
||||
* jal 0x80045110
|
||||
* addiu a1,sp,24 ; second argument = the buffer (delay slot)
|
||||
* lui a0,0x8007
|
||||
* addiu a0,a0,-12368 ; a0 = D_8006CFB0
|
||||
* move a1,s0 ; second argument = the saved first argument
|
||||
* move a2,zero
|
||||
* addiu a3,sp,24 ; fourth argument = the buffer
|
||||
* jal 0x8006D2FC
|
||||
* sw zero,16(sp) ; fifth argument = 0 (delay slot)
|
||||
* lw ra,44(sp)
|
||||
* lw s0,40(sp)
|
||||
* addiu sp,sp,48
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* The `sll`/`sra` pair on the second argument shows it is a SIGNED 16-bit value
|
||||
* promoted to int. The fifth argument goes into the outgoing stack slot at 16(sp)
|
||||
* of the 48-byte frame.
|
||||
*
|
||||
* LIMITS: the function address D_8006CFB0, the buffer size and the two callees are
|
||||
* hypotheses read from the instruction shape; what the buffer and the callees mean
|
||||
* is unknown and is not guessed here. Only the compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
extern char D_8006CFB0[];
|
||||
|
||||
void func_80048E20(char *a0, short a1) {
|
||||
short buf[8];
|
||||
|
||||
func_80045110(a1, buf);
|
||||
func_8006D2FC((int)D_8006CFB0, a0, 0, buf, 0);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* func_8005784C — 80 bytes at 0x8005784C..0x8005789C
|
||||
*
|
||||
* One member of a THREE-MEMBER family (with 0x8005784C and 0x800579A0 and
|
||||
* 0x80057AE0): a ten-argument call whose second argument is a small mode constant
|
||||
* (3) and whose fourth argument is the first argument masked by whether the
|
||||
* second argument's low byte is non-zero. The only difference between the members
|
||||
* is 3.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-48
|
||||
* andi a3,a1,0xff ; low = second argument & 0xff
|
||||
* andi a2,a2,0xff ; high = third argument & 0xff
|
||||
* sw a3,32(sp) ; ninth argument = low
|
||||
* sltu a3,zero,a3 ; (low != 0)
|
||||
* negu a3,a3 ; -(low != 0)
|
||||
* li a1,3 ; second argument = 3
|
||||
* sw a2,36(sp) ; tenth argument = high
|
||||
* li a2,-1 ; third argument = -1
|
||||
* and a3,a0,a3 ; fourth argument = a0 & -(low != 0)
|
||||
* sw ra,40(sp)
|
||||
* sw zero,16(sp) ; fifth argument = 0
|
||||
* sw zero,20(sp) ; sixth argument = 0
|
||||
* sw zero,24(sp) ; seventh argument = 0
|
||||
* jal 0x80057664
|
||||
* sw zero,28(sp) ; eighth argument = 0 (delay slot)
|
||||
* lw ra,40(sp)
|
||||
* addiu sp,sp,48
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* The `sltu`/`negu` pair is the branchless form of a ternary producing 0 or -1,
|
||||
* so the fourth argument is `a0` when the low byte is non-zero and 0 otherwise.
|
||||
* The four zero arguments are materialised as four consecutive stores to the
|
||||
* outgoing stack slots 16/20/24/28(sp), and the two byte arguments go to 32/36(sp)
|
||||
* as the ninth and tenth arguments.
|
||||
*
|
||||
* LIMITS: the mode constant (3), the callee and the argument types are
|
||||
* hypotheses read from the instruction shape; what the mode and the callee mean is
|
||||
* unknown and is not guessed here. The `andi 0xff` pairs show the two byte
|
||||
* arguments are truncated before use. Only the compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
void func_8005784C(int a0, int a1, int a2) {
|
||||
int low = a1 & 0xFF;
|
||||
int high = a2 & 0xFF;
|
||||
int mask = low != 0 ? -1 : 0;
|
||||
|
||||
func_80057664(a0, 3, -1, a0 & mask, 0, 0, 0, 0, low, high);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* func_800579A0 — 80 bytes at 0x800579A0..0x800579F0
|
||||
*
|
||||
* One member of a THREE-MEMBER family (with 0x8005784C and 0x800579A0 and
|
||||
* 0x80057AE0): a ten-argument call whose second argument is a small mode constant
|
||||
* (10) and whose fourth argument is the first argument masked by whether the
|
||||
* second argument's low byte is non-zero. The only difference between the members
|
||||
* is 10.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-48
|
||||
* andi a3,a1,0xff ; low = second argument & 0xff
|
||||
* andi a2,a2,0xff ; high = third argument & 0xff
|
||||
* sw a3,32(sp) ; ninth argument = low
|
||||
* sltu a3,zero,a3 ; (low != 0)
|
||||
* negu a3,a3 ; -(low != 0)
|
||||
* li a1,10 ; second argument = 10
|
||||
* sw a2,36(sp) ; tenth argument = high
|
||||
* li a2,-1 ; third argument = -1
|
||||
* and a3,a0,a3 ; fourth argument = a0 & -(low != 0)
|
||||
* sw ra,40(sp)
|
||||
* sw zero,16(sp) ; fifth argument = 0
|
||||
* sw zero,20(sp) ; sixth argument = 0
|
||||
* sw zero,24(sp) ; seventh argument = 0
|
||||
* jal 0x80057664
|
||||
* sw zero,28(sp) ; eighth argument = 0 (delay slot)
|
||||
* lw ra,40(sp)
|
||||
* addiu sp,sp,48
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* The `sltu`/`negu` pair is the branchless form of a ternary producing 0 or -1,
|
||||
* so the fourth argument is `a0` when the low byte is non-zero and 0 otherwise.
|
||||
* The four zero arguments are materialised as four consecutive stores to the
|
||||
* outgoing stack slots 16/20/24/28(sp), and the two byte arguments go to 32/36(sp)
|
||||
* as the ninth and tenth arguments.
|
||||
*
|
||||
* LIMITS: the mode constant (10), the callee and the argument types are
|
||||
* hypotheses read from the instruction shape; what the mode and the callee mean is
|
||||
* unknown and is not guessed here. The `andi 0xff` pairs show the two byte
|
||||
* arguments are truncated before use. Only the compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
void func_800579A0(int a0, int a1, int a2) {
|
||||
int low = a1 & 0xFF;
|
||||
int high = a2 & 0xFF;
|
||||
int mask = low != 0 ? -1 : 0;
|
||||
|
||||
func_80057664(a0, 10, -1, a0 & mask, 0, 0, 0, 0, low, high);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* func_80057AE0 — 80 bytes at 0x80057AE0..0x80057B30
|
||||
*
|
||||
* One member of a THREE-MEMBER family (with 0x8005784C and 0x800579A0 and
|
||||
* 0x80057AE0): a ten-argument call whose second argument is a small mode constant
|
||||
* (14) and whose fourth argument is the first argument masked by whether the
|
||||
* second argument's low byte is non-zero. The only difference between the members
|
||||
* is 14.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-48
|
||||
* andi a3,a1,0xff ; low = second argument & 0xff
|
||||
* andi a2,a2,0xff ; high = third argument & 0xff
|
||||
* sw a3,32(sp) ; ninth argument = low
|
||||
* sltu a3,zero,a3 ; (low != 0)
|
||||
* negu a3,a3 ; -(low != 0)
|
||||
* li a1,14 ; second argument = 14
|
||||
* sw a2,36(sp) ; tenth argument = high
|
||||
* li a2,-1 ; third argument = -1
|
||||
* and a3,a0,a3 ; fourth argument = a0 & -(low != 0)
|
||||
* sw ra,40(sp)
|
||||
* sw zero,16(sp) ; fifth argument = 0
|
||||
* sw zero,20(sp) ; sixth argument = 0
|
||||
* sw zero,24(sp) ; seventh argument = 0
|
||||
* jal 0x80057664
|
||||
* sw zero,28(sp) ; eighth argument = 0 (delay slot)
|
||||
* lw ra,40(sp)
|
||||
* addiu sp,sp,48
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* The `sltu`/`negu` pair is the branchless form of a ternary producing 0 or -1,
|
||||
* so the fourth argument is `a0` when the low byte is non-zero and 0 otherwise.
|
||||
* The four zero arguments are materialised as four consecutive stores to the
|
||||
* outgoing stack slots 16/20/24/28(sp), and the two byte arguments go to 32/36(sp)
|
||||
* as the ninth and tenth arguments.
|
||||
*
|
||||
* LIMITS: the mode constant (14), the callee and the argument types are
|
||||
* hypotheses read from the instruction shape; what the mode and the callee mean is
|
||||
* unknown and is not guessed here. The `andi 0xff` pairs show the two byte
|
||||
* arguments are truncated before use. Only the compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
void func_80057AE0(int a0, int a1, int a2) {
|
||||
int low = a1 & 0xFF;
|
||||
int high = a2 & 0xFF;
|
||||
int mask = low != 0 ? -1 : 0;
|
||||
|
||||
func_80057664(a0, 14, -1, a0 & mask, 0, 0, 0, 0, low, high);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/* func_8006B1CC — 0x8006B1CC..0x8006B214 (72 bytes).
|
||||
*
|
||||
* Original words:
|
||||
* 8F840550 lw a0,1360(gp) a0 = D_80121E88 (gp + 0x550)
|
||||
* 27BDFFE8 addiu sp,sp,-24
|
||||
* AFBF0014 sw ra,20(sp)
|
||||
* 10800009 beqz a0,0x8006B200
|
||||
* AFB00010 _sw s0,16(sp) (delay slot)
|
||||
* 8C85000C lw a1,12(a0) <- loop top
|
||||
* 8CB0018C lw s0,396(a1)
|
||||
* 0C01AAA2 jal 0x8006AA88
|
||||
* 00000000 nop
|
||||
* 02002021 move a0,s0
|
||||
* 1480FFF9 bnez a0,loop
|
||||
* 00000000 _nop (delay slot)
|
||||
* 8FBF0014 lw ra,20(sp) <- 0x8006B200
|
||||
* 8FB00010 lw s0,16(sp)
|
||||
* 27BD0018 addiu sp,sp,24
|
||||
* 03E00008 jr ra
|
||||
* 00000000 nop
|
||||
*
|
||||
* Walks a linked list held in a global and calls one routine per node, following a
|
||||
* **second** link to get the next node rather than the one it was reached by.
|
||||
*
|
||||
* The loop reads `node->0xc` (a sub-object) and then the sub-object's field 0x18c as
|
||||
* the successor, so the list is threaded through the inner object, not through the
|
||||
* node itself. That is why `a1` is reloaded every iteration from `a0`: both the node
|
||||
* and its sub-object are needed by the call.
|
||||
*
|
||||
* The guard is a single `beqz` before the loop, so a null global does nothing at all
|
||||
* — the frame is still set up and torn down, and the `sw s0` sits in the `beqz`
|
||||
* delay slot, which is why the saved-register spill appears before the loop rather
|
||||
* than in a contiguous prologue.
|
||||
*
|
||||
* The global is gp-relative (`1360(gp)`, cookbook finding 10), so `gp` is 0x80121938
|
||||
* and the address is **0x80121E88**; the symbol needs a `gp` marker row.
|
||||
*
|
||||
* LIMITS: the displacements 0xc and 0x18c and the gp offset are read from the bytes.
|
||||
* That the successor field belongs to the inner object rather than the node is read
|
||||
* directly from which base each load uses; whether the chain is a list or a tree
|
||||
* walked by one child is not provable from a single successor pointer. The callee is
|
||||
* named for its address and its two arguments are inferred from the registers left
|
||||
* in place.
|
||||
*/
|
||||
|
||||
extern int D_80121E88;
|
||||
|
||||
void func_8006AA88(int node, int inner);
|
||||
|
||||
void func_8006B1CC(void)
|
||||
{
|
||||
int node = D_80121E88;
|
||||
|
||||
if (node != 0) {
|
||||
do {
|
||||
int inner = *(int *)(node + 0xc);
|
||||
int next = *(int *)(inner + 0x18c);
|
||||
|
||||
func_8006AA88(node, inner);
|
||||
node = next;
|
||||
} while (node != 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* func_8008F4AC — 0x8008F4AC..0x8008F4F4 (72 bytes).
|
||||
*
|
||||
* Original words:
|
||||
* 27BDFFE8 addiu sp,sp,-24
|
||||
* 1CA00003 bgtz a1,0x8008F4C0
|
||||
* AFBF0010 _sw ra,16(sp) (delay slot)
|
||||
* 08023D34 j 0x8008F4D0
|
||||
* 24050001 _li a1,1 (delay slot) clamp low
|
||||
* 28A20080 slti v0,a1,128 <- 0x8008F4C0
|
||||
* 14400002 bnez v0,0x8008F4D0
|
||||
* 00000000 _nop (delay slot)
|
||||
* 2405007F li a1,127 clamp high
|
||||
* 3C018012 lui at,0x8012 <- 0x8008F4D0
|
||||
* 00240821 addu at,at,a0
|
||||
* A0251ED8 sb a1,7896(at) D_80121ED8[index] = value
|
||||
* 0C03FA1E jal 0x800FE878
|
||||
* 00000000 nop
|
||||
* 8FBF0010 lw ra,16(sp)
|
||||
* 27BD0018 addiu sp,sp,24
|
||||
* 03E00008 jr ra
|
||||
* 00000000 nop
|
||||
*
|
||||
* Clamps a value into 1..127, stores it into a byte array indexed by the first
|
||||
* argument, and then calls an update routine.
|
||||
*
|
||||
* The clamp is **two-sided and open at both ends**: `value <= 0` becomes 1 and
|
||||
* `value >= 128` becomes 127, so the stored byte always has its high bit clear —
|
||||
* which is consistent with a signed `char` target. The low clamp is reached by a
|
||||
* `bgtz` falling through to a `j` whose delay slot loads the 1, and the high clamp
|
||||
* by a `slti`/`bnez` pair; both arms converge on the store, so this is one shared
|
||||
* epilogue for the clamp and not two returns.
|
||||
*
|
||||
* The store is the symbol-plus-register macro form (`lui at` + `addu at,at,a0` +
|
||||
* `sb %lo(at)`), so the base is the global array at **0x80121ED8** — the same array
|
||||
* that `func_8008F4F4` reads from, which is independent corroboration that the
|
||||
* symbol is a byte array and that the index is used raw (no scaling).
|
||||
*
|
||||
* The update routine receives no fresh argument setup, so it is called with `a0`
|
||||
* (the index) and `a1` (the clamped value) still in place.
|
||||
*
|
||||
* LIMITS: the bounds 1, 128 and 127 and the displacement are read from the bytes;
|
||||
* that the range is a hardware or protocol limit rather than a policy choice is not
|
||||
* observable. The callee is named for its address.
|
||||
*/
|
||||
|
||||
extern signed char D_80121ED8[];
|
||||
|
||||
void func_800FE878(int index, int value);
|
||||
|
||||
void func_8008F4AC(int index, int value)
|
||||
{
|
||||
if (value <= 0)
|
||||
value = 1;
|
||||
else if (value >= 128)
|
||||
value = 127;
|
||||
D_80121ED8[index] = value;
|
||||
func_800FE878(index, value);
|
||||
}
|
||||
Reference in New Issue
Block a user