Files
BFM-decomp/cookbook/C0252.md
T

3.0 KiB
Raw Blame History

§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.