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