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
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
1
335
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
2 import struct
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
3 from .objectfile import ObjectFile
335
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
4 from . import CompilerError
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
5
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
6 def align(x, m):
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
7 while ((x % m) != 0):
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
8 x = x + 1
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
9 return x
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
10
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
11 def wrap_negative(x, bits):
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
12 b = struct.unpack('<I', struct.pack('<i', x))[0]
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
13 mask = (1 << bits) - 1
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
14 return b & mask
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
15
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
16 reloc_map = {}
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
17
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
18 def reloc(t):
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
19 def f(c):
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
20 reloc_map[t] = c
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
21 return f
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
22
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
23
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
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
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
78
345
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
79 # ARM reloc!!
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
80 # TODO: move to target classes???
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
81 @reloc('b_imm24')
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
82 def apply_b_imm24(reloc, sym, section, reloc_value):
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
83 assert sym.value % 4 == 0
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
84 assert reloc_value % 4 == 0
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
85 offset = (sym.value - (reloc_value + 8))
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
86 rel24 = wrap_negative(offset >> 2, 24)
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
87 section.data[reloc.offset+2] = (rel24 >> 16) & 0xFF
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
88 section.data[reloc.offset+1] = (rel24 >> 8) & 0xFF
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
89 section.data[reloc.offset+0] = rel24 & 0xFF
b4882ff0ed06 Added more arm isa tests
Windel Bouwman
parents: 336
diff changeset
90
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
91
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
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
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
96 # Create new object file to store output:
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
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
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
102
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
103 # First copy all sections into output sections:
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
104 for iobj in objs:
335
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
105 offsets = {}
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
106 # Merge sections:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
107 for in_s in iobj.sections.values():
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
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
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
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
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
117
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
118 # Merge symbols:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
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
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
123
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
124 # Merge relocations:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
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
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
128
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
129 # Perform relocations:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
130 for reloc in self.dst.relocations:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
131 # Lookup symbol:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
132 if reloc.sym not in self.dst.symbols:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
133 raise CompilerError('Undefined reference "{}"'.format(reloc.sym))
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
134 sym = self.dst.symbols[reloc.sym]
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
135 # patch up:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
136 section = self.dst.get_section(reloc.section)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
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
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
144 else:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
145 raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ))
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
146
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
147 return self.dst