mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-03 16:16:50 -04:00
fix(phase-30 S48-0b): JTBL_PADS follows its span through jr isolation
The 0b blocker was not "the pads line is left behind" alone — it fails two different ways, and the second one is silent: * bare isolate + `make build`: the stale line arms the pads filter on the RESIDUAL object, which emits no jump table -> `jtbl_rodata_pads: consumed 0 rodata .align(s) but 4 pad spec(s) given` (S47). * isolate -> jtbl_carve (the jtbl_family_bank path): `set_pads_vars` regenerates the block keyed by the CURRENT subseg names, finds no prior spec under the new `_jr_<addr>` name, and DROPS the line. cc1's natural `.align 3` then pads the span's non-8-aligned interior tables and the image shifts — reported only as `built, bytes differ`. - jr_isolate_all.repoint_overlays_mk: repoint the `build/src/<ov>/<sub>.o: JTBL_PADS` target with the `--order` leaf whenever a carve moves; refuse loud if the old object still hosts a .rodata piece (R32). - jtbl_carve.set_pads_vars: second, disagreeing oracle (R34) — refuse when a spec would vanish for a subseg no longer in the carve set (rename/merge drift), instead of silently emitting a padless object. R37 probe: func_801789AC -> ov_SC02_037 went `built, bytes differ` -> BANKED on the whole-binary byte gate. ov_SC02_037's spec is 0,0,0,0 over tables +0x0,+0x14,+0x34,+0x4c — load-bearing (span start is 4 mod 8).
This commit is contained in:
+2
-2
@@ -4938,8 +4938,8 @@ ov_SC02_037_ELF := $(ov_SC02_037_OUT).elf
|
||||
ov_SC02_037_MAPFILE := $(ov_SC02_037_OUT).map
|
||||
ov_SC02_037_LD_SCRIPT := $(ov_SC02_037_OUT).ld
|
||||
ov_SC02_037_SPLAT_YAML := config/splat.ov_SC02_037.yaml
|
||||
ov_SC02_037_JTBL_INTERLEAVE := --order tail.data.o,ov_SC02_037.o,tail2.data.o,trailing.o # Phase-26 §8 jtbl-rodata carve
|
||||
build/src/ov_SC02_037/ov_SC02_037.o: JTBL_PADS := 0,0,0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x14,+0x34,+0x4c
|
||||
ov_SC02_037_JTBL_INTERLEAVE := --order tail.data.o,ov_SC02_037_jr_801789AC.o,tail2.data.o,ov_SC02_037_jr_8017AE2C.o,tail3.data.o,trailing.o # Phase-26 §8 jtbl-rodata carve
|
||||
build/src/ov_SC02_037/ov_SC02_037_jr_8017AE2C.o: JTBL_PADS := 0,0,0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x14,+0x34,+0x4c
|
||||
ov_SC02_037_CHECK_SHA := config/check.ov_SC02_037.sha
|
||||
ov_SC02_037_SYMBOLS := config/symbols.ov_SC02_037.txt
|
||||
ov_SC02_037_SIG := .run/sig.ov_SC02_037.jsonl
|
||||
|
||||
@@ -93,10 +93,14 @@ segments:
|
||||
# shift the code start. Mark it `rodata` (section_order places .rodata first) so it lands at
|
||||
# 0x80128158 ahead of the code, a 1-word analogue of main's rodata-island (no ld_interleave).
|
||||
# - [0x0, rodata, head]
|
||||
- [0x0, c, ov_SC02_037] # code: starts at file 0x0 (overlays open with a prologue)
|
||||
- [0x0, c, ov_SC02_037]
|
||||
- [0x50854, c, ov_SC02_037_jr_801789AC]
|
||||
- [0x52cd4, c, ov_SC02_037_jr_8017AE2C]
|
||||
- [0x5ba68, data, tail]
|
||||
- [0xa01d4, .rodata, ov_SC02_037] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py)
|
||||
- [0xa0238, data, tail2]
|
||||
- [0x9ff24, .rodata, ov_SC02_037_jr_801789AC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py)
|
||||
- [0x9ff3c, data, tail2]
|
||||
- [0xa01d4, .rodata, ov_SC02_037_jr_8017AE2C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py)
|
||||
- [0xa0238, data, tail3]
|
||||
- [0xA198C, bin, trailing] # final 3 bytes (EOF not 4-aligned; spimdisasm drops a partial word)
|
||||
- [0xA198F] # EOF marker = the 0.4.dec byte length
|
||||
# @TRAILING@ (above) is replaced by tools/new_overlay.sh: for a non-4-aligned overlay it becomes
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+37
-5
@@ -535,7 +535,26 @@ def _render_region(header, items, old_sub, new_sub, ambient):
|
||||
return "\n".join(parts) + "\n"
|
||||
|
||||
|
||||
def repoint_overlays_mk(carve_renames, dry):
|
||||
def repoint_overlays_mk(carve_renames, dry, ov=None, cfg_lines=None):
|
||||
"""Repoint both overlays.mk consumers of a renamed carve object: the `--order` leaf AND the
|
||||
§8e `JTBL_PADS` target var.
|
||||
|
||||
THE PADS LINE MUST FOLLOW ITS SPAN (P30 S48, the 0b blocker). A multi-table span's pad spec is
|
||||
keyed by the OBJECT that emits the tables, so when isolation moves the span's owner into
|
||||
`<ov>_jr_<addr>` the spec has to move with it. Leaving it behind fails TWO different ways, both
|
||||
observed on ov_SC02_037's 4-table span (spec `0,0,0,0`, tables +0x0,+0x14,+0x34,+0x4c):
|
||||
* plain `make build` after a bare isolate -> the stale line arms the pads filter on the
|
||||
residual object, which now emits NO jump table:
|
||||
`jtbl_rodata_pads: consumed 0 rodata .align(s) but 4 pad spec(s) given` (S47, hard error);
|
||||
* the jtbl_family_bank path (isolate -> jtbl_carve) -> `set_pads_vars` regenerates the block
|
||||
keyed by the CURRENT subseg names, finds no prior spec under the new name, and the line is
|
||||
SILENTLY DROPPED. cc1's natural `.align 3` then pads the span's non-8-aligned interior
|
||||
tables (+4 before table 2 here) and the image shifts: `built, bytes differ`.
|
||||
Byte-neutral: only the target NAME changes; the spec and its `tables=` record are untouched.
|
||||
|
||||
Fails loud (R32) if the old object still hosts a `.rodata` piece — then the line is ambiguous
|
||||
(jtbl_carve's invariant is one contiguous .rodata run per object, so this should be
|
||||
unreachable; if it ever fires, the carve set is the thing to fix, not this rename)."""
|
||||
mk = os.path.join(REPO, "config/overlays.mk")
|
||||
txt = open(mk).read()
|
||||
changed = []
|
||||
@@ -543,7 +562,20 @@ def repoint_overlays_mk(carve_renames, dry):
|
||||
pat = rf'(--order[^#\n]*?){re.escape(old_sub)}\.o'
|
||||
if re.search(pat, txt):
|
||||
txt = re.sub(pat, lambda m: m.group(1) + new_sub + ".o", txt, count=1)
|
||||
changed.append(f"{old_sub}.o -> {new_sub}.o")
|
||||
changed.append(f"--order {old_sub}.o -> {new_sub}.o")
|
||||
if ov is None:
|
||||
continue
|
||||
pads_pat = rf'^(build/src/{re.escape(ov)}/){re.escape(old_sub)}(\.o: JTBL_PADS := )'
|
||||
if not re.search(pads_pat, txt, re.M):
|
||||
continue
|
||||
if cfg_lines is not None and any(
|
||||
re.match(rf'^\s*- \[0x[0-9A-Fa-f]+,\s*\.rodata,\s*{re.escape(old_sub)}\]', ln)
|
||||
for ln in cfg_lines):
|
||||
sys.exit(f"jr_isolate_all: {old_sub} has a JTBL_PADS line AND still hosts a .rodata "
|
||||
f"carve after the split — refusing to repoint the spec to {new_sub} (R32). "
|
||||
f"One object must own at most one contiguous .rodata run.")
|
||||
txt = re.sub(pads_pat, lambda m: m.group(1) + new_sub + m.group(2), txt, count=1, flags=re.M)
|
||||
changed.append(f"JTBL_PADS {old_sub}.o -> {new_sub}.o")
|
||||
if not dry:
|
||||
open(mk, "w").write(txt)
|
||||
return changed
|
||||
@@ -588,10 +620,10 @@ def main():
|
||||
f"subseg lines from an un-reverted isolation — `git diff config/splat.{a.ov}.yaml` "
|
||||
f"and clean it first.")
|
||||
seen_off, seen_nm = off, seen_nm | {nm}
|
||||
mk_changes = repoint_overlays_mk(carve_renames, dry=True)
|
||||
mk_changes = repoint_overlays_mk(carve_renames, dry=True, ov=a.ov, cfg_lines=cfg_lines)
|
||||
print(f" -> {len(new_files)} region .c files; carve repoints: {carve_renames or '(none)'}")
|
||||
for c in mk_changes:
|
||||
print(f" overlays.mk --order: {c}")
|
||||
print(f" overlays.mk: {c}")
|
||||
|
||||
if a.dry_run:
|
||||
print(" [dry-run] no files written.")
|
||||
@@ -605,7 +637,7 @@ def main():
|
||||
# shadow nothing since we overwrite region 0 to the same path). Write all region files:
|
||||
for path, content in new_files.items():
|
||||
open(path, "w").write(content)
|
||||
repoint_overlays_mk(carve_renames, dry=False)
|
||||
repoint_overlays_mk(carve_renames, dry=False, ov=a.ov, cfg_lines=cfg_lines)
|
||||
print(f" wrote config + {len(new_files)} region files + overlays.mk. Run `make extract "
|
||||
f"BINARY={a.ov} && make build BINARY={a.ov}` to byte-gate (R22).")
|
||||
|
||||
|
||||
@@ -721,6 +721,21 @@ def set_pads_vars(ov, pads_map):
|
||||
txt = open(mk).read()
|
||||
before = current_pads_specs(ov, txt)
|
||||
after = {sub: sr for sub, sr in pads_map.items() if len(sr[0]) > 1}
|
||||
# SECOND, DISAGREEING ORACLE (R34; P30 S48). The carry above is keyed by SUBSEG NAME, so a span
|
||||
# whose owning object was RENAMED (jr_isolate_all moving it into `<ov>_jr_<addr>`) looks like a
|
||||
# span with no prior spec and its line is dropped — silently, and never byte-neutral: the pads
|
||||
# exist precisely because cc1's `.align 3` would otherwise pad a non-8-aligned interior table
|
||||
# (measured on ov_SC02_037: spec 0,0,0,0 lost => `built, bytes differ`). A spec may legitimately
|
||||
# disappear only when its span is re-derived to a single table; if the SUBSEG ITSELF is gone from
|
||||
# the carve set, the loss is drift, not derivation. jr_isolate_all now repoints the line with the
|
||||
# span, so this should be unreachable — it is here because the failure mode is a silent byte diff.
|
||||
live_subs = set(re.findall(r"- \[0x[0-9A-Fa-f]+,\s*\.rodata,\s*(\w+)\]", open(cfg_path(ov)).read()))
|
||||
vanished = [s for s in before if s not in after and s not in live_subs]
|
||||
if vanished:
|
||||
sys.exit(f"jtbl_carve: JTBL_PADS spec(s) for {vanished} would VANISH — their subseg is no "
|
||||
f"longer in {ov}'s carve set, so the spec was not re-derived, it was LOST (R32/R34). "
|
||||
f"If the object was renamed, repoint the line to the new object; if two spans "
|
||||
f"merged, fold the `tables=` starts into the surviving line first.")
|
||||
# drop all current lines for this overlay, then insert the regenerated block
|
||||
txt = re.sub(pads_line_re(ov) + r"\n", "", txt, flags=re.M)
|
||||
if after:
|
||||
|
||||
Reference in New Issue
Block a user