Running Programs Compiled with ACCGen

Introduction

In a previous blog entry, I listed the necessary steps to retarget the LLVM compiler to ARM using the ACCGen project, the ArchC Compiler Generator. In this document, I will describe how we can test this compiler by using it to compile MiBench programs to ARM binaries and also how to assess their performance by running them on the ArchC ARM simulator.

Updated 9/6/2013: Now ACCGen is included into the ArchC virtual machine (Ubuntu virtual machine with ArchC 2.2). If you decide to download and use it, you can assume all configuration and installing steps of the ACCGen previous tutorial are already completed.

Environment

I suppose you already completed the steps in this previous blog entry or you downloaded the ArchC virtual machine with ACCGen preinstalled. You should have set up paths to use ArchC and the ACCGen generated compiler (already done in the virtual machine).

Additionally, we will use an existing ARM assembler and linker to test our C programs. We do not use the ArchC assembler generator here because it produces linkers that are incompatible with the ARM EABI. Adhering to the EABI is important if we want to link to an existing ARM C library (either newlib of glibc).

If we wanted to compile bare-metal C programs that are not linked with a runtime library, we could use the complete ArchC toolchain generation suite (ACCGen and acbinutils). Nevertheless, we do not want to create custom benchmarks to test our compiler, therefore we rely on the MiBench benchmark which depends on the C runtime library.

1) Use arm-softfloat-gcc 3.4.5 with glibc 2.3.6. I will point to a link to download it below.

Installing the ARM assembler and linker

Uncompress the ARM toolchain package:

$ wget http://www.ic.unicamp.br/~auler/arm-softfloat-linux-gnu.tar.bz2
$ tar xjvf arm-softfloat-linux-gnu.tar.bz2

This toolchain was built with crosstool. The correct gcc cross compiler that target the ArchC ARM model v0.7.0 is the gcc 3.4.5 with software floating point and glibc 2.3.6. Notice that our ARM model does not implement floating point instructions. I could write a tutorial to build your own ARM toolchain, but things can get really clumsy depending on your Linux version, so I decided to just pack the final binary and release it to download. However, you may also adventure yourself into the crosstool page to build your own version.

You must set the PATH to use this ARM toolchain.

$ export PATH=$PATH:$(pwd)/arm-softfloat-linux-gnu/bin

Now you should be able to compile ARM programs using a gcc cross compiler, if you want to. Just use the prefix arm-softfloat-linux-gnu. For example:

$ arm-softfloat-linux-gnu-gcc myprogram.c -o armbinary

However, in this tutorial we will only use its assembler, linker and the glibc libraries. The compiler per se was generated by ACCGen in the previous tutorial and we want to test it.

Building the ARM simulator

This step is unnecessary if you have downloaded the ArchC virtual machine. Just use the arm-sim command to run the simulator.

We will use ArchC to generate an ARM simulator based on the ARM model v0.7.0. I suppose you already set up the environment from the previous blog post, so:

$ cd armv5-v0.7.0
$ acsim armv5e.ac -nw -abi
$ make -f Makefile.archc

You should wait around 3 minutes. After compilation, we can install it in our default directory to avoid setting up another path.

$ cp armv5e.x ../install/bin

Testing the simulator

Our new simulator is able to load dynamic libraries, and that is the reason it can run executables produced by the ARM toolchain that uses glibc, which is always dynamic (I believe that if it is possible to build a static glibc, it should be painful). The down side is the necessity to manually configure the path to the shared libraries of ARM. Since we are using the toolchain produced by crosstool, we need to set up a path to it. The name of the environmental variable was selected to be meaningful only to ArchC simulators and avoid confusion with the dynamic libraries from your host system. We also use this variable to hold another path to the ARM model directory, since the dynamic linker will use it to load a relocation code conversion table (ac_rtld.relmap) to be able to understand the ARM ABI, used in a toolchain that is not from ArchC (the cross gcc).

$ cd ..
$ export AC_LIBRARY_PATH=$(pwd)/arm-softfloat-linux-gnu/arm-softfloat-linux-gnu/lib:$(pwd)/armv5-v0.7.0

Now, we need a compiler driver to use a variety of tools to finish compilation. If you recall correctly, we will use our own LLVM compiler, generated by ACCGen, and the assembler, linker and runtime library of the gcc cross compiler for ARM. I wrote a naive driver that compiles .C files to illustrate the concept. Install this script in your path:

$ cd install/bin
$ wget http://www.ic.unicamp.br/~auler/my_cc

Check the contents so you understand what is happening:

$ cat my_cc
$ cd ../..

Now we are finally able to compile and run our first C application using our automatically generated compiler. Remember the simple program from the previous tutorial? I will copy its code here to refresh your memory:

#include 

int
main() {
  int i = 0;
  scanf ("%d", &i);
  printf ("%d\n", i + 5);
  return 0;
}

We saved it as test.c. Now compile it using the full toolchain. It should generate test.s, the assembly file, using LLVM, generate the object code test.o using binutils assembler and finally generate the final executable "test" using binutils ld. This executable is dynamically linked to the C runtime library glibc for ARM.

$ my_cc test.c

Run the test program using the simulator that was previously created.

$ armv5e.x --load=test

The program should start running and then stop when calling the read() syscall, waiting for your input (a number). Type any number and then press enter. The program will print its output and, when it calls the exit() syscall, the simulator quits.

Compiling and testing the MiBench benchmark

You can download a package with a subset of MiBench applications that already has adjusted Makefiles to work with this infrastructure.

$ wget http://www.ic.unicamp.br/~auler/mibench-arm.tar.bz2
$ tar xjvf mibench-arm.tar.bz2

Enter the folder of the program you want to test. The Makefile is configured to compile it using either your gcc toolchain or our automatically generated LLVM toolchain. When you want to use the first, you should use the "original" Makefile rule, and for the latter use "archc". For example, to compile adpcm using our generated LLVM compiler, use:

$ cd mibench/adpcm
$ make archc

You can test each MiBench program using either a small or large input. If you want to use a small input, you can run the runme_small.sh script. However, if you prefer large inputs, run runme_large.sh. Whatever is your choice, remember you need to set the SIMULATOR environmental variable to point to our generated simulador with ArchC.

$ export SIMULATOR="armv5e.x --load="
$ ./runme_small.sh

Notice that if you are using the preinstalled arm simulator that comes in the ArchC virtual machine, the SIMULATOR variable should be "arm-sim --load=".

You should see the simulator running, but the output of the program is typically saved to some files. Find the files starting with "output" to check for them.