Mercurial > lcfOS
comparison python/outstream.py @ 335:582a1aaa3983
Added long branch format
author | Windel Bouwman |
---|---|
date | Mon, 17 Feb 2014 20:41:30 +0100 |
parents | 56e6ff84f646 |
children | b00219172a42 |
comparison
equal
deleted
inserted
replaced
334:6f4753202b9a | 335:582a1aaa3983 |
---|---|
1 import binascii | 1 import binascii |
2 from target import Instruction, Label, DebugInfo | 2 from target import Instruction, DebugInfo, Alignment |
3 from ppci.objectfile import ObjectFile | |
3 | 4 |
4 """ | 5 """ |
5 The output stream is a stream of instructions that can be output | 6 The output stream is a stream of instructions that can be output |
6 to a file or binary or hexfile. | 7 to a file or binary or hexfile. |
7 """ | 8 """ |
8 | 9 |
9 | 10 |
10 class Section: | 11 class OutputStream: |
11 def __init__(self): | |
12 self.address = 0 | |
13 self.instructions = [] | |
14 | |
15 def emit(self, item): | 12 def emit(self, item): |
16 assert isinstance(item, Instruction) | 13 raise NotImplementedError('Abstract base class') |
17 self.instructions.append(item) | |
18 | |
19 def to_bytes(self): | |
20 d = bytearray() | |
21 for i in self.instructions: | |
22 addr = i.address | |
23 insword = i.encode() | |
24 assert type(insword) is bytes | |
25 d.extend(insword) | |
26 return bytes(d) | |
27 | |
28 @property | |
29 def Size(self): | |
30 return len(self.to_bytes()) | |
31 | |
32 def debugInfos(self): | |
33 di = [i for i in self.instructions if isinstance(i, DebugInfo)] | |
34 return di | |
35 | |
36 | |
37 class OutputStream: | |
38 def __init__(self): | |
39 self.sections = {} | |
40 self.currentSection = None | |
41 | |
42 def emit(self, item): | |
43 assert self.currentSection | |
44 self.currentSection.emit(item) | |
45 | 14 |
46 def selectSection(self, sname): | 15 def selectSection(self, sname): |
47 self.currentSection = self.getSection(sname) | 16 raise NotImplementedError('Abstract base class') |
48 | 17 |
49 def getLabelAddress(self, lname): | |
50 assert isinstance(lname, str) | |
51 for s in self.sections.values(): | |
52 for i in s.instructions: | |
53 if type(i) is Label: | |
54 if i.name == lname: | |
55 return i.address | |
56 return 0 | |
57 | |
58 def getSection(self, name): | |
59 if not name in self.sections: | |
60 self.sections[name] = Section() | |
61 return self.sections[name] | |
62 | |
63 def backpatch(self): | |
64 """ Fixup references to other parts in the assembler """ | |
65 for s in self.sections.values(): | |
66 address = s.address | |
67 for i in s.instructions: | |
68 i.address = address | |
69 i.resolve(self.getLabelAddress) | |
70 bts = i.encode() | |
71 address += len(bts) | |
72 | 18 |
73 class OutputStreamWriter: | 19 class OutputStreamWriter: |
74 def __init__(self, extra_indent=''): | 20 def __init__(self, extra_indent=''): |
75 self.extra_indent = extra_indent | 21 self.extra_indent = extra_indent |
76 | 22 |
77 def dump(self, stream, f): | 23 def dump(self, stream, f): |
78 stream.backpatch() | |
79 stream.backpatch() | |
80 for s in sorted(stream.sections.keys()): | 24 for s in sorted(stream.sections.keys()): |
81 # print('.section '+ s) | 25 # print('.section '+ s) |
82 self.dumpSection(stream.sections[s], f) | 26 self.dumpSection(stream.sections[s], f) |
83 | 27 |
84 def dumpSection(self, s, f): | 28 def dumpSection(self, s, f): |
94 print(' {}'.format(asm), file=f) | 38 print(' {}'.format(asm), file=f) |
95 else: | 39 else: |
96 print(' 0x{0:08x} 0x{1} {2}'.format(addr, insword, asm), file=f) | 40 print(' 0x{0:08x} 0x{1} {2}'.format(addr, insword, asm), file=f) |
97 | 41 |
98 | 42 |
99 class TextOutputStream(OutputStream): | 43 class BinaryOutputStream(OutputStream): |
100 pass | 44 """ Output stream that writes to object file """ |
45 def __init__(self, obj_file): | |
46 super().__init__() | |
47 self.obj_file = obj_file | |
101 | 48 |
49 def emit(self, item): | |
50 """ Encode instruction and add symbol and relocation information """ | |
51 assert isinstance(item, Instruction) | |
52 assert self.currentSection | |
53 section = self.currentSection | |
54 address = self.currentSection.Size | |
55 b = item.encode() | |
56 syms = item.symbols() | |
57 relocs = item.relocations() | |
58 section.add_data(b) | |
59 for sym in syms: | |
60 self.obj_file.add_symbol(sym, address, section.name) | |
61 for sym, typ in relocs: | |
62 self.obj_file.add_relocation(sym, address, typ, section.name) | |
63 # Special case for align, TODO do this different? | |
64 if type(item) is Alignment: | |
65 while section.Size % item.align != 0: | |
66 section.add_data(bytes([0])) | |
102 | 67 |
103 class BinOutputStream(OutputStream): | 68 def selectSection(self, sname): |
104 | 69 self.currentSection = self.obj_file.get_section(sname) |
105 @property | |
106 def Data(self): | |
107 d = self.dump() | |
108 return bytes(d) | |
109 | |
110 def dump(self): | |
111 self.backpatch() | |
112 self.backpatch() | |
113 section = self.sections[list(self.sections.keys())[0]] | |
114 return section.to_bytes() |