Mercurial > lcfOS
annotate python/ppci/linker.py @ 345:b4882ff0ed06
Added more arm isa tests
author | Windel Bouwman |
---|---|
date | Sun, 02 Mar 2014 17:12:08 +0100 |
parents | d1ecc493384e |
children | 442fb043d149 |
rev | line source |
---|---|
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') | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
25 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
|
26 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
|
27 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
|
28 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
|
29 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
|
30 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
|
31 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
32 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
33 @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
|
34 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
|
35 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
|
36 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
|
37 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
|
38 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
|
39 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
|
40 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
41 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
42 @reloc('rel8') |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
43 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
|
44 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
|
45 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
|
46 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
|
47 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
|
48 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
|
49 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
50 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
51 @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
|
52 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
|
53 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
|
54 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
|
55 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
|
56 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
|
57 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
|
58 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
|
59 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
|
60 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
|
61 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
|
62 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
|
63 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
|
64 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
65 @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
|
66 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
|
67 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
|
68 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
|
69 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
|
70 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
|
71 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
|
72 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
|
73 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
|
74 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
|
75 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
|
76 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
|
77 section.data[reloc.offset + 1] |= (s << 2) |
335 | 78 |
345 | 79 # ARM reloc!! |
80 # TODO: move to target classes??? | |
81 @reloc('b_imm24') | |
82 def apply_b_imm24(reloc, sym, section, reloc_value): | |
83 assert sym.value % 4 == 0 | |
84 assert reloc_value % 4 == 0 | |
85 offset = (sym.value - (reloc_value + 8)) | |
86 rel24 = wrap_negative(offset >> 2, 24) | |
87 section.data[reloc.offset+2] = (rel24 >> 16) & 0xFF | |
88 section.data[reloc.offset+1] = (rel24 >> 8) & 0xFF | |
89 section.data[reloc.offset+0] = rel24 & 0xFF | |
90 | |
334 | 91 |
92 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
|
93 """ 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
|
94 performs relocation """ |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
95 def link(self, objs, layout={}): |
335 | 96 # Create new object file to store output: |
334 | 97 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
|
98 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
99 # Create sections with address: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
100 for section_name, address in layout.items(): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
101 self.dst.get_section(section_name).address = address |
335 | 102 |
334 | 103 # First copy all sections into output sections: |
104 for iobj in objs: | |
335 | 105 offsets = {} |
106 # Merge sections: | |
107 for in_s in iobj.sections.values(): | |
108 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
|
109 # 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
|
110 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
|
111 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
|
112 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
113 # 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
|
114 offsets[in_s.name] = out_s.Size |
335 | 115 out_s.add_data(in_s.data) |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
116 |
335 | 117 |
118 # Merge symbols: | |
119 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
|
120 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
|
121 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
|
122 self.dst.add_symbol(sym.name, value, sym.section) |
335 | 123 |
124 # Merge relocations: | |
125 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
|
126 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
|
127 self.dst.add_relocation(reloc.sym, offset, reloc.typ, reloc.section) |
335 | 128 |
129 # Perform relocations: | |
130 for reloc in self.dst.relocations: | |
131 # Lookup symbol: | |
132 if reloc.sym not in self.dst.symbols: | |
133 raise CompilerError('Undefined reference "{}"'.format(reloc.sym)) | |
134 sym = self.dst.symbols[reloc.sym] | |
135 # patch up: | |
136 section = self.dst.get_section(reloc.section) | |
137 | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
138 # 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
|
139 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
|
140 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
141 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
|
142 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
|
143 f(reloc, sym, section, reloc_value) |
335 | 144 else: |
145 raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ)) | |
146 | |
334 | 147 return self.dst |