Files
BFM-decomp/cookbook/C0256.md
T

1.6 KiB

§235 — THE PHANTOM SYMBOL: A MASKED MATCH CAN CARRY A RELOCATION THAT DOES NOT EXIST (P31 S58b)

match_one masks HI16/LO16/jal identity (Law 1c). Therefore a draft can score a clean MATCH while naming a symbol that is not in the binary at all, and the failure surfaces only at link time in the whole-binary gate, with no per-instruction diff to steer you.

THE CARD. func_801800D0 (ov_SC03_029, banked twice, waves ar/bc). The Ghidra seed invented DAT_801d9752. No such label exists: asm/ov_SC03_029/data/tail18.data.s defines only D_801D9750/54/58/5C. The target reaches the middle halfword through the REAL label — BYTE-VERIFIED in func_801800D0.s:

lui  $at, %hi(D_801D9750 + 0x2)
sh   $v0, %lo(D_801D9750 + 0x2)($at)

THE C SPELLING THAT FOLDS A CONSTANT INDEX INTO symbol + offset INSIDE %hi/%lo IS ARRAY INDEXING ON AN INCOMPLETE-ARRAY EXTERN: extern u16 D_801D9750[]; … D_801D9750[1] = v; A scalar extern u16 D_801D9752 emits bare %hi(D_801D9752) — right address, wrong relocation TEXT, and an undefined symbol at link.

GENERALISATION. Whenever the target's own relocation lines show %hi(SYM + K), the source used one object and indexed into it. Whenever they show two distinct %hi(SYM_A) / %hi(SYM_B) pairs for adjacent addresses, the source used two distinct objects (§216, and see func_8018BB44 in §250). Read the relocation TEXT, not the effective address.

BOUNDARY. This is not the extern-type conflict class (§12/§14c) — the symbol simply does not exist. Symptom is a link/gate failure with a green oracle and a clean type audit.