1 # SPDX-License-Identifier: LGPL-3-or-later
2 # Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
3 # Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
7 takes powerpc assembly instructions and turns them into LE/BE binary
8 data. calls powerpc64-linux-gnu-as, ld and objcopy to do so.
16 from io
import BytesIO
18 from openpower
.simulator
.envcmds
import cmds
20 filedir
= os
.path
.dirname(os
.path
.realpath(__file__
))
21 memmap
= os
.path
.join(filedir
, "memmap")
25 def __init__(self
, instructions
, bigendian
, orig_filename
=None):
26 self
.bigendian
= bigendian
28 self
.endian_fmt
= "elf64-big"
33 self
.endian_fmt
= "elf64-little"
36 if isinstance(instructions
, bytes
): # actual bytes
37 self
.binfile
= BytesIO(instructions
)
38 if orig_filename
is None:
39 self
.binfile
.name
= "bytes"
41 self
.binfile
.name
= orig_filename
42 self
.assembly
= '' # noo disassemble number fiiive
43 print("binary", self
.binfile
)
44 elif isinstance(instructions
, str): # filename
45 # read instructions into a BytesIO to avoid "too many open files"
46 with
open(instructions
, "rb") as f
:
48 self
.binfile
= BytesIO(b
)
49 self
.assembly
= '' # noo disassemble number fiiive
50 print("program", self
.binfile
)
52 if isinstance(instructions
, list):
53 instructions
= '\n'.join(instructions
)
54 self
.assembly
= instructions
+ '\n' # plus final newline
56 self
._instructions
= list(self
._get
_instructions
())
61 def __exit__(self
, type, value
, traceback
):
64 def _get_binary(self
, elffile
):
65 with tempfile
.NamedTemporaryFile(suffix
=".bin") as binfile
:
66 args
= [cmds
['objcopy'],
68 "-I", self
.endian_fmt
,
71 subprocess
.check_output(args
)
72 # copy over to persistent binfile (BytesIO)
73 self
.binfile
= BytesIO()
74 self
.binfile
.write(binfile
.read())
77 def _link(self
, ofile
):
78 with tempfile
.NamedTemporaryFile(suffix
=".elf") as elffile
:
84 subprocess
.check_output(args
)
85 self
._get
_binary
(elffile
)
88 with tempfile
.NamedTemporaryFile(suffix
=".o") as outfile
:
95 with subprocess
.Popen(args
, stdin
=subprocess
.PIPE
) as p
:
96 p
.communicate(self
.assembly
.encode('utf-8'))
98 print("Error in program:")
103 def _get_instructions(self
):
105 data
= self
.binfile
.read(4)
108 yield struct
.unpack('<I', data
)[0] # unsigned int
110 def generate_instructions(self
):
111 yield from self
._instructions
117 curpos
= self
.binfile
.tell()
118 self
.binfile
.seek(0, 2) # Seek to end of file
119 size
= self
.binfile
.tell()
120 self
.binfile
.seek(curpos
, 0)
123 def write_bin(self
, fname
):
125 data
= self
.binfile
.read()
126 with
open(fname
, "wb") as f
:
132 if __name__
== '__main__':
133 lst
= ['addi 5, 0, 4660/2',
139 lst
= ["addi 9, 0, 0x10", # i = 16
140 "addi 9,9,-1", # i = i - 1
141 "cmpi 2,1,9,12", # compare 9 to value 12, store in CR2
142 "bc 4,10,-8", # branch if CR2 "test was != 12"
146 with
Program(lst
, False) as p
:
147 for instruction
in p
.generate_instructions():
148 print (hex(instruction
))
149 p
.write_bin("/tmp/test.bin")