1
0

Made infernal-intepreter more unix-like.

This commit is contained in:
Jon Michael Aanes 2017-11-19 16:53:15 +01:00
parent 57049e1377
commit 8d0b672b63
7 changed files with 131 additions and 89 deletions

View File

@ -6,7 +6,6 @@ from opcodes import OPCODES
REGISTERS=["%rax", "%rbx", "%rcx", "%rdx", "%rsp", "%rbp", "%rsi", "%rdi", REGISTERS=["%rax", "%rbx", "%rcx", "%rdx", "%rsp", "%rbp", "%rsi", "%rdi",
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"] "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"]
JUNK_VALUE = Junk.Junk()
class CodeParseException (BaseException): class CodeParseException (BaseException):
@ -14,16 +13,19 @@ class CodeParseException (BaseException):
self.line_nr = line_nr self.line_nr = line_nr
self.string = string self.string = string
class InternalExecutionException (BaseException):
pass
class Emulator: class Emulator:
def __init__ (self, source_text, max_stack_size=1000): def __init__ (self, source_text, max_stack_size=1000):
self.source = source_text self.source = source_text
self.registers = {} self.registers = {}
for reg_name in REGISTERS: for reg_name in REGISTERS:
self.registers[reg_name] = JUNK_VALUE self.registers[reg_name] = Junk.Junk()
self.stack = {} self.stack = {}
for i in range(max_stack_size): for i in range(max_stack_size):
self.stack[i] = JUNK_VALUE self.stack[i] = Junk.Junk()
self.code = [] self.code = []
self.labels = {} self.labels = {}
self.changes = {} self.changes = {}
@ -43,12 +45,12 @@ class Emulator:
for element in stack_list: for element in stack_list:
i -= 1 i -= 1
self.stack[i] = element self.stack[i] = element
if (not 'set_rsp' in kwargs) or kwargs['set_rsp']: self.setRegs(rsp=i)
self.setRegs(rsp=i) self.last_sp = i-1
self.last_sp = i-1
def setRegs (self, **reg_dict): def setRegs (self, **reg_dict):
for reg_name, reg_val in reg_dict.iteritems(): for reg_name, reg_val in reg_dict.iteritems():
assert(reg_name[0] != '%')
self.registers["%"+reg_name] = reg_val self.registers["%"+reg_name] = reg_val
def getVal (self, val_text): def getVal (self, val_text):
@ -127,8 +129,10 @@ class Emulator:
def iterate (self): def iterate (self):
old_rip = self.registers['%rip'] old_rip = self.registers['%rip']
self.last_sp = self.registers['%rsp'] self.last_sp = self.registers['%rsp']
if self.registers['%rip'] >= len(self.code): if self.registers['%rip'] >= len(self.code) or isinstance(self.registers['%rip'], Junk.Junk):
return None return None
if not isinstance(self.registers['%rip'], (int, long)):
raise InternalExecutionException("Register %rip should be integer, but was "+str(self.registers['%rip']))
instruct = self.code[self.registers['%rip']] instruct = self.code[self.registers['%rip']]
opcode = instruct[0] opcode = instruct[0]
self.changes = {} self.changes = {}
@ -153,4 +157,4 @@ class Emulator:
return output return output
def getUsedRegisters (self): def getUsedRegisters (self):
return [reg_name for reg_name, reg_val in self.registers.iteritems() if reg_val!=JUNK_VALUE] return [reg_name for reg_name, reg_val in self.registers.iteritems() if not isinstance(reg_val, Junk.Junk)]

11
Junk.py
View File

@ -5,14 +5,17 @@ class JunkComparisonException (BaseException):
class Junk: class Junk:
def __init__ (self): def __init__ (self, represents = None):
pass assert(represents == None or isinstance(represents, basestring))
self.repr = represents
def __str__ (self): def __str__ (self):
return "[Junk]" if self.repr:
return '['+self.repr+']'
return "[junk]"
def __repr__ (self): def __repr__ (self):
return "[Junk]" return self.__str__()
def __add__ (self, other): def __add__ (self, other):
return self return self

View File

@ -33,6 +33,7 @@ class TikzPainter:
pos -= 1.5 pos -= 1.5
base_sp = min(emu.last_sp, emu.getVal('%rsp')) base_sp = min(emu.last_sp, emu.getVal('%rsp'))
pos += 0.5 * max(0, emu.getVal('%rsp')-emu.last_sp) pos += 0.5 * max(0, emu.getVal('%rsp')-emu.last_sp)
assert(isinstance(emu.getVal('%rsp'), (int, long)))
for index in range(base_sp, 3+min(emu.max_stack_size, emu.getVal('%rsp')+self.max_stack_size)): for index in range(base_sp, 3+min(emu.max_stack_size, emu.getVal('%rsp')+self.max_stack_size)):
reg_state = emu.regState("m"+str(index)) reg_state = emu.regState("m"+str(index))
reg_dect = "register_node, fill="+self.getRegColor(reg_state)+"!10" reg_dect = "register_node, fill="+self.getRegColor(reg_state)+"!10"
@ -110,7 +111,7 @@ class TikzPainter:
self.addText("\t\\node[text_node]() at ({}, {}){{TOS-{}}};\n", self.addText("\t\\node[text_node]() at ({}, {}){{TOS-{}}};\n",
x, pos, index) x, pos, index)
def __str__ (self): def to_string (self):
PRE = """ \\documentclass{standalone} PRE = """ \\documentclass{standalone}
\\usepackage{tikz} \\usepackage{tikz}
\\begin{document} \\begin{document}
@ -118,3 +119,6 @@ class TikzPainter:
POST = """\\end{tikzpicture} POST = """\\end{tikzpicture}
\\end{document}""" \\end{document}"""
return PRE + "".join(self.text) + POST return PRE + "".join(self.text) + POST
def __str__ (self):
return 'TikzPainter[]'

View File

@ -0,0 +1,25 @@
# Interative Fibonnaci
# %rdi is the number for iterations.
fib: push %rbp # push previous base pointer
movq %rsp,%rbp # setup new base pointer
if: cmpq $1, %rdi # if (a-1) > 0: goto loops
jg loops
quick: movq %rdi, %rax
jmp return
loops: movq %rdi, %r8 # i (r8) = a
movq $1, %rdi # minus_one (rdi) = 1
movq $0, %rax # minus_two (rax) = 0
loopb: movq %rdi, %9 # r = minus_one
addq %rax, %rdi # minus_one += minus_two
movq %9, %rax # minus_two = r
subq $1, %r8 # i--
cmpq $0, %r8 # if a > 0
jg loopb
return: leave # Clean up
ret # return m (rax)

View File

@ -0,0 +1,24 @@
# Recursive Fibonnaci
# %rdi is the number for iterations.
fib: push %rbp # push previous base pointer
movq %rsp,%rbp # setup new base pointer
if: cmpq $1, %rdi # if (a-1) > 0: goto long
jg long
quick: movq %rdi, %rax
jmp return
long: pushq %rdi # Push a onto the stack
subq $1, %rdi
call fib # Call fib(a-1)
pushq %rax # Push fib(a-1) onto the stack
subq $1, %rdi
call fib # Call fib(a-2)
popq %rdi # pop fib(a-1) into rdi
addq %rdi, %rax # rax = fib(a-1)+fib(a-2)
popq %rdi # Guarantee that a lies in rdi.
return: leave # Clean up (stack pointers?)
ret # return m (rax)

View File

@ -1,10 +1,64 @@
import sys import sys
import getopt
from Emulator import Emulator, CodeParseException import re
import argparse
from Emulator import Emulator, CodeParseException, REGISTERS
from TikzPainter import TikzPainter from TikzPainter import TikzPainter
from Junk import Junk, JunkComparisonException import Junk
def parse_args ():
parser = argparse.ArgumentParser(description="For fun x86-64 emulator and stack visualizer.")
parser.add_argument('-i', '--input-file', default='-', help = '.S file to use as input', dest = 'filename')
for register in REGISTERS:
parser.add_argument('--'+register[1:], nargs = 1, type = int, default = [Junk.Junk()], dest = register)
args = vars(parser.parse_args())
# Determine args #
registers_init = {}
for register in REGISTERS:
registers_init[register[1:]] = args[register][0]
registers_init['rip'] = 0
registers_init['rsp'] = 0
registers_init['rbp'] = Junk.Junk('old bp')
program = ""
if args['filename'] == '-':
program = sys.stdin.read()
else:
with open(args['filename']) as file:
program = file.read()
return (program, registers_init)
def main ():
(program, registers_init) = parse_args()
# Determine registers to display
registers_to_draw = ["%rip","%rbp","%rsp", ""]
for match in re.findall(r"%r[a-z0-9]{1,2}", program):
if match not in registers_to_draw:
registers_to_draw.append(match)
# Setup emulator and drawer
emu = Emulator(program)
emu.setRegs(**registers_init)
emu.setStack(Junk.Junk("junk..."), Junk.Junk("calling eip"))
painter = TikzPainter(registers_to_draw)
# Iteratively draw states.
painter.drawState(emu)
for line_nr in emu:
painter.drawState(emu, line_nr)
painter.drawNames(emu)
# Display result
print(painter.to_string())
if __name__ == "__main__": if __name__ == "__main__":
pass main()

View File

@ -1,72 +0,0 @@
import os,sys,inspect
sys.path.insert(1, os.path.join(sys.path[0], '..'))
import infernal
fib_prog = """
fib: push %rbp # push previous base pointer
movq %rsp,%rbp # setup new base pointer
if: cmpq $1, %rdi # if (a-1) > 0: goto long
jg long
quick: movq %rdi, %rax
jmp return
long: pushq %rdi # Push a onto the stack
subq $1, %rdi
call fib # Call fib(a-1)
pushq %rax # Push fib(a-1) onto the stack
subq $1, %rdi
call fib # Call fib(a-2)
popq %rdi # pop fib(a-1) into rdi
addq %rdi, %rax # rax = fib(a-1)+fib(a-2)
popq %rdi # Garentee that a lies in rdi.
return: leave # Clean up (stack pointers?)
ret # return m (rax)
"""
fib_iter_prog = """
fib: push %rbp # push previous base pointer
movq %rsp,%rbp # setup new base pointer
if: cmpq $1, %rdi # if (a-1) > 0: goto loops
jg loops
quick: movq %rdi, %rax
jmp return
loops: movq %rdi, %r8 # i (r8) = a
movq $1, %rdi # minus_one (rdi) = 1
movq $0, %rax # minus_two (rax) = 0
loopb: movq %rdi, %9 # r = minus_one
addq %rax, %rdi # minus_one += minus_two
movq %9, %rax # minus_two = r
subq $1, %r8 # i--
cmpq $0, %r8 # if a > 0
jg loopb
return: leave # Clean up
ret # return m (rax)
"""
def printf (str, *args):
print(str.format(*args))
if __name__ == "__main__":
a = 3
printf("Running for fib({})", a)
# Setup
registers = ["%rip","%rbp","%rsp","","%rax","%rdi","%r8","%r9"]
emu = infernal.Emulator(fib_prog)
painter = infernal.TikzPainter(registers)
emu.setStack("junk...", "calling eip")
emu.setRegs( rip = 0, rbp = 'old bp', rdi = a )
painter.drawState(emu)
for line_nr in emu:
painter.drawState(emu, line_nr)
painter.drawNames(emu)
printf("fib({}) = {}", a, emu.registers["%rax"])
with open("tikz.tex","w") as f:
f.write(str(painter))