On this page:
2.1.1 Assignment Summary
2.1.2 Language Diagram
2.1.3 Preface
2.1.4 Testing Your Development Machine
2.1.5 x64 References
8.10

2.1 Assignment 0: x64 to elf64

2.1.1 Assignment Summary

The goal of this assignment is to ensure that you have a working environment to start writing your compiler. Modern compiler construction always starts from an existing language and toolchain. This assignment will instruct you to install and test the required tools.

Assignment Checklist
  • Either:
    • Connect to a VUB machine, or

    • Setup a 64-bit Linux (virtual) machine for local development

  • Ensure racket >= 8.3 is installed.

  • Ensure nasm >= 2.13 is installed.

  • Ensure nasm is callable from Racket.

  • Compile and execute fact.s from the command line.

  • Compile and execute fact.s from Racket.

2.1.2 Language Diagram

%3L0x64L1elf64L0->L1nasm

2.1.3 Preface

Throughout this course, each assignment will come in two parts: an existing target language, and a new source language. The target language will be the same as the source language from the previous assignment. The goal of the assignment will be to identify limitations in the target language, design new abstractions that address those limitations, and implement a new source language with those abstractions. The implementation will be at least a compiler from source to target. The new compiler will be an extension of the old compiler.

However, for the first assignment, we have a problem: we have no previous languages, and no previous compiler.

We therefore start from someone else’s languages and compiler. For the source language, we pick x64. For the target, we choose bin64. Thankfully, someone has already written a compiler, called nasm, from x64 to bin64 for most machines. You can read more about these languages in A Compiler Begins with a Language.

2.1.4 Testing Your Development Machine

If you’re running your own Linux machine, I trust you can figure out how to install racket and nasm.

If you don’t have a Linux machine you should be using a VUB machine.

Whichever you choose, the following exercises will make sure your machine is setup and working properly.

First, let’s ensure Racket is installed properly and the right version. You will need racket version 8.3 or higher.

Exercise 1: Run racket --version, and check that a message like "Welcome to Racket v8.3.0.1" is printed, and that the version is at least "v8.3".

Next, we’ll test nasm. We need nasm version 2.13 or higher.

Exercise 2: Run nasm --version, and check that a message like "NASM version 2.14.02" is printed and that the version is at least "2.13".

We also need to be sure racket can find "nasm".

Exercise 3: Run racket -e "(with-output-to-string (thunk (system \"nasm --version\")))", and check that a message like "NASM version 2.14.02" is printed and that the version is at least "2.13".

Now you should be able to create and compile the following file fact.s.

global start

section .text

start:
  mov r8, 5

fact:
  mov r9, 1

fact_acc:
  cmp r8, 0
  je fact_done
  imul r9, r8
  dec r8
  jmp fact_acc

fact_done:
exit:
  mov     rax, 60
  mov     rdi, r9
  syscall
> nasm -f elf64 -o fact.o fact.s
> ld -e start -o fact.exe fact.o
> ./fact.exe
> echo $?
> 120

Exercise 4: Compile and execute fact.s from the command line. You should observe 120 as the exit code.

Instead of compiling manully using shell commands, we can compile and execute a file from Racket using system or system/exit-code to make calls to command line programs from Racket. This is how the last pass of the compiler will translate your code into an executable, and how you will test your compiler from Racket. The file fact.rkt demonstrates how to do this with the above assembly program.

Exercise 5: Modify and run the fact.rkt file to ensure the test passes, using raco test fact.rkt.

2.1.5 x64 References