348
|
1 import logging
|
208
|
2 import binascii
|
366
|
3 from .target import Instruction, Alignment
|
|
4 from .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:
|
366
|
13 """ Interface to generator code with. """
|
237
|
14 def emit(self, item):
|
335
|
15 raise NotImplementedError('Abstract base class')
|
219
|
16
|
348
|
17 def select_section(self, sname):
|
335
|
18 raise NotImplementedError('Abstract base class')
|
234
|
19
|
208
|
20
|
335
|
21 class BinaryOutputStream(OutputStream):
|
|
22 """ Output stream that writes to object file """
|
|
23 def __init__(self, obj_file):
|
|
24 super().__init__()
|
|
25 self.obj_file = obj_file
|
381
|
26 self.literal_pool = []
|
208
|
27
|
335
|
28 def emit(self, item):
|
|
29 """ Encode instruction and add symbol and relocation information """
|
341
|
30 assert isinstance(item, Instruction), str(item) + str(type(item))
|
335
|
31 assert self.currentSection
|
|
32 section = self.currentSection
|
|
33 address = self.currentSection.Size
|
|
34 b = item.encode()
|
|
35 syms = item.symbols()
|
|
36 relocs = item.relocations()
|
|
37 section.add_data(b)
|
|
38 for sym in syms:
|
|
39 self.obj_file.add_symbol(sym, address, section.name)
|
|
40 for sym, typ in relocs:
|
|
41 self.obj_file.add_relocation(sym, address, typ, section.name)
|
|
42 # Special case for align, TODO do this different?
|
|
43 if type(item) is Alignment:
|
|
44 while section.Size % item.align != 0:
|
|
45 section.add_data(bytes([0]))
|
236
|
46
|
348
|
47 def select_section(self, sname):
|
335
|
48 self.currentSection = self.obj_file.get_section(sname)
|
337
|
49
|
|
50
|
|
51 class DummyOutputStream(OutputStream):
|
348
|
52 """ Stream that implements the bare minimum and does nothing """
|
337
|
53 def emit(self, item):
|
|
54 pass
|
|
55
|
348
|
56 def select_section(self, sname):
|
337
|
57 pass
|
348
|
58
|
|
59
|
|
60 class LoggerOutputStream(OutputStream):
|
|
61 """ Stream that emits instructions as text in the log """
|
|
62 def __init__(self):
|
|
63 self.logger = logging.getLogger('LoggerOutputStream')
|
|
64
|
|
65 def emit(self, item):
|
|
66 self.logger.debug(str(item))
|
|
67
|
|
68 def select_section(self, sname):
|
|
69 self.logger.debug('.section {}'.format(sname))
|
|
70
|
|
71
|
|
72 class MasterOutputStream(OutputStream):
|
|
73 """ Stream that emits to multiple sub streams """
|
366
|
74 def __init__(self, substreams=[]):
|
|
75 self.substreams = list(substreams) # Use copy constructor!!!
|
348
|
76
|
|
77 def add_substream(self, output_stream):
|
|
78 self.substreams.append(output_stream)
|
|
79
|
|
80 def emit(self, item):
|
|
81 for output_stream in self.substreams:
|
|
82 output_stream.emit(item)
|
|
83
|
|
84 def select_section(self, sname):
|
|
85 for output_stream in self.substreams:
|
|
86 output_stream.select_section(sname)
|
381
|
87
|
|
88
|
|
89 def BinaryAndLoggingStream(output):
|
|
90 """ Create a stream object that both logs and writes to an object file """
|
|
91 o2 = BinaryOutputStream(output)
|
|
92 o1 = LoggerOutputStream()
|
|
93 ostream = MasterOutputStream([o1, o2])
|
|
94 return ostream
|