Mercurial > lcfOS
annotate python/ppci/linker.py @ 383:173e20a47fda
Added linker description loader
author | Windel Bouwman |
---|---|
date | Sun, 27 Apr 2014 17:40:39 +0200 |
parents | 6df89163e114 |
children | d056b552d3f4 |
rev | line source |
---|---|
348 | 1 import logging |
335 | 2 import struct |
334 | 3 from .objectfile import ObjectFile |
335 | 4 from . import CompilerError |
365 | 5 from .bitfun import encode_imm32 |
383 | 6 from .layout import Layout, Section |
7 | |
335 | 8 |
9 def align(x, m): | |
10 while ((x % m) != 0): | |
11 x = x + 1 | |
12 return x | |
13 | |
14 def wrap_negative(x, bits): | |
15 b = struct.unpack('<I', struct.pack('<i', x))[0] | |
16 mask = (1 << bits) - 1 | |
17 return b & mask | |
18 | |
19 reloc_map = {} | |
20 | |
21 def reloc(t): | |
22 def f(c): | |
23 reloc_map[t] = c | |
24 return f | |
25 | |
26 | |
27 @reloc('lit_add_8') | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
28 def apply_lit8(reloc, sym, section, reloc_value): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
29 assert sym.value % 4 == 0 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
30 offset = (sym.value - (align(reloc_value + 2, 4))) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
31 assert offset in range(0, 1024, 4), str(offset)+str( self.dst.sections) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
32 rel8 = offset >> 2 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
33 section.data[reloc.offset] = rel8 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
34 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
35 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
36 @reloc('wrap_new11') |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
37 def apply_wrap_new11(reloc, sym, section, reloc_value): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
38 offset = sym.value - (align(reloc_value, 2) + 4) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
39 assert offset in range(-2048, 2046, 2) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
40 imm11 = wrap_negative(offset >> 1, 11) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
41 section.data[reloc.offset] = (imm11 & 0xff) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
42 section.data[reloc.offset + 1] |= (imm11 >> 8) & 0x7 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
43 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
44 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
45 @reloc('rel8') |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
46 def apply_rel8(reloc, sym, section, reloc_value): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
47 assert sym.value % 2 == 0 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
48 offset = sym.value - (align(reloc_value, 2) + 4) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
49 assert offset in range(-256, 254, 2), str(offset) + str(reloc) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
50 imm8 = wrap_negative(offset >> 1, 8) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
51 section.data[reloc.offset] = imm8 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
52 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
53 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
54 @reloc('bl_imm11_imm10') |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
55 def apply_bl_imm11(reloc, sym, section, reloc_value): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
56 assert sym.value % 2 == 0 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
57 offset = sym.value - (align(reloc_value, 2) + 4) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
58 assert offset in range(-16777216, 16777214, 2), str(offset) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
59 imm32 = wrap_negative(offset >> 1, 32) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
60 imm11 = imm32 & 0x7FF |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
61 imm10 = (imm32 >> 11) & 0x3FF |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
62 s = (imm32 >> 24) & 0x1 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
63 section.data[reloc.offset + 2] = imm11 & 0xFF |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
64 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
65 section.data[reloc.offset] = imm10 & 0xff |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
66 section.data[reloc.offset + 1] |= ((imm10 >> 8) & 0x3) | (s << 2) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
67 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
68 @reloc('b_imm11_imm6') |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
69 def apply_b_imm11_imm6(reloc, sym, section, reloc_value): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
70 assert sym.value % 2 == 0 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
71 offset = sym.value - (align(reloc_value, 2) + 4) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
72 assert offset in range(-1048576, 1048574, 2), str(offset) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
73 imm32 = wrap_negative(offset >> 1, 32) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
74 imm11 = imm32 & 0x7FF |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
75 imm6 = (imm32 >> 11) & 0x3F |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
76 s = (imm32 >> 24) & 0x1 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
77 section.data[reloc.offset + 2] = imm11 & 0xFF |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
78 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
79 section.data[reloc.offset] |= imm6 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
80 section.data[reloc.offset + 1] |= (s << 2) |
335 | 81 |
345 | 82 # ARM reloc!! |
83 # TODO: move to target classes??? | |
84 @reloc('b_imm24') | |
85 def apply_b_imm24(reloc, sym, section, reloc_value): | |
86 assert sym.value % 4 == 0 | |
87 assert reloc_value % 4 == 0 | |
88 offset = (sym.value - (reloc_value + 8)) | |
89 rel24 = wrap_negative(offset >> 2, 24) | |
90 section.data[reloc.offset+2] = (rel24 >> 16) & 0xFF | |
91 section.data[reloc.offset+1] = (rel24 >> 8) & 0xFF | |
92 section.data[reloc.offset+0] = rel24 & 0xFF | |
93 | |
334 | 94 |
350 | 95 @reloc('ldr_imm12') |
96 def apply_ldr_imm12(reloc, sym, section, reloc_value): | |
97 assert sym.value % 4 == 0 | |
98 assert reloc_value % 4 == 0 | |
99 offset = (sym.value - (reloc_value + 8)) | |
100 U = 1 | |
101 if offset < 0: | |
102 offset = -offset | |
103 U = 0 | |
381 | 104 assert offset < 4096, str(sym) + str(section) + str(reloc) |
365 | 105 section.data[reloc.offset+2] |= (U << 7) |
350 | 106 section.data[reloc.offset+1] |= (offset >> 8) & 0xF |
107 section.data[reloc.offset+0] = offset & 0xFF | |
108 | |
354 | 109 @reloc('adr_imm12') |
110 def apply_adr_imm12(reloc, sym, section, reloc_value): | |
111 assert sym.value % 4 == 0 | |
112 assert reloc_value % 4 == 0 | |
113 offset = (sym.value - (reloc_value + 8)) | |
114 U = 2 | |
115 if offset < 0: | |
116 offset = -offset | |
117 U = 1 | |
118 assert offset < 4096 | |
365 | 119 offset = encode_imm32(offset) |
364 | 120 section.data[reloc.offset+2] |= (U << 6) |
354 | 121 section.data[reloc.offset+1] |= (offset >> 8) & 0xF |
122 section.data[reloc.offset+0] = offset & 0xFF | |
123 | |
364 | 124 @reloc('absaddr32') |
125 def apply_absaddr32(reloc, sym, section, reloc_value): | |
126 assert sym.value % 4 == 0 | |
127 assert reloc_value % 4 == 0 | |
128 offset = sym.value | |
129 section.data[reloc.offset+3] = (offset >> 24) & 0xFF | |
130 section.data[reloc.offset+2] = (offset >> 16) & 0xFF | |
131 section.data[reloc.offset+1] = (offset >> 8) & 0xFF | |
132 section.data[reloc.offset+0] = offset & 0xFF | |
133 | |
354 | 134 |
334 | 135 class Linker: |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
136 """ Merges the sections of several object files and |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
137 performs relocation """ |
348 | 138 def __init__(self): |
139 self.logger = logging.getLogger('Linker') | |
140 | |
381 | 141 def link(self, objs, layout): |
377 | 142 assert type(objs) is list |
383 | 143 assert type(layout) is Layout |
335 | 144 # Create new object file to store output: |
334 | 145 self.dst = ObjectFile() |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
146 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
147 # Create sections with address: |
383 | 148 for mem in layout.mems: |
149 for inp in mem.inputs: | |
150 if type(inp) is Section: | |
151 self.dst.get_section(inp.section_name).address = mem.location | |
335 | 152 |
334 | 153 # First copy all sections into output sections: |
154 for iobj in objs: | |
335 | 155 offsets = {} |
156 # Merge sections: | |
157 for in_s in iobj.sections.values(): | |
158 out_s = self.dst.get_section(in_s.name) | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
159 # TODO: align section in other way: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
160 while out_s.Size % 4 != 0: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
161 out_s.add_data(bytes([0])) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
162 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
163 # Add new section: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
164 offsets[in_s.name] = out_s.Size |
335 | 165 out_s.add_data(in_s.data) |
348 | 166 self.logger.debug('{} {}({})'.format(offsets[in_s.name], iobj, in_s.name)) |
335 | 167 |
168 # Merge symbols: | |
169 for sym in iobj.symbols.values(): | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
170 out_s = self.dst.get_section(sym.section) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
171 value = offsets[sym.section] + out_s.address + sym.value |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
172 self.dst.add_symbol(sym.name, value, sym.section) |
363 | 173 self.logger.debug('{} at 0x{:08X} in section {}'.format(sym.name, value, sym.section)) |
335 | 174 |
175 # Merge relocations: | |
176 for reloc in iobj.relocations: | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
177 offset = offsets[reloc.section] + reloc.offset |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
178 self.dst.add_relocation(reloc.sym, offset, reloc.typ, reloc.section) |
335 | 179 |
381 | 180 # Apply layout rules: |
181 # TODO | |
182 | |
335 | 183 # Perform relocations: |
184 for reloc in self.dst.relocations: | |
185 # Lookup symbol: | |
186 if reloc.sym not in self.dst.symbols: | |
187 raise CompilerError('Undefined reference "{}"'.format(reloc.sym)) | |
188 sym = self.dst.symbols[reloc.sym] | |
189 # patch up: | |
190 section = self.dst.get_section(reloc.section) | |
191 | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
192 # Determine location in memory of reloc patchup position: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
193 reloc_value = section.address + reloc.offset |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
194 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
195 if reloc.typ in reloc_map: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
196 f = reloc_map[reloc.typ] |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
197 f(reloc, sym, section, reloc_value) |
335 | 198 else: |
199 raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ)) | |
200 | |
334 | 201 return self.dst |