mirror of
https://github.com/HeyPuter/gex.git
synced 2026-11-13 20:12:43 -10:00
gexcc-rpath prints or replaces a module's run path (dylink.0's runtime path), in place and at the same size, as meson's depfixer does an ELF's DT_RUNPATH at install. gexcc-objdump -p prints it as RUNPATH, so dpkg-shlibdeps finds a library in a directory the run path names. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_c8c04c00da9a4525ab21b0b9f146c598
137 lines
4.9 KiB
Python
Executable File
137 lines
4.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""objdump for gexcc's output. A wasm side module (a shared library or
|
|
program built with GEXCC_SHARED=1) is described the way GNU objdump
|
|
describes an ELF shared object, for the tools that read that (Debian's
|
|
dh_makeshlibs and dpkg-shlibdeps, libtool):
|
|
|
|
-f the file format line (elf32-wasm32)
|
|
-p the dynamic section: NEEDED and RUNPATH (dylink.0) and SONAME (the
|
|
module name)
|
|
-T the dynamic symbols: exports defined, env imports *UND*
|
|
-w and -R are accepted (no relocation records), -x is -fpT
|
|
|
|
Anything else, or any other file, goes to llvm-objdump.
|
|
"""
|
|
import os, sys
|
|
|
|
|
|
def leb(w, p):
|
|
r = sh = 0
|
|
while True:
|
|
x = w[p]; p += 1
|
|
r |= (x & 0x7f) << sh; sh += 7
|
|
if not x & 0x80:
|
|
return r, p
|
|
|
|
|
|
def name(w, p):
|
|
n, p = leb(w, p)
|
|
return w[p:p + n].decode('utf-8', 'replace'), p + n
|
|
|
|
|
|
def describe(path):
|
|
"""(soname, needed, runpath, defined [(name, kind)], undefined [name])
|
|
of a side module, or None for anything else."""
|
|
try:
|
|
w = open(path, 'rb').read()
|
|
except OSError:
|
|
return None
|
|
if w[:4] != b'\0asm':
|
|
return None
|
|
soname, needed, runpath, defined, undefined, dylink = None, [], [], [], [], False
|
|
p = 8
|
|
while p < len(w):
|
|
sid = w[p]; n, q = leb(w, p + 1); end = q + n
|
|
if sid == 0:
|
|
nm, q = name(w, q)
|
|
if nm == 'dylink.0':
|
|
dylink = True
|
|
while q < end:
|
|
kind = w[q]; ln, q = leb(w, q + 1); sub_end = q + ln
|
|
if kind == 2: # WASM_DYLINK_NEEDED
|
|
cnt, r = leb(w, q)
|
|
for _ in range(cnt):
|
|
lib, r = name(w, r); needed.append(lib)
|
|
elif kind == 5: # WASM_DYLINK_RUNTIME_PATH
|
|
cnt, r = leb(w, q)
|
|
for _ in range(cnt):
|
|
d, r = name(w, r); runpath.append(d)
|
|
q = sub_end
|
|
elif nm == 'name' and w[q] == 0: # module name
|
|
_, r = leb(w, q + 1)
|
|
soname, _ = name(w, r)
|
|
elif sid == 2:
|
|
cnt, q = leb(w, q)
|
|
for _ in range(cnt):
|
|
m, q = name(w, q); f, q = name(w, q)
|
|
kind = w[q]; q += 1
|
|
if kind == 0:
|
|
_, q = leb(w, q)
|
|
if m == 'env' or m == 'GOT.func':
|
|
undefined.append(f)
|
|
elif kind == 1:
|
|
q += 1; fl, q = leb(w, q); _, q = leb(w, q)
|
|
if fl & 1:
|
|
_, q = leb(w, q)
|
|
elif kind == 2:
|
|
fl, q = leb(w, q); _, q = leb(w, q)
|
|
if fl & 1:
|
|
_, q = leb(w, q)
|
|
elif kind == 3:
|
|
q += 2
|
|
elif kind == 4:
|
|
q += 1; _, q = leb(w, q)
|
|
elif sid == 7:
|
|
cnt, q = leb(w, q)
|
|
for _ in range(cnt):
|
|
f, q = name(w, q)
|
|
kind = w[q]; q += 1
|
|
_, q = leb(w, q)
|
|
if kind in (0, 3) and not f.startswith('__'):
|
|
defined.append((f, kind))
|
|
p = end
|
|
if not dylink:
|
|
return None
|
|
return soname or os.path.basename(path), needed, runpath, defined, sorted(set(undefined))
|
|
|
|
|
|
def main():
|
|
args = sys.argv[1:]
|
|
flags, files, ok = set(), [], True
|
|
for a in args:
|
|
if a.startswith('--'):
|
|
ok = False
|
|
elif a.startswith('-'):
|
|
flags |= set(a[1:])
|
|
else:
|
|
files.append(a)
|
|
descs = [describe(f) for f in files]
|
|
if not ok or not files or not flags or flags - set('fpTwRx') or any(d is None for d in descs):
|
|
os.execvp('llvm-objdump', ['llvm-objdump'] + args)
|
|
if 'x' in flags:
|
|
flags |= set('fpT')
|
|
out = []
|
|
for f, (soname, needed, runpath, defined, undefined) in zip(files, descs):
|
|
out.append('\n%s: file format elf32-wasm32\n' % f)
|
|
if 'f' in flags:
|
|
out.append('architecture: wasm32, flags 0x00000150:\nHAS_SYMS, DYNAMIC, D_PAGED\nstart address 0x00000000\n')
|
|
if 'p' in flags:
|
|
out.append('Dynamic Section:')
|
|
out += [' NEEDED %s' % n for n in needed]
|
|
out.append(' SONAME %s' % soname)
|
|
if runpath:
|
|
out.append(' RUNPATH %s' % ':'.join(runpath))
|
|
out.append('')
|
|
if 'T' in flags:
|
|
out.append('DYNAMIC SYMBOL TABLE:')
|
|
for s in undefined:
|
|
out.append('00000000 DF *UND*\t00000000 Base %s' % s)
|
|
for s, kind in defined:
|
|
out.append('00000000 g %s .%s\t00000000 Base %s' % ('DF' if kind == 0 else 'DO',
|
|
'text' if kind == 0 else 'data', s))
|
|
out.append('')
|
|
sys.stdout.write('\n'.join(out) + '\n')
|
|
|
|
|
|
main()
|