diff python/ppci/linker.py @ 336:d1ecc493384e

Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
author Windel Bouwman
date Wed, 19 Feb 2014 22:32:15 +0100
parents 582a1aaa3983
children b4882ff0ed06
line wrap: on
line diff
--- a/python/ppci/linker.py	Mon Feb 17 20:41:30 2014 +0100
+++ b/python/ppci/linker.py	Wed Feb 19 22:32:15 2014 +0100
@@ -22,19 +22,71 @@
 
 
 @reloc('lit_add_8')
-class LitAdd8:
-    def apply(self):
-        pass
+def apply_lit8(reloc, sym, section, reloc_value):
+    assert sym.value % 4 == 0
+    offset = (sym.value - (align(reloc_value + 2, 4)))
+    assert offset in range(0, 1024, 4), str(offset)+str( self.dst.sections)
+    rel8 = offset >> 2
+    section.data[reloc.offset] = rel8
+
+
+@reloc('wrap_new11')
+def apply_wrap_new11(reloc, sym, section, reloc_value):
+    offset = sym.value - (align(reloc_value, 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
+
+
+@reloc('rel8')
+def apply_rel8(reloc, sym, section, reloc_value):
+    assert sym.value % 2 == 0
+    offset = sym.value - (align(reloc_value, 2) + 4)
+    assert offset in range(-256, 254, 2), str(offset) + str(reloc)
+    imm8 = wrap_negative(offset >> 1, 8)
+    section.data[reloc.offset] = imm8
+
+
+@reloc('bl_imm11_imm10')
+def apply_bl_imm11(reloc, sym, section, reloc_value):
+    assert sym.value % 2 == 0
+    offset = sym.value - (align(reloc_value, 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)
+
+@reloc('b_imm11_imm6')
+def apply_b_imm11_imm6(reloc, sym, section, reloc_value):
+    assert sym.value % 2 == 0
+    offset = sym.value - (align(reloc_value, 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)
 
 
 class Linker:
-    def set_symbol(self, sym):
-        self.dst.add_symbol(sym.name, sym.value, sym.section)
-
-    def link(self, objs):
+    """ Merges the sections of several object files and 
+        performs relocation """
+    def link(self, objs, layout={}):
         # Create new object file to store output:
         self.dst = ObjectFile()
-        self.dst.get_section('code').address = 0x08000000
+
+        # Create sections with address:
+        for section_name, address in layout.items():
+            self.dst.get_section(section_name).address = address
 
         # First copy all sections into output sections:
         for iobj in objs:
@@ -42,19 +94,26 @@
             # 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
+                # TODO: align section in other way:
+                while out_s.Size % 4 != 0:
+                    out_s.add_data(bytes([0]))
+
+                # Add new section:
+                offsets[in_s.name] = 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)
+                out_s = self.dst.get_section(sym.section)
+                value = offsets[sym.section] + out_s.address + sym.value
+                self.dst.add_symbol(sym.name, value, sym.section)
 
             # Merge relocations:
             for reloc in iobj.relocations:
-                self.dst.add_relocation(reloc.sym, reloc.offset, reloc.typ, reloc.section)
+                offset = offsets[reloc.section] + reloc.offset
+                self.dst.add_relocation(reloc.sym, offset, reloc.typ, reloc.section)
 
-        # Check that there are no more unresolved symbols:
         # Perform relocations:
         for reloc in self.dst.relocations:
             # Lookup symbol:
@@ -64,48 +123,12 @@
             # 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)
+            # Determine location in memory of reloc patchup position:
+            reloc_value = section.address + reloc.offset
+
+            if reloc.typ in reloc_map:
+                f = reloc_map[reloc.typ]
+                f(reloc, sym, section, reloc_value)
             else:
                 raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ))