phase8: merge cycle 3 — g0007 and g0030 closed, 137 regions / 128 bodies
22 claims accepted (worker A's 8 new + 9 gp rows, worker C's 6 pure-C rows), 28 skipped as already registered, 0 rejected. Candidate gate c_regions=137, 0 differing bytes, SHA-1 e173426c; promoted, then make check green (200 tests, regions=137 disagreements=0). Worker C closed two duplicate groups that other sessions had left as near-matches: - g0007 (0x800F7FB4 x3 addresses): the unexplained 8-byte frame was cc1 loop restructuring, not a calling-convention need. `for (i = n-1; i != -1; i--) *p++ = 0;` makes cc1 emit an unused subu/addu sp pair; an explicit guard plus a do/while gives the exact 36 bytes. - g0030 (0x8009E8D0 x2 addresses): the abs-of-3-component-difference function that workers A and B both recorded as near-matches. The two BIOS stubs are still policy-gated (they need an inline-asm statement) and are not in this merge. Distinct matched bodies: 128.
This commit is contained in:
@@ -11,11 +11,13 @@
|
||||
#
|
||||
# Matched so far:
|
||||
0x80012780 0x8001278C src/func_80012780.c
|
||||
0x800127F0 0x8001281C src/func_800127F0.c
|
||||
0x8001281C 0x80012834 src/func_8001281C.c
|
||||
0x80013C88 0x80013C90 src/func_80013C88.c
|
||||
0x80016110 0x80016120 src/func_80016110.c
|
||||
0x80016158 0x80016174 src/func_80016158.c
|
||||
0x80016E50 0x80016E68 src/func_80016E50.c
|
||||
0x800171D8 0x80017200 src/func_800171D8.c
|
||||
0x800179B8 0x800179CC src/func_800179B8.c
|
||||
0x800179CC 0x800179D4 src/func_800179CC.c
|
||||
0x800179D4 0x800179E0 src/func_800179D4.c
|
||||
@@ -23,9 +25,11 @@
|
||||
0x80017AE8 0x80017AF8 src/func_80017AE8.c
|
||||
0x80017C50 0x80017C60 src/func_80017C50.c
|
||||
0x80017C60 0x80017C6C src/func_80017C60.c
|
||||
0x80017D1C 0x80017D48 src/func_80017D1C.c
|
||||
0x80017DD0 0x80017DF0 src/func_80017DD0.c
|
||||
0x80019C04 0x80019C10 src/func_80019C04.c
|
||||
0x8001AA9C 0x8001AAA8 src/func_8001AA9C.c
|
||||
0x8001CE40 0x8001CE70 src/func_8001CE40.c
|
||||
0x80021F50 0x80021F64 src/func_80021F50.c
|
||||
0x80021F88 0x80021FA8 src/func_80021F88.c
|
||||
0x80022FB8 0x80022FCC src/func_80022FB8.c
|
||||
@@ -50,13 +54,16 @@
|
||||
0x80036378 0x80036380 src/func_80036378.c
|
||||
0x80038788 0x80038790 src/func_80038788.c
|
||||
0x80038790 0x8003879C src/func_80038790.c
|
||||
0x8003B2F0 0x8003B320 src/func_8003B2F0.c
|
||||
0x80042088 0x80042090 src/func_80042088.c
|
||||
0x80042D64 0x80042D88 src/func_80042D64.c
|
||||
0x8004C090 0x8004C0AC src/func_8004C090.c
|
||||
0x8004C0F0 0x8004C110 src/func_8004C0F0.c
|
||||
0x80057DFC 0x80057E04 src/func_80057DFC.c
|
||||
0x80058288 0x800582AC src/func_80058288.c
|
||||
0x80065B6C 0x80065B8C src/func_80065B6C.c
|
||||
0x80068470 0x8006848C src/func_80068470.c
|
||||
0x80068F40 0x80068F6C src/func_80068F40.c
|
||||
0x80068F98 0x80068FA8 src/func_80068F98.c
|
||||
0x800697A4 0x800697C4 src/func_800697A4.c
|
||||
0x8006EC94 0x8006ECD4 src/func_8006EC94.c
|
||||
@@ -65,7 +72,11 @@
|
||||
0x8006FA78 0x8006FAA0 src/func_8006FA78.c
|
||||
0x8007049C 0x800704BC src/func_8007049C.c
|
||||
0x8007DC40 0x8007DC4C src/func_8007DC40.c
|
||||
0x80082914 0x80082944 src/func_80082914.c
|
||||
0x80083504 0x8008352C src/func_80083504.c
|
||||
0x8008352C 0x8008355C src/func_8008352C.c
|
||||
0x80085B80 0x80085B90 src/func_80085B80.c
|
||||
0x80089314 0x80089338 src/func_80089314.c
|
||||
0x80089C4C 0x80089C54 src/func_80042088.c
|
||||
0x80089C54 0x80089C64 src/func_80089C54.c
|
||||
0x80089C64 0x80089C74 src/func_80089C64.c
|
||||
@@ -79,8 +90,12 @@
|
||||
0x800912D4 0x800912FC src/func_800912D4.c
|
||||
0x800912FC 0x8009132C src/func_800912FC.c
|
||||
0x800920BC 0x800920DC src/func_800920BC.c
|
||||
0x800920DC 0x80092104 src/func_800920DC.c
|
||||
0x800943C4 0x800943E0 src/func_800943C4.c
|
||||
0x8009E8D0 0x8009E95C src/func_8009E8D0.c
|
||||
0x800A45E0 0x800A466C src/func_8009E8D0.c
|
||||
0x800A74BC 0x800A74D0 src/func_800A74BC.c
|
||||
0x800AA56C 0x800AA59C src/func_800AA56C.c
|
||||
0x800ACC00 0x800ACC20 src/func_800ACC00.c
|
||||
0x800AE0F4 0x800AE10C src/func_800AE0F4.c
|
||||
0x800AF1FC 0x800AF20C src/func_800AF1FC.c
|
||||
@@ -88,7 +103,9 @@
|
||||
0x800B6BDC 0x800B6C14 src/func_800B6BDC.c
|
||||
0x800BBDEC 0x800BBDF8 src/func_800BBDEC.c
|
||||
0x800F3160 0x800F316C src/func_800F3160.c maspsx=off
|
||||
0x800F5B40 0x800F5B70 src/func_800F5B40.c
|
||||
0x800F7A84 0x800F7A94 src/func_800F7A84.c
|
||||
0x800F7FB4 0x800F7FD8 src/func_800F7FB4.c
|
||||
0x800F8294 0x800F82A4 src/func_800F8294.c
|
||||
0x800F8ACC 0x800F8ADC src/func_800F8ACC.c
|
||||
0x800F8ADC 0x800F8AEC src/func_800F8ADC.c
|
||||
@@ -99,6 +116,7 @@
|
||||
0x800F8FE4 0x800F8FF8 src/func_800F8FE4.c maspsx=off
|
||||
0x800F8FF8 0x800F9008 src/func_800F8FF8.c
|
||||
0x800FB13C 0x800FB1BC src/func_800FB13C.c
|
||||
0x800FB5D4 0x800FB5DC src/func_800FB5D4.c
|
||||
0x800FB5E4 0x800FB5FC src/func_800FB5E4.c
|
||||
0x800FB6C4 0x800FB6D8 src/func_800FB6C4.c
|
||||
0x800FBDF8 0x800FBE04 src/func_800FBDF8.c
|
||||
@@ -111,6 +129,8 @@
|
||||
0x80100318 0x80100334 src/func_80100318.c
|
||||
0x80100964 0x8010097C src/func_80100964.c
|
||||
0x80102B10 0x80102B2C src/func_80102B10.c maspsx=off
|
||||
0x80103C7C 0x80103CA0 src/func_800F7FB4.c
|
||||
0x80103F84 0x80103FA8 src/func_800F7FB4.c
|
||||
0x8010513C 0x80105148 src/func_8010513C.c
|
||||
0x80105B34 0x80105B54 src/func_80105B34.c
|
||||
0x80105B54 0x80105B68 src/func_80105B54.c
|
||||
@@ -121,7 +141,9 @@
|
||||
0x80107E68 0x80107E74 src/func_80107E68.c
|
||||
0x80107E74 0x80107E84 src/func_80107E74.c
|
||||
0x80107E84 0x80107E90 src/func_80107E84.c
|
||||
0x80108710 0x80108734 src/func_80108710.c
|
||||
0x80109300 0x80109314 src/func_80109300.c
|
||||
0x80109314 0x80109338 src/func_800F8F9C.c
|
||||
0x80109F38 0x80109F48 src/func_80109F38.c
|
||||
0x8010A8B0 0x8010A8D8 src/func_8010A8B0.c
|
||||
0x8010AAA0 0x8010AABC src/func_8010AAA0.c
|
||||
|
||||
|
@@ -70,7 +70,14 @@ D_80121BF8 0x80121BF8 gp
|
||||
D_80121BF9 0x80121BF9 gp
|
||||
D_80121BFC 0x80121BFC gp
|
||||
D_80121D5C 0x80121D5C gp
|
||||
D_80121D5E 0x80121D5E gp
|
||||
D_80121D60 0x80121D60 gp
|
||||
D_80121D62 0x80121D62 gp
|
||||
D_80121D64 0x80121D64 gp
|
||||
D_80121D68 0x80121D68 gp
|
||||
D_80121D6A 0x80121D6A gp
|
||||
D_80121D6C 0x80121D6C gp
|
||||
D_80121D70 0x80121D70 gp
|
||||
D_80121DFC 0x80121DFC gp
|
||||
D_80121E04 0x80121E04 gp
|
||||
D_80121E10 0x80121E10 gp
|
||||
|
||||
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* func_800127F0 — 44 bytes at 0x800127F0..0x8001281C
|
||||
*
|
||||
* Byte-identical reconstruction of a test-and-set returning a status. `lhu`
|
||||
* fixes an unsigned 16-bit read at +6 (cookbook finding 7: plain `char` is
|
||||
* unsigned on this target, so `unsigned short` has to be stated to get `lhu`).
|
||||
* The `ori v0,v1,0x2` is computed in the branch delay slot (it is independent
|
||||
* of the branch), but the store only happens on the fall-through path, so the
|
||||
* branch direction is `if (bit set) return 0x1d;`. The `j` over the
|
||||
* `li v0,0x1d` carries `clear v0` (the `return 0`) in its delay slot
|
||||
* (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lhu v1,0x6(a0) v1 = *(unsigned short *)(base + 6)
|
||||
* nop (load delay)
|
||||
* andi v0,v1,0x2 v0 = v1 & 2
|
||||
* bne v0,zero,set if the bit is already set, go to the 0x1d return
|
||||
* ori v0,v1,0x2 (delay slot) v0 = v1 | 2
|
||||
* sh v0,0x6(a0) *(unsigned short *)(base + 6) = v1 | 2
|
||||
* j exit
|
||||
* clear v0 (delay slot) return 0
|
||||
* set:
|
||||
* li v0,0x1d return 0x1d
|
||||
* exit:
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* LIMITS: the offset, the width, the bit mask 2 and the constant 0x1d are
|
||||
* evidence; the base's real type, the flag's meaning and the reason for the two
|
||||
* distinct return values are hypotheses.
|
||||
*/
|
||||
|
||||
int func_800127F0(char *base) {
|
||||
unsigned short value = *(unsigned short *)(base + 6);
|
||||
if ((value & 2) != 0) {
|
||||
return 0x1d;
|
||||
}
|
||||
*(unsigned short *)(base + 6) = value | 2;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* func_800171D8 — 36 bytes at 0x800171D8..0x80017200
|
||||
*
|
||||
* Byte-identical reconstruction of a descending loop that clears the first word
|
||||
* of every 56-byte (0x38) element, plus one `gp`-relative clear. The loop
|
||||
* counter is a signed BYTE OFFSET running from 0xce8 down to 0 in steps of
|
||||
* 0x38, tested with `bgez`; the base is added with `lui` + `addu` (not
|
||||
* `addiu`) because the base is a symbol combined with a runtime offset
|
||||
* (cookbook finding 5). The branch delay slot is `nop` (cookbook finding 8).
|
||||
* 0xce8 is 59 * 0x38, so the loop clears 60 elements.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* li v0,0xce8 v0 = 0xce8 (byte offset of the LAST element)
|
||||
* loop:
|
||||
* lui at,0x8012
|
||||
* addu at,at,v0 at = D_80124CC0 + offset
|
||||
* sw zero,0x4cc0(at) *(int *)(at) = 0
|
||||
* addiu v0,v0,-0x38 offset -= 0x38
|
||||
* bgez v0,loop while (offset >= 0)
|
||||
* nop
|
||||
* sw zero,0xa0(gp) D_801219D8 = 0
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* LIMITS: the stride 0x38, the start offset 0xce8, the element count and the
|
||||
* cleared width are evidence; the base's type, the symbol's name and meaning,
|
||||
* and whether the original source counted elements (`i >= 0` with `i * 56`)
|
||||
* rather than bytes are hypotheses.
|
||||
*/
|
||||
|
||||
extern char D_80124CC0[];
|
||||
extern int D_801219D8;
|
||||
|
||||
void func_800171D8(void) {
|
||||
int offset;
|
||||
for (offset = 0xce8; offset >= 0; offset -= 0x38) {
|
||||
*(int *)(D_80124CC0 + offset) = 0;
|
||||
}
|
||||
D_801219D8 = 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* func_80017D1C — 44 bytes at 0x80017D1C..0x80017D48
|
||||
*
|
||||
* Byte-identical reconstruction of a conditional bit set/clear on a halfword
|
||||
* field, with ONE shared store at the end. `andi a1,a1,0xff` is the type-driven
|
||||
* mask for an `unsigned char` parameter (cookbook finding 7). The halfword is
|
||||
* loaded in EACH arm rather than once before the branch — GCC 2.7's local CSE
|
||||
* does not merge a load across the branch — and the `ori`/`andi` sits in the
|
||||
* `j` delay slot of the taken arm (cookbook finding 8). `~4` becomes
|
||||
* `andi 0xfffb` because the value is a 16-bit unsigned.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* andi a1,a1,0xff flag &= 0xff
|
||||
* beq a1,zero,clear if (flag == 0) goto the clear arm
|
||||
* nop
|
||||
* lhu v0,0x6(a0) v0 = *(unsigned short *)(base + 6)
|
||||
* j store
|
||||
* ori v0,v0,0x4 (delay slot) v0 |= 4
|
||||
* clear:
|
||||
* lhu v0,0x6(a0) v0 = *(unsigned short *)(base + 6)
|
||||
* nop (load delay)
|
||||
* andi v0,v0,0xfffb v0 &= ~4
|
||||
* store:
|
||||
* jr ra
|
||||
* sh v0,0x6(a0) (delay slot) *(unsigned short *)(base + 6) = v0
|
||||
*
|
||||
* LIMITS: the offset, the width, the bit mask 4 and the branch direction are
|
||||
* evidence; the base's real type, the field's meaning and the flag's meaning are
|
||||
* hypotheses.
|
||||
*/
|
||||
|
||||
void func_80017D1C(char *base, unsigned char flag) {
|
||||
unsigned short value;
|
||||
if (flag != 0) {
|
||||
value = *(unsigned short *)(base + 6) | 4;
|
||||
} else {
|
||||
value = *(unsigned short *)(base + 6) & ~4;
|
||||
}
|
||||
*(unsigned short *)(base + 6) = value;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* func_8001CE40 — 48 bytes at 0x8001CE40..0x8001CE70
|
||||
*
|
||||
* Byte-identical reconstruction of a two-halfword packed-value expansion with a
|
||||
* zero special case. `sra` (not `srl`) fixes an ARITHMETIC shift of the high
|
||||
* half, and `srav` an arithmetic shift by the variable amount in `v1` — so the
|
||||
* shifted value is signed. The low half is masked with `andi …,0xffff`, the
|
||||
* shift count is `(value >> 16) - 1` and it is computed in the `beq` delay slot
|
||||
* (unconditionally, cookbook finding 8); the final add is in the `j` delay slot.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* andi a1,a0,0xffff a1 = value & 0xffff
|
||||
* sra v0,a0,0x10 v0 = value >> 16 (arithmetic)
|
||||
* beq a0,zero,zero_case if (value == 0) return 0x2000
|
||||
* addiu v1,v0,-0x1 (delay slot) v1 = (value >> 16) - 1
|
||||
* li v0,0x1000 v0 = 0x1000
|
||||
* subu v0,v0,a1 v0 = 0x1000 - low
|
||||
* srav v0,v0,v1 v0 >>= v1 (arithmetic)
|
||||
* j exit
|
||||
* addu v0,a1,v0 (delay slot) v0 = low + v0
|
||||
* zero_case:
|
||||
* li v0,0x2000 return 0x2000
|
||||
* exit:
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* LIMITS: the masks, the shifts, the constants 0x1000/0x2000 and the special
|
||||
* case for zero are evidence; the packed encoding's meaning is a hypothesis, as
|
||||
* is whether the original source used `int` or `unsigned` for the argument
|
||||
* (the `sra`/`srav` fix signedness of the shift, not of the parameter).
|
||||
*/
|
||||
|
||||
int func_8001CE40(int value) {
|
||||
int low = value & 0xffff;
|
||||
int shift = (value >> 16) - 1;
|
||||
if (value == 0) {
|
||||
return 0x2000;
|
||||
}
|
||||
return low + ((0x1000 - low) >> shift);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* func_8003B2F0 — 48 bytes at 0x8003B2F0..0x8003B320
|
||||
*
|
||||
* Byte-identical reconstruction of a nine-field reset using BOTH halfword and
|
||||
* word stores. `gp` is 0x80121938 (crt0 sets it at 0x800FB3E4), so the offsets
|
||||
* 0x424/0x426/0x428/0x42a/0x42c/0x430/0x432/0x434/0x438 name 0x80121D5C,
|
||||
* 0x80121D5E, 0x80121D60, 0x80121D62, 0x80121D64, 0x80121D68, 0x80121D6A,
|
||||
* 0x80121D6C and 0x80121D70; all nine need the registry's `gp` marker so the
|
||||
* accesses are emitted `%gp_rel` (cookbook finding 10). The constant -1 is
|
||||
* materialised once in `v0` and reused for both `sh` stores; no delay-slot fill
|
||||
* is available because every store source is `zero` or an already-loaded `v0`
|
||||
* (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* li v0,-0x1 v0 = -1 (scratch, reused)
|
||||
* sh v0,0x424(gp) D_80121D5C = -1
|
||||
* sh zero,0x426(gp) D_80121D5E = 0
|
||||
* sh zero,0x428(gp) D_80121D60 = 0
|
||||
* sh zero,0x42a(gp) D_80121D62 = 0
|
||||
* sw zero,0x42c(gp) D_80121D64 = 0
|
||||
* sh v0,0x430(gp) D_80121D68 = -1
|
||||
* sh zero,0x432(gp) D_80121D6A = 0
|
||||
* sh zero,0x434(gp) D_80121D6C = 0
|
||||
* sw zero,0x438(gp) D_80121D70 = 0
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* LIMITS: the nine offsets, the two widths and the values -1/0 are evidence;
|
||||
* the globals' names, types and meanings are hypotheses, and the fields are
|
||||
* declared separately because only the addresses are evidence.
|
||||
*/
|
||||
|
||||
extern short D_80121D5C;
|
||||
extern short D_80121D5E;
|
||||
extern short D_80121D60;
|
||||
extern short D_80121D62;
|
||||
extern int D_80121D64;
|
||||
extern short D_80121D68;
|
||||
extern short D_80121D6A;
|
||||
extern short D_80121D6C;
|
||||
extern int D_80121D70;
|
||||
|
||||
void func_8003B2F0(void) {
|
||||
D_80121D5C = -1;
|
||||
D_80121D5E = 0;
|
||||
D_80121D60 = 0;
|
||||
D_80121D62 = 0;
|
||||
D_80121D64 = 0;
|
||||
D_80121D68 = -1;
|
||||
D_80121D6A = 0;
|
||||
D_80121D6C = 0;
|
||||
D_80121D70 = 0;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* func_80058288 — 36 bytes at 0x80058288..0x800582AC
|
||||
*
|
||||
* Byte-identical reconstruction of a scaled array-index address, element size
|
||||
* 44 (0x2c). The multiply is strength-reduced rather than a real `mult`, so the
|
||||
* element size was a literal at expansion time (cookbook finding 12):
|
||||
* `sll 1` / `addu` / `sll 2` / `subu` / `sll 2` is `((i*2 + i)*4 - i)*4` =
|
||||
* `i * 44`. The base is a symbol address and so uses the `addiu` form
|
||||
* (cookbook findings 4 and 5), and the addition lands in the `jr` delay slot
|
||||
* (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* sll v0,a0,0x1
|
||||
* addu v0,v0,a0
|
||||
* sll v0,v0,0x2
|
||||
* subu v0,v0,a0
|
||||
* sll v0,v0,0x2 v0 = index * 44
|
||||
* lui v1,0x8013
|
||||
* addiu v1,v1,0x202c v1 = D_8013202C (symbol form)
|
||||
* jr ra
|
||||
* addu v0,v0,v1 (delay slot) v0 = base + index * 44
|
||||
*
|
||||
* LIMITS: the element size 44 and the base address are evidence; whether the
|
||||
* base is an array of 44-byte structs or a byte array is a hypothesis, as are
|
||||
* the symbol's name and meaning.
|
||||
*/
|
||||
|
||||
extern char D_8013202C[];
|
||||
|
||||
char *func_80058288(int index) {
|
||||
return D_8013202C + index * 44;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* func_80068F40 — 44 bytes at 0x80068F40..0x80068F6C
|
||||
*
|
||||
* Byte-identical reconstruction of ten word clears on one object. The offsets
|
||||
* are NOT contiguous: 0x13c is skipped (the sequence runs 0x124, 0x128, 0x12c,
|
||||
* 0x130, 0x134, 0x138, 0x140, 0x144, 0x148, 0x14c), so these are ten separate
|
||||
* fields rather than one array — that gap is evidence, not a transcription
|
||||
* error. `zero` needs no source register, so the last store is the only thing
|
||||
* that can fill the `jr` delay slot (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* sw zero,0x124(a0) *(int *)(object + 0x124) = 0
|
||||
* sw zero,0x128(a0) *(int *)(object + 0x128) = 0
|
||||
* sw zero,0x12c(a0) *(int *)(object + 0x12c) = 0
|
||||
* sw zero,0x130(a0) *(int *)(object + 0x130) = 0
|
||||
* sw zero,0x134(a0) *(int *)(object + 0x134) = 0
|
||||
* sw zero,0x138(a0) *(int *)(object + 0x138) = 0
|
||||
* sw zero,0x140(a0) *(int *)(object + 0x140) = 0
|
||||
* sw zero,0x144(a0) *(int *)(object + 0x144) = 0
|
||||
* sw zero,0x148(a0) *(int *)(object + 0x148) = 0
|
||||
* jr ra
|
||||
* sw zero,0x14c(a0) (delay slot) *(int *)(object + 0x14c) = 0
|
||||
*
|
||||
* LIMITS: the ten offsets and the 32-bit width are evidence; the object's real
|
||||
* type and the fields' meanings are hypotheses.
|
||||
*/
|
||||
|
||||
void func_80068F40(char *object) {
|
||||
*(int *)(object + 0x124) = 0;
|
||||
*(int *)(object + 0x128) = 0;
|
||||
*(int *)(object + 0x12c) = 0;
|
||||
*(int *)(object + 0x130) = 0;
|
||||
*(int *)(object + 0x134) = 0;
|
||||
*(int *)(object + 0x138) = 0;
|
||||
*(int *)(object + 0x140) = 0;
|
||||
*(int *)(object + 0x144) = 0;
|
||||
*(int *)(object + 0x148) = 0;
|
||||
*(int *)(object + 0x14c) = 0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* func_80082914 — 48 bytes at 0x80082914..0x80082944
|
||||
*
|
||||
* Byte-identical reconstruction of a three-bit field insert into a word field
|
||||
* of a 16-byte-stride element. The element index is scaled with a shift, so the
|
||||
* stride was a literal at expansion time (cookbook finding 12); the element
|
||||
* address is computed ONCE (`addu a0,a0,v0`) and used for both the load and the
|
||||
* store, which is GCC's CSE of the repeated address expression. The mask
|
||||
* 0xffffc7ff is `li v1,-0x3801` (a sign-extended 16-bit immediate, so one
|
||||
* instruction); `andi a1,a1,0x7` and `sll a1,a1,0xb` insert three bits at bit
|
||||
* 11. The store lands in the `jr` delay slot (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* sll a0,a0,0x4 index * 16
|
||||
* li v1,-0x3801 v1 = 0xffffc7ff
|
||||
* lui v0,0x8012
|
||||
* lw v0,0x2308(v0) v0 = D_80122308 (a pointer)
|
||||
* andi a1,a1,0x7 value &= 7
|
||||
* addu a0,a0,v0 element address
|
||||
* lw v0,0x0(a0) v0 = *(int *)element
|
||||
* sll a1,a1,0xb value <<= 11
|
||||
* and v0,v0,v1 v0 &= 0xffffc7ff
|
||||
* or v0,v0,a1 v0 |= value
|
||||
* jr ra
|
||||
* sw v0,0x0(a0) (delay slot) *(int *)element = v0
|
||||
*
|
||||
* LIMITS: the stride 16, the mask, the shift and the 32-bit width are evidence;
|
||||
* the global's name, type and meaning and the field's meaning are hypotheses.
|
||||
*/
|
||||
|
||||
extern char *D_80122308;
|
||||
|
||||
void func_80082914(int index, int value) {
|
||||
*(int *)(D_80122308 + index * 16) =
|
||||
(*(int *)(D_80122308 + index * 16) & 0xffffc7ff) | ((value & 7) << 11);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* func_80083504 — 40 bytes at 0x80083504..0x8008352C
|
||||
*
|
||||
* Byte-identical reconstruction of a read-modify-write that clears bit 15 of a
|
||||
* word field in a 16-byte-stride element. The element index is scaled with a
|
||||
* shift, not a real `mult`, so the stride was a literal at expansion time
|
||||
* (cookbook finding 12). The pointer global is loaded with the assembler macro
|
||||
* form expanding into the destination register (cookbook finding 2;
|
||||
* `addiu`-adjusted halves 0x8012 / 0x2308 = 0x80122308). The mask 0xffff7fff
|
||||
* needs two instructions (`lui` + `ori`) because it does not fit a signed
|
||||
* 16-bit immediate, and the store lands in the `jr` delay slot (cookbook
|
||||
* finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lui v1,0xffff
|
||||
* lui v0,0x8012
|
||||
* lw v0,0x2308(v0) v0 = D_80122308 (a pointer)
|
||||
* sll a0,a0,0x4 index * 16
|
||||
* addu a0,a0,v0 element address
|
||||
* lw v0,0x0(a0) v0 = *(int *)element
|
||||
* ori v1,v1,0x7fff v1 = 0xffff7fff
|
||||
* and v0,v0,v1 clear bit 15
|
||||
* jr ra
|
||||
* sw v0,0x0(a0) (delay slot) *(int *)element = v0
|
||||
*
|
||||
* The element address must be the DIRECT expression. Naming it
|
||||
* (`int *element = (int *)(D_80122308 + index * 16);`) changes the register
|
||||
* allocation: the address lands in `$3` and the mask in `$5` instead of the
|
||||
* address in `a0` and the mask in `v1`, which is 9 differing bytes at the same
|
||||
* instruction count and order. This is a register-allocation tie-break, and the
|
||||
* direct expression is the form that reproduces it.
|
||||
*
|
||||
* LIMITS: the stride 16, the mask and the 32-bit width are evidence; the
|
||||
* global's name, type and meaning and the bit's meaning are hypotheses.
|
||||
*/
|
||||
|
||||
extern char *D_80122308;
|
||||
|
||||
void func_80083504(int index) {
|
||||
*(int *)(D_80122308 + index * 16) &= 0xffff7fff;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* func_8008352C — 48 bytes at 0x8008352C..0x8008355C
|
||||
*
|
||||
* Byte-identical reconstruction of a conditional bit set on a word field of a
|
||||
* 16-byte-stride element. The stride is a literal shift (cookbook finding 12),
|
||||
* and the element address is computed once and used for both the load and the
|
||||
* store. `andi v0,v1,0x7ff` tests the low 11 bits, and the set is
|
||||
* `ori v0,v1,0x8000` computed in the branch DELAY SLOT (independent of the
|
||||
* branch, cookbook finding 8) — the store only happens on the fall-through
|
||||
* path. The branch delay slot of the exit is `nop`.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lui v0,0x8012
|
||||
* lw v0,0x2308(v0) v0 = D_80122308 (a pointer)
|
||||
* sll a0,a0,0x4 index * 16
|
||||
* addu a0,v0,a0 element address
|
||||
* lw v1,0x0(a0) v1 = *(int *)element
|
||||
* nop (load delay)
|
||||
* andi v0,v1,0x7ff v0 = v1 & 0x7ff
|
||||
* beq v0,zero,exit if the low bits are clear, do nothing
|
||||
* ori v0,v1,0x8000 (delay slot) v0 = v1 | 0x8000
|
||||
* sw v0,0x0(a0) *(int *)element = v0
|
||||
* exit:
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* The element address MUST be a named pointer here, for the opposite reason to
|
||||
* func_80083504: the original encodes `addu a0,v0,a0` (base first, then the
|
||||
* scaled index), and naming the pointer is what makes the compiler emit that
|
||||
* operand order. The direct expression form emits `addu a0,a0,v0` and differs by
|
||||
* exactly 1 byte. The two functions are the two halves of this commutative
|
||||
* tie-break, and each needs the opposite spelling.
|
||||
*
|
||||
* LIMITS: the stride 16, the test mask 0x7ff, the set bit 0x8000 and the
|
||||
* 32-bit width are evidence; the global's name, type and meaning and the
|
||||
* field's meaning are hypotheses.
|
||||
*/
|
||||
|
||||
extern char *D_80122308;
|
||||
|
||||
void func_8008352C(int index) {
|
||||
int *element = (int *)(D_80122308 + index * 16);
|
||||
if ((*element & 0x7ff) != 0) {
|
||||
*element |= 0x8000;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* func_80089314 — 36 bytes at 0x80089314..0x80089338
|
||||
*
|
||||
* Byte-identical reconstruction of a read-modify-write plus two word clears.
|
||||
* The `lw`/`ori`/`sw` triple fixes a bitwise-OR of a constant into a field at
|
||||
* +0xc of the object reached through the pointer field at +0x1c. The two
|
||||
* clears are 32-bit (`sw zero`), and the last one is scheduled into the `jr`
|
||||
* delay slot (cookbook finding 8), which fixes the statement order.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lw v1,0x1c(a0) v1 = *(char **)(a0 + 0x1c)
|
||||
* nop (load delay)
|
||||
* lw v0,0xc(v1) v0 = *(int *)(v1 + 0xc)
|
||||
* nop (load delay)
|
||||
* ori v0,v0,0xf00 v0 |= 0xf00
|
||||
* sw v0,0xc(v1) *(int *)(v1 + 0xc) = v0
|
||||
* sw zero,0x14(a0) *(int *)(a0 + 0x14) = 0
|
||||
* jr ra
|
||||
* sw zero,0xc(a0) (delay slot) *(int *)(a0 + 0xc) = 0
|
||||
*
|
||||
* LIMITS: the offsets, widths and the mask 0xf00 are evidence; the base's real
|
||||
* type and the fields' meanings are hypotheses.
|
||||
*/
|
||||
|
||||
void func_80089314(char *object) {
|
||||
char *inner = *(char **)(object + 0x1c);
|
||||
*(int *)(inner + 0xc) |= 0xf00;
|
||||
*(int *)(object + 0x14) = 0;
|
||||
*(int *)(object + 0xc) = 0;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* func_800920DC — 40 bytes at 0x800920DC..0x80092104
|
||||
*
|
||||
* Byte-identical reconstruction of a single-bit field update. `andi a1,a1,0x1`
|
||||
* is an explicit `& 1` in the source (a type-driven mask would be 0xff, per
|
||||
* cookbook finding 7), `sll a1,a1,0x1` shifts it into bit 1, `li v1,-0x3`
|
||||
* gives 0xfffffffd for the clear (`~2` needs two instructions because the
|
||||
* constant does not fit a signed 16-bit immediate), and the store lands in the
|
||||
* `jr` delay slot (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lw v0,0xc(a0) v0 = *(char **)(a0 + 0xc)
|
||||
* li v1,-0x3 v1 = 0xfffffffd
|
||||
* lw a0,0x160(v0) a0 = *(char **)(v0 + 0x160)
|
||||
* andi a1,a1,0x1 flag &= 1
|
||||
* lw v0,0x4(a0) v0 = *(int *)(a0 + 4)
|
||||
* sll a1,a1,0x1 flag <<= 1
|
||||
* and v0,v0,v1 v0 &= ~2
|
||||
* or v0,v0,a1 v0 |= flag
|
||||
* jr ra
|
||||
* sw v0,0x4(a0) (delay slot) *(int *)(a0 + 4) = v0
|
||||
*
|
||||
* LIMITS: the offsets, the widths, the mask and the shift are evidence; the
|
||||
* bases' real types, the fields' meanings and the flag's type are hypotheses.
|
||||
*/
|
||||
|
||||
void func_800920DC(char *object, int flag) {
|
||||
char *inner = *(char **)(*(char **)(object + 0xc) + 0x160);
|
||||
*(int *)(inner + 4) = (*(int *)(inner + 4) & ~2) | ((flag & 1) << 1);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/* func_8009E8D0 - 0x8009E8D0..0x8009E95C (140 bytes); duplicate body, also at
|
||||
* 0x800A45E0 (census group g0030).
|
||||
*
|
||||
* Shape: absolute difference of three components, then two swap steps that move
|
||||
* the largest difference into d0, then `d0 + ((d1 + d2) >> 2)`.
|
||||
*
|
||||
* Two codegen details decide the bytes, and both are recorded because the first
|
||||
* natural reconstruction missed them (same instruction count, 21 differing
|
||||
* words, all in registers):
|
||||
*
|
||||
* 1. The absolute value must come from a folded negation of the difference,
|
||||
* i.e. `-(x) < 0 ? ... : ...` on the expression `p[i] - q[i]`, NOT
|
||||
* `if (d < 0) d = -d;`. The latter makes cc1 emit `subu d,$0,d` (negu);
|
||||
* the original recomputes the subtraction from the operands
|
||||
* (`subu v1,v0,a2`, i.e. q[0]-p[0]), which is what folding `-(p[0]-q[0])`
|
||||
* produces. The ABS(x) macro below is the idiomatic spelling of that.
|
||||
* 2. The three differences must be separate scalars. An `int d[3]` array makes
|
||||
* cc1 keep the array in memory (16-byte frame, 180 bytes) even though only
|
||||
* constant indices are used.
|
||||
*/
|
||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
int func_8009E8D0(int *p, int *q)
|
||||
{
|
||||
int d0, d1, d2, t;
|
||||
|
||||
d0 = ABS(p[0] - q[0]);
|
||||
d1 = ABS(p[1] - q[1]);
|
||||
d2 = ABS(p[2] - q[2]);
|
||||
|
||||
if (d0 < d1) {
|
||||
t = d0;
|
||||
d0 = d1;
|
||||
d1 = t;
|
||||
}
|
||||
if (d0 < d2) {
|
||||
t = d0;
|
||||
d0 = d2;
|
||||
d2 = t;
|
||||
}
|
||||
return d0 + ((d1 + d2) >> 2);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* func_800AA56C — 48 bytes at 0x800AA56C..0x800AA59C
|
||||
*
|
||||
* Byte-identical reconstruction of a byte-sum (checksum) over a
|
||||
* NUL-terminated byte string, truncated to 8 bits. `lbu` fixes a zero-extended
|
||||
* byte read (cookbook finding 7), and the accumulator is initialised with
|
||||
* `clear v0` in the first branch's delay slot. The condition's load is reused as
|
||||
* the body's value, so there is one load per iteration plus one before the
|
||||
* loop; the loop's branch delay slot is `nop` and the final `andi v0,v0,0xff`
|
||||
* sits in the `jr` delay slot (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lbu v1,0x0(a0) v1 = *p
|
||||
* nop (load delay)
|
||||
* beq v1,zero,exit if (*p == 0) return 0
|
||||
* clear v0 (delay slot) sum = 0
|
||||
* loop:
|
||||
* addu v0,v1,v0 sum += v1
|
||||
* addiu a0,a0,0x1 p++
|
||||
* lbu v1,0x0(a0) v1 = *p
|
||||
* nop (load delay)
|
||||
* bne v1,zero,loop while (*p != 0)
|
||||
* nop
|
||||
* exit:
|
||||
* jr ra
|
||||
* andi v0,v0,0xff (delay slot) return sum & 0xff
|
||||
*
|
||||
* LIMITS: the byte width, the NUL termination and the 8-bit truncation are
|
||||
* evidence; the string's meaning and the parameter's real type are hypotheses
|
||||
* (the `& 0xff` is evidence for the truncation, not for an 8-bit accumulator).
|
||||
*/
|
||||
|
||||
int func_800AA56C(unsigned char *p) {
|
||||
int sum = 0;
|
||||
while (*p != 0) {
|
||||
sum += *p;
|
||||
p++;
|
||||
}
|
||||
return sum & 0xff;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* func_800F5B40 — 48 bytes at 0x800F5B40..0x800F5B70
|
||||
*
|
||||
* Byte-identical reconstruction of a masked hardware-register write plus a
|
||||
* masked read-back. The write ORs a bit into the argument and stores it through
|
||||
* a global pointer; the read masks a different global's target with 0x00ffffff.
|
||||
* Both pointers are loaded with the assembler macro form expanding into the
|
||||
* destination register (cookbook finding 2; `addiu`-adjusted halves
|
||||
* 0x8012 / -0x561c and 0x8012 / -0x5620). 0x00ffffff needs `lui 0xff` + `ori`,
|
||||
* and the `and` lands in the `jr` delay slot (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lui v0,0x1000
|
||||
* lui v1,0x8012
|
||||
* lw v1,-0x561c(v1) v1 = D_8011A9E4 (a pointer)
|
||||
* or a0,a0,v0 argument |= 0x10000000
|
||||
* sw a0,0x0(v1) *v1 = argument
|
||||
* lui v0,0x8012
|
||||
* lw v0,-0x5620(v0) v0 = D_8011A9E0 (a pointer)
|
||||
* lui v1,0xff
|
||||
* lw v0,0x0(v0) v0 = *v0
|
||||
* ori v1,v1,0xffff v1 = 0x00ffffff
|
||||
* jr ra
|
||||
* and v0,v0,v1 (delay slot) return v0 & 0x00ffffff
|
||||
*
|
||||
* LIMITS: the two addresses, the mask 0x10000000, the mask 0x00ffffff and the
|
||||
* widths are evidence; the globals' names, types and meanings and the
|
||||
* interpretation that they point at hardware registers are hypotheses. Neither
|
||||
* access is marked `volatile` because that is not needed to reproduce these
|
||||
* bytes and would be an unproven claim about the access semantics.
|
||||
*/
|
||||
|
||||
extern int *D_8011A9E4;
|
||||
extern int *D_8011A9E0;
|
||||
|
||||
int func_800F5B40(int value) {
|
||||
*D_8011A9E4 = value | 0x10000000;
|
||||
return *D_8011A9E0 & 0x00ffffff;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/* func_800F7FB4 - 0x800F7FB4..0x800F7FD8 (36 bytes); duplicate body, also at
|
||||
* 0x80103C7C and 0x80103F84 (census group g0007).
|
||||
*
|
||||
* Original words:
|
||||
* 0x10A00006 beqz a1,+0x1c if (n == 0) return
|
||||
* 0x24A2FFFF addiu v0,a1,-1 i = n - 1 (delay slot)
|
||||
* 0x2403FFFF li v1,-1
|
||||
* 0xAC800000 sw zero,0(a0) *p = 0
|
||||
* 0x2442FFFF addiu v0,v0,-1 i -= 1
|
||||
* 0x1443FFFD bne v0,v1,+0x0 while (i != -1)
|
||||
* 0x24840004 addiu a0,a0,4 p++ (delay slot)
|
||||
* 0x03E00008 jr ra
|
||||
* 0x00000000 nop
|
||||
*
|
||||
* Pure C, no asm. The shape matters and is recorded because this body was an
|
||||
* open near-match for two phases: the obvious `for (i = n - 1; i != -1; i--)`
|
||||
* makes cc1 restructure the loop and emit an unused 8-byte frame (44 bytes
|
||||
* instead of 36). Writing the guard explicitly and the loop as a do/while keeps
|
||||
* the counter in v0, keeps the `li v1,-1` / `bne` exit test, and drops the
|
||||
* frame. `addu rt,rs,imm` in cc1 output becomes `addiu` in the assembler, which
|
||||
* is what the original shows.
|
||||
*/
|
||||
void func_800F7FB4(int *p, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = n - 1;
|
||||
if (n != 0)
|
||||
do {
|
||||
*p++ = 0;
|
||||
} while (--i != -1);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/* func_800FB5D4 — 0x800FB5D4..0x800FB5DC (8 bytes).
|
||||
*
|
||||
* Original words:
|
||||
* 0x03E00008 jr ra
|
||||
* 0x03A01021 move v0,sp
|
||||
*
|
||||
* No inline assembly is needed: the GNU C extension `register int x asm("$29")`
|
||||
* reads the stack pointer, and the compiler's own delay-slot filler moves the
|
||||
* copy into the `jr ra` slot. `-O2` emits exactly `j $31` / `move $2,$sp`
|
||||
* inside `.set noreorder` / `.set nomacro`.
|
||||
*/
|
||||
int func_800FB5D4(void)
|
||||
{
|
||||
register int sp __asm__("$29");
|
||||
|
||||
return sp;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* func_80108710 — 36 bytes at 0x80108710..0x80108734
|
||||
*
|
||||
* Byte-identical reconstruction of a "store if changed" setter. The comparison
|
||||
* is a direct register `beq` (no `slt`/`xori`), which is what an equality test
|
||||
* against a loaded global produces; the store is an absolute symbol store whose
|
||||
* `sw` macro expands through `$at` (cookbook finding 3), so this global is NOT
|
||||
* `gp`-relative. The branch delay slot is `nop` (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lui v0,0x8012
|
||||
* lw v0,0x1080(v0) v0 = D_80121080
|
||||
* nop (load delay)
|
||||
* beq a0,v0,exit if (argument == D_80121080) skip the store
|
||||
* nop
|
||||
* lui at,0x8012
|
||||
* sw a0,0x1080(at) D_80121080 = argument
|
||||
* exit:
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* The COMPARISON OPERAND ORDER is load-bearing: the original encodes
|
||||
* `beq $4,$2` (argument in `rs`), which is what `value != D_80121080` produces.
|
||||
* Writing the test the other way round (`D_80121080 != value`) emits
|
||||
* `beq $2,$4` and differs by exactly 1 byte.
|
||||
*
|
||||
* LIMITS: the address and 32-bit width are evidence; the global's name, type
|
||||
* and meaning and the "changed" semantics are hypotheses.
|
||||
*/
|
||||
|
||||
extern int D_80121080;
|
||||
|
||||
void func_80108710(int value) {
|
||||
if (value != D_80121080) {
|
||||
D_80121080 = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* func_8010A8B0 — 40 bytes at 0x8010A8B0..0x8010A8D8
|
||||
*
|
||||
* Byte-identical reconstruction of a masked read-modify-write of a hardware
|
||||
* register reached through a global pointer. The pointer is loaded with the
|
||||
* assembler macro form expanding into the destination register (cookbook
|
||||
* finding 2; `addiu`-adjusted halves 0x8012 / 0x105c = 0x8012105C). Both
|
||||
* constants need two instructions: 0xf0ffffff is `lui 0xf0ff` + `ori 0xffff`,
|
||||
* and 0x22000000 is a single `lui 0x2200`. The store lands in the `jr` delay
|
||||
* slot (cookbook finding 8).
|
||||
*
|
||||
* The observed instructions are:
|
||||
* lui a0,0x8012
|
||||
* lw a0,0x105c(a0) a0 = D_8012105C (a pointer)
|
||||
* lui v1,0xf0ff
|
||||
* lw v0,0x0(a0) v0 = *a0
|
||||
* ori v1,v1,0xffff v1 = 0xf0ffffff
|
||||
* and v0,v0,v1 v0 &= 0xf0ffffff
|
||||
* lui v1,0x2200 v1 = 0x22000000
|
||||
* or v0,v0,v1 v0 |= 0x22000000
|
||||
* jr ra
|
||||
* sw v0,0x0(a0) (delay slot) *a0 = v0
|
||||
*
|
||||
* LIMITS: the two constants and the 32-bit width are evidence; the global's
|
||||
* name, type and meaning and the interpretation that the target is a hardware
|
||||
* register are hypotheses. The source is not marked `volatile` because that is
|
||||
* not needed to reproduce these bytes and would be an unproven claim.
|
||||
*/
|
||||
|
||||
extern int *D_8012105C;
|
||||
|
||||
void func_8010A8B0(void) {
|
||||
*D_8012105C = (*D_8012105C & 0xf0ffffff) | 0x22000000;
|
||||
}
|
||||
Reference in New Issue
Block a user