348
|
1 import logging
|
208
|
2 import binascii
|
346
|
3 from ppci.target import Instruction, Alignment
|
335
|
4 from ppci.objectfile import ObjectFile
|
234
|
5
|
208
|
6 """
|
|
7 The output stream is a stream of instructions that can be output
|
|
8 to a file or binary or hexfile.
|
|
9 """
|
|
10
|
219
|
11
|
335
|
12 class OutputStream:
|
237
|
13 def emit(self, item):
|
335
|
14 raise NotImplementedError('Abstract base class')
|
219
|
15
|
348
|
16 def select_section(self, sname):
|
335
|
17 raise NotImplementedError('Abstract base class')
|
234
|
18
|
208
|
19
|
316
|
20 class OutputStreamWriter:
|
|
21 def __init__(self, extra_indent=''):
|
|
22 self.extra_indent = extra_indent
|
208
|
23
|
316
|
24 def dump(self, stream, f):
|
|
25 for s in sorted(stream.sections.keys()):
|
|
26 # print('.section '+ s)
|
|
27 self.dumpSection(stream.sections[s], f)
|
|
28
|
|
29 def dumpSection(self, s, f):
|
|
30 for i in s.instructions:
|
234
|
31 addr = i.address
|
|
32 insword = i.encode()
|
|
33 assert type(insword) is bytes
|
|
34 insword = binascii.hexlify(bytes(reversed(insword))).decode('ascii')
|
|
35 asm = str(i)
|
235
|
36 if len(insword) == 0:
|
316
|
37 print(' {}'.format(asm), file=f)
|
235
|
38 else:
|
316
|
39 print(' 0x{0:08x} 0x{1} {2}'.format(addr, insword, asm), file=f)
|
208
|
40
|
296
|
41
|
335
|
42 class BinaryOutputStream(OutputStream):
|
|
43 """ Output stream that writes to object file """
|
|
44 def __init__(self, obj_file):
|
|
45 super().__init__()
|
|
46 self.obj_file = obj_file
|
208
|
47
|
335
|
48 def emit(self, item):
|
|
49 """ Encode instruction and add symbol and relocation information """
|
341
|
50 assert isinstance(item, Instruction), str(item) + str(type(item))
|
335
|
51 assert self.currentSection
|
|
52 section = self.currentSection
|
|
53 address = self.currentSection.Size
|
|
54 b = item.encode()
|
|
55 syms = item.symbols()
|
|
56 relocs = item.relocations()
|
|
57 section.add_data(b)
|
|
58 for sym in syms:
|
|
59 self.obj_file.add_symbol(sym, address, section.name)
|
|
60 for sym, typ in relocs:
|
|
61 self.obj_file.add_relocation(sym, address, typ, section.name)
|
|
62 # Special case for align, TODO do this different?
|
|
63 if type(item) is Alignment:
|
|
64 while section.Size % item.align != 0:
|
|
65 section.add_data(bytes([0]))
|
236
|
66
|
348
|
67 def select_section(self, sname):
|
335
|
68 self.currentSection = self.obj_file.get_section(sname)
|
337
|
69
|
|
70
|
|
71 class DummyOutputStream(OutputStream):
|
348
|
72 """ Stream that implements the bare minimum and does nothing """
|
337
|
73 def emit(self, item):
|
|
74 pass
|
|
75
|
348
|
76 def select_section(self, sname):
|
337
|
77 pass
|
348
|
78
|
|
79
|
|
80 class LoggerOutputStream(OutputStream):
|
|
81 """ Stream that emits instructions as text in the log """
|
|
82 def __init__(self):
|
|
83 self.logger = logging.getLogger('LoggerOutputStream')
|
|
84
|
|
85 def emit(self, item):
|
|
86 self.logger.debug(str(item))
|
|
87
|
|
88 def select_section(self, sname):
|
|
89 self.logger.debug('.section {}'.format(sname))
|
|
90
|
|
91
|
|
92 class MasterOutputStream(OutputStream):
|
|
93 """ Stream that emits to multiple sub streams """
|
|
94 def __init__(self):
|
|
95 self.substreams = []
|
|
96
|
|
97 def add_substream(self, output_stream):
|
|
98 self.substreams.append(output_stream)
|
|
99
|
|
100 def emit(self, item):
|
|
101 for output_stream in self.substreams:
|
|
102 output_stream.emit(item)
|
|
103
|
|
104 def select_section(self, sname):
|
|
105 for output_stream in self.substreams:
|
|
106 output_stream.select_section(sname)
|