annotate python/ppci/linker.py @ 335:582a1aaa3983

Added long branch format
author Windel Bouwman
date Mon, 17 Feb 2014 20:41:30 +0100
parents 6f4753202b9a
children d1ecc493384e
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')
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
25 class LitAdd8:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
26 def apply(self):
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
27 pass
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
28
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
29
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
30 class Linker:
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
31 def set_symbol(self, sym):
335
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
32 self.dst.add_symbol(sym.name, sym.value, sym.section)
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
33
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
34 def link(self, objs):
335
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
35 # Create new object file to store output:
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
36 self.dst = ObjectFile()
335
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
37 self.dst.get_section('code').address = 0x08000000
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
38
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
39 # First copy all sections into output sections:
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
40 for iobj in objs:
335
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
41 offsets = {}
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
42 # Merge sections:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
43 for in_s in iobj.sections.values():
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
44 out_s = self.dst.get_section(in_s.name)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
45 offsets[in_s.name] = out_s.address + out_s.Size
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
46 out_s.add_data(in_s.data)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
47 # TODO: align section
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
48
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
49 # Merge symbols:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
50 for sym in iobj.symbols.values():
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
51 self.set_symbol(sym)
335
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
52
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
53 # Merge relocations:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
54 for reloc in iobj.relocations:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
55 self.dst.add_relocation(reloc.sym, reloc.offset, reloc.typ, reloc.section)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
56
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
57 # Check that there are no more unresolved symbols:
335
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
58 # Perform relocations:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
59 for reloc in self.dst.relocations:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
60 # Lookup symbol:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
61 if reloc.sym not in self.dst.symbols:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
62 raise CompilerError('Undefined reference "{}"'.format(reloc.sym))
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
63 sym = self.dst.symbols[reloc.sym]
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
64 # patch up:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
65 section = self.dst.get_section(reloc.section)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
66
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
67 if reloc.typ == 'lit_add_8':
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
68 assert sym.value % 4 == 0
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
69 offset = (sym.value - (align(reloc.offset + 2, 4)))
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
70 assert offset in range(0, 1024, 4)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
71 rel8 = offset >> 2
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
72 section.data[reloc.offset] = rel8
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
73 elif reloc.typ == 'wrap_new11':
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
74 offset = sym.value - (align(reloc.offset, 2) + 4)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
75 assert offset in range(-2048, 2046, 2)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
76 imm11 = wrap_negative(offset >> 1, 11)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
77 section.data[reloc.offset] = (imm11 & 0xff)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
78 section.data[reloc.offset + 1] |= (imm11 >> 8) & 0x7
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
79 elif reloc.typ == 'rel8':
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
80 assert sym.value % 2 == 0
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
81 offset = sym.value - (align(reloc.offset, 2) + 4)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
82 assert offset in range(-256, 254, 2), str(offset) + str(reloc)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
83 imm8 = wrap_negative(offset >> 1, 8)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
84 section.data[reloc.offset] = imm8
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
85 elif reloc.typ == 'bl_imm11_imm10':
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
86 assert sym.value % 2 == 0
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
87 offset = sym.value - (align(reloc.offset, 2) + 4)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
88 assert offset in range(-16777216, 16777214, 2), str(offset)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
89 imm32 = wrap_negative(offset >> 1, 32)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
90 imm11 = imm32 & 0x7FF
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
91 imm10 = (imm32 >> 11) & 0x3FF
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
92 s = (imm32 >> 24) & 0x1
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
93 section.data[reloc.offset + 2] = imm11 & 0xFF
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
94 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
95 section.data[reloc.offset] = imm10 & 0xff
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
96 section.data[reloc.offset + 1] |= ((imm10 >> 8) & 0x3) | (s << 2)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
97 elif reloc.typ == 'b_imm11_imm6':
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
98 assert sym.value % 2 == 0
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
99 offset = sym.value - (align(reloc.offset, 2) + 4)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
100 assert offset in range(-1048576, 1048574, 2), str(offset)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
101 imm32 = wrap_negative(offset >> 1, 32)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
102 imm11 = imm32 & 0x7FF
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
103 imm6 = (imm32 >> 11) & 0x3F
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
104 s = (imm32 >> 24) & 0x1
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
105 section.data[reloc.offset + 2] = imm11 & 0xFF
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
106 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
107 section.data[reloc.offset] |= imm6
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
108 section.data[reloc.offset + 1] |= (s << 2)
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
109 else:
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
110 raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ))
582a1aaa3983 Added long branch format
Windel Bouwman
parents: 334
diff changeset
111
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
112 return self.dst