phase9: merge cycle 2 close — 260 regions / 251 distinct bodies
14 more regions merged and gated MATCH (c_regions=260, whole-binary SHA-1 e173426c157384ebf1b6caf8c6fea18a85a14af9); make check green (AGREE + MATCH). Full audit passed from clean state (CMP_OK, SHA-1, 223 tests, gate, extents). Worker A: 12 more (tier-2 wrappers incl. 7-arg o32 forwarder, GTE-forwarder adjacent to the registered maspsx=off 0x800F3160, and 0x80036380 — a byte-proven 48-byte empty-frame registered under an honest limits header). New: maspsx-conflict scope limit (finding 17 corrected: maspsx=off unsafe for bodies with move pseudo-instructions — addu-vs-or expansion), alloc- tiebreak negative 0x80019700. Worker C: 2 boundary-crossing matches accepted under the decided policy (verified work is claimable across regenerated partition edges); handoff 0x8010A748 accepted. F10 named-pointer base-first for register bases (closes the F5 gap), F11 duplicate stores need volatile, F12 if-conversion is a compiler class (0x80010418 exclusion recommended and accepted). Collision policy decided: verified work is claimable regardless of the regenerated partition boundary; overlapping staging is deduped by the merge. All boundary crossings reported by the workers.
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
0x80017C50 0x80017C60 src/func_80017C50.c
|
||||
0x80017C60 0x80017C6C src/func_80017C60.c
|
||||
0x80017D1C 0x80017D48 src/func_80017D1C.c
|
||||
0x80017D48 0x80017D88 src/func_80017D48.c
|
||||
0x80017DD0 0x80017DF0 src/func_80017DD0.c
|
||||
0x800182D4 0x800182F4 src/func_800182D4.c
|
||||
0x800198C0 0x800198F4 src/func_800198C0.c
|
||||
@@ -67,6 +68,7 @@
|
||||
0x8002D288 0x8002D2A0 src/func_8002D288.c gp=-D_80121F84
|
||||
0x8002D2A0 0x8002D2BC src/func_8002D2A0.c
|
||||
0x8002D2BC 0x8002D2D4 src/func_8002D2BC.c
|
||||
0x8002D5D0 0x8002D608 src/func_8002D5D0.c
|
||||
0x8002DEB4 0x8002DF1C src/func_8002DEB4.c
|
||||
0x8002E7C4 0x8002E7E4 src/func_8002E7C4.c
|
||||
0x8002F2F8 0x8002F300 src/func_8002F2F8.c
|
||||
@@ -76,16 +78,19 @@
|
||||
0x80036308 0x80036328 src/func_80036308.c
|
||||
0x8003636C 0x80036378 src/func_8003636C.c
|
||||
0x80036378 0x80036380 src/func_80036378.c
|
||||
0x80036380 0x80036390 src/func_80036380.c
|
||||
0x80036AD8 0x80036B14 src/func_80036AD8.c
|
||||
0x8003768C 0x800376CC src/func_8003768C.c
|
||||
0x80038788 0x80038790 src/func_80038788.c
|
||||
0x80038790 0x8003879C src/func_80038790.c
|
||||
0x8003B2F0 0x8003B320 src/func_8003B2F0.c
|
||||
0x8003B320 0x8003B34C src/func_8003B320.c
|
||||
0x80041A24 0x80041A58 src/func_80041A24.c
|
||||
0x80042088 0x80042090 src/func_80042088.c
|
||||
0x80042D64 0x80042D88 src/func_80042D64.c
|
||||
0x80043D8C 0x80043DC4 src/func_80043D8C.c
|
||||
0x80044F58 0x80044FA4 src/func_80044F58.c gp=-D_80121BFC
|
||||
0x800453C0 0x800453F8 src/func_800453C0.c
|
||||
0x8004C060 0x8004C090 src/func_8004C060.c
|
||||
0x8004C090 0x8004C0AC src/func_8004C090.c
|
||||
0x8004C0AC 0x8004C0F0 src/func_8004C0AC.c
|
||||
@@ -112,6 +117,7 @@
|
||||
0x8006F944 0x8006F95C src/func_8006F944.c
|
||||
0x8006FA78 0x8006FAA0 src/func_8006FA78.c
|
||||
0x8007049C 0x800704BC src/func_8007049C.c
|
||||
0x80072BA8 0x80072BDC src/func_80072BA8.c
|
||||
0x8007A404 0x8007A428 src/func_8007A404.c
|
||||
0x8007C4EC 0x8007C524 src/func_8007C4EC.c
|
||||
0x8007DC40 0x8007DC4C src/func_8007DC40.c
|
||||
@@ -137,6 +143,7 @@
|
||||
0x80090048 0x80090058 src/func_80090048.c
|
||||
0x80090A44 0x80090A70 src/func_80090A44.c
|
||||
0x80090B64 0x80090B7C src/func_80090B64.c
|
||||
0x80090C8C 0x80090CAC src/func_80090C8C.c
|
||||
0x800912D4 0x800912FC src/func_800912D4.c
|
||||
0x800912FC 0x8009132C src/func_800912FC.c
|
||||
0x80092068 0x80092088 src/func_80092068.c
|
||||
@@ -147,6 +154,7 @@
|
||||
0x800943C4 0x800943E0 src/func_800943C4.c
|
||||
0x80099A94 0x80099AE4 src/func_80099A94.c
|
||||
0x80099E14 0x80099E34 src/func_80099E14.c
|
||||
0x8009AC08 0x8009AC28 src/func_8009AC08.c
|
||||
0x8009D8A0 0x8009D8E0 src/func_8009D8A0.c
|
||||
0x8009E8D0 0x8009E95C src/func_8009E8D0.c
|
||||
0x8009F0E8 0x8009F120 src/func_8009F0E8.c
|
||||
@@ -155,6 +163,7 @@
|
||||
0x800A74BC 0x800A74D0 src/func_800A74BC.c
|
||||
0x800A8B48 0x800A8B8C src/func_800A8B48.c
|
||||
0x800AA56C 0x800AA59C src/func_800AA56C.c
|
||||
0x800AC818 0x800AC85C src/func_800AC818.c
|
||||
0x800ACC00 0x800ACC20 src/func_800ACC00.c
|
||||
0x800AE0F4 0x800AE10C src/func_800AE0F4.c
|
||||
0x800AE548 0x800AE574 src/func_800AE548.c
|
||||
@@ -170,9 +179,11 @@
|
||||
0x800B7230 0x800B7264 src/func_800B7230.c
|
||||
0x800BBDEC 0x800BBDF8 src/func_800BBDEC.c
|
||||
0x800BFE80 0x800BFEA0 src/func_800BFE80.c
|
||||
0x800BFEC0 0x800BFEE0 src/func_800BFEC0.c
|
||||
0x800BFEE0 0x800BFF00 src/func_800BFEE0.c
|
||||
0x800C5C84 0x800C5CBC src/func_800C5C84.c
|
||||
0x800F2F6C 0x800F2FB8 src/func_800F2F6C.c maspsx=off
|
||||
0x800F3140 0x800F3160 src/func_800F3140.c
|
||||
0x800F3160 0x800F316C src/func_800F3160.c maspsx=off
|
||||
0x800F3E70 0x800F3E88 src/func_800F3E70.c
|
||||
0x800F5200 0x800F521C src/func_800F5200.c
|
||||
@@ -189,13 +200,16 @@
|
||||
0x800F8ACC 0x800F8ADC src/func_800F8ACC.c
|
||||
0x800F8ADC 0x800F8AEC src/func_800F8ADC.c
|
||||
0x800F8AEC 0x800F8AF8 src/func_800F8AEC.c maspsx=off
|
||||
0x800F8B18 0x800F8B38 src/func_800F8B18.c
|
||||
0x800F8B38 0x800F8B58 src/func_800F8B38.c
|
||||
0x800F8B58 0x800F8B6C src/func_800F8B58.c maspsx=off
|
||||
0x800F8B6C 0x800F8B80 src/func_800F8B6C.c maspsx=off
|
||||
0x800F8F5C 0x800F8F7C src/func_800F8F5C.c
|
||||
0x800F8F7C 0x800F8F9C src/func_800F8F7C.c
|
||||
0x800F8F9C 0x800F8FC0 src/func_800F8F9C.c
|
||||
0x800F8FE4 0x800F8FF8 src/func_800F8FE4.c maspsx=off
|
||||
0x800F8FF8 0x800F9008 src/func_800F8FF8.c
|
||||
0x800FA960 0x800FA980 src/func_800FA960.c
|
||||
0x800FB13C 0x800FB1BC src/func_800FB13C.c
|
||||
0x800FB5D4 0x800FB5DC src/func_800FB5D4.c
|
||||
0x800FB5E4 0x800FB5FC src/func_800FB5E4.c
|
||||
|
||||
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* func_80017D48 — 64 bytes at 0x80017D48..0x80017D88
|
||||
*
|
||||
* Reads a gp-relative packed value, splits it into two 16-bit halves, and derives
|
||||
* a scale factor from them: the low half is the base, the high half minus one is
|
||||
* a variable shift count, and the result is the base plus a shifted complement.
|
||||
* A low half of 4096 or more is clamped to a fixed 15000.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lw v0,32(gp) ; v0 = D_80121958 (gp = 0x80121938)
|
||||
* li v1,4096
|
||||
* andi a0,v0,0xffff ; low = value & 0xffff
|
||||
* srl v0,v0,0x10 ; value >> 16
|
||||
* addiu v0,v0,-1 ; shift = (value >> 16) - 1
|
||||
* subu v1,v1,a0 ; 4096 - low
|
||||
* srlv v1,v1,v0 ; (4096 - low) >> shift <- UNSIGNED, variable
|
||||
* addu v1,a0,v1 ; result = low + that
|
||||
* sltiu a0,a0,4096 ; low < 4096 <- UNSIGNED compare
|
||||
* beqz a0,0x80017D7C ; if (!(low < 4096)) goto 15000
|
||||
* srl v0,v1,0x2 ; result >> 2 (delay slot)
|
||||
* j 0x80017D80
|
||||
* addu v0,v1,v0 ; return result + (result >> 2) (delay slot)
|
||||
* 7C: li v0,15000
|
||||
* 80: jr ra
|
||||
* nop
|
||||
*
|
||||
* Both the variable shift (`srlv`) and the range test (`sltiu`) are UNSIGNED, so
|
||||
* the source operands are unsigned — a signed source would emit `srav`/`slti`.
|
||||
*
|
||||
* LIMITS: the symbol name D_80121958, the constants (4096, 15000), the shift
|
||||
* amount (2) and the packing (two 16-bit halves) are hypotheses read from the
|
||||
* instruction shape; the offset 32 is a fact about this executable's gp layout.
|
||||
* What the packed value means is unknown and is not guessed here. Only the
|
||||
* compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
extern int D_80121958;
|
||||
|
||||
int func_80017D48(void) {
|
||||
unsigned int value = D_80121958;
|
||||
unsigned int low = value & 0xFFFF;
|
||||
unsigned int shift = (value >> 16) - 1;
|
||||
unsigned int result = low + ((4096 - low) >> shift);
|
||||
|
||||
if (low >= 4096)
|
||||
return 15000;
|
||||
|
||||
return result + (result >> 2);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* func_80021F24 — 44 bytes at 0x80021F24..0x80021F50
|
||||
*
|
||||
* Framed wrapper: calls one routine with two `gp`-relative halfwords and its own argument.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* move a2,a0 00803021 a2 = a0
|
||||
* lh a0,0x922(gp) 87a40922 a0 = *(short *)(gp + 0x922)
|
||||
* lh a1,0x924(gp) 87a50924 a1 = *(short *)(gp + 0x924)
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x80021d90 0c008764 call func_80021D90
|
||||
* nop 00000000 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The incoming argument moves to a2 **before** a0 and a1 are overwritten, so the call is
|
||||
* `f(global0, global1, arg)` — the argument is shifted two slots. Both globals are read as
|
||||
* signed **halfwords** (`lh`), which fixes them as 16-bit signed objects, and both loads are
|
||||
* hoisted above the frame setup.
|
||||
*
|
||||
* `0x922(gp)` and `0x924(gp)` are `gp`-relative accesses off gp 0x80121938, i.e. 0x8012225A
|
||||
* and 0x8012225C, both already `gp`-marked in `config/symbols.tsv` as `D_8012225A` and
|
||||
* `D_8012225C`, so no request row is needed.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the two globals' meanings are hypotheses; only
|
||||
* the bytes are evidence. The wrapper sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern short D_8012225A;
|
||||
extern short D_8012225C;
|
||||
extern void func_80021D90(int a0, int a1, int a2);
|
||||
|
||||
void func_80021F24(int a0)
|
||||
{
|
||||
func_80021D90(D_8012225A, D_8012225C, a0);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* func_80026F14 — 40 bytes at 0x80026F14..0x80026F3C
|
||||
*
|
||||
* Framed routine that makes an **indirect** call through a `gp`-relative function pointer,
|
||||
* but only when the pointer is non-null.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lw v0,0x214(gp) 8f820214 v0 = *(int *)(gp + 0x214)
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* beq v0,zero,0x80026f2c 10400003 if (v0 == 0) goto epilogue
|
||||
* sw ra,0x10(sp) afbf0010 save ra (delay slot)
|
||||
* jalr v0 0040f809 call v0
|
||||
* nop 00000000 (delay slot)
|
||||
* 0x80026f2c:
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* `0x214(gp)` is a `gp`-relative access off gp 0x80121938, i.e. 0x80121B4C. It is **not**
|
||||
* in `config/symbols.tsv`, so this region needs the registry row `D_80121B4C 0x80121B4C gp`
|
||||
* (staged in `symbols-request.tsv`); without the `gp` marker the harness emits an absolute
|
||||
* access and the region cannot match.
|
||||
*
|
||||
* The pointer is loaded **once** into v0 and used for both the null test and the `jalr`, so
|
||||
* the source binds it to a local rather than reading the global twice. The guard is checked
|
||||
* before the frame is established: the `sw ra` that saves the return address is placed in
|
||||
* the branch's delay slot, so `ra` is only saved on the path that reaches the call.
|
||||
*
|
||||
* LIMITS: the function name, the claim that the global holds a function pointer and the
|
||||
* callee's identity are hypotheses; only the bytes are evidence — the value is data, so
|
||||
* nothing here proves it is code. The routine sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern int D_80121B4C;
|
||||
|
||||
void func_80026F14(void)
|
||||
{
|
||||
void (*fn)(void) = (void (*)(void))D_80121B4C;
|
||||
|
||||
if (fn != 0)
|
||||
fn();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* func_8002D5D0 — 56 bytes at 0x8002D5D0..0x8002D608
|
||||
*
|
||||
* Leaf routine that appends a value to a bounded array, using a `gp`-relative counter.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lh a1,0x2b8(gp) 87a102b8 a1 = *(short *)(gp + 0x2b8)
|
||||
* addiu sp,sp,-0x8 27bdfff8 frame, 8 bytes
|
||||
* slti v0,a1,0x1e 28a2001e v0 = (a1 < 30) signed
|
||||
* beq v0,zero,0x8002d5fc 10400007 if (!(a1 < 30)) goto epilogue
|
||||
* move v1,a1 00a01821 v1 = a1 (delay slot)
|
||||
* addiu v0,v1,0x1 24620001 v0 = v1 + 1
|
||||
* sh v0,0x2b8(gp) a7a202b8 *(short *)(gp + 0x2b8) = v0
|
||||
* sll v0,a1,0x2 00051080 v0 = a1 * 4
|
||||
* lui at,0x8013 3c018013 \
|
||||
* addu at,at,v0 00220821 / at = 0x80130000 + a1 * 4
|
||||
* sw a0,-0x5390(at) ac24ac70 *(int *)(at - 0x5390) = a0
|
||||
* 0x8002d5fc:
|
||||
* addiu sp,sp,0x8 27bd0008 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* `0x2b8(gp)` is a `gp`-relative access off gp 0x80121938, i.e. 0x80121BF0, which the
|
||||
* registry already carries as `D_80121BF0` with the `gp` marker. It is read as a signed
|
||||
* **halfword** (`lh`) and incremented as one (`sh`), and the bound test is signed
|
||||
* (`slti`), so the counter is a 16-bit signed object and 30 is the limit.
|
||||
*
|
||||
* The array store is the explicit indexed symbol form: `lui at,%hi` / `addu at,at,index` /
|
||||
* `sw rt,%lo(at)`. The displacement is **-0x5390 with high half 0x8013**, i.e. the base is
|
||||
* 0x80130000 - 0x5390 = **0x8012AC70**; reading the pair as 0x8013AC70 would be wrong.
|
||||
*
|
||||
* The 8-byte frame is allocated and never written — cc1 reserves it for the local and then
|
||||
* keeps everything in registers. It is reproduced by declaring the counter as a local
|
||||
* rather than by any flag.
|
||||
*
|
||||
* LIMITS: the function name, the array, the counter's purpose and the bound 30 are
|
||||
* hypotheses; only the bytes are evidence. The array elements are 32-bit.
|
||||
*/
|
||||
|
||||
extern short D_80121BF0;
|
||||
extern int D_8012AC70[];
|
||||
|
||||
void func_8002D5D0(int a0)
|
||||
{
|
||||
short i = D_80121BF0;
|
||||
|
||||
if (i < 30) {
|
||||
D_80121BF0 = i + 1;
|
||||
D_8012AC70[i] = a0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* func_80036380 — 16 bytes at 0x80036380..0x80036390
|
||||
*
|
||||
* An empty function that still allocates and releases a 48-byte stack frame.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x30 27bdffd0 allocate 48 bytes
|
||||
* addiu sp,sp,0x30 27bd0030 release 48 bytes
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* There is no body, no saved register and **no `sw ra`** — so this is not a call frame;
|
||||
* `ra` is untouched and the function is a leaf. The frame exists only because a local was
|
||||
* allocated, and the exact pair `addiu sp,sp,-0x30` / `addiu sp,sp,0x30` with nothing in
|
||||
* between is what this compiler emits when a local object is *allocated* but its uses are
|
||||
* all gone: the size survives, the accesses do not.
|
||||
*
|
||||
* Three spellings were measured to find what keeps the frame:
|
||||
* - `volatile int buf[12];` (unused) -> 16 bytes, MATCH
|
||||
* - `int buf[12]; buf[11] = 0;` (dead store) -> 20 bytes (the store survives)
|
||||
* - `int buf[12]; (void)buf;` (address taken, no use) -> 16 bytes, MATCH
|
||||
* The last is the spelling used here, because taking the local's address is the ordinary
|
||||
* reason a compiler allocates stack it then never touches, and it does not depend on a
|
||||
* qualifier that would have no other effect.
|
||||
*
|
||||
* LIMITS: the function name is a hypothesis and there is no evidence at all about what the
|
||||
* local was — only that 48 bytes of stack were reserved for something. A body that was
|
||||
* conditionally compiled out, a removed call, or an unused scratch buffer are all consistent
|
||||
* with these four instructions; the C below is a reconstruction of the *codegen*, not a
|
||||
* recovery of the original source. This is the one region in this batch whose C cannot be
|
||||
* argued from the bytes beyond the frame size.
|
||||
*/
|
||||
|
||||
void func_80036380(void)
|
||||
{
|
||||
int buf[12];
|
||||
|
||||
(void)buf;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* func_80041A24 — 52 bytes at 0x80041A24..0x80041A58
|
||||
*
|
||||
* Framed routine: calls a routine that returns a pointer, and if the pointer is
|
||||
* non-null initialises two bytes at its start.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x800419d0 0c010674 call func_800419D0
|
||||
* nop 00000000 (delay slot)
|
||||
* move v1,v0 00401821 v1 = result
|
||||
* beq v1,zero,0x80041a48 10200004 if (v1 == 0) goto epilogue
|
||||
* li v0,0xff 240200ff v0 = 0xff (delay slot)
|
||||
* sb zero,0x0(v1) a0200000 *(char *)v1 = 0
|
||||
* sb v0,0x1(v1) a0220001 *(char *)(v1 + 1) = 0xff
|
||||
* 0x80041a48:
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The callee's result is copied to v1 rather than tested in place, and the constant
|
||||
* 0xff is materialised in the guard's branch delay slot — so the byte value is written
|
||||
* by the guard, not inside the taken block. Both stores are byte-wide (`sb`), which is
|
||||
* what fixes the pointed-to type as `char`.
|
||||
*
|
||||
* LIMITS: the function name, the callee, the two initialised bytes and their meaning are
|
||||
* hypotheses; only the bytes are evidence. The routine sets no result of its own, so it
|
||||
* is `void`; whether the callee's pointer is to a 2-byte object or a longer structure is
|
||||
* not recoverable from these bytes.
|
||||
*/
|
||||
|
||||
extern char *func_800419D0(void);
|
||||
|
||||
void func_80041A24(void)
|
||||
{
|
||||
char *v1 = func_800419D0();
|
||||
|
||||
if (v1 != 0) {
|
||||
v1[0] = 0;
|
||||
v1[1] = 0xff;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* func_800453C0 — 56 bytes at 0x800453C0..0x800453F8
|
||||
*
|
||||
* 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,0x800453e8 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 0x8005a81c 0c016a07 call func_8005A81C
|
||||
* nop 00000000 (delay slot)
|
||||
* 0x800453e8:
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* Two things are scheduled unusually and both follow from the C. The flag load is hoisted
|
||||
* **above** the frame setup, and the `sw ra` that establishes the frame is placed in the
|
||||
* guard's branch delay slot — so `ra` is only saved on the path that reaches the call, and
|
||||
* the epilogue's `lw ra` is likewise only correct on that path. The incoming argument is
|
||||
* moved to a1 before a0 is overwritten with the global, so the call is
|
||||
* `f(global, arg)` with the two operands in the opposite order from the parameters.
|
||||
*
|
||||
* Both globals use the same-register `lui`+load form (cookbook finding 2), so they are
|
||||
* written as named symbols. The address arithmetic is exact and 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_8005A81C(int a0, int a1);
|
||||
|
||||
void func_800453C0(int a0)
|
||||
{
|
||||
unsigned char v0 = D_80122374;
|
||||
|
||||
if (v0 == 0)
|
||||
func_8005A81C(D_8012D88C, a0);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* func_80068D54 — 36 bytes at 0x80068D54..0x80068D78
|
||||
*
|
||||
* Framed wrapper: calls one routine with a zero second argument and a literal third.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* addu a1,zero,zero 00002821 a1 = 0
|
||||
* jal 0x800f6f00 0c03dbc0 call func_800F6F00
|
||||
* li a2,0x190 24060190 a2 = 0x190 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* a0 is forwarded untouched; the zero uses `addu rd,zero,zero` and the literal uses `li`.
|
||||
* The zero is issued before the `jal` while the literal is scheduled into its delay slot.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the meaning of 0x190 are hypotheses; only the
|
||||
* bytes are evidence. The wrapper sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern void func_800F6F00(int a0, int a1, int a2);
|
||||
|
||||
void func_80068D54(int a0)
|
||||
{
|
||||
func_800F6F00(a0, 0, 0x190);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* func_80068F6C — 44 bytes at 0x80068F6C..0x80068F98
|
||||
*
|
||||
* Framed wrapper: calls one routine with four zero arguments and masks the result to a byte.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x20 27bdffe0 frame, 32 bytes
|
||||
* addu a1,zero,zero 00002821 a1 = 0
|
||||
* addu a2,zero,zero 00003021 a2 = 0
|
||||
* addu a3,zero,zero 00003821 a3 = 0
|
||||
* sw ra,0x18(sp) afbf0018 save ra
|
||||
* jal 0x80068d78 0c01a35e call func_80068D78
|
||||
* sw zero,0x10(sp) afa00010 arg5 = 0 (delay slot)
|
||||
* lw ra,0x18(sp) 8fbf0018 restore ra
|
||||
* andi v0,v0,0xff 304200ff v0 &= 0xff
|
||||
* jr ra 03e00008
|
||||
* addiu sp,sp,0x20 27bd0020 frame release (delay slot)
|
||||
*
|
||||
* The frame is 32 bytes: 16 for the four register arguments' home slots, 8 for the fifth
|
||||
* argument at 0x10, and 8 for the saved `ra` at 0x18 — so the call takes **five** arguments,
|
||||
* with a0 forwarded and the rest zero. All four register zeroes use `addu rd,zero,zero` (this
|
||||
* compiler's zeroing form, not `li rd,0`), and the stack argument is scheduled into the `jal`
|
||||
* delay slot.
|
||||
*
|
||||
* The `andi ...,0xff` after the call is the mask this ABI applies when an `unsigned char`
|
||||
* return value is widened to `int`, so the callee returns `unsigned char` and the wrapper
|
||||
* widens it. That is why the return type below is `int` with a `unsigned char` callee.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the meaning of the zeros are hypotheses; only
|
||||
* the bytes are evidence.
|
||||
*/
|
||||
|
||||
extern unsigned char func_80068D78(int a0, int a1, int a2, int a3, int a4);
|
||||
|
||||
int func_80068F6C(int a0)
|
||||
{
|
||||
return func_80068D78(a0, 0, 0, 0, 0);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* func_80072BA8 — 52 bytes at 0x80072BA8..0x80072BDC
|
||||
*
|
||||
* Framed routine: calls the routine that immediately follows it with seven arguments,
|
||||
* three of them constants passed on the stack.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x28 27bdffd8 frame, 40 bytes
|
||||
* li v0,0x8 24020008 v0 = 8
|
||||
* move a2,a3 00e03021 a2 = a3
|
||||
* li a3,-0x1 2407ffff a3 = -1
|
||||
* sw ra,0x20(sp) afbf0020 save ra
|
||||
* sw zero,0x10(sp) afa00010 arg5 = 0
|
||||
* sw zero,0x14(sp) afa00014 arg6 = 0
|
||||
* jal 0x80072bdc 0c01caf7 call func_80072BDC
|
||||
* sw v0,0x18(sp) afa20018 arg7 = 8 (delay slot)
|
||||
* lw ra,0x20(sp) 8fbf0020 restore ra
|
||||
* addiu sp,sp,0x28 27bd0028 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The callee is the **next address** (0x80072BDC = 0x80072BA8 + 0x34), so this is a
|
||||
* forwarder into the following body rather than a call into unrelated code.
|
||||
*
|
||||
* The frame is 40 bytes: 16 for the four register arguments' home slots, 16 for the
|
||||
* three extra arguments at 0x10/0x14/0x18, and 8 for the saved `ra` at 0x20. The extra
|
||||
* arguments are stored at 16(sp), 20(sp) and 24(sp), which is the o32 convention for
|
||||
* arguments five, six and seven — so the call takes seven arguments, with a0 and a1
|
||||
* forwarded untouched, a3 moved into a2's slot, and -1 in a3.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the meanings of the constants (8, 0, 0) are
|
||||
* hypotheses; only the bytes are evidence. The stack argument slots are written as a
|
||||
* seven-parameter call; whether the original declared them individually or as a struct
|
||||
* is not recoverable from these instructions.
|
||||
*/
|
||||
|
||||
extern void func_80072BDC(int a0, int a1, int a2, int a3, int a4, int a5, int a6);
|
||||
|
||||
void func_80072BA8(int a0, int a1, int a2, int a3)
|
||||
{
|
||||
func_80072BDC(a0, a1, a3, -1, 0, 0, 8);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* func_800900A0 — 44 bytes at 0x800900A0..0x800900CC
|
||||
*
|
||||
* Framed wrapper: calls one routine with a fixed address, its own argument, and a zero.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* move a1,a0 00802821 a1 = a0
|
||||
* lui a0,0x8009 3c048009 \
|
||||
* addiu a0,a0,0x58 24840058 / a0 = 0x80090058 (D_80090058)
|
||||
* jal 0x800fb6c4 0c03edb1 call func_800FB6C4
|
||||
* addu a2,zero,zero 00003021 a2 = 0 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The argument is moved to a1 before a0 is overwritten, so the call is `f(address, arg, 0)`
|
||||
* with the address in the first slot. The address is materialised as `lui`+`addiu` (the
|
||||
* linker-resolved symbol form, cookbook finding 4), so it is written as a named symbol and
|
||||
* not a literal (finding 5's `lui`+`ori`).
|
||||
*
|
||||
* LIMITS: the function name, the callee, the pointed-to object and the meaning of the zero
|
||||
* argument are hypotheses; only the bytes are evidence. Whether the address names data or code
|
||||
* is not recoverable; it is written as a `char[]` so it stays an address. The wrapper sets no
|
||||
* result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern char D_80090058[];
|
||||
extern void func_800FB6C4(char *a0, int a1, int a2);
|
||||
|
||||
void func_800900A0(int a0)
|
||||
{
|
||||
func_800FB6C4(D_80090058, a0, 0);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* func_80090C8C — 32 bytes at 0x80090C8C..0x80090CAC
|
||||
*
|
||||
* Framed wrapper: calls one routine with its argument masked to eight bits.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x800fe844 0c03fa11 call func_800FE844
|
||||
* andi a0,a0,0xff 308400ff a0 &= 0xff (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The `andi ...,0xff` is the promotion mask this ABI applies to an unsigned `char`
|
||||
* parameter (cookbook finding 7), so the parameter is declared `unsigned char` and the
|
||||
* mask is not written in the C. cc1 schedules it into the `jal` delay slot, so the
|
||||
* callee receives the masked value.
|
||||
*
|
||||
* LIMITS: the function name and the callee's purpose are hypotheses; only the bytes are
|
||||
* evidence. The wrapper sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern void func_800FE844(unsigned char a0);
|
||||
|
||||
void func_80090C8C(unsigned char a0)
|
||||
{
|
||||
func_800FE844(a0);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* func_8009AC08 — 32 bytes at 0x8009AC08..0x8009AC28
|
||||
*
|
||||
* Framed wrapper: calls one routine with a zero second argument.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x8009a904 0c026a41 call func_8009A904
|
||||
* addu a1,zero,zero 00002821 a1 = 0 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* a0 is never touched, so the wrapper forwards its first argument; the zero uses
|
||||
* `addu rd,zero,zero` (this compiler's zeroing form, not `li rd,0`) and is scheduled
|
||||
* into the `jal` delay slot.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the meaning of the zero argument are
|
||||
* hypotheses; only the bytes are evidence. The wrapper sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern void func_8009A904(int a0, int a1);
|
||||
|
||||
void func_8009AC08(int a0)
|
||||
{
|
||||
func_8009A904(a0, 0);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* func_800AC818 — 68 bytes at 0x800AC818..0x800AC85C
|
||||
*
|
||||
* Selects one of three globals from two byte-wide flags and stores it through the
|
||||
* output pointer, returning it as well. All three arms converge on ONE epilogue,
|
||||
* so the source keeps a single `value` local.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* andi a2,a2,0xff ; a2 &= 0xff
|
||||
* beqz a2,0x800AC84C ; if (a2 == 0) use the third global
|
||||
* andi v0,a3,0xff ; a3 &= 0xff (delay slot)
|
||||
* beqz v0,0x800AC83C ; if (a3 == 0) use the second global
|
||||
* nop
|
||||
* lui v0,0x8014
|
||||
* lw v0,-15556(v0) ; value = D_8013C33C
|
||||
* j 0x800AC854
|
||||
* nop
|
||||
* 3C: lui v0,0x8014
|
||||
* lw v0,-15552(v0) ; value = D_8013C340
|
||||
* j 0x800AC854
|
||||
* nop
|
||||
* 4C: lui v0,0x8014
|
||||
* lw v0,-15548(v0) ; value = D_8013C344
|
||||
* 54: jr ra
|
||||
* sw v0,0(a0) ; *out = value (delay slot)
|
||||
*
|
||||
* The return value is the LOADED global, not the output pointer: `v0` holds the
|
||||
* global at the `jr ra` and the store in the delay slot consumes it. The first
|
||||
* parameter is a pointer while the other three are used only as masked bytes.
|
||||
*
|
||||
* The blocks are MIRRORED (cookbook finding 28): the `first_flag == 0` arm is
|
||||
* emitted LAST and reached by a forward branch, so the natural `== 0` chain
|
||||
* spelling emits an inverted `bne` and the wrong block order. The nested
|
||||
* `!= 0` guards below reproduce the original's order. The symbol addresses are
|
||||
* 0x8013C33C / 0x8013C340 / 0x8013C344 — reachable as `lui 0x8014` plus the
|
||||
* sign-extended displacements -15556 / -15552 / -15548.
|
||||
*
|
||||
* LIMITS: the three symbol addresses (0x8013C34C/350/354), the byte masks and the
|
||||
* parameter types are hypotheses read from the instruction shape; the second
|
||||
* parameter is not referenced by any instruction in the body and its purpose is
|
||||
* NOT guessed. What the globals mean is unknown. Only the compiled bytes are
|
||||
* evidence.
|
||||
*/
|
||||
|
||||
extern int D_8013C33C;
|
||||
extern int D_8013C340;
|
||||
extern int D_8013C344;
|
||||
|
||||
int func_800AC818(int *out, int unused, int first_flag, int second_flag) {
|
||||
int value;
|
||||
|
||||
if ((first_flag & 0xFF) != 0) {
|
||||
if ((second_flag & 0xFF) != 0)
|
||||
value = D_8013C33C;
|
||||
else
|
||||
value = D_8013C340;
|
||||
} else {
|
||||
value = D_8013C344;
|
||||
}
|
||||
|
||||
*out = value;
|
||||
return value;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* func_800AC85C — 40 bytes at 0x800AC85C..0x800AC884
|
||||
*
|
||||
* Framed wrapper: calls one routine with a global loaded from a fixed address.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lui a0,0x8014 3c048014 \
|
||||
* lw a0,-0x3cb8(a0) 8c84c348 / a0 = *(int *)0x8013C348
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x8002e870 0c00ba1c call func_8002E870
|
||||
* nop 00000000 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The global load is hoisted **above** the frame setup, and the address arithmetic carries:
|
||||
* `lui 0x8014` with the signed displacement -0x3cb8 gives **0x8013C348**, not 0x8014C348 —
|
||||
* the same trap as func_800F4B54 and func_800F7990.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the global's type are hypotheses; only the bytes
|
||||
* are evidence. The global is read as a 32-bit value and passed as the only argument. The
|
||||
* wrapper sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern int D_8013C348;
|
||||
extern void func_8002E870(int a0);
|
||||
|
||||
void func_800AC85C(void)
|
||||
{
|
||||
func_8002E870(D_8013C348);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* func_800BFEC0 — 32 bytes at 0x800BFEC0..0x800BFEE0
|
||||
*
|
||||
* Framed wrapper: calls one routine, deriving the third argument from the second.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x800bf734 0c02fdcd call func_800BF734
|
||||
* addiu a2,a1,0x378 24a60378 a2 = a1 + 0x378 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The third callee is func_800BF734, reached here with offset 0x378 — the same callee
|
||||
* and the same shape as func_800BFE80 (0x128) and func_800BFEE0 (0x4a0), so the three
|
||||
* are one callee reached through three different record offsets. The offset is again
|
||||
* computed in the `jal` delay slot.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the meaning of the 0x378 offset are
|
||||
* hypotheses; only the bytes are evidence. The wrapper is `void` because no return value
|
||||
* is set.
|
||||
*/
|
||||
|
||||
extern void func_800BF734(int a0, int a1, int a2);
|
||||
|
||||
void func_800BFEC0(int a0, int a1)
|
||||
{
|
||||
func_800BF734(a0, a1, a1 + 0x378);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* func_800F3140 — 32 bytes at 0x800F3140..0x800F3160
|
||||
*
|
||||
* Framed wrapper: calls the GTE control-register write that this project has already
|
||||
* matched as func_80102FD4.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x80102fd4 0c040bf5 call func_80102FD4
|
||||
* nop 00000000 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* Nothing is set up before the `jal`, so the argument is **forwarded**: the callee is
|
||||
* `void func_80102FD4(int h)` (registered at 0x80102FD4..0x80102FE0, a single `ctc2` to
|
||||
* the GTE H register), and a forwarding wrapper emits no instructions for a0. Writing the
|
||||
* wrapper with no parameter and a literal argument would instead emit a `clear a0`, so the
|
||||
* absence of any setup is the evidence for the parameter.
|
||||
*
|
||||
* This region also sits immediately before the registered 0x800F3160..0x800F316C, which
|
||||
* needs `maspsx=off` — the two are adjacent, not overlapping.
|
||||
*
|
||||
* LIMITS: the function name and the claim that the value is a projection-plane distance
|
||||
* are hypotheses; only the bytes are evidence. The wrapper sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern void func_80102FD4(int h);
|
||||
|
||||
void func_800F3140(int h)
|
||||
{
|
||||
func_80102FD4(h);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* func_800F3A00 — 36 bytes at 0x800F3A00..0x800F3A24
|
||||
*
|
||||
* Framed wrapper: loads a field from its argument and passes it on.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* lw a0,0x10(a0) 8c840010 a0 = *(int *)(a0 + 0x10)
|
||||
* jal 0x800f452c 0c03d14b call func_800F452C
|
||||
* nop 00000000 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* The field load targets **a0 itself**, overwriting the incoming pointer, so the wrapper
|
||||
* dereferences its argument once and forwards the loaded word. Nothing else is set up, so
|
||||
* the callee takes exactly one argument.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the field at +0x10 are hypotheses; only the
|
||||
* bytes are evidence. The load is 32-bit. The wrapper sets no result, so it is `void`.
|
||||
*/
|
||||
|
||||
extern void func_800F452C(int a0);
|
||||
|
||||
void func_800F3A00(int a0)
|
||||
{
|
||||
func_800F452C(*(int *)(a0 + 0x10));
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* func_800F8B18 — 32 bytes at 0x800F8B18..0x800F8B38
|
||||
*
|
||||
* Framed wrapper: calls one routine and returns its result untouched.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x80106154 0c041855 call func_80106154
|
||||
* nop 00000000 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* addiu sp,sp,0x18 27bd0018 frame release
|
||||
* jr ra 03e00008
|
||||
* nop 00000000 (delay slot)
|
||||
*
|
||||
* Nothing touches v0 after the call, so the callee's result is the return value. Same
|
||||
* shape as func_800F8638 and func_800F8B38 with a different callee.
|
||||
*
|
||||
* LIMITS: the function name and the callee's purpose are hypotheses; only the bytes are
|
||||
* evidence. A parameter-forwarding wrapper would produce the same instructions, so the
|
||||
* parameter list is not recoverable.
|
||||
*/
|
||||
|
||||
extern int func_80106154(void);
|
||||
|
||||
int func_800F8B18(void)
|
||||
{
|
||||
return func_80106154();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* func_800F8F5C — 32 bytes at 0x800F8F5C..0x800F8F7C
|
||||
*
|
||||
* Framed wrapper: calls one routine and reports whether the result is zero.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x8010703c 0c041c0f call func_8010703C
|
||||
* nop 00000000 (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* sltiu v0,v0,0x1 2c420001 v0 = (v0 < 1) unsigned
|
||||
* jr ra 03e00008
|
||||
* addiu sp,sp,0x18 27bd0018 frame release (delay slot)
|
||||
*
|
||||
* The `sltiu` against 1 is this compiler's idiom for `x == 0`; writing the comparison as
|
||||
* `== 0` (rather than `< 1`) keeps the immediate form. Same shape as func_800F8F7C with a
|
||||
* different callee.
|
||||
*
|
||||
* LIMITS: the function name and the callee's purpose are hypotheses; only the bytes are
|
||||
* evidence. The callee's return type is written `int`; an `unsigned` or pointer result
|
||||
* would produce the same unsigned comparison, so the type is not pinned.
|
||||
*/
|
||||
|
||||
extern int func_8010703C(void);
|
||||
|
||||
int func_800F8F5C(void)
|
||||
{
|
||||
return func_8010703C() == 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* func_800FA960 — 32 bytes at 0x800FA960..0x800FA980
|
||||
*
|
||||
* Framed wrapper: calls one routine with a literal third argument and reports whether the
|
||||
* result is zero.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
|
||||
* sw ra,0x10(sp) afbf0010 save ra
|
||||
* jal 0x80102e10 0c040b84 call func_80102E10
|
||||
* li a2,0xc 2406000c a2 = 0xc (delay slot)
|
||||
* lw ra,0x10(sp) 8fbf0010 restore ra
|
||||
* sltiu v0,v0,0x1 2c420001 v0 = (v0 < 1) unsigned
|
||||
* jr ra 03e00008
|
||||
* addiu sp,sp,0x18 27bd0018 frame release (delay slot)
|
||||
*
|
||||
* a0 and a1 are never touched, so the first two arguments are forwarded; the third is the
|
||||
* literal 0xc, materialised in the `jal` delay slot. The `sltiu` against 1 is this
|
||||
* compiler's idiom for `x == 0`, so the wrapper returns a boolean.
|
||||
*
|
||||
* LIMITS: the function name, the callee and the meaning of 0xc are hypotheses; only the
|
||||
* bytes are evidence. The callee's return type is written `int`; the unsigned comparison
|
||||
* does not pin it.
|
||||
*/
|
||||
|
||||
extern int func_80102E10(int a0, int a1, int a2);
|
||||
|
||||
int func_800FA960(int a0, int a1)
|
||||
{
|
||||
return func_80102E10(a0, a1, 0xc) == 0;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* func_8010A748 — 68 bytes at 0x8010A748..0x8010A78C
|
||||
*
|
||||
* Writes a 16-bit value into a table indexed by the first argument, shifting the
|
||||
* value down by a runtime amount from a global when a flag is set. The index
|
||||
* scaling is computed once and lands in the first branch's delay slot.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* bnez a2,0x8010A768 ; if (flag != 0) take the shifted arm
|
||||
* sll v0,a0,0x1 ; offset = index * 2 (delay slot)
|
||||
* lui v1,0x8012
|
||||
* lw v1,4168(v1) ; v1 = D_80121048 (table base)
|
||||
* nop
|
||||
* addu v0,v0,v1 ; table + offset (offset first)
|
||||
* j 0x8010A784
|
||||
* sh a1,0(v0) ; *(short *)... = value (delay slot)
|
||||
* 68: lui a0,0x8012 ; RELOAD the table base
|
||||
* lw a0,4168(a0)
|
||||
* lui v1,0x8012
|
||||
* lw v1,0x1070(v1) ; v1 = D_80121070 (shift amount)
|
||||
* addu v0,v0,a0 ; table + offset (offset first)
|
||||
* srlv v1,a1,v1 ; value >> shift <- UNSIGNED, variable
|
||||
* sh v1,0(v0)
|
||||
* 84: jr ra
|
||||
* nop
|
||||
*
|
||||
* The table base is loaded in EACH arm, so the source references the global in
|
||||
* both — caching it in one local would emit a single load and change the bytes.
|
||||
* The index scaling must ALSO stay inline: binding `index * 2` to a local makes
|
||||
* cc1 compute it into the argument register before the branch and then copy it,
|
||||
* which costs an extra instruction (72 vs 68). Written inline, cc1 CSEs it into
|
||||
* the branch delay slot exactly as the original does. The shift is `srlv`, so the
|
||||
* shifted operand is unsigned.
|
||||
*
|
||||
* LIMITS: the two symbol names, the element stride (2), the field width and the
|
||||
* parameter types are hypotheses read from the instruction shape; the offsets
|
||||
* 4168/0x1070 are facts about this executable's globals. What the table holds is
|
||||
* unknown and is not guessed here. Only the compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
extern int D_80121048;
|
||||
extern int D_80121070;
|
||||
|
||||
void func_8010A748(int index, int value, int flag) {
|
||||
if (flag == 0)
|
||||
*(short *)((char *)D_80121048 + index * 2) = value;
|
||||
else
|
||||
*(short *)((char *)D_80121048 + index * 2) =
|
||||
(short)((unsigned int)value >> D_80121070);
|
||||
}
|
||||
Reference in New Issue
Block a user