phase11: merge 29 + cookbook 105/119 — 548 bodies / 557 regions
Worker D's 0x80106AA8 (136 B, first attempt) -- found by the REDUNDANCY filter, not adjacency, which is the first row where the ranker did the finding alone. Eight stores through four global pointers, each re-materialised per store. Cookbook 105's dial now has THREE measured settings: per statement (0x8006BC74 46x and 0x80106AA8 8x, both matched), once per block (matched), once per function (does not match). So per-statement re-reads are the NORMAL shape, not an extreme. 119: worker D ran the fragment check, called 0x80058BA0 a confirmed fragment, then SELF-CORRECTED -- it is legal, because in o32 a frameless leaf may both read and write the caller's outgoing argument area (sp+0..sp+31). All three of D's suspects are legal. Worker B found the read side, worker D the write side, and both had to read the row to do it: a heuristic keyed on shape must state its exclusions, and only the worker reading the row can find them.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* func_800689DC — 136 bytes at 0x800689DC..0x80068A64
|
||||
*
|
||||
* Hypothesis, not a claim about meaning: copies four 4-int vectors from one area of the
|
||||
* object to another, then returns 1. A leaf with no frame, no calls, no branches and no
|
||||
* arithmetic — four struct assignments, which is why it matched on the FIRST spelling.
|
||||
*
|
||||
* Original words (int-index form; byte offsets are 4x):
|
||||
* 8C820040 lw v0,64(a0) ; *(V4 *)(a0 + 0) = *(V4 *)(a0 + 16)
|
||||
* 8C830044 lw v1,68(a0)
|
||||
* 8C850048 lw a1,72(a0)
|
||||
* 8C86004C lw a2,76(a0)
|
||||
* AC820000 sw v0,0(a0)
|
||||
* AC830004 sw v1,4(a0)
|
||||
* AC850008 sw a1,8(a0)
|
||||
* AC86000C sw a2,12(a0)
|
||||
* 8C820050 lw v0,80(a0) ; *(V4 *)(a0 + 4) = *(V4 *)(a0 + 20)
|
||||
* ... AC86001C sw a2,28(a0)
|
||||
* 8C820060 lw v0,96(a0) ; *(V4 *)(a0 + 8) = *(V4 *)(a0 + 24)
|
||||
* ... AC86002C sw a2,44(a0)
|
||||
* 8C820070 lw v0,112(a0) ; *(V4 *)(a0 + 12) = *(V4 *)(a0 + 28)
|
||||
* ... AC86003C sw a2,60(a0)
|
||||
* 03E00008 jr ra
|
||||
* 24020001 li v0,1 ; return 1, in the delay slot
|
||||
*
|
||||
* BYTE-REQUIRED SHAPES:
|
||||
*
|
||||
* 1. **Each copy is a STRUCT ASSIGNMENT** (`*(struct V4 *)(a0 + 0) = *(struct V4 *)(a0 + 16);`)
|
||||
* — four loads then four stores. Ninth independent confirmation of this lever; four
|
||||
* element stores interleave load/store and change the bytes.
|
||||
* 2. **The four 4-int vectors are 16 bytes apart** (int offsets 0/16, 4/20, 8/24, 12/28) —
|
||||
* the project's 4-int vector layout again, so the object's first 64 bytes are sixteen
|
||||
* ints in four vector-shaped groups.
|
||||
* 3. **The `return 1` lands in the `jr ra` delay slot** and there is NO frame at all — no
|
||||
* `addiu sp,sp,-N` and no saved registers, because the function is a leaf with no
|
||||
* locals. Writing the copy through an index variable introduces a frame.
|
||||
*
|
||||
* LIMITS: the function name, the object layout and the whole "copy four vectors" reading are
|
||||
* hypotheses taken from the instruction shape; only the bytes are evidence. The `V4` struct
|
||||
* exists purely to obtain the 4-word block moves; its real layout is unknown. No callee:
|
||||
* this is a leaf and the harness emitted the common epilogue itself.
|
||||
*/
|
||||
|
||||
struct V4 { int v[4]; };
|
||||
|
||||
int func_800689DC(int *a0)
|
||||
{
|
||||
*(struct V4 *)(a0 + 0) = *(struct V4 *)(a0 + 16);
|
||||
*(struct V4 *)(a0 + 4) = *(struct V4 *)(a0 + 20);
|
||||
*(struct V4 *)(a0 + 8) = *(struct V4 *)(a0 + 24);
|
||||
*(struct V4 *)(a0 + 12) = *(struct V4 *)(a0 + 28);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* func_8009F4B4 — 248 bytes at 0x8009F4B4..0x8009F5AC
|
||||
*
|
||||
* Transposes a 3x3 short matrix through a 16-byte-stride int local, negates two
|
||||
* of the local's rows, and transposes it back.
|
||||
*
|
||||
* The observed instructions read m in the order 0,3,6,1,4,7,2,5,8 and write it
|
||||
* back in the same order, while the local's three groups sit 16 bytes apart at
|
||||
* sp+0, sp+16 and sp+32. A 16-byte stride with the values stored as full words
|
||||
* means the local is `int t[3][4]`; its fourth column is never read.
|
||||
*
|
||||
* Rows 0 and 2 of the local are negated (m[0],m[3],m[6] and m[2],m[5],m[8]);
|
||||
* row 1 (m[1],m[4],m[7]) is left alone. The negation is a separate
|
||||
* read-modify-write, so each of those six slots is stored twice, and cc1 does
|
||||
* not eliminate the first store.
|
||||
*/
|
||||
|
||||
void func_8009F4B4(short *m)
|
||||
{
|
||||
int t[3][4];
|
||||
|
||||
t[0][0] = m[0];
|
||||
t[0][1] = m[3];
|
||||
t[0][2] = m[6];
|
||||
t[1][0] = m[1];
|
||||
t[1][1] = m[4];
|
||||
t[1][2] = m[7];
|
||||
t[2][0] = m[2];
|
||||
t[2][1] = m[5];
|
||||
t[2][2] = m[8];
|
||||
t[0][0] = -t[0][0];
|
||||
t[0][1] = -t[0][1];
|
||||
t[0][2] = -t[0][2];
|
||||
t[2][0] = -t[2][0];
|
||||
t[2][1] = -t[2][1];
|
||||
t[2][2] = -t[2][2];
|
||||
m[0] = t[0][0];
|
||||
m[3] = t[0][1];
|
||||
m[6] = t[0][2];
|
||||
m[1] = t[1][0];
|
||||
m[4] = t[1][1];
|
||||
m[7] = t[1][2];
|
||||
m[2] = t[2][0];
|
||||
m[5] = t[2][1];
|
||||
m[8] = t[2][2];
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* func_80106AA8 — 136 bytes at 0x80106AA8..0x80106B30
|
||||
*
|
||||
* Goal B, Phase 11. **First attempt.** Found by the REDUNDANCY filter (cookbook 109): 136 bytes,
|
||||
* **zero branches**, and the same five-instruction shape repeated eight times. Not adjacent to any
|
||||
* of this worker's matches — the ranker's redundancy score is what surfaced it.
|
||||
*
|
||||
* A 4-byte command/parameter burst: eight stores through four global POINTERS, each pointer
|
||||
* re-loaded immediately before its store.
|
||||
*
|
||||
* *D_80120154 = 2;
|
||||
* *D_8012015C = a0[0]; *D_80120160 = a0[1];
|
||||
* *D_80120154 = 3;
|
||||
* *D_80120158 = a0[2]; *D_8012015C = a0[3];
|
||||
* *D_80120160 = 32;
|
||||
* return 0;
|
||||
*
|
||||
* The observed instructions are (34 words, no branches, no frame, no callee-saved register):
|
||||
* lui v1,0x8012 / lw v1,0x154(v1) / li v0,2 / sb v0,0(v1)
|
||||
* lui v1,0x8012 / lw v1,0x15c(v1) / lbu v0,0(a0) / nop / sb v0,0(v1)
|
||||
* lui v1,0x8012 / lw v1,0x160(v1) / lbu v0,1(a0) / nop / sb v0,0(v1)
|
||||
* lui v1,0x8012 / lw v1,0x154(v1) / li v0,3 / sb v0,0(v1)
|
||||
* lui v1,0x8012 / lw v1,0x158(v1) / lbu v0,2(a0) / nop / sb v0,0(v1)
|
||||
* lui v1,0x8012 / lw v1,0x15c(v1) / lbu v0,3(a0) / nop / sb v0,0(v1)
|
||||
* lui v1,0x8012 / lw v1,0x160(v1) / li v0,32 / sb v0,0(v1)
|
||||
* jr ra / move v0,zero
|
||||
*
|
||||
* THE RE-READ GRANULARITY IS THE **PER-STATEMENT** SETTING (cookbook 105). Every one of the eight
|
||||
* stores re-materialises its pointer from the global with its own `lui`/`lw` pair, and the load of
|
||||
* `a0` is repeated for each byte. That is the same dial measured at the opposite end from the 700 B
|
||||
* row's *once per statement* — here the dial's "per statement re-read" setting is exactly right, on a
|
||||
* row with no local pointer at all. Together with 0x8006BC74 (per statement, 46 times) and
|
||||
* 0x800320D8 (once per block), the dial now has three measured settings.
|
||||
*
|
||||
* The 0x154/0x158/0x15c/0x160 offsets are a 4-pointer table at 0x80120154 with 0x80120158 and
|
||||
* 0x8012015C both used twice and 0x80120154/0x80120160 used twice each — the write order is
|
||||
* 0x154, 0x15c, 0x160, 0x154, 0x158, 0x15c, 0x160, i.e. NOT monotonic, and the source order must be
|
||||
* reproduced exactly.
|
||||
*
|
||||
* LIMITS: the function name and the meaning of the four pointers and of the constants 2/3/32 are
|
||||
* hypotheses reconstructed from the disassembly; only the compiled bytes are evidence. The pointers
|
||||
* are declared `unsigned char *` because the stores are `sb` and the sources `lbu`; the registry only
|
||||
* supplies the ADDRESS, so the pointer-ness comes from these declarations. No symbol rows required —
|
||||
* the `D_XXXXXXXX` names resolve implicitly.
|
||||
*/
|
||||
|
||||
extern unsigned char *D_80120154;
|
||||
extern unsigned char *D_80120158;
|
||||
extern unsigned char *D_8012015C;
|
||||
extern unsigned char *D_80120160;
|
||||
|
||||
int func_80106AA8(unsigned char *a0)
|
||||
{
|
||||
*D_80120154 = 2;
|
||||
*D_8012015C = a0[0];
|
||||
*D_80120160 = a0[1];
|
||||
*D_80120154 = 3;
|
||||
*D_80120158 = a0[2];
|
||||
*D_8012015C = a0[3];
|
||||
*D_80120160 = 32;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user