Files
BFM-decomp/cookbook/C0127.md
T

3.5 KiB

§116 — Optimization level is a property of the FILE, not the function: read a family 0/N against the member's stub HOME (Phase 29 T79)

family_sweep --hseq templates the exemplar's C into each member's stub file. -O0-ness is applied by the Makefile per object (WHALE_O0B_OBJS, O0_CLUSTER_OBJS, build/src/boot.o, …), so a family whose exemplar was matched at -O0 banks only where the member's stub happens to live in an -O0 object too. Nothing in the sweep, the remap, or the byte-gate reports the mismatch: the draft compiles fine, and the gate correctly rejects 137 subtly-wrong bodies.

0x801457a4 swept 0/137 on exactly this. In ov_SC01_077 the definition sits in ov_SC01_077_o0b.c (the whale -O0 object); in all 137 other overlays the same function's stub sits in <ov>_after.c, which is -O2. Same C, same remap, wrong flag.

The tell, before spending a sweep: find the exemplar's home file and ask whether the Makefile gives that object a non-default CC1FLAGS. If it does, check where the members' stubs live. This is the same class as the Phase-29 Task-1 swing verdict (0x8013c964/0x8013c938 compiled -O2 by the sweep and masked-MATCHing only at -O0) — that one was diagnosed at the compile-flag level; this one shows the flag is really a file-placement question.

The fix moves the DEFINITION, not the stub — and here is why the obvious shortcut fails

A carved -O0 object whose .text ends exactly at the target function's vram can absorb that function by appending it, so the linker places it at the same address either way. That makes "just move the member's INCLUDE_ASM(...) line into the -O0 file" look byte-neutral by construction. It is not even buildable, and the reason is splat, not the linker:

INCLUDE_ASM("asm/<ov>/nonmatchings/<ov>_after", func_X) resolves to a .s file that splat only emits while func_X is INCLUDE_ASM'd in that segment's own .c. Delete the line from <ov>_after.c and the next make extract stops generating asm/<ov>/nonmatchings/<ov>_after/func_X.s — so the relocated reference in <ov>_o0b.c fails assembly with can't open … func_X.s. Verified across all 133 overlays at once (Phase 29 T80).

asm/ layout follows the segment; object membership follows the .c file. Moving a stub line changes the second while silently invalidating the first. ov_SC01_077 gets away with the _o0b placement only because it holds a real definition there — nothing references a .s.

So the rollout is: stage the remapped body into <ov>_o0b.c and drop the INCLUDE_ASM from <ov>_after.c in the same edit, then gate. That is a two-file atomic substitution, which harvest_verify/family_sweep do not do (they substitute a draft for the stub in the stub's own file), so this class needs its own small driver. Still prefer it over a splat re-carve — a re-carve is the Arm-A wall (+0x20 data-symbol shift on 3 of 4 sampled overlays).

The law: a family-wide 0/N whose exemplar lives in a flag-overridden object is a build-graph statement, not a codegen one. Check the object's flags and the members' stub homes before routing it to the permuter or logging it as intrinsic.

The corollary, learned the hard way: "byte-neutral by construction" is a claim about the linker. The build graph has other stages, and splat's asm generation is keyed to a different partition (segment) than the one you are editing (object). Build it before you call it neutral.