4.9 KiB
§265 — THE VERBATIM-ASM BANK LANE: A FUNCTION NO -O2 C CAN EVER MATCH BANKS AS A RAW __asm__ BODY (P31 S59b; two banked cards, two in-tree precedents)
The symptom you see in a diff. Every draft plateaus at SIZE-MISMATCH or an unclosable structural
residual, and the target has one of the un-compilable tells: the -O0 prologue (addu $fp,$sp,$zero /
21F0A003, nop in every delay slot, per-statement li) while the object's Makefile globs compile it
-O2 (§261: 116 functions / 14,148 ins are stranded this way — nothing matches src/md_*/); or the
splat header says /* Handwritten function */; or the shape is one gcc-2.7.2 never emits (a bgez
whose OR-path falls through into a j chain, hand-placed GTE hazard nops). No C source can score
MATCH against these under the object's real CC1FLAGS. Stop drafting C.
The mechanism. A raw __asm__ body is opt-level-independent: cc1 passes the string through
untouched, so it emits the identical instructions whether the TU compiles -O0 or -O2, and the ordinary
whole-binary gate accepts it the moment the INCLUDE_ASM stub line is replaced. Two byte-banked forms:
- File-scope block (for a stranded ordinary function): transcribe the whole
.s—__asm__(".text\n.align 2\n.globl <fn>\n.ent\t<fn>\n" "<fn>:\n.frame $sp,40,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" ".set\tnoreorder\n" …every instruction… ".set\treorder\n.end\t<fn>\n");Banked:func_800D0440(93/93, md_MAIN_003 — a gcc -O0 body inside an -O2 module, atsrc/md_MAIN_003/md_MAIN_003.c:329). Precedent:func_80185810(src/ov_SC03_105/ov_SC03_105_jr_8017C8D0.c:5493). - C-definition wrapper (for a
/* Handwritten function */):void <fn>() { __asm__ __volatile__(".set\tnoreorder\n" … ); }Banked:func_800CBA44(109/109, md_MAIN_027, handwritten GTE add-halfwords loop, atsrc/md_MAIN_027/md_MAIN_027.c:225). Precedent:src/800b2.c.
The transcription rules (each one cost a compile or a session somewhere):
- MASPSX REJECTS HEX IMMEDIATES inside
__asm__strings — the error isinvalid literal for int() with base 10: '0x20'. Every immediate must be decimal (65535,-40,24).%hi(SYM)/%lo(SYM)and barejal <sym>work and relocate correctly. - Transcribe verbatim, model nothing. The -O0
$fpprologue, every delay-slotnop, and fake frames all stay:func_800CBA44carries a mid-bodyaddiu $sp,-8+lw 0x18/0x1C($sp)whose only purpose is reloading stack args 5/6 and hostingcfc2flag spills — transcribe it, do not turn it into C locals. - Ship NO C externs with the file-scope form. The asm resolves symbols at link time; a guessed type
for an otherwise-undeclared global (
D_800EC894) is pure §236-1 conflict risk with zero benefit. - Leave the recovered C semantics in a comment beside the body so the eventual real decomp (post §260/§261 lane work) starts warm.
What was tried and failed (the reason this lane exists): three sessions of near-79/83
SIZE-MISMATCH C drafts on func_800D0440 against a hardcoded -O2 oracle — a feedback loop that cannot
converge (§261); and a 7-oracle-call full lever sweep (polarity flips, goto tails, ternaries, pins,
hoists, rtps nop orders) on the /* Handwritten function */ homonym of func_8017FB04
(ov_SC03_030, 83 ins, rtps/ctc2) whose bgez-with-OR-fallthrough tail no compiler output ever
contains — see Refuted #3 below. Check the handwritten tag and the §261 prologue oracle FIRST;
grep -l 'Handwritten' asm/<ov>/nonmatchings/*/<fn>.s is free.
ACCOUNTING (added at review, P31 S59b). A verbatim-asm body is not an INCLUDE_ASM stub, so
corpus.stubs() — and therefore every progress number derived from it — counts it as MATCHED. That
is a true number about something narrower than the reader assumes (R32/R41): the bytes are proven,
the function is not decompiled. Two exist in the tree today (func_800D0440 @ md_MAIN_003,
func_80185810 @ ov_SC03_105) plus the src/800b2.c wrapper form, so the distortion is currently
negligible — but the §261-stranded population is 116 functions, and banking them this way would move
the headline metric without decompiling a line. Use it for hand-written asm, where no C is the
right answer; for an -O0 C function, the right answer is the -O0 object (§261/§261a) and this lane is
a temporary hold at best. If a future session banks more than a handful this way, split the metric
before the number is quoted anywhere.
Boundary. This banks bytes, not understanding — it is the escape hatch for the §261-stranded
population and hand-written asm only. An ordinary -O2 function that merely resists you is not in
scope; neither is an -O0 function already inside an _o0* object (those bank as real C per §261a and
are STRICTLY easier). Grep bait: verbatim asm, asm body, handwritten, maspsx hex immediate,
decimal immediates, -O0 stranded, .set noreorder body.