1
0
notes/website/2018-02-06-infernal-interpreter.md

4.7 KiB

Infernal Interpreter

The dComArk Course

My first semester of University (summer 2015) I had a course named Computer Architecture commonly shorted to dComArk. It was a standard course about the low level construction of modern computers. It followed Tanenbaum's classic Structured Computer Organization. The course itself was known for its idiosyncratic lecturer, and for being hard as hell. Topics included registers, the stack, assembly code, micro-code, and the architecture of processors in general.

Jumping directly from just having learnt Java, as a first programming language, to suddenly having to understand and write low-level programming languages such as IJVM and X86-64 assembly, was tough, and many of my fellow students dropped out because of it.

My favorite assignment was the one where we extended IJVM with a new op-code. You see, some processors are programmable, in their own highly restricted programming language. Changing something you think is set in stone - like the set of op-codes a processor has - changes the way you see the world.

But this article is neither about IJVM, nor about micro-code. It's about the course's fifth and final assignment. For this assignment we were to write a recursive fibonnaci function in x86-64, and then describe how it worked, with visualizations of the registers and stack at every instruction.

Example of the recursive Fibonacci function in x86, with
comments.

A friend of mine spent an entire evening on this assignment carefully drawing the registers and stack into Excel. I decided I'd rather spend an evening programming, than messing about with Excel, so I began writing a program that could generate code for embedding into LaTeX. The program needed to emulate just enough X86-64 to run the function, and no more.

The Infernal Interpreter

Example of Infernal Interpreter output. Columns describe the
movement of data when executing x86
op-codes.

Infernal Interpreter is an emulator and visualizer of a subset of the AMD x86-64 ABI, using the GAS syntax. You give it a bunch of symbolic machine code, after which it produces a visualization of the running code, either to the terminal, or as a LaTeX file with Tikz.

It's old, written in Python 2, and for an incredibly specific purpose, but I enjoy going back and looking at the output.

There is something at once uncomfortable and fascinating about looking at old code. Thoughts of "How could I ever write code this bad?" and "Damned, I've gotten a lot better since then". While writing this article I wanted some images that fits the style of my website, so I added a ascii painting mode, that shows the trace in the terminal. This was non-trivial, given the existing structures, which were clearly designed to be as obscure as possible. Along the way the frontend was updated to be more UNIX-like. The backend is a nightmare, and has been kept without major changes.

If you'd like to take at look at it as well, you can find an an example of the tikz output here. Alternatively you can download the program itself, or view the official Git repository. Infernal Interpreter requires Python 2, and will crash on anything remotely complicated. Notably: it does not model the heap. The source-code is available under the BEERWARE license, so you are free to modify it as you like.

Example of Infernal Interpreter output, with the Tikz painter.
Columns describe the movement of data when executing x86
op-codes.

The program includes two example files in the examples folder, both of which were part of my assignment, and has been included unaltered. You can run them with a command like this:

./infernal
    -i=examples/fibonnaci_recursive.S
    --rdi=3

The --rdi=3 argument is important, because it sets the %rdi register to 3, and thus tells the program to compute the 3rd Fibonacci number. This writes ascii directly to the terminal. To produce Tikz, simply change the painter: --painter tikz. The full options can be found by running ./infernal --help