Mercurial > lcfOS
annotate python/ppci/objectfile.py @ 377:9667d78ba79e
Switched to xml for project description
author | Windel Bouwman |
---|---|
date | Fri, 11 Apr 2014 15:47:50 +0200 |
parents | 86b02c98a717 |
children | 0c44e494ef58 |
rev | line source |
---|---|
334 | 1 |
2 """ | |
3 Object files are used to store assembled code. Information contained | |
4 is code, symbol table and relocation information. | |
5 """ | |
6 | |
377 | 7 import json |
8 import binascii | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
9 from . import CompilerError |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
10 |
334 | 11 class Symbol: |
335 | 12 def __init__(self, name, value, section): |
334 | 13 self.name = name |
14 self.value = value | |
335 | 15 self.section = section |
16 | |
17 def __repr__(self): | |
18 return 'SYM {}, val={} sec={}'.format(self.name, self.value, self.section) | |
334 | 19 |
377 | 20 def __eq__(self, other): |
21 return (self.name, self.value, self.section) == \ | |
22 (other.name, other.value, other.section) | |
23 | |
334 | 24 |
25 class Relocation: | |
342 | 26 """ Represents a relocation entry. A relocation always has a symbol to refer to |
27 and a relocation type """ | |
335 | 28 def __init__(self, sym, offset, typ, section): |
29 self.sym = sym | |
30 self.offset = offset | |
31 self.typ = typ | |
32 self.section = section | |
33 | |
34 def __repr__(self): | |
35 return 'RELOC {} off={} t={} sec={}'.format(self.sym, self.offset, self.typ, self.section) | |
334 | 36 |
377 | 37 def __eq__(self, other): |
38 return (self.sym, self.offset, self.typ, self.section) ==\ | |
39 (other.sym, other.offset, other.typ, other.section) | |
40 | |
334 | 41 |
42 class Section: | |
43 def __init__(self, name): | |
44 self.name = name | |
335 | 45 self.address = 0 |
46 self.data = bytearray() | |
47 | |
48 def add_data(self, data): | |
49 self.data += data | |
50 | |
51 @property | |
52 def Size(self): | |
53 return len(self.data) | |
54 | |
55 def __repr__(self): | |
56 return 'SECTION {}'.format(self.name) | |
334 | 57 |
377 | 58 def __eq__(self, other): |
59 return (self.name == other.name) and (self.address == other.address) \ | |
60 and (self.data == other.data) | |
61 | |
334 | 62 |
63 class ObjectFile: | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
64 """ Container for sections with compiled code or data. |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
65 Also contains symbols and relocation entries """ |
334 | 66 def __init__(self): |
67 self.symbols = {} | |
68 self.sections = {} | |
69 self.relocations = [] | |
70 | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
71 def find_symbol(self, name): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
72 return self.symbols[name] |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
73 |
335 | 74 def add_symbol(self, name, value, section): |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
75 if name in self.symbols: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
76 raise CompilerError('{} already defined'.format(name)) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
77 assert section in self.sections |
335 | 78 sym = Symbol(name, value, section) |
334 | 79 self.symbols[name] = sym |
80 return sym | |
335 | 81 |
82 def add_relocation(self, sym_name, offset, typ, section): | |
342 | 83 assert type(sym_name) is str, str(sym_name) |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
84 assert section in self.sections |
377 | 85 # assert sym_name in self.symbols |
335 | 86 reloc = Relocation(sym_name, offset, typ, section) |
87 self.relocations.append(reloc) | |
88 return reloc | |
89 | |
90 def get_section(self, name): | |
91 if not name in self.sections: | |
92 self.sections[name] = Section(name) | |
93 return self.sections[name] | |
377 | 94 |
95 def __eq__(self, other): | |
96 return (self.symbols == other.symbols) and \ | |
97 (self.sections == other.sections) and \ | |
98 (self.relocations == other.relocations) | |
99 | |
100 def save(self, f): | |
101 save_object(self, f) | |
102 | |
103 | |
104 def save_object(o, f): | |
105 json.dump(serialize(o), f, indent=2, sort_keys=True) | |
106 | |
107 | |
108 def load_object(f): | |
109 return deserialize(json.load(f)) | |
110 | |
111 | |
112 def serialize(x): | |
113 res = {} | |
114 if isinstance(x, ObjectFile): | |
115 res['sections'] = [] | |
116 for sname in sorted(x.sections.keys()): | |
117 s = x.sections[sname] | |
118 res['sections'].append(serialize(s)) | |
119 res['symbols'] = [] | |
120 for sname in sorted(x.symbols.keys()): | |
121 s = x.symbols[sname] | |
122 res['symbols'].append(serialize(s)) | |
123 res['relocations'] = [] | |
124 for reloc in x.relocations: | |
125 res['relocations'].append(serialize(reloc)) | |
126 elif isinstance(x, Section): | |
127 res['name'] = x.name | |
128 res['address'] = hex(x.address) | |
129 res['data'] = binascii.hexlify(x.data).decode('ascii') | |
130 elif isinstance(x, Symbol): | |
131 res['name'] = x.name | |
132 res['value'] = hex(x.value) | |
133 res['section'] = x.section | |
134 elif isinstance(x, Relocation): | |
135 res['symbol'] = x.sym | |
136 res['offset'] = hex(x.offset) | |
137 res['type'] = x.typ | |
138 res['section'] = x.section | |
139 return res | |
140 | |
141 | |
142 def deserialize(d): | |
143 obj = ObjectFile() | |
144 for section in d['sections']: | |
145 so = obj.get_section(section['name']) | |
146 so.address = int(section['address'][2:], 16) | |
147 so.data = bytearray(binascii.unhexlify(section['data'].encode('ascii'))) | |
148 for reloc in d['relocations']: | |
149 obj.add_relocation(reloc['symbol'], int(reloc['offset'][2:], 16), | |
150 reloc['type'], reloc['section']) | |
151 for sym in d['symbols']: | |
152 obj.add_symbol(sym['name'], int(sym['value'][2:], 16), sym['section']) | |
153 return obj | |
154 |