Files
BFM-decomp/cookbook/C0286.md
T

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:

  1. 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, at src/md_MAIN_003/md_MAIN_003.c:329). Precedent: func_80185810 (src/ov_SC03_105/ov_SC03_105_jr_8017C8D0.c:5493).
  2. 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, at src/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 is invalid literal for int() with base 10: '0x20'. Every immediate must be decimal (65535, -40, 24). %hi(SYM)/%lo(SYM) and bare jal <sym> work and relocate correctly.
  • Transcribe verbatim, model nothing. The -O0 $fp prologue, every delay-slot nop, and fake frames all stay: func_800CBA44 carries a mid-body addiu $sp,-8 + lw 0x18/0x1C($sp) whose only purpose is reloading stack args 5/6 and hosting cfc2 flag 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.