#!/usr/bin/env python3 # # Generate the jsix style symbol table. The format in memory of this table # is as follows: # # : 8 bytes # : 24 * N bytes # : variable # # Each index entry has the format # : 8 bytes # : 8 bytes # : 8 bytes # # Name offsets are from the start of the symbol table as a whole. (ie, # where is located.) import re sym_re = re.compile(r'([0-9a-fA-F]{16}) ([0-9a-fA-F]{16} )?[tTvVwW] (.*)') def parse_syms(infile): """Take the output of the `nm` command, and parse it into a tuple representing the symbols in the text segment of the binary. Returns a list of (address, symbol_name).""" syms = [] for line in sys.stdin: match = sym_re.match(line) if not match: continue addr = int(match.group(1), base=16) size = int(match.group(2) or "0", base=16) name = match.group(3) if size == 0: if not "." in name: print(f"SYMBOL WARNING: zero size for symbol {name}") continue syms.append([addr, size, name, 0]) return syms def write_table(syms, outfile): """Write the given symbol table as generated by parse_syms() to the outfile, index first, and then name character data.""" import struct outfile.write(struct.pack("@Q", len(syms))) index_pos = outfile.tell() outfile.seek(struct.calcsize("@QQQ") * len(syms), 1) nul = b'\0' for s in syms: s[3] = outfile.tell() outfile.write(s[2].encode('utf-8')) outfile.write(nul) outfile.seek(index_pos) for s in syms: addr = s[0] size = s[1] pos = s[3] outfile.write(struct.pack("@QQQ", addr, size, pos)) return len(syms) if __name__ == "__main__": import sys if len(sys.argv) != 2: print(f"Usage: nm -n -S --demangle | {sys.argv[0]} ") sys.exit(1) syms = 0 size = 0 with open(sys.argv[1], "wb") as outfile: syms = write_table(parse_syms(sys.stdin), outfile) outfile.seek(0, 2) size = outfile.tell() print(f"Wrote {syms} symbols ({size/1024:.1f} KiB) to {sys.argv[1]}.")