mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-01 23:52:03 -04:00
fix(phase-30 S48): scope_data_externs spliced carried externs INTO a comment
`_body_open_brace` ran BOTH its scans on unmasked text. A crack agent's draft
opens with a header comment that names the function and quotes C at it:
/* func_801EE8E0 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs …
* 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION
so `sig` matched the COMMENT's first line and `find('{')` found the comment's
`do {`. Every carried `extern` was spliced into the comment — silently
commented out — and the gate reported `'D_8011511A' undeclared`.
The sweep classified that CC1-FAIL, so it read as a property of the SIBLING
(all 4 members failed identically) when it was a property of the EXEMPLAR'S
PROSE. It had nothing to do with module binaries, which is where I had filed
it. Every richly-commented agent draft is a carrier; the trigger is any brace
inside the header comment — so this would have grown with the campaign.
- both scans now run on `cdecl._mask`ed text and index the original by the
masked offsets (§134 / R33: one masking oracle);
- refuse outright if the length invariant is broken, rather than mis-place a
declaration into live code (R32).
Measured: family func_8017CBC8 -> its 4 md_ siblings went 0/4 -> 4/4 banked.
This commit is contained in:
@@ -120,7 +120,130 @@ INCLUDE_ASM("asm/md_SC03_076/nonmatchings/md_SC03_076", func_801EFBB4);
|
||||
|
||||
INCLUDE_ASM("asm/md_SC03_076/nonmatchings/md_SC03_076", func_801F0210);
|
||||
|
||||
INCLUDE_ASM("asm/md_SC03_076/nonmatchings/md_SC03_076", func_801F03C0);
|
||||
typedef struct { s8 c[8]; } Blk8_8012C890_8017C348_801F03C0;
|
||||
typedef struct { s16 m[3][3]; s32 t[3]; } MTX_C974_801F03C0;
|
||||
|
||||
/* func_801F03C0 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs
|
||||
* asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_801789AC/func_801F03C0.s
|
||||
*
|
||||
* Sprite/quad draw dispatcher: builds an OT chain for one "part list" entry.
|
||||
*
|
||||
* Idioms that were load-bearing here (feed these back into the cookbook):
|
||||
* 1) `dim`/`dim2`/`dim3` are DELIBERATE copies of `flag`. The target keeps
|
||||
* `flag` in $s7 and copies it into $s6 in each loop preheader and into $s0
|
||||
* for the tail. A plain `x = flag;` written in the same basic block as its
|
||||
* use is killed by cse; it survives only when a multi-pred label separates
|
||||
* def from use. So: the loop-1 copy is written at the END of the outer
|
||||
* body (loop.c hoists it into the preheader), the loop-2 copy is written in
|
||||
* the preheader itself, and the tail copy needs a hard-register pin
|
||||
* (`register s32 dim3 __asm__("$16")`) because nothing separates it from
|
||||
* its uses. Same shape as the matched sibling func_8013FAF8 (ov_SC06_008),
|
||||
* which also needed a pin for exactly this call pair.
|
||||
* 2) `bp = sp18;` exists only to fix the ORDER of the two loop-1 preheader
|
||||
* insns. loop.c emits hoisted invariants in body order; writing the
|
||||
* sp18-relative store address as an explicit pointer makes `addiu $s5,$sp,0x18`
|
||||
* the FIRST movable, so the `dim` copy lands after it (as in the target).
|
||||
* 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION
|
||||
* lever, not dead syntax. flow.c weights REG_N_REFS by loop_depth; the
|
||||
* extra (never-iterating) loop note gives `ot` 18 weighted refs instead of
|
||||
* 16, which raises its global-alloc priority above `s` (21 refs / 159 insns)
|
||||
* and lands the a0/a1 params in $s2/$s3 exactly as the target does.
|
||||
* `mode` is hoisted out of the wrapper so `dim` does NOT get the same +1
|
||||
* (that would swap $s5/$s6 between `bp` and `dim`).
|
||||
* 4) Low half of sp60[0] uses `& 0xFFFF`, NOT a (u16) cast: the mask keeps the
|
||||
* operands in SImode so both halves load with `lh`; a (u16) cast makes
|
||||
* gcc-2.7.2 emit `lhu`.
|
||||
*/
|
||||
|
||||
|
||||
extern s32 func_80024054(u8 *, u8 *);
|
||||
extern s32 func_800D2650(s32, u8 *, s16, s16, s32, s32);
|
||||
extern s32 func_800D27DC(s32, s32, void *, s16, s32);
|
||||
extern s32 func_800D29F8(s32, s32, void *, s16, s32);
|
||||
extern s32 func_801F06B0(s32, s16, s16, s16, s32 *);
|
||||
|
||||
s32 func_801F03C0(s32 ot, u8 *s, s16 c) {
|
||||
|
||||
extern u16 D_8011511A;
|
||||
extern u8 D_801F341C[];
|
||||
extern s32 *D_801F3394[];
|
||||
u8 sp18[72];
|
||||
s32 sp60[5];
|
||||
s32 sp78[8];
|
||||
s32 flag;
|
||||
s32 dim;
|
||||
s32 dim2;
|
||||
register s32 dim3 __asm__("$16");
|
||||
s32 t;
|
||||
s16 i;
|
||||
s16 k;
|
||||
s32 *p;
|
||||
u8 *bp;
|
||||
s16 *q;
|
||||
s32 r;
|
||||
s32 mode;
|
||||
|
||||
if (c == 0) {
|
||||
flag = 0;
|
||||
} else {
|
||||
flag = -(D_8011511A != c) & 0xFF;
|
||||
}
|
||||
|
||||
t = *(s32 *)(s + 0x14);
|
||||
if (t < 0) {
|
||||
func_80024054((u8 *)t, sp18);
|
||||
ot = func_800D2650(ot, sp18, *(s16 *)(s + 0x10), *(s16 *)(s + 0x12), 1,
|
||||
flag ? 0x585858 : 0x808080);
|
||||
} else {
|
||||
p = D_801F3394[t];
|
||||
for (k = 0; k < D_801F341C[*(s32 *)(s + 0x14)]; k++) {
|
||||
bp = sp18;
|
||||
dim = flag;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (i == 0) {
|
||||
sp60[0] = (((s16 *)p)[0] + *(s16 *)(s + 0x10)) & 0xFFFF |
|
||||
((((s16 *)p)[1] + *(s16 *)(s + 0x12)) << 16);
|
||||
} else {
|
||||
*(s32 *)(bp + 0x48 + i * 4) = p[i];
|
||||
}
|
||||
}
|
||||
mode = dim ? 3 : 2;
|
||||
do {
|
||||
ot = func_800D27DC(mode, ot, sp60, 1, 0);
|
||||
} while (0);
|
||||
p += 5;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
q = *(s16 **)(s + 0x18);
|
||||
dim2 = flag;
|
||||
for (;;) {
|
||||
r = func_801F06B0(*(s32 *)(s + 0x1C), *(s16 *)s, c, i++, sp78);
|
||||
if (r == 0) {
|
||||
break;
|
||||
}
|
||||
if (r < 0) {
|
||||
func_80024054((u8 *)r, sp18);
|
||||
if (dim2 != 0) {
|
||||
sp78[0] = 0x585858;
|
||||
}
|
||||
ot = func_800D2650(ot, sp18, q[0], q[1], 1, sp78[0]);
|
||||
} else {
|
||||
p = D_801F3394[r];
|
||||
*p = (u16)q[0] | (q[1] << 16);
|
||||
ot = func_800D27DC(dim2 ? 3 : 2, ot, p, 1, 0);
|
||||
}
|
||||
q += 2;
|
||||
}
|
||||
|
||||
dim3 = flag;
|
||||
return func_800D29F8(dim3,
|
||||
func_800D27DC(dim3 != 0, ot, (void *)*(s32 *)(s + 4),
|
||||
*(s16 *)(s + 0xC), 0),
|
||||
(void *)*(s32 *)(s + 8), *(s16 *)(s + 0xE), 0);
|
||||
}
|
||||
|
||||
|
||||
INCLUDE_ASM("asm/md_SC03_076/nonmatchings/md_SC03_076", func_801F06B0);
|
||||
|
||||
|
||||
@@ -120,7 +120,130 @@ INCLUDE_ASM("asm/md_SC03_135/nonmatchings/md_SC03_135", func_801E2D34);
|
||||
|
||||
INCLUDE_ASM("asm/md_SC03_135/nonmatchings/md_SC03_135", func_801E3390);
|
||||
|
||||
INCLUDE_ASM("asm/md_SC03_135/nonmatchings/md_SC03_135", func_801E3540);
|
||||
typedef struct { s8 c[8]; } Blk8_8012C890_8017C348_801E3540;
|
||||
typedef struct { s16 m[3][3]; s32 t[3]; } MTX_C974_801E3540;
|
||||
|
||||
/* func_801E3540 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs
|
||||
* asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_801789AC/func_801E3540.s
|
||||
*
|
||||
* Sprite/quad draw dispatcher: builds an OT chain for one "part list" entry.
|
||||
*
|
||||
* Idioms that were load-bearing here (feed these back into the cookbook):
|
||||
* 1) `dim`/`dim2`/`dim3` are DELIBERATE copies of `flag`. The target keeps
|
||||
* `flag` in $s7 and copies it into $s6 in each loop preheader and into $s0
|
||||
* for the tail. A plain `x = flag;` written in the same basic block as its
|
||||
* use is killed by cse; it survives only when a multi-pred label separates
|
||||
* def from use. So: the loop-1 copy is written at the END of the outer
|
||||
* body (loop.c hoists it into the preheader), the loop-2 copy is written in
|
||||
* the preheader itself, and the tail copy needs a hard-register pin
|
||||
* (`register s32 dim3 __asm__("$16")`) because nothing separates it from
|
||||
* its uses. Same shape as the matched sibling func_8013FAF8 (ov_SC06_008),
|
||||
* which also needed a pin for exactly this call pair.
|
||||
* 2) `bp = sp18;` exists only to fix the ORDER of the two loop-1 preheader
|
||||
* insns. loop.c emits hoisted invariants in body order; writing the
|
||||
* sp18-relative store address as an explicit pointer makes `addiu $s5,$sp,0x18`
|
||||
* the FIRST movable, so the `dim` copy lands after it (as in the target).
|
||||
* 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION
|
||||
* lever, not dead syntax. flow.c weights REG_N_REFS by loop_depth; the
|
||||
* extra (never-iterating) loop note gives `ot` 18 weighted refs instead of
|
||||
* 16, which raises its global-alloc priority above `s` (21 refs / 159 insns)
|
||||
* and lands the a0/a1 params in $s2/$s3 exactly as the target does.
|
||||
* `mode` is hoisted out of the wrapper so `dim` does NOT get the same +1
|
||||
* (that would swap $s5/$s6 between `bp` and `dim`).
|
||||
* 4) Low half of sp60[0] uses `& 0xFFFF`, NOT a (u16) cast: the mask keeps the
|
||||
* operands in SImode so both halves load with `lh`; a (u16) cast makes
|
||||
* gcc-2.7.2 emit `lhu`.
|
||||
*/
|
||||
|
||||
|
||||
extern s32 func_80024054(u8 *, u8 *);
|
||||
extern s32 func_800D2650(s32, u8 *, s16, s16, s32, s32);
|
||||
extern s32 func_800D27DC(s32, s32, void *, s16, s32);
|
||||
extern s32 func_800D29F8(s32, s32, void *, s16, s32);
|
||||
extern s32 func_801E3830(s32, s16, s16, s16, s32 *);
|
||||
|
||||
s32 func_801E3540(s32 ot, u8 *s, s16 c) {
|
||||
|
||||
extern u16 D_8011511A;
|
||||
extern u8 D_801E6584[];
|
||||
extern s32 *D_801E64FC[];
|
||||
u8 sp18[72];
|
||||
s32 sp60[5];
|
||||
s32 sp78[8];
|
||||
s32 flag;
|
||||
s32 dim;
|
||||
s32 dim2;
|
||||
register s32 dim3 __asm__("$16");
|
||||
s32 t;
|
||||
s16 i;
|
||||
s16 k;
|
||||
s32 *p;
|
||||
u8 *bp;
|
||||
s16 *q;
|
||||
s32 r;
|
||||
s32 mode;
|
||||
|
||||
if (c == 0) {
|
||||
flag = 0;
|
||||
} else {
|
||||
flag = -(D_8011511A != c) & 0xFF;
|
||||
}
|
||||
|
||||
t = *(s32 *)(s + 0x14);
|
||||
if (t < 0) {
|
||||
func_80024054((u8 *)t, sp18);
|
||||
ot = func_800D2650(ot, sp18, *(s16 *)(s + 0x10), *(s16 *)(s + 0x12), 1,
|
||||
flag ? 0x585858 : 0x808080);
|
||||
} else {
|
||||
p = D_801E64FC[t];
|
||||
for (k = 0; k < D_801E6584[*(s32 *)(s + 0x14)]; k++) {
|
||||
bp = sp18;
|
||||
dim = flag;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (i == 0) {
|
||||
sp60[0] = (((s16 *)p)[0] + *(s16 *)(s + 0x10)) & 0xFFFF |
|
||||
((((s16 *)p)[1] + *(s16 *)(s + 0x12)) << 16);
|
||||
} else {
|
||||
*(s32 *)(bp + 0x48 + i * 4) = p[i];
|
||||
}
|
||||
}
|
||||
mode = dim ? 3 : 2;
|
||||
do {
|
||||
ot = func_800D27DC(mode, ot, sp60, 1, 0);
|
||||
} while (0);
|
||||
p += 5;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
q = *(s16 **)(s + 0x18);
|
||||
dim2 = flag;
|
||||
for (;;) {
|
||||
r = func_801E3830(*(s32 *)(s + 0x1C), *(s16 *)s, c, i++, sp78);
|
||||
if (r == 0) {
|
||||
break;
|
||||
}
|
||||
if (r < 0) {
|
||||
func_80024054((u8 *)r, sp18);
|
||||
if (dim2 != 0) {
|
||||
sp78[0] = 0x585858;
|
||||
}
|
||||
ot = func_800D2650(ot, sp18, q[0], q[1], 1, sp78[0]);
|
||||
} else {
|
||||
p = D_801E64FC[r];
|
||||
*p = (u16)q[0] | (q[1] << 16);
|
||||
ot = func_800D27DC(dim2 ? 3 : 2, ot, p, 1, 0);
|
||||
}
|
||||
q += 2;
|
||||
}
|
||||
|
||||
dim3 = flag;
|
||||
return func_800D29F8(dim3,
|
||||
func_800D27DC(dim3 != 0, ot, (void *)*(s32 *)(s + 4),
|
||||
*(s16 *)(s + 0xC), 0),
|
||||
(void *)*(s32 *)(s + 8), *(s16 *)(s + 0xE), 0);
|
||||
}
|
||||
|
||||
|
||||
INCLUDE_ASM("asm/md_SC03_135/nonmatchings/md_SC03_135", func_801E3830);
|
||||
|
||||
|
||||
@@ -120,7 +120,130 @@ INCLUDE_ASM("asm/md_SC04_027/nonmatchings/md_SC04_027", func_801E8274);
|
||||
|
||||
INCLUDE_ASM("asm/md_SC04_027/nonmatchings/md_SC04_027", func_801E88D0);
|
||||
|
||||
INCLUDE_ASM("asm/md_SC04_027/nonmatchings/md_SC04_027", func_801E8A80);
|
||||
typedef struct { s8 c[8]; } Blk8_8012C890_8017C348_801E8A80;
|
||||
typedef struct { s16 m[3][3]; s32 t[3]; } MTX_C974_801E8A80;
|
||||
|
||||
/* func_801E8A80 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs
|
||||
* asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_801789AC/func_801E8A80.s
|
||||
*
|
||||
* Sprite/quad draw dispatcher: builds an OT chain for one "part list" entry.
|
||||
*
|
||||
* Idioms that were load-bearing here (feed these back into the cookbook):
|
||||
* 1) `dim`/`dim2`/`dim3` are DELIBERATE copies of `flag`. The target keeps
|
||||
* `flag` in $s7 and copies it into $s6 in each loop preheader and into $s0
|
||||
* for the tail. A plain `x = flag;` written in the same basic block as its
|
||||
* use is killed by cse; it survives only when a multi-pred label separates
|
||||
* def from use. So: the loop-1 copy is written at the END of the outer
|
||||
* body (loop.c hoists it into the preheader), the loop-2 copy is written in
|
||||
* the preheader itself, and the tail copy needs a hard-register pin
|
||||
* (`register s32 dim3 __asm__("$16")`) because nothing separates it from
|
||||
* its uses. Same shape as the matched sibling func_8013FAF8 (ov_SC06_008),
|
||||
* which also needed a pin for exactly this call pair.
|
||||
* 2) `bp = sp18;` exists only to fix the ORDER of the two loop-1 preheader
|
||||
* insns. loop.c emits hoisted invariants in body order; writing the
|
||||
* sp18-relative store address as an explicit pointer makes `addiu $s5,$sp,0x18`
|
||||
* the FIRST movable, so the `dim` copy lands after it (as in the target).
|
||||
* 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION
|
||||
* lever, not dead syntax. flow.c weights REG_N_REFS by loop_depth; the
|
||||
* extra (never-iterating) loop note gives `ot` 18 weighted refs instead of
|
||||
* 16, which raises its global-alloc priority above `s` (21 refs / 159 insns)
|
||||
* and lands the a0/a1 params in $s2/$s3 exactly as the target does.
|
||||
* `mode` is hoisted out of the wrapper so `dim` does NOT get the same +1
|
||||
* (that would swap $s5/$s6 between `bp` and `dim`).
|
||||
* 4) Low half of sp60[0] uses `& 0xFFFF`, NOT a (u16) cast: the mask keeps the
|
||||
* operands in SImode so both halves load with `lh`; a (u16) cast makes
|
||||
* gcc-2.7.2 emit `lhu`.
|
||||
*/
|
||||
|
||||
|
||||
extern s32 func_80024054(u8 *, u8 *);
|
||||
extern s32 func_800D2650(s32, u8 *, s16, s16, s32, s32);
|
||||
extern s32 func_800D27DC(s32, s32, void *, s16, s32);
|
||||
extern s32 func_800D29F8(s32, s32, void *, s16, s32);
|
||||
extern s32 func_801E8D70(s32, s16, s16, s16, s32 *);
|
||||
|
||||
s32 func_801E8A80(s32 ot, u8 *s, s16 c) {
|
||||
|
||||
extern u16 D_8011511A;
|
||||
extern u8 D_801EBAEC[];
|
||||
extern s32 *D_801EBA64[];
|
||||
u8 sp18[72];
|
||||
s32 sp60[5];
|
||||
s32 sp78[8];
|
||||
s32 flag;
|
||||
s32 dim;
|
||||
s32 dim2;
|
||||
register s32 dim3 __asm__("$16");
|
||||
s32 t;
|
||||
s16 i;
|
||||
s16 k;
|
||||
s32 *p;
|
||||
u8 *bp;
|
||||
s16 *q;
|
||||
s32 r;
|
||||
s32 mode;
|
||||
|
||||
if (c == 0) {
|
||||
flag = 0;
|
||||
} else {
|
||||
flag = -(D_8011511A != c) & 0xFF;
|
||||
}
|
||||
|
||||
t = *(s32 *)(s + 0x14);
|
||||
if (t < 0) {
|
||||
func_80024054((u8 *)t, sp18);
|
||||
ot = func_800D2650(ot, sp18, *(s16 *)(s + 0x10), *(s16 *)(s + 0x12), 1,
|
||||
flag ? 0x585858 : 0x808080);
|
||||
} else {
|
||||
p = D_801EBA64[t];
|
||||
for (k = 0; k < D_801EBAEC[*(s32 *)(s + 0x14)]; k++) {
|
||||
bp = sp18;
|
||||
dim = flag;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (i == 0) {
|
||||
sp60[0] = (((s16 *)p)[0] + *(s16 *)(s + 0x10)) & 0xFFFF |
|
||||
((((s16 *)p)[1] + *(s16 *)(s + 0x12)) << 16);
|
||||
} else {
|
||||
*(s32 *)(bp + 0x48 + i * 4) = p[i];
|
||||
}
|
||||
}
|
||||
mode = dim ? 3 : 2;
|
||||
do {
|
||||
ot = func_800D27DC(mode, ot, sp60, 1, 0);
|
||||
} while (0);
|
||||
p += 5;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
q = *(s16 **)(s + 0x18);
|
||||
dim2 = flag;
|
||||
for (;;) {
|
||||
r = func_801E8D70(*(s32 *)(s + 0x1C), *(s16 *)s, c, i++, sp78);
|
||||
if (r == 0) {
|
||||
break;
|
||||
}
|
||||
if (r < 0) {
|
||||
func_80024054((u8 *)r, sp18);
|
||||
if (dim2 != 0) {
|
||||
sp78[0] = 0x585858;
|
||||
}
|
||||
ot = func_800D2650(ot, sp18, q[0], q[1], 1, sp78[0]);
|
||||
} else {
|
||||
p = D_801EBA64[r];
|
||||
*p = (u16)q[0] | (q[1] << 16);
|
||||
ot = func_800D27DC(dim2 ? 3 : 2, ot, p, 1, 0);
|
||||
}
|
||||
q += 2;
|
||||
}
|
||||
|
||||
dim3 = flag;
|
||||
return func_800D29F8(dim3,
|
||||
func_800D27DC(dim3 != 0, ot, (void *)*(s32 *)(s + 4),
|
||||
*(s16 *)(s + 0xC), 0),
|
||||
(void *)*(s32 *)(s + 8), *(s16 *)(s + 0xE), 0);
|
||||
}
|
||||
|
||||
|
||||
INCLUDE_ASM("asm/md_SC04_027/nonmatchings/md_SC04_027", func_801E8D70);
|
||||
|
||||
|
||||
@@ -120,7 +120,130 @@ INCLUDE_ASM("asm/md_SC05_026/nonmatchings/md_SC05_026", func_801EE0D4);
|
||||
|
||||
INCLUDE_ASM("asm/md_SC05_026/nonmatchings/md_SC05_026", func_801EE730);
|
||||
|
||||
INCLUDE_ASM("asm/md_SC05_026/nonmatchings/md_SC05_026", func_801EE8E0);
|
||||
typedef struct { s8 c[8]; } Blk8_8012C890_8017C348_801EE8E0;
|
||||
typedef struct { s16 m[3][3]; s32 t[3]; } MTX_C974_801EE8E0;
|
||||
|
||||
/* func_801EE8E0 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs
|
||||
* asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_801789AC/func_801EE8E0.s
|
||||
*
|
||||
* Sprite/quad draw dispatcher: builds an OT chain for one "part list" entry.
|
||||
*
|
||||
* Idioms that were load-bearing here (feed these back into the cookbook):
|
||||
* 1) `dim`/`dim2`/`dim3` are DELIBERATE copies of `flag`. The target keeps
|
||||
* `flag` in $s7 and copies it into $s6 in each loop preheader and into $s0
|
||||
* for the tail. A plain `x = flag;` written in the same basic block as its
|
||||
* use is killed by cse; it survives only when a multi-pred label separates
|
||||
* def from use. So: the loop-1 copy is written at the END of the outer
|
||||
* body (loop.c hoists it into the preheader), the loop-2 copy is written in
|
||||
* the preheader itself, and the tail copy needs a hard-register pin
|
||||
* (`register s32 dim3 __asm__("$16")`) because nothing separates it from
|
||||
* its uses. Same shape as the matched sibling func_8013FAF8 (ov_SC06_008),
|
||||
* which also needed a pin for exactly this call pair.
|
||||
* 2) `bp = sp18;` exists only to fix the ORDER of the two loop-1 preheader
|
||||
* insns. loop.c emits hoisted invariants in body order; writing the
|
||||
* sp18-relative store address as an explicit pointer makes `addiu $s5,$sp,0x18`
|
||||
* the FIRST movable, so the `dim` copy lands after it (as in the target).
|
||||
* 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION
|
||||
* lever, not dead syntax. flow.c weights REG_N_REFS by loop_depth; the
|
||||
* extra (never-iterating) loop note gives `ot` 18 weighted refs instead of
|
||||
* 16, which raises its global-alloc priority above `s` (21 refs / 159 insns)
|
||||
* and lands the a0/a1 params in $s2/$s3 exactly as the target does.
|
||||
* `mode` is hoisted out of the wrapper so `dim` does NOT get the same +1
|
||||
* (that would swap $s5/$s6 between `bp` and `dim`).
|
||||
* 4) Low half of sp60[0] uses `& 0xFFFF`, NOT a (u16) cast: the mask keeps the
|
||||
* operands in SImode so both halves load with `lh`; a (u16) cast makes
|
||||
* gcc-2.7.2 emit `lhu`.
|
||||
*/
|
||||
|
||||
|
||||
extern s32 func_80024054(u8 *, u8 *);
|
||||
extern s32 func_800D2650(s32, u8 *, s16, s16, s32, s32);
|
||||
extern s32 func_800D27DC(s32, s32, void *, s16, s32);
|
||||
extern s32 func_800D29F8(s32, s32, void *, s16, s32);
|
||||
extern s32 func_801EEBD0(s32, s16, s16, s16, s32 *);
|
||||
|
||||
s32 func_801EE8E0(s32 ot, u8 *s, s16 c) {
|
||||
|
||||
extern u16 D_8011511A;
|
||||
extern u8 D_801F1974[];
|
||||
extern s32 *D_801F18EC[];
|
||||
u8 sp18[72];
|
||||
s32 sp60[5];
|
||||
s32 sp78[8];
|
||||
s32 flag;
|
||||
s32 dim;
|
||||
s32 dim2;
|
||||
register s32 dim3 __asm__("$16");
|
||||
s32 t;
|
||||
s16 i;
|
||||
s16 k;
|
||||
s32 *p;
|
||||
u8 *bp;
|
||||
s16 *q;
|
||||
s32 r;
|
||||
s32 mode;
|
||||
|
||||
if (c == 0) {
|
||||
flag = 0;
|
||||
} else {
|
||||
flag = -(D_8011511A != c) & 0xFF;
|
||||
}
|
||||
|
||||
t = *(s32 *)(s + 0x14);
|
||||
if (t < 0) {
|
||||
func_80024054((u8 *)t, sp18);
|
||||
ot = func_800D2650(ot, sp18, *(s16 *)(s + 0x10), *(s16 *)(s + 0x12), 1,
|
||||
flag ? 0x585858 : 0x808080);
|
||||
} else {
|
||||
p = D_801F18EC[t];
|
||||
for (k = 0; k < D_801F1974[*(s32 *)(s + 0x14)]; k++) {
|
||||
bp = sp18;
|
||||
dim = flag;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (i == 0) {
|
||||
sp60[0] = (((s16 *)p)[0] + *(s16 *)(s + 0x10)) & 0xFFFF |
|
||||
((((s16 *)p)[1] + *(s16 *)(s + 0x12)) << 16);
|
||||
} else {
|
||||
*(s32 *)(bp + 0x48 + i * 4) = p[i];
|
||||
}
|
||||
}
|
||||
mode = dim ? 3 : 2;
|
||||
do {
|
||||
ot = func_800D27DC(mode, ot, sp60, 1, 0);
|
||||
} while (0);
|
||||
p += 5;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
q = *(s16 **)(s + 0x18);
|
||||
dim2 = flag;
|
||||
for (;;) {
|
||||
r = func_801EEBD0(*(s32 *)(s + 0x1C), *(s16 *)s, c, i++, sp78);
|
||||
if (r == 0) {
|
||||
break;
|
||||
}
|
||||
if (r < 0) {
|
||||
func_80024054((u8 *)r, sp18);
|
||||
if (dim2 != 0) {
|
||||
sp78[0] = 0x585858;
|
||||
}
|
||||
ot = func_800D2650(ot, sp18, q[0], q[1], 1, sp78[0]);
|
||||
} else {
|
||||
p = D_801F18EC[r];
|
||||
*p = (u16)q[0] | (q[1] << 16);
|
||||
ot = func_800D27DC(dim2 ? 3 : 2, ot, p, 1, 0);
|
||||
}
|
||||
q += 2;
|
||||
}
|
||||
|
||||
dim3 = flag;
|
||||
return func_800D29F8(dim3,
|
||||
func_800D27DC(dim3 != 0, ot, (void *)*(s32 *)(s + 4),
|
||||
*(s16 *)(s + 0xC), 0),
|
||||
(void *)*(s32 *)(s + 8), *(s16 *)(s + 0xE), 0);
|
||||
}
|
||||
|
||||
|
||||
INCLUDE_ASM("asm/md_SC05_026/nonmatchings/md_SC05_026", func_801EEBD0);
|
||||
|
||||
|
||||
@@ -50,9 +50,13 @@ CLI (diagnostics):
|
||||
--func func_8015AE2C [--out fixed.c]
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import cdecl # noqa: E402 — the ONE masking oracle (§134/R33)
|
||||
|
||||
# a col-0 (file-scope) `extern ...;` on one line. Leading whitespace => block scope, which is what we
|
||||
# emit and never need to re-place.
|
||||
FILE_EXTERN_RE = re.compile(r'^extern\b[^;{}\n]*;', re.M)
|
||||
@@ -79,11 +83,28 @@ def _body_open_brace(body, func):
|
||||
the brace on the signature line, the ANSI form with the brace on its own line, AND the K&R form whose
|
||||
param decls sit between the signature and the `{`). The first cut of this used `^\s*\{\s*$` — own-line
|
||||
braces only — and silently no-op'd on every ANSI draft (the same silent-skip disease as the four
|
||||
catalogued in §40/§8d; caught because the h_seq re-sweep banked 0/780)."""
|
||||
sig = re.search(rf'^[^\n]*\b{re.escape(func)}\s*\(', body, re.M)
|
||||
catalogued in §40/§8d; caught because the h_seq re-sweep banked 0/780).
|
||||
|
||||
BOTH SCANS RUN ON `cdecl._mask`ed TEXT (P30 S48, byte-witnessed). A crack agent's draft opens with
|
||||
a header comment that NAMES the function and quotes C at it:
|
||||
|
||||
/* func_801EE8E0 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs …
|
||||
* 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION lever …
|
||||
|
||||
Unmasked, `sig` matched the COMMENT's first line and `find('{')` then found the comment's
|
||||
`do {`, so every carried `extern` was spliced INTO THE COMMENT — silently commented out. The
|
||||
gate reported `'D_8011511A' undeclared` and the sweep classified it CC1-FAIL, i.e. it read as a
|
||||
property of the SIBLING (all 4 members of the family failed identically) when it was a property
|
||||
of the EXEMPLAR'S PROSE. Every richly-commented agent draft is a carrier; the trigger is any
|
||||
brace inside the header comment. Same §134 class as `_mask_cpp_directives` and the wrapped-decl
|
||||
scans — mask first, then index the ORIGINAL by the masked offsets."""
|
||||
masked = cdecl._mask(body)
|
||||
if len(masked) != len(body): # R32: the length invariant is what makes offsets portable
|
||||
return None # refuse rather than mis-place a decl into live code
|
||||
sig = re.search(rf'^[^\n]*\b{re.escape(func)}\s*\(', masked, re.M)
|
||||
if not sig:
|
||||
return None
|
||||
i = body.find('{', sig.end())
|
||||
i = masked.find('{', sig.end())
|
||||
if i < 0:
|
||||
return None
|
||||
j = body.find('\n', i)
|
||||
|
||||
Reference in New Issue
Block a user