mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
fix(psyq_identify): read .text bytes, not objdump's rendering — 10 more objects located
obj_text_pattern parsed ONE WORD PER DISASSEMBLY LINE, and objdump collapses a run of identical words into a single `...` line. Every collapsed word was silently missing from the pattern, so from the first run onward the pattern was MISALIGNED against the image and find() returned None -- printed as the confident, wrong sentence "not linked by EXE". Measured on 2D_BG0.o (libgs): 3 `...` lines, 520 words parsed for a 526-word object. It was listed as absent while 507 of its 507 non-relocated words match the EXE exactly at 0x8005080C. Any object whose .text holds a run of >=3 identical words was invisible -- to the map the entire library-linking pipeline consumes for placement. That is why 2D_BG0.o was never linked: not excluded by a reason, just invisible. It sits in config/splat.us.exe.yaml under a scattered-.bss exclusion that cannot apply to it, since the object has no .bss section at all. Reading the section bytes and taking relocation offsets from `objdump -r` removes the pretty-printer from the loop (R33). MEASURED: libgs goes from 36/201 to 46/201 objects located.
This commit is contained in:
+32
-24
@@ -34,33 +34,41 @@ text = b[TLO - VRAM_BASE: THI - VRAM_BASE]
|
||||
twords = [struct.unpack_from("<I", text, i)[0] for i in range(0, len(text), 4)]
|
||||
|
||||
def obj_text_pattern(o):
|
||||
"""Return (words, mask) for the object's .text; mask[i]=0 on relocated/jump words.
|
||||
"""Return (words, mask) for the object's `.text`, READ FROM THE SECTION BYTES.
|
||||
|
||||
A data-only object (no `.text` section — e.g. libgs GLOBAL.o, which defines only
|
||||
globals) makes `objdump -j .text` exit non-zero; treat that as an empty .text so the
|
||||
caller's `no-.text` path handles it instead of crashing."""
|
||||
p = subprocess.run(["mipsel-linux-gnu-objdump", "-dr", "-j", ".text", o],
|
||||
capture_output=True, text=True)
|
||||
if p.returncode != 0:
|
||||
return [], []
|
||||
d = p.stdout
|
||||
words, mask = [], []
|
||||
pending_reloc = False
|
||||
for line in d.splitlines():
|
||||
mi = re.match(r"\s+([0-9a-f]+):\s+([0-9a-f]{8})\s", line)
|
||||
if mi:
|
||||
w = int(mi.group(2), 16)
|
||||
words.append(w)
|
||||
# mask jal/j (opcode 2/3) always (R_MIPS_26 target is link-resolved)
|
||||
mask.append(0 if (w >> 26) in (2, 3) else 0xFFFFFFFF)
|
||||
elif "R_MIPS" in line and words:
|
||||
# relocation annotation follows its instruction line -> mask low 16 (hi/lo/pc16)
|
||||
if "_26" in line:
|
||||
mask[-1] = 0
|
||||
else:
|
||||
mask[-1] = 0xFFFF0000
|
||||
WHY NOT `objdump -dr` (P31 S77). The first version parsed one word per DISASSEMBLY LINE, and
|
||||
objdump COLLAPSES a run of identical words into a single `...` line. Every collapsed word was
|
||||
silently missing from the pattern, so from the first run onward the pattern was MISALIGNED
|
||||
against the image and `find` returned None -- reported as the confident, wrong sentence
|
||||
"not linked by EXE".
|
||||
|
||||
Measured on `2D_BG0.o` (libgs): 3 `...` lines, **520 words parsed for a 526-word object**, so
|
||||
it was listed as absent while 507 of its 507 non-relocated words match the EXE exactly at
|
||||
0x8005080C. It had been excluded from the LINKED build under a `.bss` reason that cannot even
|
||||
apply to it -- the object has no `.bss` section at all. Any object whose `.text` holds a run of
|
||||
>=3 identical words was invisible to this map, which is the map the whole library-linking
|
||||
pipeline consumes.
|
||||
|
||||
Reading the section bytes and taking relocation offsets from `objdump -r` removes the rendering
|
||||
from the loop entirely (R33: derive from the bytes, do not re-parse a pretty-printer)."""
|
||||
h = subprocess.run(["mipsel-linux-gnu-objdump", "-h", o], capture_output=True, text=True).stdout
|
||||
m = re.search(r"^\s*\d+\s+\.text\s+([0-9a-f]+)\s+\S+\s+\S+\s+([0-9a-f]+)", h, re.M)
|
||||
if not m:
|
||||
return [], [] # data-only object (e.g. libgs GLOBAL.o)
|
||||
size, off = int(m.group(1), 16), int(m.group(2), 16)
|
||||
blob = open(o, "rb").read()[off:off + size]
|
||||
words = list(struct.unpack("<%dI" % (len(blob) // 4), blob[:len(blob) // 4 * 4]))
|
||||
mask = [0 if (w >> 26) in (2, 3) else 0xFFFFFFFF for w in words] # jal/j always link-resolved
|
||||
rr = subprocess.run(["mipsel-linux-gnu-objdump", "-r", o], capture_output=True, text=True).stdout
|
||||
body = re.search(r"RELOCATION RECORDS FOR \[\.text\]:(.*?)(?=\nRELOCATION RECORDS|\Z)", rr, re.S)
|
||||
if body:
|
||||
for rm in re.finditer(r"^([0-9a-f]+)\s+(R_MIPS_\w+)", body.group(1), re.M):
|
||||
i = int(rm.group(1), 16) // 4
|
||||
if 0 <= i < len(mask):
|
||||
mask[i] = 0 if "_26" in rm.group(2) else 0xFFFF0000
|
||||
return words, mask
|
||||
|
||||
|
||||
def find(words, mask):
|
||||
n = len(words)
|
||||
if n < 2:
|
||||
|
||||
Reference in New Issue
Block a user