diff python/ppci/linker.py @ 335:582a1aaa3983

Added long branch format
author Windel Bouwman
date Mon, 17 Feb 2014 20:41:30 +0100
parents 6f4753202b9a
children d1ecc493384e
line wrap: on
line diff
--- a/python/ppci/linker.py	Thu Feb 13 22:02:08 2014 +0100
+++ b/python/ppci/linker.py	Mon Feb 17 20:41:30 2014 +0100
@@ -1,19 +1,112 @@
 
+import struct
 from .objectfile import ObjectFile
+from . import CompilerError
+
+def align(x, m):
+    while ((x % m) != 0):
+        x = x + 1
+    return x
+
+def wrap_negative(x, bits):
+    b = struct.unpack('<I', struct.pack('<i', x))[0]
+    mask = (1 << bits) - 1
+    return b & mask
+
+reloc_map = {}
+
+def reloc(t):
+    def f(c):
+        reloc_map[t] = c
+    return f
+
+
+@reloc('lit_add_8')
+class LitAdd8:
+    def apply(self):
+        pass
+
 
 class Linker:
     def set_symbol(self, sym):
-        self.dst.add_symbol(sym.name, sym.value)
+        self.dst.add_symbol(sym.name, sym.value, sym.section)
 
     def link(self, objs):
+        # Create new object file to store output:
         self.dst = ObjectFile()
+        self.dst.get_section('code').address = 0x08000000
+
         # First copy all sections into output sections:
         for iobj in objs:
-            for sym in iobj.symbols:
-                print(sym)
+            offsets = {}
+            # Merge sections:
+            for in_s in iobj.sections.values():
+                out_s = self.dst.get_section(in_s.name)
+                offsets[in_s.name] = out_s.address + out_s.Size
+                out_s.add_data(in_s.data)
+                # TODO: align section
+
+            # Merge symbols:
+            for sym in iobj.symbols.values():
                 self.set_symbol(sym)
-        # Do relocations:
-        # TODO
+
+            # Merge relocations:
+            for reloc in iobj.relocations:
+                self.dst.add_relocation(reloc.sym, reloc.offset, reloc.typ, reloc.section)
+
         # Check that there are no more unresolved symbols:
-        # TODO
+        # Perform relocations:
+        for reloc in self.dst.relocations:
+            # Lookup symbol:
+            if reloc.sym not in self.dst.symbols:
+                raise CompilerError('Undefined reference "{}"'.format(reloc.sym))
+            sym = self.dst.symbols[reloc.sym]
+            # patch up:
+            section = self.dst.get_section(reloc.section)
+
+            if reloc.typ == 'lit_add_8':
+                assert sym.value % 4 == 0
+                offset = (sym.value - (align(reloc.offset + 2, 4)))
+                assert offset in range(0, 1024, 4)
+                rel8 = offset >> 2
+                section.data[reloc.offset] = rel8
+            elif reloc.typ == 'wrap_new11':
+                offset = sym.value - (align(reloc.offset, 2) + 4)
+                assert offset in range(-2048, 2046, 2)
+                imm11 = wrap_negative(offset >> 1, 11)
+                section.data[reloc.offset] = (imm11 & 0xff)
+                section.data[reloc.offset + 1] |= (imm11 >> 8) & 0x7
+            elif reloc.typ == 'rel8':
+                assert sym.value % 2 == 0
+                offset = sym.value - (align(reloc.offset, 2) + 4)
+                assert offset in range(-256, 254, 2), str(offset) + str(reloc)
+                imm8 = wrap_negative(offset >> 1, 8)
+                section.data[reloc.offset] = imm8
+            elif reloc.typ == 'bl_imm11_imm10':
+                assert sym.value % 2 == 0
+                offset = sym.value - (align(reloc.offset, 2) + 4)
+                assert offset in range(-16777216, 16777214, 2), str(offset)
+                imm32 = wrap_negative(offset >> 1, 32)
+                imm11 = imm32 & 0x7FF
+                imm10 = (imm32 >> 11) & 0x3FF
+                s = (imm32 >> 24) & 0x1
+                section.data[reloc.offset + 2] = imm11 & 0xFF
+                section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
+                section.data[reloc.offset] = imm10 & 0xff
+                section.data[reloc.offset + 1] |= ((imm10 >> 8) & 0x3) | (s << 2)
+            elif reloc.typ == 'b_imm11_imm6':
+                assert sym.value % 2 == 0
+                offset = sym.value - (align(reloc.offset, 2) + 4)
+                assert offset in range(-1048576, 1048574, 2), str(offset)
+                imm32 = wrap_negative(offset >> 1, 32)
+                imm11 = imm32 & 0x7FF
+                imm6 = (imm32 >> 11) & 0x3F
+                s = (imm32 >> 24) & 0x1
+                section.data[reloc.offset + 2] = imm11 & 0xFF
+                section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
+                section.data[reloc.offset] |= imm6
+                section.data[reloc.offset + 1] |= (s << 2)
+            else:
+                raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ))
+
         return self.dst