334
|
1
|
335
|
2 import struct
|
334
|
3 from .objectfile import ObjectFile
|
335
|
4 from . import CompilerError
|
|
5
|
|
6 def align(x, m):
|
|
7 while ((x % m) != 0):
|
|
8 x = x + 1
|
|
9 return x
|
|
10
|
|
11 def wrap_negative(x, bits):
|
|
12 b = struct.unpack('<I', struct.pack('<i', x))[0]
|
|
13 mask = (1 << bits) - 1
|
|
14 return b & mask
|
|
15
|
|
16 reloc_map = {}
|
|
17
|
|
18 def reloc(t):
|
|
19 def f(c):
|
|
20 reloc_map[t] = c
|
|
21 return f
|
|
22
|
|
23
|
|
24 @reloc('lit_add_8')
|
|
25 class LitAdd8:
|
|
26 def apply(self):
|
|
27 pass
|
|
28
|
334
|
29
|
|
30 class Linker:
|
|
31 def set_symbol(self, sym):
|
335
|
32 self.dst.add_symbol(sym.name, sym.value, sym.section)
|
334
|
33
|
|
34 def link(self, objs):
|
335
|
35 # Create new object file to store output:
|
334
|
36 self.dst = ObjectFile()
|
335
|
37 self.dst.get_section('code').address = 0x08000000
|
|
38
|
334
|
39 # First copy all sections into output sections:
|
|
40 for iobj in objs:
|
335
|
41 offsets = {}
|
|
42 # Merge sections:
|
|
43 for in_s in iobj.sections.values():
|
|
44 out_s = self.dst.get_section(in_s.name)
|
|
45 offsets[in_s.name] = out_s.address + out_s.Size
|
|
46 out_s.add_data(in_s.data)
|
|
47 # TODO: align section
|
|
48
|
|
49 # Merge symbols:
|
|
50 for sym in iobj.symbols.values():
|
334
|
51 self.set_symbol(sym)
|
335
|
52
|
|
53 # Merge relocations:
|
|
54 for reloc in iobj.relocations:
|
|
55 self.dst.add_relocation(reloc.sym, reloc.offset, reloc.typ, reloc.section)
|
|
56
|
334
|
57 # Check that there are no more unresolved symbols:
|
335
|
58 # Perform relocations:
|
|
59 for reloc in self.dst.relocations:
|
|
60 # Lookup symbol:
|
|
61 if reloc.sym not in self.dst.symbols:
|
|
62 raise CompilerError('Undefined reference "{}"'.format(reloc.sym))
|
|
63 sym = self.dst.symbols[reloc.sym]
|
|
64 # patch up:
|
|
65 section = self.dst.get_section(reloc.section)
|
|
66
|
|
67 if reloc.typ == 'lit_add_8':
|
|
68 assert sym.value % 4 == 0
|
|
69 offset = (sym.value - (align(reloc.offset + 2, 4)))
|
|
70 assert offset in range(0, 1024, 4)
|
|
71 rel8 = offset >> 2
|
|
72 section.data[reloc.offset] = rel8
|
|
73 elif reloc.typ == 'wrap_new11':
|
|
74 offset = sym.value - (align(reloc.offset, 2) + 4)
|
|
75 assert offset in range(-2048, 2046, 2)
|
|
76 imm11 = wrap_negative(offset >> 1, 11)
|
|
77 section.data[reloc.offset] = (imm11 & 0xff)
|
|
78 section.data[reloc.offset + 1] |= (imm11 >> 8) & 0x7
|
|
79 elif reloc.typ == 'rel8':
|
|
80 assert sym.value % 2 == 0
|
|
81 offset = sym.value - (align(reloc.offset, 2) + 4)
|
|
82 assert offset in range(-256, 254, 2), str(offset) + str(reloc)
|
|
83 imm8 = wrap_negative(offset >> 1, 8)
|
|
84 section.data[reloc.offset] = imm8
|
|
85 elif reloc.typ == 'bl_imm11_imm10':
|
|
86 assert sym.value % 2 == 0
|
|
87 offset = sym.value - (align(reloc.offset, 2) + 4)
|
|
88 assert offset in range(-16777216, 16777214, 2), str(offset)
|
|
89 imm32 = wrap_negative(offset >> 1, 32)
|
|
90 imm11 = imm32 & 0x7FF
|
|
91 imm10 = (imm32 >> 11) & 0x3FF
|
|
92 s = (imm32 >> 24) & 0x1
|
|
93 section.data[reloc.offset + 2] = imm11 & 0xFF
|
|
94 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
|
|
95 section.data[reloc.offset] = imm10 & 0xff
|
|
96 section.data[reloc.offset + 1] |= ((imm10 >> 8) & 0x3) | (s << 2)
|
|
97 elif reloc.typ == 'b_imm11_imm6':
|
|
98 assert sym.value % 2 == 0
|
|
99 offset = sym.value - (align(reloc.offset, 2) + 4)
|
|
100 assert offset in range(-1048576, 1048574, 2), str(offset)
|
|
101 imm32 = wrap_negative(offset >> 1, 32)
|
|
102 imm11 = imm32 & 0x7FF
|
|
103 imm6 = (imm32 >> 11) & 0x3F
|
|
104 s = (imm32 >> 24) & 0x1
|
|
105 section.data[reloc.offset + 2] = imm11 & 0xFF
|
|
106 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
|
|
107 section.data[reloc.offset] |= imm6
|
|
108 section.data[reloc.offset + 1] |= (s << 2)
|
|
109 else:
|
|
110 raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ))
|
|
111
|
334
|
112 return self.dst
|