diff --git a/tools/psyq_identify.py b/tools/psyq_identify.py index acda4269a..12c304fd5 100644 --- a/tools/psyq_identify.py +++ b/tools/psyq_identify.py @@ -34,33 +34,41 @@ text = b[TLO - VRAM_BASE: THI - VRAM_BASE] twords = [struct.unpack_from("> 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: