phase10: merge 14 + negatives reconciliation — 450 distinct bodies / 459 regions
+3 bodies from 447. Candidate gate MATCH before promotion. Negatives reconciliation (the protocol step that protects worker findings from being lost with ignored staging): imported 26 new negatives from all three workers' staging into the tracked index. Index 140 -> 166 rows, address-ordered, 0 duplicates, 0 registered. excluded_recorded_negative 116 -> 142; worklist 1268 rows; 0 unregistered negatives survive into the worklist. make check green: regions=459 disagreements=0 AGREE, c_regions=459 differing_bytes=0 MATCH, SHA-1 e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
+1048
-1077
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,7 @@
|
||||
0x8001DC20 - near-match -
|
||||
0x8001EAFC 12 deferred shared-block-not-a-function
|
||||
0x80022E44 52 near-match adjacent-zero-store merge
|
||||
0X800238BC 264 near-match candidate_bytes=264 (correct length) differing_bytes=5 first_difference=0x80023900. Structure solved: `if (arg == 0) { out->x=out->y=out->z=0; } else
|
||||
0x800245D8 - near-match -
|
||||
0x80024630 56 near-match stack-routed min (temp elided by optimizer)
|
||||
0x8002515C - near-match -
|
||||
@@ -40,13 +41,18 @@
|
||||
0x80025EAC - near-match -
|
||||
0x8002622C - near-match -
|
||||
0x800266A8 68 near-match byte-replication alloc (first sll register; fresh-context re-spelling 3B; named-locals regresses)
|
||||
0X800268F4 136 near-match differing_bytes=9 result=DIFF at 136 bytes with the shared-result spelling (r-268f4-shared): branch target 0x80026968 vs 0x80026964 and the delay slot
|
||||
0X80026A04 152 near-match LENGTH-MISMATCH: `for (i=0;i<10;i++)` gives 136 bytes (34 words) vs 152; cc1 ROTATED the loop into a do-while with the test at the bottom, and dropped
|
||||
0x80027BE8 - near-match -
|
||||
0X80028750 244 near-match candidate_bytes=236 vs 244 (8 short) with `int r[4]; int s;` and with `int r[3]; int s;`. Structure understood: s = f(p0,q0)+f(p1,q1)+f(p2,q2); r[i] =
|
||||
0x8002D014 - near-match -
|
||||
0x8002D060 72 near-match -
|
||||
0X8002E198 180 deferred 4 prologue callee-saved assignment: ORIGINAL copies a0->s2, a1->s3, a2->s1 and the func_800A8700 result->s0 (save order s2,s3,s1, then s0 in the jal d
|
||||
0x80037984 - near-match -
|
||||
0x800379E0 - near-match -
|
||||
0x80039308 - near-match -
|
||||
0x8003A5F4 80 near-match alloc+layout (j-to-done second guard; worker-C residual confirmed by coordinator)
|
||||
0X8003A9C8 240 near-match candidate_bytes=216 vs 240 (24 short). `int d[3]; int t[3];` reproduces the original's 64-byte frame and its s0/s1/ra offsets exactly, so the array le
|
||||
0x8003EB18 - near-match -
|
||||
0x80042CE0 80 near-match paired-array geometry (stride 1428, single walked at-register)
|
||||
0x80042D88 76 near-match strength-reduce (sra5+sll2 vs cc1 folded shift)
|
||||
@@ -55,12 +61,16 @@
|
||||
0x80042E68 - near-match -
|
||||
0x80045540 56 near-match constant-materialisation-order
|
||||
0x80045F00 - near-match -
|
||||
0X80045FD8 120 deferred 4 register shift: original reloads a3->a0, a4->v0, and in the L1 block a4->a1; candidate gets a3->v0, a4->v0, a4->v1 (i.e. the allocator's choice star
|
||||
0x800460AC 40 near-match constant-materialisation-order
|
||||
0x80047468 72 near-match alloc (move-zero-in-delay + *76 strength-reduce; 2 coordinator spellings 76B; the *76 and pointer-slot table-lever patterns confirmed)
|
||||
0x8004820C - near-match -
|
||||
0x800496CC - near-match -
|
||||
0X8004D7C8 220 near-match candidate_bytes=220 = CORRECT length, differing_bytes=7 first_difference=0x8004D7F4. Structure: `v = *(char**)(p+32); s1 = *(int*)(*(char**)(v+244)+8)
|
||||
0x800518BC 88 near-match return-merge/sltiu (3 spellings: goto-shared 80B, combined cond 80B, two-exit if 80B; original keeps move-zero at separate target + j-to-shared-return; sltiu needs unsigned val which alone fixes the compare byte but not the 8-byte layout)
|
||||
0x800582AC 64 near-match -
|
||||
0X800589E8 192 near-match candidate_bytes=196 vs 192 with `V4 d; V4 r;` and with `int d[3]; int r[3];` (the array form gives the original's 64-byte... no: frame 64 with s1 also
|
||||
0X80058AA8 248 near-match candidate_bytes=252 vs 248 (4 over, 121 differing bytes from one shifted instruction). Structure: `V4 d; V4 v; v = *(V4*)D_8010D138; func_80027ECC(&v,
|
||||
0x8005DEF8 124 near-match register-tiebreak
|
||||
0x80065494 80 near-match popcount scheduling (base in beqz delay slot)
|
||||
0x800690E4 68 near-match loop-rotation+head-match-early-return (3 spellings: do/while arg-test-top 84B, while+conditional 76B, while-test 64B; the j/li early path and bnez-back-to-bne rotation are the residual)
|
||||
@@ -87,19 +97,25 @@
|
||||
0x8009C750 436 deferred trapping-arithmetic
|
||||
0x8009F064 - near-match -
|
||||
0x800A6658 88 near-match alloc+symbol-recompute (3 coordinator spellings; original recomputes lui/addu per iteration into two separate symbol arrays; cc1 pre-materializes base pointers — worker-A finding-8 CSE class)
|
||||
0X800A6B38 104 near-match candidate_bytes=104 differing_bytes=6 result=DIFF at 0x800A6B56. Count right (26 words), structure right, EVERY instruction identical except that the
|
||||
0x800A82D0 64 near-match -
|
||||
0x800A86B4 - near-match -
|
||||
0x800A8AEC - near-match -
|
||||
0x800AAC44 - near-match -
|
||||
0X800AB504 148 near-match candidate_bytes=172 vs 148 (24 over). Structure solved: recursive free of a linked record (`if (n) func_800AB504(n);`), then a counted loop of `count
|
||||
0x800AC9D8 56 near-match constant-materialisation-order
|
||||
0X800ACA10 184 near-match candidate_bytes=188 vs 184 (one extra instruction). Structure solved: `v = 0; for (i=0;i<9;i++) if (D_80116E3C[i] == 1) { v = D_80116E84[i]; break; }`
|
||||
0x800B0B88 - near-match -
|
||||
0x800B34A4 88 near-match alloc-tiebreak (bit-index/base register pair a0/a1 vs cc1 a0/v1; 2 spellings both 80B; original keeps base in a1 via direct +0x10 load)
|
||||
0X800BC6EC 236 deferred 0 NOT attempted beyond disassembly. The body switches the STACK POINTER to the PSX scratchpad and back: `lui at,0x1f80` + `sw sp,1020(at)` (saves sp t
|
||||
0X800C1424 152 near-match candidate_bytes=148 vs 152 (4 short) after moving `found = 0;` to AFTER the two guards (that change alone took 144 -> 148 and put `move s0,zero` in th
|
||||
0x800C1E54 - near-match -
|
||||
0x800C3514 88 near-match alloc+layout (priority selector; original: all stack loads hoisted, beqz+nop+li groups, sltu first test; cc1 interleaves with bnez — 2 coordinator spellings 84B)
|
||||
0x800F3BB4 164 near-match global-ra-save guard (ra through D_8012A57C is CRT/library asm, not usable C; GTE $0..$7 block verified as the rotation/translation macros — gte_ldTRX/TRY/TRZ added to gtemac.h from this row)
|
||||
0x800F4B54 - near-match -
|
||||
0x800F4C08 - near-match -
|
||||
0x800F50B0 - near-match -
|
||||
0X800F6948 116 near-match maspsx=off: candidate_bytes=116 differing_bytes=4 first_difference=0x800F6954. maspsx on: candidate_bytes=120 (one extra nop: cc1 emits `addu sp,sp,40
|
||||
0x800F6ED0 44 near-match cc1-scheduling
|
||||
0x800F6F20 - near-match -
|
||||
0x800F7610 - near-match -
|
||||
@@ -108,24 +124,33 @@
|
||||
0x800F88F0 - near-match -
|
||||
0x800F8928 - near-match -
|
||||
0x800F9134 - near-match -
|
||||
0X800FB6D8 128 near-match differing_bytes=56 result=DIFF, 128 bytes both sides. Instruction MULTISET and register allocation are IDENTICAL (handler in s0, previous in v0, buffe
|
||||
0X800FB758 112 near-match rare-epilogue-order-35b; residual 6B at 0x800FB7BC; tried default;--no-maspsx;--cc1 gcc-2.91.66-psx;--cc1 gcc-2.8.1-ps
|
||||
0x800FBD80 - near-match -
|
||||
0x800FBDC0 - near-match -
|
||||
0x800FBF5C 56 near-match -
|
||||
0x800FC280 - near-match -
|
||||
0X800FCB4C 228 near-match two residuals, both named. (i) WITHOUT parentheses around the multiply-minus: `base + n*36 - 36` reassociates to `(base + n*36) - 36` -> 232 bytes (4
|
||||
0x800FCC30 - near-match -
|
||||
0x800FD220 88 near-match exit-duplication
|
||||
0x800FDE54 - near-match -
|
||||
0X800FE970 84 near-match differing_bytes=6 result=DIFF, 84 bytes both sides. EXACT residual: the last two words swap - candidate `lw ra,24(sp)` / `addiu sp,sp,32` / `jr ra` /
|
||||
0x800FF43C 64 near-match two-epilogue
|
||||
0x800FF47C 64 near-match reorg-thread-fill
|
||||
0x800FF6DC 76 near-match -
|
||||
0x800FFB74 72 near-match base-materialization (original: lui v0,0x8014 + addiu 0x5ac0 + addiu 0x678 in v0; cc1: lui v1 + one addiu or ori; gp stores need D_80122168/6C gp rows; 4 coordinator spellings)
|
||||
0x800FFBBC 48 near-match reorg-thread-fill
|
||||
0X800FFF60 140 near-match maspsx on + default -G0: candidate_bytes=148 (cc1 CSEs the address of 0x801221AC into s0: lui s0/ori s0/sw s0/lw s0). maspsx on + cc1=-G4: candidate_b
|
||||
0x80100334 - near-match -
|
||||
0x8010036C 56 near-match rare-epilogue-order (F21)
|
||||
0X801003A4 148 near-match candidate_bytes=180 vs 148 (32 over). Structure read off the original: two calls, then a 24-iteration loop over 72-byte records at 0x80145AC0 where th
|
||||
0x80100998 80 near-match -
|
||||
0X80101764 212 near-match correct LENGTH (212) with `int one = 1;` used for `one << mask` and both loop comparisons, but 139 differing bytes. WITHOUT the `one` local: 216 bytes
|
||||
0x80101C5C 32 blocked -
|
||||
0x80101C7C - near-match -
|
||||
0x80101E50 76 near-match custom-compare loop shape (back-up-mismatch path; cc1 rewrites to 52B)
|
||||
0X80102A00 128 near-match candidate_bytes=124 vs 128 expected, ONE extra instruction in the original: the original has a `nop` at 0x80102A64 between `lw v0,-724(v0)` (0x80102A6
|
||||
0X80102A80 132 near-match rare-epilogue-r1-r2-measured; residual 4B at 0x80102A88; tried default maspsx 136 vs 132 LENGTH-MISMATCH (reorder nop block
|
||||
0x80102F58 - near-match -
|
||||
0x80102FE4 - near-match -
|
||||
0x80103AA4 - near-match -
|
||||
@@ -141,6 +166,7 @@
|
||||
0x801086B0 - near-match -
|
||||
0x801092C0 52 near-match -
|
||||
0x801097A0 - near-match -
|
||||
0X8010A940 232 deferred 5 5 attempts. The LOOP is fully solved: `unsigned short v = 0xC000; int i = 23; unsigned short *p = &D_80121112; for (; i >= 0; i--) { *p = v; p--; }`
|
||||
0x8010AA28 112 near-match maspsx mutual exclusion (finding 17 in its purest form: maspsx=off -> 2 differing bytes at 0x8010AA6C; maspsx on -> 124 bytes, three unfilled delay slots; maspsx 2.56 has no flag suppressing only the jump-slot nop)
|
||||
0x8010B420 - near-match -
|
||||
0x801BB450 - near-match -
|
||||
|
||||
|
@@ -218,12 +218,14 @@
|
||||
0x8006F6BC 0x8006F6F4 src/func_8006F6BC.c
|
||||
0x8006F930 0x8006F944 src/func_8006F930.c
|
||||
0x8006F944 0x8006F95C src/func_8006F944.c
|
||||
0x8006F9B4 0x8006FA78 src/func_8006F9B4.c
|
||||
0x8006FA78 0x8006FAA0 src/func_8006FA78.c
|
||||
0x8007049C 0x800704BC src/func_8007049C.c
|
||||
0x80072BA8 0x80072BDC src/func_80072BA8.c
|
||||
0x80073250 0x80073284 src/func_80073250.c
|
||||
0x80073364 0x800733C4 src/func_80073364.c
|
||||
0x800734A4 0x800734DC src/func_800734A4.c
|
||||
0x80073F78 0x8007405C src/func_80073F78.c
|
||||
0x80074C00 0x80074C74 src/func_80074C00.c
|
||||
0x8007A404 0x8007A428 src/func_8007A404.c
|
||||
0x8007A428 0x8007A4FC src/func_8007A428.c
|
||||
@@ -331,6 +333,7 @@
|
||||
0x800AE0F4 0x800AE10C src/func_800AE0F4.c
|
||||
0x800AE4DC 0x800AE548 src/func_800AE4DC.c
|
||||
0x800AE548 0x800AE574 src/func_800AE548.c
|
||||
0x800AE6C0 0x800AE7A0 src/func_800AE6C0.c
|
||||
0x800AF1FC 0x800AF20C src/func_800AF1FC.c
|
||||
0x800AF20C 0x800AF260 src/func_800AF20C.c
|
||||
0x800AFB1C 0x800AFB6C src/func_800AFB1C.c
|
||||
|
||||
|
@@ -0,0 +1,111 @@
|
||||
/* func_8006F9B4 — 0x8006F9B4..0x8006FA78 (196 bytes).
|
||||
*
|
||||
* Original words (objdump of the validated payload, little-endian):
|
||||
* lui v0,0x8012 \
|
||||
* lhu v0,13926(v0) / v0 = *(unsigned short *)0x80123666 (hoisted)
|
||||
* addiu sp,sp,-24
|
||||
* sw ra,20(sp)
|
||||
* sw s0,16(sp)
|
||||
* sw a0,2924(gp) D_801224A4 = a0
|
||||
* andi v0,v0,0x10 v0 &= 0x10
|
||||
* beqz v0,0x8006F9FC bit 4 clear -> use the argument unchanged
|
||||
* _srl v0,a1,0x10 (delay slot) v0 = a1 >> 16 LOGICAL
|
||||
* andi v0,v0,0xff v0 &= 0xff
|
||||
* andi v1,a1,0xff00 \
|
||||
* sra v1,v1,0x8 / v1 = (a1 & 0xff00) >> 8 ARITHMETIC
|
||||
* addu v0,v0,v1 |
|
||||
* andi v1,a1,0xff |
|
||||
* addu v0,v0,v1 | v0 = hi + mid + lo
|
||||
* sra v0,v0,0x2 | ARITHMETIC: the sum is signed
|
||||
* j 0x8006FA00 |
|
||||
* _sll s0,v0,0x8 (delay slot) s0 = avg << 8
|
||||
* 0x8006F9FC:
|
||||
* move s0,a1 s0 = a1
|
||||
* 0x8006FA00:
|
||||
* sw s0,2928(gp) D_801224A8 = s0
|
||||
* sw zero,2932(gp) D_801224AC = 0
|
||||
* jal 0x800F3E70
|
||||
* _nop
|
||||
* li a1,31
|
||||
* subu a1,a1,v0 a1 = 31 - func_800F3E70()
|
||||
* lui a0,0xff a0 = 0x00FF0000
|
||||
* and v1,s0,a0 \ lane 0x00FF0000: (x - (x>>2)) >> sh, masked
|
||||
* sra v0,v1,0x2 |
|
||||
* subu v1,v1,v0 |
|
||||
* srav v1,v1,a1 |
|
||||
* and v1,v1,a0 /
|
||||
* andi v0,s0,0xff00 \ lane 0x0000FF00: same shape
|
||||
* sra a0,v0,0x2 |
|
||||
* subu v0,v0,a0 |
|
||||
* srav v0,v0,a1 |
|
||||
* andi v0,v0,0xff00 /
|
||||
* or v1,v1,v0 |
|
||||
* andi v0,s0,0xff \ lane 0x000000FF: same shape
|
||||
* sra a0,v0,0x2 |
|
||||
* subu v0,v0,a0 |
|
||||
* srav v0,v0,a1 |
|
||||
* andi v0,v0,0xff /
|
||||
* or v1,v1,v0
|
||||
* sw v1,2936(gp) D_801224B0 = v1
|
||||
* lw ra,20(sp) (epilogue)
|
||||
* lw s0,16(sp)
|
||||
* addiu sp,sp,24
|
||||
* jr ra
|
||||
* _nop
|
||||
*
|
||||
* Stores an argument, then either uses a second argument unchanged or replaces it
|
||||
* with a byte-average shifted into the middle of the word, then rescales the three
|
||||
* colour-style lanes of that value by a shift derived from a callee. The frame is
|
||||
* 24 bytes = the 16-byte o32 outgoing argument area plus s0 at 16 and ra at 20.
|
||||
*
|
||||
* FOUR THINGS THE BYTES PIN DOWN:
|
||||
*
|
||||
* 1. THE LANES ARE 24-BIT: the mask constant is `lui a0,0xff` = 0x00FF0000, so the
|
||||
* three lanes are 0x00FF0000 / 0x0000FF00 / 0x000000FF. I first wrote
|
||||
* 0xFF000000 (a 32-bit top lane); that is a different `lui` immediate and shows
|
||||
* up as a single-instruction residual.
|
||||
* 2. THE AVERAGE IS UNSIGNED AND THE SCALE IS SIGNED — the same expression needs
|
||||
* BOTH shift kinds: `srl v0,a1,0x10` (logical, so the shifted operand is
|
||||
* unsigned) and `sra v0,v0,0x2` (arithmetic, so the SUM is signed). Written
|
||||
* wholly unsigned the final shift comes out `srl` and differs by exactly ONE
|
||||
* byte at 0x8006F9F0. The spelling that works casts the byte extraction to
|
||||
* unsigned and then casts the sum back to int:
|
||||
* `(int)(((unsigned)a1 >> 16 & 0xff) + ((a1 & 0xff00) >> 8) + (a1 & 0xff)) >> 2 << 8`.
|
||||
* Assigning the sum to a signed local first compiles identically. Diagnostic:
|
||||
* a 1-byte residual inside a shift is a SIGNEDNESS difference, not a scheduling
|
||||
* one — compare the funct field (srl 0x02 vs sra 0x03, srlv 0x06 vs srav 0x07).
|
||||
* 3. The per-lane scale is `(x - (x >> 2))`, i.e. subtract a quarter from itself,
|
||||
* then shift right by a variable amount. Both halves are signed (`sra`/`srav`),
|
||||
* which is consistent with `s0` being an int.
|
||||
* 4. The shift amount is `31 - func_800F3E70()`, computed once and shared by all
|
||||
* three lanes.
|
||||
*
|
||||
* LIMITS: what the three stored words mean, the bit-4 flag's meaning, why the
|
||||
* average is shifted left by 8, and the callee's semantics are hypotheses read from
|
||||
* the instruction shapes. The four globals are gp-relative (+2924/2928/2932/2936 =
|
||||
* 0x801224A4/0x801224A8/0x801224AC/0x801224B0) and are NOT in the registry, so the
|
||||
* harness resolved them from their name-encoded addresses. Only the compiled bytes
|
||||
* are evidence.
|
||||
*/
|
||||
|
||||
extern int D_801224A4, D_801224A8, D_801224AC, D_801224B0;
|
||||
extern int func_800F3E70(void);
|
||||
|
||||
void func_8006F9B4(int a0, int a1)
|
||||
{
|
||||
int s0;
|
||||
int sh;
|
||||
|
||||
D_801224A4 = a0;
|
||||
if (*(unsigned short *)0x80123666 & 0x10) {
|
||||
s0 = (int)((((unsigned)a1 >> 16) & 0xff) + ((a1 & 0xff00) >> 8) + (a1 & 0xff)) >> 2 << 8;
|
||||
} else {
|
||||
s0 = a1;
|
||||
}
|
||||
D_801224A8 = s0;
|
||||
D_801224AC = 0;
|
||||
sh = 31 - func_800F3E70();
|
||||
D_801224B0 = (((s0 & 0xFF0000) - ((s0 & 0xFF0000) >> 2)) >> sh & 0xFF0000)
|
||||
| (((s0 & 0xFF00) - ((s0 & 0xFF00) >> 2)) >> sh & 0xFF00)
|
||||
| (((s0 & 0xFF) - ((s0 & 0xFF) >> 2)) >> sh & 0xFF);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/* func_80073F78 — 0x80073F78..0x8007405C (228 bytes).
|
||||
*
|
||||
* Original words (objdump of the validated payload, little-endian):
|
||||
* addiu sp,sp,-48
|
||||
* sw s2,40(sp)
|
||||
* move s2,a0 s2 = argument 0
|
||||
* sw s0,32(sp)
|
||||
* move s0,a1 s0 = argument 1
|
||||
* move a0,a2 \
|
||||
* addiu a1,sp,16 / func_80010B14(argument2, &buf)
|
||||
* sw s1,36(sp)
|
||||
* sw ra,44(sp)
|
||||
* jal 0x80010B14
|
||||
* _move s1,a3 (delay slot) s1 = argument 3
|
||||
* jal 0x8006F6BC
|
||||
* _move a0,s0 (delay slot) func_8006F6BC(argument1)
|
||||
* lui a0,0x8012 \
|
||||
* lw a0,9144(a0) / a0 = *(int *)0x801223B8 (ABSOLUTE load)
|
||||
* move a1,s1 a1 = argument 3
|
||||
* andi a0,a0,0x1 a0 &= 1
|
||||
* jal 0x8006F9B4
|
||||
* _ori a0,a0,0x4 (delay slot) func_8006F9B4(a0 | 4, argument3)
|
||||
* addiu a0,sp,16 a0 = &buf
|
||||
* li a1,32767
|
||||
* li v0,32
|
||||
* sw v0,3056(gp) D_80122528 = 32
|
||||
* jal 0x8006FAEC
|
||||
* _move a2,zero (delay slot) func_8006FAEC(&buf, 32767, 0)
|
||||
* li a0,8
|
||||
* li a1,7
|
||||
* jal 0x8006FB44
|
||||
* _li a2,1 (delay slot) r = func_8006FB44(8, 7, 1)
|
||||
* move a0,v0 a0 = r
|
||||
* beqz a0,0x8007403C r == 0 -> return r
|
||||
* _nop
|
||||
* bltz s2,0x80074038 argument0 < 0 -> the shared tail
|
||||
* _sll v0,s2,0x2 (delay slot) v0 = argument0 * 4
|
||||
* lui v1,0x8012 \
|
||||
* lw v1,7168(v1) / v1 = *(int *)0x80121C00 (ABSOLUTE load)
|
||||
* _nop load-delay slot
|
||||
* addu v0,v0,v1 v0 = table + argument0*4
|
||||
* lw v0,0(v0) v0 = table[argument0]
|
||||
* _nop load-delay slot
|
||||
* lw v0,8(v0) v0 = *(int *)(v0 + 8)
|
||||
* _nop load-delay slot
|
||||
* lbu v0,11(v0) v0 = *(unsigned char *)(v0 + 11)
|
||||
* _nop load-delay slot
|
||||
* andi v0,v0,0x1 v0 &= 1
|
||||
* beqz v0,0x80074038 bit clear -> the shared tail
|
||||
* _li v0,-30 (delay slot) SIGN-EXTENDED -30
|
||||
* sb v0,46(a0) *(signed char *)(r + 46) = -30
|
||||
* 0x80074038:
|
||||
* sh zero,36(a0) *(short *)(r + 36) = 0
|
||||
* 0x8007403C:
|
||||
* move v0,a0 return r
|
||||
* lw ra,44(sp) (epilogue)
|
||||
* lw s2,40(sp)
|
||||
* lw s1,36(sp)
|
||||
* lw s0,32(sp)
|
||||
* addiu sp,sp,48
|
||||
* jr ra
|
||||
* _nop
|
||||
*
|
||||
* Setup-and-stamp routine: fills a local record, runs three setup calls, obtains an
|
||||
* object from a fourth, and — only when the object is non-null — conditionally
|
||||
* stamps two of its fields before returning it. The frame is 48 bytes = 16 (o32
|
||||
* outgoing args) + the 16-byte record at sp+16 + the s0/s1/s2/ra quad at
|
||||
* sp+32..44. Three arguments and the record address are live across the calls.
|
||||
*
|
||||
* THREE THINGS THE BYTES PIN DOWN:
|
||||
*
|
||||
* 1. THE STAMPED FIELD IS `signed char`, AND THAT CHANGES THE LOADED CONSTANT EVEN
|
||||
* THOUGH THE STORED BYTE IS IDENTICAL. The original materialises `-30` as
|
||||
* `addiu v0,zero,-30` (0xFFFFFFE2) and stores it with `sb`. Declaring the
|
||||
* target `char *` makes cc1 load `226` (0x000000E2) instead — same byte stored,
|
||||
* ONE differing byte in the instruction. Declaring it `signed char *` restores
|
||||
* the sign-extended constant. Diagnostic: a 1-byte residual on a `li`/`addiu`
|
||||
* immediate whose low byte is unchanged is a SIGNEDNESS difference in the
|
||||
* destination type, not a value difference.
|
||||
* 2. `0x80121C00` and `0x801223B8` are both LOADED absolutely (`lui`+`lw`), so both
|
||||
* use the literal-address spelling. 0x80121C00 is the pointer table already
|
||||
* indexed by claims 6, 18, 20, 22 and 24.
|
||||
* 3. The two guards share ONE tail: `sh zero,36(r)` is reached from both the
|
||||
* `argument0 < 0` branch and the bit-test branch, and the `beqz r` exit jumps
|
||||
* past it. So the source has the shared statement AFTER the inner `if`, not
|
||||
* duplicated in both arms.
|
||||
*
|
||||
* LIMITS: the record's layout, the meaning of the +46/+36 fields, the constants
|
||||
* 32767 / 32 / 8 / 7 / 1 / 0 and the five callees' semantics are hypotheses read
|
||||
* from the instruction shapes. `func_8006F9B4` is my own claim 21 (matched this
|
||||
* cycle) and `func_8006FAEC` / `func_8006FB44` sit immediately after it. Only the
|
||||
* compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
extern int D_80122528;
|
||||
extern int func_80010B14(int a0, void *a1);
|
||||
extern int func_8006F6BC(int a0);
|
||||
extern void func_8006F9B4(int a0, int a1);
|
||||
extern int func_8006FAEC(void *a0, int a1, int a2);
|
||||
extern int func_8006FB44(int a0, int a1, int a2);
|
||||
|
||||
int func_80073F78(int a0, int a1, int a2, int a3)
|
||||
{
|
||||
int buf[4];
|
||||
int r;
|
||||
int v;
|
||||
|
||||
func_80010B14(a2, buf);
|
||||
func_8006F6BC(a1);
|
||||
func_8006F9B4((*(int *)0x801223B8 & 1) | 4, a3);
|
||||
D_80122528 = 32;
|
||||
func_8006FAEC(buf, 32767, 0);
|
||||
r = func_8006FB44(8, 7, 1);
|
||||
if (r != 0) {
|
||||
if (a0 >= 0) {
|
||||
v = *(int *)(*(int *)0x80121C00 + a0 * 4);
|
||||
if (*(unsigned char *)(*(int *)(v + 8) + 11) & 1)
|
||||
*(signed char *)(r + 46) = -30;
|
||||
}
|
||||
*(short *)(r + 36) = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/* func_800AE6C0 — 0x800AE6C0..0x800AE7A0 (224 bytes).
|
||||
*
|
||||
* Original words (objdump of the validated payload, little-endian):
|
||||
* addiu sp,sp,-32
|
||||
* lui v0,0x8012 \
|
||||
* lw v0,7168(v0) / v0 = *(int *)0x80121C00 (ABSOLUTE load)
|
||||
* sll a1,a1,0x2 a1 = argument 1 * 4
|
||||
* sw ra,28(sp)
|
||||
* sw s2,24(sp)
|
||||
* sw s1,20(sp)
|
||||
* sw s0,16(sp)
|
||||
* addu a1,a1,v0 a1 = table + argument1*4
|
||||
* lw s0,0(a1) s0 = table[argument1]
|
||||
* move s2,a0 s2 = argument 0
|
||||
* lbu v0,0(s0) v0 = *(unsigned char *)p
|
||||
* _nop load-delay slot
|
||||
* andi v0,v0,0x20 v0 &= 0x20
|
||||
* bnez v0,0x800AE784 bit 5 set -> epilogue
|
||||
* _move s1,a2 (delay slot) s1 = argument 2
|
||||
* lh v0,2(s0) v0 = *(short *)(p + 2)
|
||||
* lui a0,0x8012 \
|
||||
* lw a0,7164(a0) / a0 = *(int *)0x80121BFC (ABSOLUTE load)
|
||||
* sll v1,v0,0x2 \ v1 = v0 * 76 (strength-reduced)
|
||||
* addu v1,v1,v0 |
|
||||
* sll v1,v1,0x2 |
|
||||
* subu v1,v1,v0 |
|
||||
* sll v1,v1,0x2 /
|
||||
* addu v1,v1,a0 v1 = base + v0*76
|
||||
* lh v1,72(v1) v1 = t = *(short *)(v1 + 72)
|
||||
* li v0,-1
|
||||
* beq v1,v0,0x800AE754 t == -1 -> the c = -1 arm
|
||||
* _sll v0,v1,0x2 (delay slot) the byte arm's first instruction
|
||||
* addu v0,v0,v1 \ v0 = t * 76
|
||||
* sll v0,v0,0x2 |
|
||||
* subu v0,v0,v1 |
|
||||
* sll v0,v0,0x2 /
|
||||
* addu v0,v0,a0 v0 = base + t*76
|
||||
* lbu v1,42(v0) v1 = c = *(unsigned char *)(v0 + 42)
|
||||
* j 0x800AE75C
|
||||
* _li v0,73 (delay slot)
|
||||
* 0x800AE754:
|
||||
* li v1,-1 c = -1
|
||||
* li v0,73
|
||||
* 0x800AE75C:
|
||||
* beq v1,v0,0x800AE770 c == 73 -> skip the call
|
||||
* _move a0,s0 (delay slot)
|
||||
* jal 0x800AE548
|
||||
* _move a0,s0 (delay slot)
|
||||
* 0x800AE770:
|
||||
* jal 0x800AE4DC
|
||||
* _move a1,s1 (delay slot) TWO arguments
|
||||
* move a0,s2
|
||||
* jal 0x800ADDE8
|
||||
* _move a1,s0 (delay slot)
|
||||
* 0x800AE784:
|
||||
* lw ra,28(sp) (epilogue)
|
||||
* lw s2,24(sp)
|
||||
* lw s1,20(sp)
|
||||
* lw s0,16(sp)
|
||||
* addiu sp,sp,32
|
||||
* jr ra
|
||||
* _nop
|
||||
*
|
||||
* Looks up an object in a pointer table, bails out when a flag bit is set,
|
||||
* resolves a second index through a 76-byte-strided record table, compares one
|
||||
* byte against 73, and then runs two forwarding calls. The frame is 32 bytes = 16
|
||||
* (o32 outgoing args) + s0/s1/s2 at sp+16/20/24 + ra at sp+28.
|
||||
*
|
||||
* FOUR THINGS THE BYTES PIN DOWN:
|
||||
*
|
||||
* 1. CONDITIONAL POLARITY, FOURTH INSTANCE — and the first where it decides which
|
||||
* arm is the DELAY-SLOT FILLER. The source must be
|
||||
* if (t != -1) c = <byte>; else c = -1;
|
||||
* so that the byte arm is the fall-through and `c = -1` sits at the branch
|
||||
* target. The natural `if (t == -1) c = -1; else c = <byte>;` emits
|
||||
* `bne v1,v0, <else>` with the `c = -1` arm as the fall-through and comes out
|
||||
* 4 bytes SHORT (220 vs 224) with the index computation no longer in the delay
|
||||
* slot. This lever is now 4-for-4 across claims 14, 19, 22 and the claim-20
|
||||
* family; treat "residual starts at a two-arm branch" as "try flipping the
|
||||
* condition" FIRST.
|
||||
* 2. The 76-byte stride appears TWICE, both strength-reduced as
|
||||
* `((idx*5)*4 - idx)*4` — the same shape as claim 16, so both are
|
||||
* `idx * 76` with a variable index.
|
||||
* 3. `0x80121C00` and `0x80121BFC` are both LOADED ABSOLUTELY (`lui`+`lw`), so both
|
||||
* use the literal-address spelling. `D_80121BFC` IS registry gp-marked (the same
|
||||
* trap as claim 16, where it is also read absolutely), and `D_80121C00` is the
|
||||
* pointer table already indexed by claims 6, 18, 20 and 22.
|
||||
* 4. THE CALL SITE IS WIDER THAN THE CALLEE'S OWN PROTOTYPE. `0x800AE4DC` is
|
||||
* registered as taking ONE argument, but this call sets a1 as well, so the
|
||||
* caller-side declaration here takes two. A call site that materialises an
|
||||
* argument the callee's body never reads is still real code and must be
|
||||
* declared (same shape as the claim-4/claim-10 "call leaves a0 holding the
|
||||
* parameter" cases, in reverse).
|
||||
*
|
||||
* LIMITS: the table's element type, the flag bit 5, the +72/+42 fields, the value
|
||||
* 73 and the three callees' semantics are hypotheses read from the instruction
|
||||
* shapes. `func_800AE4DC` is my own claim 8 (matched this cycle) — the row was
|
||||
* matched from its disassembly, not from that source, and the two agree. Only the
|
||||
* compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
extern int func_800AE548(int a0);
|
||||
extern void func_800AE4DC(char *p, int a1);
|
||||
extern void func_800ADDE8(int a0, int a1);
|
||||
|
||||
void func_800AE6C0(int a0, int a1, int a2)
|
||||
{
|
||||
int s0 = *(int *)(*(int *)0x80121C00 + a1 * 4);
|
||||
int base;
|
||||
int t;
|
||||
int c;
|
||||
|
||||
if (*(unsigned char *)s0 & 0x20)
|
||||
return;
|
||||
base = *(int *)0x80121BFC;
|
||||
t = *(short *)(base + *(short *)(s0 + 2) * 76 + 72);
|
||||
if (t != -1)
|
||||
c = *(unsigned char *)(base + t * 76 + 42);
|
||||
else
|
||||
c = -1;
|
||||
if (c != 73)
|
||||
func_800AE548(s0);
|
||||
func_800AE4DC((char *)s0, a2);
|
||||
func_800ADDE8(a0, s0);
|
||||
}
|
||||
Reference in New Issue
Block a user