diff --git a/config/regions.tsv b/config/regions.tsv index 6fb8dfa..2e6cca8 100644 --- a/config/regions.tsv +++ b/config/regions.tsv @@ -152,13 +152,16 @@ 0x80052C98 0x80052CAC src/func_80052C98.c 0x80057524 0x80057564 src/func_80057524.c 0x80057748 0x80057798 src/func_80057748.c +0x80057798 0x800577E8 src/func_80057798.c 0x8005784C 0x8005789C src/func_8005784C.c 0x8005789C 0x800578EC src/func_8005789C.c 0x800579A0 0x800579F0 src/func_800579A0.c 0x800579F0 0x80057A40 src/func_800579F0.c 0x80057AE0 0x80057B30 src/func_80057AE0.c 0x80057B84 0x80057BE8 src/func_80057B84.c +0x80057BE8 0x80057C30 src/func_80057BE8.c 0x80057C30 0x80057C80 src/func_80057C30.c +0x80057C80 0x80057CD0 src/func_80057C80.c 0x80057DFC 0x80057E04 src/func_80057DFC.c 0x80058230 0x80058288 src/func_80058230.c 0x80058288 0x800582AC src/func_80058288.c diff --git a/src/func_80057798.c b/src/func_80057798.c new file mode 100644 index 0000000..682894a --- /dev/null +++ b/src/func_80057798.c @@ -0,0 +1,53 @@ +/* func_80057798 — 0x80057798..0x800577E8 (80 bytes). + * + * Fifth member of the 0x80057xxx argument-block family, identical in shape to the already + * matched `0x80057748` with the selector 6. + * + * Original words: + * 27BDFFD0 addiu sp,sp,-48 + * 30A700FF andi a3,a1,0xff + * 30C600FF andi a2,a2,0xff + * AFA70020 sw a3,32(sp) outgoing arg 9 = narrowed a1 + * 0007382B sltu a3,zero,a3 + * 00073823 negu a3,a3 + * 24050006 li a1,6 the selector + * AFA60024 sw a2,36(sp) outgoing arg 10 = narrowed a2 + * 2406FFFF li a2,-1 + * 00873824 and a3,a0,a3 + * AFBF0028 sw ra,40(sp) + * AFA00010 sw zero,16(sp) outgoing arg 5 = 0 + * AFA00014 sw zero,20(sp) outgoing arg 6 = 0 + * AFA00018 sw zero,24(sp) outgoing arg 7 = 0 + * 0C015D99 jal 0x80057664 + * AFA0001C _sw zero,28(sp) (delay slot) outgoing arg 8 = 0 + * 8FBF0028 lw ra,40(sp) + * 27BD0030 addiu sp,sp,48 + * 03E00008 jr ra + * 00000000 nop + * + * The frame is 48 bytes and the six words at 16–36(sp) are the **outgoing argument area**, so + * the callee takes ten arguments: four in registers, six on the stack. The two narrowed values + * land at 32 and 36(sp) — args 9 and 10 — which is the trap that cost an attempt earlier in this + * family and is now only a matter of reading the frame arithmetic. + * + * The conditional is **branchless**, which is this family's discriminator: `sltu` then `negu` + * builds a 0-or-−1 mask so `narrowed1 ? a0 : 0` costs no branch. Per the family's rule that means + * exactly **one** distinct value is being selected here (as against `0x80057B84`, which selects + * two and therefore needs a real `beqz`/`j`). + * + * LIMITS: the selector 6, the mask 0xff and the frame layout are read from the bytes. What the + * selector selects is not observable from this body; the evidence that it *is* a selector comes + * from the byte-identical siblings that differ only in this constant. The callee is named for its + * address. + */ + +void func_80057664(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, + int a8, int a9); + +void func_80057798(int a0, int a1, int a2) +{ + int narrowed1 = a1 & 0xff; + int narrowed2 = a2 & 0xff; + + func_80057664(a0, 6, -1, narrowed1 ? a0 : 0, 0, 0, 0, 0, narrowed1, narrowed2); +} diff --git a/src/func_80057BE8.c b/src/func_80057BE8.c new file mode 100644 index 0000000..7e16fcc --- /dev/null +++ b/src/func_80057BE8.c @@ -0,0 +1,52 @@ +/* func_80057BE8 — 0x80057BE8..0x80057C30 (72 bytes). + * + * Seventh member of the 0x80057xxx argument-block family, and the one whose argument **positions** + * differ rather than just the selector. + * + * Original words: + * 27BDFFD0 addiu sp,sp,-48 + * 93A20040 lbu v0,64(sp) the FIFTH incoming parameter + * 30A500FF andi a1,a1,0xff + * AFA50020 sw a1,32(sp) outgoing arg 9 = narrowed a1 + * 2405000F li a1,15 the selector + * AFA60018 sw a2,24(sp) outgoing arg 7 = a2 + * 2406FFFF li a2,-1 + * AFA7001C sw a3,28(sp) outgoing arg 8 = a3 + * 00003821 move a3,zero outgoing arg 4 = 0 + * AFBF0028 sw ra,40(sp) + * AFA00010 sw zero,16(sp) outgoing arg 5 = 0 + * AFA00014 sw zero,20(sp) outgoing arg 6 = 0 + * 0C015D99 jal 0x80057664 + * AFA20024 _sw v0,36(sp) (delay slot) outgoing arg 10 = the fifth parameter + * 8FBF0028 lw ra,40(sp) + * 27BD0030 addiu sp,sp,48 + * 03E00008 jr ra + * 00000000 nop + * + * **THE REGISTER ARGUMENTS ARE THE ONES THAT MOVED, NOT JUST THE SELECTOR.** In the other members + * outgoing args 4–8 are either a masked `a0` or zeros; here arg 4 is a plain **zero** (a + * `move a3,zero`, not the branchless mask), args 5 and 6 are zero, and args 7 and 8 carry the + * routine's **`a2` and `a3`** — so this row forwards its third and fourth parameters into the + * callee's seventh and eighth slots, which no other member does. + * + * Note also that there is **no `negu`** here: the mask machinery is absent because nothing is being + * conditionally selected — the only non-constant value placed in a register argument is zero. So + * the family's branchless-mask discriminator predicts this row's shape correctly: no conditional + * selection means no mask. + * + * The narrowed `a1` still goes to arg 9 and the fifth incoming parameter to arg 10, so those two + * positions are stable across the family while the register arguments are not — which is the + * reason each member's argument map has to be read rather than assumed. + * + * LIMITS: the selector 15, the mask 0xff, the displacements and the frame layout are read from the + * bytes. The fifth parameter is `unsigned char` by the single `lbu`. The callee is named for its + * address and nothing establishes what the selector means. + */ + +void func_80057664(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, + int a8, int a9); + +void func_80057BE8(int a0, int a1, int a2, int a3, unsigned char a4) +{ + func_80057664(a0, 15, -1, 0, 0, 0, a2, a3, a1 & 0xff, a4); +} diff --git a/src/func_80057C80.c b/src/func_80057C80.c new file mode 100644 index 0000000..61eec7b --- /dev/null +++ b/src/func_80057C80.c @@ -0,0 +1,52 @@ +/* func_80057C80 — 0x80057C80..0x80057CD0 (80 bytes). + * + * Sixth member of the 0x80057xxx argument-block family, identical in shape to the already + * matched `0x80057748` with the selector 17. + * + * Original words: + * 27BDFFD0 addiu sp,sp,-48 + * 30A700FF andi a3,a1,0xff + * 30C600FF andi a2,a2,0xff + * AFA70020 sw a3,32(sp) outgoing arg 9 = narrowed a1 + * 0007382B sltu a3,zero,a3 + * 00073823 negu a3,a3 + * 24050011 li a1,17 the selector + * AFA60024 sw a2,36(sp) outgoing arg 10 = narrowed a2 + * 2406FFFF li a2,-1 + * 00873824 and a3,a0,a3 + * AFBF0028 sw ra,40(sp) + * AFA00010 sw zero,16(sp) outgoing arg 5 = 0 + * AFA00014 sw zero,20(sp) outgoing arg 6 = 0 + * AFA00018 sw zero,24(sp) outgoing arg 7 = 0 + * 0C015D99 jal 0x80057664 + * AFA0001C _sw zero,28(sp) (delay slot) outgoing arg 8 = 0 + * 8FBF0028 lw ra,40(sp) + * 27BD0030 addiu sp,sp,48 + * 03E00008 jr ra + * 00000000 nop + * + * Byte-for-byte the same as `0x80057798` except `li a1,17` where that row has `li a1,6`. With the + * family now holding several such pairs — `0x8005789C`/`0x80057C30` differing only in 4 versus 16, + * and this row versus `0x80057798` differing only in 17 versus 6 — the selector reading is + * established well beyond a single observation: **the constant is the only thing that varies + * between structurally identical rows**, so it selects the callee's behaviour rather than carrying + * data. + * + * That is also why matching the family as a set is worth the effort: the argument map is derived + * once and each additional member costs only a constant change and a verification run. + * + * LIMITS: the selector 17, the mask 0xff and the frame layout are read from the bytes; what 17 + * selects is not observable. The branchless mask shows exactly one distinct value is being + * selected, per the family's discriminator. The callee is named for its address. + */ + +void func_80057664(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, + int a8, int a9); + +void func_80057C80(int a0, int a1, int a2) +{ + int narrowed1 = a1 & 0xff; + int narrowed2 = a2 & 0xff; + + func_80057664(a0, 17, -1, narrowed1 ? a0 : 0, 0, 0, 0, 0, narrowed1, narrowed2); +}