3.0 KiB
§231 — TRANSCRIPTION AND SEMANTIC-READ HYGIENE: six ways the listing misleads (P31 S58)
1. REBUILD SPLIT CONSTANTS FROM THE MASKS, NEVER FROM VISUAL ADJACENCY. func_80181960
(ov_SC07_007): splat renders lui/ori as masked halves ((K>>16)) / (K&0xFFFF). The draft
reassembled 0x000F0140 by concatenating rendered fragments of two different constants — the
lui 0xF0 belonged to 0x00F00140. Always rebuild K = (hi<<16) | lo from the two halves of the
SAME pair.
2. READ THE lui/ori PAIR; DO NOT ASSUME A REPEATING BYTE PATTERN. func_80185520
(ov_SC06_000, 67/67): the tail constant is 0x202020 (lui 0x20 / ori 0x2020), not
0x20202020.
3. THE LISTING'S TEXT CAN DISAGREE WITH ITS OWN HEX COLUMN. func_801AA4EC (md_SC07_004): a
line rendered addiu $a2,$a1,0x10 for hex 0x24A60010 (correct), but a neighbouring line's text
disagreed with 0x02280021, which decodes as addu $a1,$s0,$zero. When an argument wiring reads
implausibly, decode the /* */ hex column directly — it settled that both calls take
(param_1, param_2, …) and the second is not chained off param_2+8.
4. USE THE NUMERIC EXIT-LABEL OFFSET TO DISAMBIGUATE break FROM continue. func_80184CCC
(ov_SC04_011, 59/59): two per-entry guards look like loop exits; the exit-label offset (+0x4C,
landing on the lh/0x8000 check) proved they are independent jumps to loop bottom, not
breaks. Writing them as one && gave the shared-target branch shape instead. (This is the
masked_diff blind spot §195-D names, applied as a positive drafting tool.)
5. A "CLEAN REGISTER SWAP" RESIDUAL CAN BE A SEMANTIC ERROR — RE-READ THE addu SOURCES.
func_801A9810 (md_SC07_004, 47/47): the atlas's REGALLOC-PERM label was a misdiagnosis trap. The
4-instruction residual looked like an $s0/$s1 swap but was a wrong argument: the target does
addu $a0,$s0,$zero where $s0 is the OBJECT, so the tail call is func_8012AD44(object, 2), not
(s1, 2). Passing the wrong pointer forced gcc to keep it live across three calls and cascaded the
allocation; fixing the argument alone flipped everything. §176-B ("REGALLOC-PERM 1-4 instructions
off ⇒ usually NOT register allocation") generalises: re-read the target's own addu SOURCES before
believing a swap signature. func_80186248 (ov_SC02_027) is the same class from the other side —
a read-modify-write whose value feeds only a store leaves that value out of the argument set
entirely, and the diff's missing $a0 move was the tell.
6. sra N IS NOT ALWAYS A DIVIDE. func_80180EC8 (ov_SC07_007, 28/28): sll 16 ; sra 14 is
sext(u16) << 2 — a folded sign-extend-plus-scale, sra amount = 16 − log2(scale). §167-03's
HImode-division reading of sra 14 is a false friend; the discriminator is that the value feeds an
lw ADDRESS, not an addu/subu sum. Write the index unscaled ((v<<16)>>16) and let gcc fold
the scale and the extension into the one sra; a literal *4 gave an sra 12 mismatch.