refactor: one more step towards arch-agnostic design
[lunaix-os.git] / lunaix-os / scripts / syms_export.py
diff --git a/lunaix-os/scripts/syms_export.py b/lunaix-os/scripts/syms_export.py
new file mode 100644 (file)
index 0000000..af5d901
--- /dev/null
@@ -0,0 +1,86 @@
+import subprocess
+import math
+import re
+
+sym_line = re.compile(r"^(?P<addr>[0-9a-f]+)\s[a-z]\s+F\s+\.[a-z._]+\s+[0-9a-f]+(?P<label>.+)$")
+
+def main(kbin, sym_out, endianness='little', bits=32):
+    assert bits >= 32
+    assert (1 << int(math.log2(bits))) == bits
+
+    b_len = bits // 8
+    result = subprocess.run(["objdump", "--syms", kbin],stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    if result.returncode != 0:
+        print(result.stderr)
+        return
+    
+    def to_native(val: int):
+        return val.to_bytes(b_len, endianness, signed=False)
+    
+    output = result.stdout.split(b'\n')
+    functions = []
+    for l in output:
+        l = l.decode("ascii")
+        if not l:
+            continue
+        
+        mo = sym_line.match(l)
+        if not mo:
+            continue
+
+        mg = mo.groupdict()
+        addr = int(mg["addr"], 16)
+        label = mg["label"].strip() + '\0'
+
+        functions.append((addr, label))
+
+    functions = sorted(functions, key=lambda x: x[0])
+    
+    # struct {
+    #   ptr_t addr;
+    #   unsigned int label_off;
+    # }
+    sym_struct_sz = b_len * 2
+    meta_struct_sz = 4 * 2
+    label_off_base = sym_struct_sz * len(functions) + meta_struct_sz
+    alignment = bytearray([b'\0' for _ in range(b_len - 4)])
+
+    label_off = 0
+    bmask = b_len - 1   
+    text_region = bytearray()
+    null = bytearray(b'\0')
+    with open(sym_out, mode='wb') as f:
+        # struct {
+        #   unsigned int num_entry;
+        #   unsigned int label_off_base;
+        # }
+        f.write(to_native(len(functions)))
+        f.write(to_native(label_off_base))
+
+        for a, l in functions:
+            f.write(to_native(a))
+            f.write(to_native(label_off))
+            f.write(alignment)
+            
+            text_region += bytes(l, 'ascii')
+            aligned_len = (len(l) + bmask) & ~bmask
+            for i in range(aligned_len - len(l)):
+                text_region.append(null[0])
+
+            label_off += aligned_len
+        
+        f.write(text_region)
+
+import argparse
+import sys
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument('elf_exec')
+    parser.add_argument('-o', '--outfile', required=True)
+    parser.add_argument('--bits', default=32)
+    parser.add_argument('--order', default='little')
+
+    args = parser.parse_args()
+
+    main(args.elf_exec, args.outfile, endianness=args.order, bits=int(args.bits))
+