Mercurial > lcfOS
comparison python/ppci/linker.py @ 385:d056b552d3f4
Made better use of layout
author | Windel Bouwman |
---|---|
date | Thu, 01 May 2014 14:03:12 +0200 |
parents | 173e20a47fda |
children | 2a970e7270e2 |
comparison
equal
deleted
inserted
replaced
384:94f5b719ad0b | 385:d056b552d3f4 |
---|---|
1 import logging | 1 import logging |
2 import struct | |
3 from .objectfile import ObjectFile | 2 from .objectfile import ObjectFile |
4 from . import CompilerError | 3 from . import CompilerError |
5 from .bitfun import encode_imm32 | |
6 from .layout import Layout, Section | 4 from .layout import Layout, Section |
7 | 5 |
8 | 6 |
9 def align(x, m): | 7 class Linker: |
10 while ((x % m) != 0): | 8 """ Merges the sections of several object files and |
11 x = x + 1 | 9 performs relocation """ |
12 return x | 10 def __init__(self, target): |
11 self.logger = logging.getLogger('Linker') | |
12 self.target = target | |
13 | 13 |
14 def wrap_negative(x, bits): | 14 def layout_sections(self, dst, layout): |
15 b = struct.unpack('<I', struct.pack('<i', x))[0] | 15 """ Use the given layout to place sections into memories """ |
16 mask = (1 << bits) - 1 | 16 # Create sections with address: |
17 return b & mask | 17 dst.images = {} |
18 | 18 for mem in layout.memories: |
19 reloc_map = {} | 19 cur_addr = mem.location |
20 | 20 output_memory = bytearray() |
21 def reloc(t): | 21 for memory_input in mem.inputs: |
22 def f(c): | 22 if type(memory_input) is Section: |
23 reloc_map[t] = c | 23 section = dst.get_section(memory_input.section_name) |
24 return f | 24 section.address = cur_addr |
25 | 25 cur_addr += section.Size |
26 | 26 output_memory += section.data |
27 @reloc('lit_add_8') | 27 # TODO: align sections |
28 def apply_lit8(reloc, sym, section, reloc_value): | 28 else: |
29 assert sym.value % 4 == 0 | 29 print(memory_input) |
30 offset = (sym.value - (align(reloc_value + 2, 4))) | 30 dst.images[mem.name] = bytes(output_memory) |
31 assert offset in range(0, 1024, 4), str(offset)+str( self.dst.sections) | |
32 rel8 = offset >> 2 | |
33 section.data[reloc.offset] = rel8 | |
34 | |
35 | |
36 @reloc('wrap_new11') | |
37 def apply_wrap_new11(reloc, sym, section, reloc_value): | |
38 offset = sym.value - (align(reloc_value, 2) + 4) | |
39 assert offset in range(-2048, 2046, 2) | |
40 imm11 = wrap_negative(offset >> 1, 11) | |
41 section.data[reloc.offset] = (imm11 & 0xff) | |
42 section.data[reloc.offset + 1] |= (imm11 >> 8) & 0x7 | |
43 | |
44 | |
45 @reloc('rel8') | |
46 def apply_rel8(reloc, sym, section, reloc_value): | |
47 assert sym.value % 2 == 0 | |
48 offset = sym.value - (align(reloc_value, 2) + 4) | |
49 assert offset in range(-256, 254, 2), str(offset) + str(reloc) | |
50 imm8 = wrap_negative(offset >> 1, 8) | |
51 section.data[reloc.offset] = imm8 | |
52 | |
53 | |
54 @reloc('bl_imm11_imm10') | |
55 def apply_bl_imm11(reloc, sym, section, reloc_value): | |
56 assert sym.value % 2 == 0 | |
57 offset = sym.value - (align(reloc_value, 2) + 4) | |
58 assert offset in range(-16777216, 16777214, 2), str(offset) | |
59 imm32 = wrap_negative(offset >> 1, 32) | |
60 imm11 = imm32 & 0x7FF | |
61 imm10 = (imm32 >> 11) & 0x3FF | |
62 s = (imm32 >> 24) & 0x1 | |
63 section.data[reloc.offset + 2] = imm11 & 0xFF | |
64 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7 | |
65 section.data[reloc.offset] = imm10 & 0xff | |
66 section.data[reloc.offset + 1] |= ((imm10 >> 8) & 0x3) | (s << 2) | |
67 | |
68 @reloc('b_imm11_imm6') | |
69 def apply_b_imm11_imm6(reloc, sym, section, reloc_value): | |
70 assert sym.value % 2 == 0 | |
71 offset = sym.value - (align(reloc_value, 2) + 4) | |
72 assert offset in range(-1048576, 1048574, 2), str(offset) | |
73 imm32 = wrap_negative(offset >> 1, 32) | |
74 imm11 = imm32 & 0x7FF | |
75 imm6 = (imm32 >> 11) & 0x3F | |
76 s = (imm32 >> 24) & 0x1 | |
77 section.data[reloc.offset + 2] = imm11 & 0xFF | |
78 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7 | |
79 section.data[reloc.offset] |= imm6 | |
80 section.data[reloc.offset + 1] |= (s << 2) | |
81 | |
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 | |
94 | |
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 | |
104 assert offset < 4096, str(sym) + str(section) + str(reloc) | |
105 section.data[reloc.offset+2] |= (U << 7) | |
106 section.data[reloc.offset+1] |= (offset >> 8) & 0xF | |
107 section.data[reloc.offset+0] = offset & 0xFF | |
108 | |
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 | |
119 offset = encode_imm32(offset) | |
120 section.data[reloc.offset+2] |= (U << 6) | |
121 section.data[reloc.offset+1] |= (offset >> 8) & 0xF | |
122 section.data[reloc.offset+0] = offset & 0xFF | |
123 | |
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 | |
134 | |
135 class Linker: | |
136 """ Merges the sections of several object files and | |
137 performs relocation """ | |
138 def __init__(self): | |
139 self.logger = logging.getLogger('Linker') | |
140 | 31 |
141 def link(self, objs, layout): | 32 def link(self, objs, layout): |
142 assert type(objs) is list | 33 assert type(objs) is list |
143 assert type(layout) is Layout | 34 assert type(layout) is Layout |
144 # Create new object file to store output: | 35 # Create new object file to store output: |
145 self.dst = ObjectFile() | 36 dst = ObjectFile() |
146 | |
147 # Create sections with address: | |
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 | |
152 | 37 |
153 # First copy all sections into output sections: | 38 # First copy all sections into output sections: |
154 for iobj in objs: | 39 for iobj in objs: |
155 offsets = {} | 40 offsets = {} |
156 # Merge sections: | 41 # Merge sections: |
157 for in_s in iobj.sections.values(): | 42 for in_s in iobj.sections.values(): |
158 out_s = self.dst.get_section(in_s.name) | 43 out_s = dst.get_section(in_s.name) |
159 # TODO: align section in other way: | 44 # TODO: align section in other way: |
160 while out_s.Size % 4 != 0: | 45 while out_s.Size % 4 != 0: |
161 out_s.add_data(bytes([0])) | 46 out_s.add_data(bytes([0])) |
162 | 47 |
163 # Add new section: | 48 # Add new section: |
165 out_s.add_data(in_s.data) | 50 out_s.add_data(in_s.data) |
166 self.logger.debug('{} {}({})'.format(offsets[in_s.name], iobj, in_s.name)) | 51 self.logger.debug('{} {}({})'.format(offsets[in_s.name], iobj, in_s.name)) |
167 | 52 |
168 # Merge symbols: | 53 # Merge symbols: |
169 for sym in iobj.symbols.values(): | 54 for sym in iobj.symbols.values(): |
170 out_s = self.dst.get_section(sym.section) | 55 out_s = dst.get_section(sym.section) |
171 value = offsets[sym.section] + out_s.address + sym.value | 56 value = offsets[sym.section] + sym.value |
172 self.dst.add_symbol(sym.name, value, sym.section) | 57 dst.add_symbol(sym.name, value, sym.section) |
173 self.logger.debug('{} at 0x{:08X} in section {}'.format(sym.name, value, sym.section)) | 58 self.logger.debug('{} at 0x{:08X} in section {}'.format(sym.name, value, sym.section)) |
174 | 59 |
175 # Merge relocations: | 60 # Merge relocations: |
176 for reloc in iobj.relocations: | 61 for reloc in iobj.relocations: |
177 offset = offsets[reloc.section] + reloc.offset | 62 offset = offsets[reloc.section] + reloc.offset |
178 self.dst.add_relocation(reloc.sym, offset, reloc.typ, reloc.section) | 63 dst.add_relocation(reloc.sym, offset, reloc.typ, reloc.section) |
179 | 64 |
180 # Apply layout rules: | 65 # Apply layout rules: |
181 # TODO | 66 self.layout_sections(dst, layout) |
182 | 67 |
183 # Perform relocations: | 68 # Perform relocations: |
184 for reloc in self.dst.relocations: | 69 for reloc in dst.relocations: |
185 # Lookup symbol: | 70 # Lookup symbol: |
186 if reloc.sym not in self.dst.symbols: | 71 if reloc.sym not in dst.symbols: |
187 raise CompilerError('Undefined reference "{}"'.format(reloc.sym)) | 72 raise CompilerError('Undefined reference "{}"'.format(reloc.sym)) |
188 sym = self.dst.symbols[reloc.sym] | 73 |
189 # patch up: | 74 sym_value = dst.get_symbol_value(reloc.sym) |
190 section = self.dst.get_section(reloc.section) | 75 section = dst.get_section(reloc.section) |
191 | 76 |
192 # Determine location in memory of reloc patchup position: | 77 # Determine location in memory of reloc patchup position: |
193 reloc_value = section.address + reloc.offset | 78 reloc_value = section.address + reloc.offset |
194 | 79 |
195 if reloc.typ in reloc_map: | 80 if reloc.typ in self.target.reloc_map: |
196 f = reloc_map[reloc.typ] | 81 f = self.target.reloc_map[reloc.typ] |
197 f(reloc, sym, section, reloc_value) | 82 f(reloc, sym_value, section, reloc_value) |
198 else: | 83 else: |
199 raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ)) | 84 raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ)) |
200 | 85 |
201 return self.dst | 86 # Create memories for the second time |
87 # TODO: make this nicer? | |
88 self.layout_sections(dst, layout) | |
89 | |
90 return dst |