3.1 KiB
§440 ★★★ — A .rodata CARVE PIECE BINDS TO A SUBSEG, NOT TO A FUNCTION: EXTEND THE CARVE INSTEAD OF ISOLATING (P31 S74; 6 banked, resident included)
§8b's "non-adjacent tables → ISOLATE the function into its own subseg" is over-strict. A carve
piece attaches to a code SUBSEG, and that object's .rodata is the address-ordered concatenation of
- cc1's tables for the functions in it that are banked, and
- still-stubbed functions' migrated tables,
.included by theirINCLUDE_ASMin source order.
So a span may legitimately hold a MIX, and a carve may be EXTENDED across material that belongs to
functions nobody has drafted yet. Measured: extending ov_SC06_029_jr_8017C954's carve across an
align-pad word and two unrelated still-stubbed tables was byte-identical with nothing banked, and
then took two banks — where the tooling had demanded a jr-isolation.
Four corollaries, each byte-proven:
- Migrated tables self-align. spimdisasm emits the block's
.align 3iff the table's span-relative offset is 8-aligned (+0x0got one;+0x3cand+0xb4did not;+0xc8got one and reproduced the retail zero word at+0xc4). So a stubbed table needs no spec entry. JTBL_PADScounts cc1 tables ONLY (the filter keys on.align 3followed by$L), so a mixed span's spec grows as each sibling banks:0,0,4,4→0,0,4,4,0→0,0,4,4,0t1,0.- The zero-word rule (§8e) is INVALID across a migrated boundary — the word before the entry is
zero, but that zero is supplied by the preceding migrated block, so the lead entry is
0, not4. - A covered table at a 4-mod-8 span offset gains 4 bytes when it banks, because cc1 always emits
.align 3. That is thecovered-tpadcase: bankable, but it needs a0t<n>spec entry.
And the verdict that hid all of this. A table already inside a carve bound to its own subseg
needs no carve work at all — in stub state the migrated block fills the piece exactly, and banking
swaps it for cc1's identical one. island_probe classified such a function tail on the table's
ADDRESS; apply() sent it to build_carve, which resolves spans out of the RAW data asm where a
carved table no longer is; harvest_verify booked CARVE-REFUSED. That is a verdict about the
route we chose, not about the function (R43). jtbl_carve now has covered / covered-tpad
verdicts and treats a fully-covered batch as a no-op.
THE RESIDENT CAN CARVE LIKE AN OVERLAY — its three tables are adjacent and lead its island
(0x450e0..0x451ac, one span, subseg resident). The new part is the layout: the resident opens
with - [0x0, rodata, hdr], a 1-word .rodata header BEFORE the code, so it is
rodata → text → data → rodata(carve) → data. ld_interleave --order cannot express that — every
listed piece is emitted after TEXT_START, so hdr.rodata.o(.rodata) lands in the unchecked empties
bucket, is parked after the text, and moves every byte. --pre places a leading-rodata piece ahead
of the text; resident_JTBL_INTERLEAVE := --pre hdr.rodata.o --order tail.data.o,resident.o,tail2.data.o.