phase9: merge worker C handoff close — 283 regions / 274 distinct bodies
Worker C rotated out on budget with a clean handoff (28 claims total, all verified; 18 negatives with hypotheses). Its final 2 rows verified MATCH (0x80101838 reopening closed via do/while + sentinel: this closes B's cycle-2 negative on the same address!; 0x8007C4A8). Handoff inheritance: orig.py disassembly helper, F1-F14 findings confirmed, 2-byte free claim 0x800266A8 left with its exact hypothesis. Gate MATCH whole-binary SHA-1 e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
@@ -130,6 +130,7 @@
|
||||
0x80072BA8 0x80072BDC src/func_80072BA8.c
|
||||
0x800734A4 0x800734DC src/func_800734A4.c
|
||||
0x8007A404 0x8007A428 src/func_8007A404.c
|
||||
0x8007C4A8 0x8007C4EC src/func_8007C4A8.c
|
||||
0x8007C4EC 0x8007C524 src/func_8007C4EC.c
|
||||
0x8007DC40 0x8007DC4C src/func_8007DC40.c
|
||||
0x8007DF00 0x8007DF34 src/func_8007DF00.c
|
||||
@@ -245,6 +246,7 @@
|
||||
0x80100964 0x8010097C src/func_80100964.c
|
||||
0x8010097C 0x80100998 src/func_8010097C.c
|
||||
0x80101244 0x8010128C src/func_80101244.c
|
||||
0x80101838 0x80101878 src/func_80101838.c
|
||||
0x80101CAC 0x80101CDC src/func_80101CAC.c
|
||||
0x801027CC 0x801027F8 src/func_801027CC.c
|
||||
0x80102B10 0x80102B2C src/func_80102B10.c maspsx=off
|
||||
|
||||
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* func_800281A4 — 64 bytes at 0x800281A4..0x800281E4
|
||||
*
|
||||
* Framed routine: passes two words of its first argument to a routine and stores the result
|
||||
* through its second argument, returning 0.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* move v0,a0 00801021 v0 = a0
|
||||
* sw s0,0x10(sp) afb00010 save s0
|
||||
* move s0,a1 00a08021 s0 = a1
|
||||
* sw ra,0x14(sp) afbf0014 save ra
|
||||
* lw a0,0x0(v0) 8c440000 a0 = *(int *)v0
|
||||
* lw a1,0x8(v0) 8c450008 a1 = *(int *)(v0 + 8)
|
||||
* jal 0x800f2fc0 0c03cbf0 call func_800F2FC0
|
||||
* nop 00000000 (delay slot)
|
||||
* sw v0,0x0(s0) ae020000 *(int *)s0 = v0
|
||||
* addu v0,zero,zero 00001021 v0 = 0
|
||||
* lw ra,0x14(sp) 8fbf0014 restore ra
|
||||
* lw s0,0x10(sp) 8e100010 restore s0
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The first argument is copied to **v0** and both of its words are read through that copy, so
|
||||
* a0 is free to receive the callee's first argument — the pointer is preserved in a scratch
|
||||
* register rather than on the stack. The second argument is copied to **s0**, a callee-saved
|
||||
* register, because it is used as the store base *after* the call. The frame saves s0 at 0x10
|
||||
* and ra at 0x14.
|
||||
*
|
||||
* The wrapper's own result is the constant 0, set after the store, so it is not the callee's
|
||||
* value.
|
||||
*
|
||||
* LIMITS: the function name, the callee, the two source words and the claim that the second
|
||||
* argument is an output pointer are hypotheses; only the bytes are evidence. All accesses are
|
||||
* 32-bit.
|
||||
*/
|
||||
|
||||
extern int func_800F2FC0(int a0, int a1);
|
||||
|
||||
int func_800281A4(int a0, int *a1)
|
||||
{
|
||||
int v0 = a0;
|
||||
|
||||
*a1 = func_800F2FC0(*(int *)v0, *(int *)(v0 + 8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* func_8002A9D4 — 68 bytes at 0x8002A9D4..0x8002AA18
|
||||
*
|
||||
* Leaf routine that walks a 133-entry table of pointers and clears one field of every entry
|
||||
* whose field holds 1.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addu a1,zero,zero 00002821 i = 0
|
||||
* li a2,0x1 24060001 a2 = 1
|
||||
* lui a0,0x8011 3c048011 \
|
||||
* addiu a0,a0,-0xf10 2484f0f0 / a0 = 0x8010F0F0 (D_8010F0F0)
|
||||
* 0x8002a9e4:
|
||||
* lw v1,0x0(a0) 8c830000 v1 = *p
|
||||
* nop 00000000 load-delay slot
|
||||
* lw v0,0x14(v1) 8c620014 v0 = *(int *)(v1 + 0x14)
|
||||
* nop 00000000 load-delay slot
|
||||
* bne v0,a2,0x8002aa00 14460001 if (v0 != 1) goto the increment
|
||||
* nop 00000000 (delay slot)
|
||||
* sw zero,0x14(v1) ac600014 *(int *)(v1 + 0x14) = 0
|
||||
* 0x8002aa00:
|
||||
* addiu a1,a1,0x1 24a50001 i++
|
||||
* slti v0,a1,0x85 28a20085 v0 = (i < 133) signed
|
||||
* bne v0,zero,0x8002a9e4 1440fff8 if (v0) loop
|
||||
* addiu a0,a0,0x4 24840004 p++ (delay slot)
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The table is a walked pointer of 4-byte elements built with `lui`+`addiu` (the linker-resolved
|
||||
* symbol form, cookbook finding 4), each element being a **pointer** whose +0x14 field is
|
||||
* compared with 1 and zeroed on a match. The comparison constant is materialised once outside
|
||||
* the loop, the bound test is `slti` (signed) against 133, and the pointer is advanced in the
|
||||
* branch delay slot.
|
||||
*
|
||||
* LIMITS: the function name, the table, the pointer elements, the field at +0x14 and the meaning
|
||||
* of the value 1 are hypotheses; only the bytes are evidence. All accesses are 32-bit. Whether
|
||||
* the elements are valid pointers for all 133 entries is not established.
|
||||
*/
|
||||
|
||||
extern int D_8010F0F0[];
|
||||
|
||||
void func_8002A9D4(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 133; i++) {
|
||||
int v1 = D_8010F0F0[i];
|
||||
|
||||
if (*(int *)(v1 + 0x14) == 1)
|
||||
*(int *)(v1 + 0x14) = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* func_80057524 — 64 bytes at 0x80057524..0x80057564
|
||||
*
|
||||
* Framed routine: calls one routine with a field reached through two dereferences, then calls
|
||||
* a second routine with its own argument.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw s0,0x10(sp) afb00010 save s0
|
||||
* move s0,a0 00808021 s0 = a0
|
||||
* sw ra,0x14(sp) afbf0014 save ra
|
||||
* lw v0,0x20(s0) 8e020020 v0 = *(int *)(a0 + 0x20)
|
||||
* nop 00000000 load-delay slot
|
||||
* lw a0,0xf8(v0) 8c4400f8 a0 = *(int *)(v0 + 0xf8)
|
||||
* jal 0x8003636c 0c00d8db call func_8003636C
|
||||
* nop 00000000 (delay slot)
|
||||
* jal 0x80057418 0c015d06 call func_80057418
|
||||
* move a0,s0 02002021 a0 = s0 (delay slot)
|
||||
* lw ra,0x14(sp) 8fbf0014 restore ra
|
||||
* lw s0,0x10(sp) 8e100010 restore s0
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The argument is copied to **s0**, a callee-saved register, because it must survive the first
|
||||
* call to become the second call's argument — the same tell as func_800128E4. The second call
|
||||
* restores it in its own `jal` delay slot. The first callee, 0x8003636C, is the store-only
|
||||
* function cookbook finding 13 is built on.
|
||||
*
|
||||
* LIMITS: the function name, both callees, the pointer chain and the field at +0xf8 are
|
||||
* hypotheses; only the bytes are evidence. The routine sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern void func_8003636C(int a0);
|
||||
extern void func_80057418(int a0);
|
||||
|
||||
void func_80057524(int a0)
|
||||
{
|
||||
func_8003636C(*(int *)(*(int *)(a0 + 0x20) + 0xf8));
|
||||
func_80057418(a0);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* func_8007C4A8 — 68 bytes at 0x8007C4A8..0x8007C4EC
|
||||
*
|
||||
* Copies three words out of a 16-byte-stride table entry into a caller buffer and
|
||||
* RETURNS the fourth. The entry index is a byte field of the source structure, and
|
||||
* the table base is materialised as `lui` + `addiu` with a sign-adjusted low half
|
||||
* — the symbol form (cookbook finding 4) — so the base is written as an
|
||||
* address-shaped array.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lbu v0,37(a0) ; index = p->byte_25
|
||||
* lui v1,0x8014 ; %hi of the table base
|
||||
* addiu v1,v1,-31224 ; v1 = D_80138608 (%lo, sign-adjusted)
|
||||
* sll v0,v0,0x4 ; index * 16
|
||||
* addu v0,v0,v1 ; table + index*16 (index first)
|
||||
* lw v1,0(v0) / nop / sw v1,0(a1)
|
||||
* lw v1,4(v0) / nop / sw v1,4(a1)
|
||||
* lw v1,8(v0) / nop / sw v1,8(a1)
|
||||
* lw v0,12(v0) ; the returned word
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* The element stride is 16 and the table is indexed by a struct, so the entry is
|
||||
* modelled as a four-word record and the index scaling falls out of `sizeof`.
|
||||
* The `nop`s after each load are maspsx's load-delay fills.
|
||||
*
|
||||
* LIMITS: the table base (0x80138608), the stride (16), the index field offset
|
||||
* (0x25) and the record's four-word layout are hypotheses read from the
|
||||
* instruction shape; what the table holds is unknown and is not guessed here. The
|
||||
* `lbu` is what shows the index byte is unsigned. Only the compiled bytes are
|
||||
* evidence.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int word_00;
|
||||
int word_04;
|
||||
int word_08;
|
||||
int word_0c;
|
||||
} func_8007C4A8_entry;
|
||||
|
||||
extern func_8007C4A8_entry D_80138608[];
|
||||
|
||||
int func_8007C4A8(char *p, int *dst) {
|
||||
func_8007C4A8_entry *entry = &D_80138608[*(unsigned char *)(p + 37)];
|
||||
|
||||
dst[0] = entry->word_00;
|
||||
dst[1] = entry->word_04;
|
||||
dst[2] = entry->word_08;
|
||||
return entry->word_0c;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* func_8007ED4C — 64 bytes at 0x8007ED4C..0x8007ED8C
|
||||
*
|
||||
* Framed routine: calls a routine returning a pointer and, when it is non-null, stores -1 into
|
||||
* an element of a halfword array selected by a byte field of the returned object.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x8007eb8c 0c01fae3 call func_8007EB8C
|
||||
* nop 00000000 (delay slot)
|
||||
* beq v0,zero,0x8007ed7c 10400005 if (v0 == 0) goto epilogue
|
||||
* li v1,-0x1 2403ffff v1 = -1 (delay slot)
|
||||
* lbu v0,0x25(v0) 90420025 v0 = *(unsigned char *)(v0 + 0x25)
|
||||
* nop 00000000 load-delay slot
|
||||
* sll v0,v0,0x1 00021040 v0 *= 2
|
||||
* lui at,0x8012 3c018012 \
|
||||
* addu at,at,v0 00220821 / at = 0x80120000 + index * 2
|
||||
* sh v1,0x2618(at) a4232618 *(short *)(at + 0x2618) = -1
|
||||
* 0x8007ed7c:
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The constant -1 is materialised in the guard's branch delay slot, so the guard carries the
|
||||
* stored value. The array access is the explicit indexed symbol form with a 2-byte stride
|
||||
* (`sll ...,1`), so the element type is 16-bit, and the address arithmetic carries:
|
||||
* `lui 0x8012` with the signed displacement 0x2618 gives **0x80122618**.
|
||||
*
|
||||
* LIMITS: the function name, the callee, the byte field at +0x25 and the halfword array are
|
||||
* hypotheses; only the bytes are evidence. The routine sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern char *func_8007EB8C(void);
|
||||
extern short D_80122618[];
|
||||
|
||||
void func_8007ED4C(void)
|
||||
{
|
||||
char *v0 = func_8007EB8C();
|
||||
|
||||
if (v0 != 0)
|
||||
D_80122618[*(unsigned char *)(v0 + 0x25)] = -1;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* func_80096324 — 64 bytes at 0x80096324..0x80096364
|
||||
*
|
||||
* Framed routine that dispatches to one of two routines on a byte field.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* lbu v1,0x26(a0) 90830026 v1 = *(unsigned char *)(a0 + 0x26)
|
||||
* li v0,0x9 24020009 v0 = 9
|
||||
* bne v1,v0,0x8009634c 14620003 if (v1 != 9) goto the else arm
|
||||
* nop 00000000 (delay slot)
|
||||
* jal 0x800964f8 0c02593e call func_800964F8
|
||||
* nop 00000000 (delay slot)
|
||||
* j 0x80096354 081002d5 goto epilogue
|
||||
* nop 00000000 (delay slot)
|
||||
* 0x8009634c:
|
||||
* jal 0x80095d74 0c02575d call func_80095D74
|
||||
* nop 00000000 (delay slot)
|
||||
* 0x80096354:
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The comparison constant is materialised into v0 by `li` (SGIs have no branch-immediate form),
|
||||
* the taken arm is the first callee, and the else arm is the branch target. The first arm ends
|
||||
* with a `j` over the second, so the source is a plain `if`/`else` and not a `switch` — a
|
||||
* two-case switch would produce a different layout.
|
||||
*
|
||||
* LIMITS: the function name, both callees, the field at +0x26 and the meaning of the value 9
|
||||
* are hypotheses; only the bytes are evidence. The routine sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern void func_800964F8(void);
|
||||
extern void func_80095D74(void);
|
||||
|
||||
void func_80096324(int a0)
|
||||
{
|
||||
if (*(unsigned char *)(a0 + 0x26) == 9)
|
||||
func_800964F8();
|
||||
else
|
||||
func_80095D74();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* func_80101838 — 64 bytes at 0x80101838..0x80101878
|
||||
*
|
||||
* Initialises sixteen parallel fields of a structure: two byte arrays indexed by
|
||||
* the loop counter and two 16-bit arrays indexed by twice the counter, with two
|
||||
* single 16-bit fields cleared outside the loop (one before, one after).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* sh zero,64(a0) ; *(short *)(base + 0x40) = 0
|
||||
* move a1,zero ; i = 0
|
||||
* li a3,127 ; the byte constant
|
||||
* li a2,8192 ; the 16-bit constant (0x2000)
|
||||
* move v1,a0 ; v1 walks base + i*2
|
||||
* 4C: addu v0,a0,a1 ; base + i
|
||||
* sb zero,68(v0) ; *(char *)(base + i + 0x44) = 0
|
||||
* sb a3,84(v0) ; *(char *)(base + i + 0x54) = 127
|
||||
* sh zero,100(v1) ; *(short *)(base + i*2 + 0x64) = 0
|
||||
* sh a2,132(v1) ; *(short *)(base + i*2 + 0x84) = 0x2000
|
||||
* addiu a1,a1,1 ; i++
|
||||
* slti v0,a1,16 ; i < 16
|
||||
* bnez v0,0x8010184C ; loop
|
||||
* addiu v1,v1,2 ; v1 += 2 (delay slot)
|
||||
* jr ra
|
||||
* sh zero,66(a0) ; *(short *)(base + 0x42) = 0 (delay slot)
|
||||
*
|
||||
* The two indexings differ on purpose and must be kept distinct: the byte fields
|
||||
* use `base + i` (an `addu` of base and the counter) while the 16-bit fields use
|
||||
* a separate pointer walked by two. Writing all four as `base + i * 2` or all
|
||||
* four as `base + i` will not reproduce the `addu v0,a0,a1` plus walking-pointer
|
||||
* pair.
|
||||
*
|
||||
* LIMITS: every offset, the count (16), the two constants (127 and 8192) and the
|
||||
* field widths are hypotheses read from the instruction shape; what the structure
|
||||
* holds is unknown and is not guessed here. The `sh` at the very end lands in the
|
||||
* `jr ra` delay slot, which is why it appears out of source order. Only the
|
||||
* compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
void func_80101838(char *base) {
|
||||
int i;
|
||||
|
||||
*(short *)(base + 64) = 0;
|
||||
for (i = 0; i < 16; i++) {
|
||||
*(char *)(base + i + 68) = 0;
|
||||
*(char *)(base + i + 84) = 127;
|
||||
*(short *)(base + i * 2 + 100) = 0;
|
||||
*(short *)(base + i * 2 + 132) = 8192;
|
||||
}
|
||||
*(short *)(base + 66) = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user