From cb7a280994c096814b023ca33e1f60750ee922fa Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Mon, 15 Jun 2026 20:55:28 -0600 Subject: [PATCH] =?UTF-8?q?refactor(phase-9):=20T8a=20=E2=80=94=20de-defau?= =?UTF-8?q?lt=20the=20EXE-curation=20helpers=20(thread=20--exe/--vram-base?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - make_snd_used.py + make_apicard_used.py: argparse --exe/--vram-base (default the EXE's); thread into psyq_identify subprocess + link_object (required post-T8b). RLO/RHI/EXCLUDE_ADDR kept as the EXE's region data (EXE-specific, documented) - gen_lib_subsegs.py: --vram-base/--exe (default EXE); threaded into psyq_identify and the pos->fileoff arithmetic (module VRAM_BASE constant removed) - split_src_region.py: --symbols overrides SYMS_PATH (default the EXE's symbols.us.txt) - checks: snd_used (60) + apicard_used (22) regenerate BYTE-IDENTICAL; gen_lib_subsegs libgte -> 22 blocks/53 objs; clean build -> 143dbb89 --- tools/gen_lib_subsegs.py | 35 ++++++++++++++++++++++------------- tools/make_apicard_used.py | 21 ++++++++++++++++----- tools/make_snd_used.py | 22 +++++++++++++++++----- tools/split_src_region.py | 12 ++++++++---- 4 files changed, 63 insertions(+), 27 deletions(-) diff --git a/tools/gen_lib_subsegs.py b/tools/gen_lib_subsegs.py index ed868c7521..e57358d4cd 100644 --- a/tools/gen_lib_subsegs.py +++ b/tools/gen_lib_subsegs.py @@ -28,13 +28,12 @@ import os, re, subprocess, sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from psyq_link import section_table # noqa: E402 -VRAM_BASE = 0x8000F800 - -def placements(elf_dir, win): +def placements(elf_dir, win, vram_base, exe): cmd = ["python3", "tools/psyq_identify.py", elf_dir] if win: cmd += [f"0x{win[0]:X}", f"0x{win[1]:X}"] + cmd += ["--vram-base", hex(vram_base), "--exe", exe] objs = [] for ln in subprocess.check_output(cmd, text=True).splitlines(): m = re.match(r"\s+0x([0-9A-Fa-f]+)\s+(\S+\.o)\s+\((\d+) ins\)", ln) @@ -56,13 +55,23 @@ def contiguous_blocks(objs): def main(): - if len(sys.argv) not in (6, 8): - sys.exit(__doc__) - elf_dir, libbase, gamebase = sys.argv[1], sys.argv[2], sys.argv[3] - rlo, rhi = int(sys.argv[4], 0), int(sys.argv[5], 0) - win = (int(sys.argv[6], 0), int(sys.argv[7], 0)) if len(sys.argv) == 8 else None + import argparse + ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("elf_dir") + ap.add_argument("libbase") + ap.add_argument("gamebase") + ap.add_argument("region_lo") + ap.add_argument("region_hi") + ap.add_argument("window", nargs="*", help="optional placement window: win_lo win_hi") + ap.add_argument("--vram-base", default="0x8000F800", help="fileoff->vram delta (EXE default)") + ap.add_argument("--exe", default="extracted/retail/SLUS_007.26", help="target binary (EXE default)") + a = ap.parse_args() + elf_dir, libbase, gamebase = a.elf_dir, a.libbase, a.gamebase + rlo, rhi = int(a.region_lo, 0), int(a.region_hi, 0) + win = (int(a.window[0], 0), int(a.window[1], 0)) if len(a.window) >= 2 else None + vram_base = int(a.vram_base, 0) - objs = placements(elf_dir, win) + objs = placements(elf_dir, win, vram_base, a.exe) inreg = [o for o in objs if rlo <= o[0] < rhi] skipped = [o for o in objs if not (rlo <= o[0] < rhi)] if not inreg: @@ -88,18 +97,18 @@ def main(): for lo, hi, b in ranges: if lo > pos: nm = gname() - out.append(f" - [0x{pos - VRAM_BASE:X}, c, {nm}]" - f" # game code (vram 0x{VRAM_BASE + (pos - VRAM_BASE):08X}-0x{lo:08X})") + out.append(f" - [0x{pos - vram_base:X}, c, {nm}]" + f" # game code (vram 0x{vram_base + (pos - vram_base):08X}-0x{lo:08X})") li += 1 sub = f"{libbase}{li}" stubs.append(sub) names = f"{b[0][1]}..{b[-1][1]}" if len(b) > 1 else b[0][1] - out.append(f" - [0x{lo - VRAM_BASE:X}, c, {sub}]" + out.append(f" - [0x{lo - vram_base:X}, c, {sub}]" f" # {libbase} block {li}: {len(b)} obj ({names}) vram 0x{lo:08X}-0x{hi:08X}") pos = hi if pos < rhi: nm = gname() - out.append(f" - [0x{pos - VRAM_BASE:X}, c, {nm}]" + out.append(f" - [0x{pos - vram_base:X}, c, {nm}]" f" # game code (vram 0x{pos:08X}-0x{rhi:08X})") print("\n".join(out)) diff --git a/tools/make_apicard_used.py b/tools/make_apicard_used.py index a4f3407444..3ef9b44c21 100644 --- a/tools/make_apicard_used.py +++ b/tools/make_apicard_used.py @@ -11,22 +11,32 @@ from collections import defaultdict sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from psyq_link import link_object # noqa: E402 +# EXE-curation tool: --exe/--vram-base default to the retail EXE's (threaded into psyq_identify + +# link_object, which require them post-T8). RLO/RHI are the EXE's 800c2 region (EXE-specific). EXE = "extracted/retail/SLUS_007.26" +VRAM_BASE = 0x8000F800 RLO, RHI = 0x80061F38, 0x80062888 -def place(lib): - out = subprocess.check_output(["python3", "tools/psyq_identify.py", f".run/obj40/{lib}"], text=True) +def place(lib, exe, vram_base): + out = subprocess.check_output(["python3", "tools/psyq_identify.py", f".run/obj40/{lib}", + "--vram-base", hex(vram_base), "--exe", exe], text=True) return {m.group(2): int(m.group(1), 16) for ln in out.splitlines() if (m := re.match(r"\s+0x([0-9A-Fa-f]+)\s+(\S+\.o)\s+\((\d+) ins\)", ln))} def main(): - exe = open(EXE, "rb").read() + import argparse + ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("--exe", default=EXE) + ap.add_argument("--vram-base", default=hex(VRAM_BASE)) + args = ap.parse_args() + exe_path, vram_base = args.exe, int(args.vram_base, 0) + exe = open(exe_path, "rb").read() byaddr = defaultdict(list) for lib in ("libapi", "libcard"): - for nm, a in place(lib).items(): + for nm, a in place(lib, exe_path, vram_base).items(): byaddr[a].append((lib, nm)) dst = ".run/obj40/apicard_used" shutil.rmtree(dst, ignore_errors=True) @@ -36,7 +46,8 @@ def main(): if not (RLO <= a < RHI): continue lib, nm = next(((l, m) for l, m in byaddr[a] - if link_object(f".run/obj40/{l}/{m}", a, name=m, exe_bytes=exe)["ok"]), + if link_object(f".run/obj40/{l}/{m}", a, name=m, exe_bytes=exe, + vram_base=vram_base)["ok"]), byaddr[a][0]) shutil.copy(f".run/obj40/{lib}/{nm}", f"{dst}/{nm}") n += 1 diff --git a/tools/make_snd_used.py b/tools/make_snd_used.py index 747817fa21..da021b45da 100644 --- a/tools/make_snd_used.py +++ b/tools/make_snd_used.py @@ -22,13 +22,18 @@ from collections import defaultdict sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from psyq_link import link_object # noqa: E402 +# EXE-curation tool: --exe/--vram-base default to the retail EXE's values (threaded explicitly into +# psyq_identify + link_object, which require them post-T8). RLO/RHI/EXCLUDE_ADDR are the EXE's sound +# region + the 4 unreconcilable addresses (EXE-specific; an overlay would supply its own). EXE = "extracted/retail/SLUS_007.26" +VRAM_BASE = 0x8000F800 RLO, RHI = 0x8003A444, 0x8004239C EXCLUDE_ADDR = {0x8003C438, 0x8003D424, 0x8003D94C, 0x8003FA64} # see module docstring -def place(lib): - out = subprocess.check_output(["python3", "tools/psyq_identify.py", f".run/obj40/{lib}"], text=True) +def place(lib, exe, vram_base): + out = subprocess.check_output(["python3", "tools/psyq_identify.py", f".run/obj40/{lib}", + "--vram-base", hex(vram_base), "--exe", exe], text=True) d = {} for ln in out.splitlines(): m = re.match(r"\s+0x([0-9A-Fa-f]+)\s+(\S+\.o)\s+\((\d+) ins\)", ln) @@ -38,10 +43,16 @@ def place(lib): def main(): - exe = open(EXE, "rb").read() + import argparse + ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("--exe", default=EXE) + ap.add_argument("--vram-base", default=hex(VRAM_BASE)) + args = ap.parse_args() + exe_path, vram_base = args.exe, int(args.vram_base, 0) + exe = open(exe_path, "rb").read() byaddr = defaultdict(list) for lib in ("libspu", "libsnd"): - for nm, a in place(lib).items(): + for nm, a in place(lib, exe_path, vram_base).items(): byaddr[a].append((lib, nm)) dst = ".run/obj40/snd_used" @@ -53,7 +64,8 @@ def main(): continue cands = byaddr[a] pick = next(((lib, nm) for lib, nm in cands - if link_object(f".run/obj40/{lib}/{nm}", a, name=nm, exe_bytes=exe)["ok"]), + if link_object(f".run/obj40/{lib}/{nm}", a, name=nm, exe_bytes=exe, + vram_base=vram_base)["ok"]), cands[0]) lib, nm = pick shutil.copy(f".run/obj40/{lib}/{nm}", f"{dst}/{nm}") diff --git a/tools/split_src_region.py b/tools/split_src_region.py index 6ea3539d10..a1c10b86a4 100644 --- a/tools/split_src_region.py +++ b/tools/split_src_region.py @@ -145,10 +145,14 @@ def inject(dstpath, movepath): def main(): - if len(sys.argv) >= 5 and sys.argv[1] == "trim": - trim(sys.argv[2], int(sys.argv[3], 0), int(sys.argv[4], 0), sys.argv[5]) - elif len(sys.argv) == 4 and sys.argv[1] == "inject": - inject(sys.argv[2], sys.argv[3]) + global SYMS_PATH + args = sys.argv[1:] + if "--symbols" in args: # Phase 9: per-binary symbol file (default = the EXE's) + k = args.index("--symbols"); SYMS_PATH = args[k + 1]; del args[k:k + 2] + if len(args) >= 5 and args[0] == "trim": + trim(args[1], int(args[2], 0), int(args[3], 0), args[4]) + elif len(args) == 3 and args[0] == "inject": + inject(args[1], args[2]) else: sys.exit(__doc__)