Introduction

Recently, I got to teach a graduate course about Computer Architecture and Assembly Language and for the homework part, I wanted students to write SPARC assembly programs.

Since actual SPARC computers are not very common these days, my choice went on using QEMU to do the job of running those programs.

In this article, I detail two solutions, both using QEMU. The first uses a full system emulation, which is when QEMU runs a fully fledged operating system (such as Debian). The second solution, much simpler, uses QEMU as an userspace emulator, thus not requiring any functional operating system running underneath.

QEMU as system emulator

My first intuition was that I would distribute QEMU images containing a Debian installation as explained in this tutorial.

After downloading the prebuilt image, I updated it, changed the keyboard layout and installed a gcc toolchain as explained in this tutorial.

Once QEMU is installed on the host computer, running a simulation is not difficult (here we start the emulation of a SPARC computer with 256 Mb of memory):

$ qemu-system-sparc -m 256 -hda debian_etch_sparc_small.qcow2

However, if we want to write the source code of our programs on the host computer and then be able to copy the source on the emulated Debian system, we have to create a ssh port redirection:

$ qemu-system-sparc -m 256 -hda debian_etch_sparc_small.qcow2 -redir tcp:2222::22

The command above means that the port 2222 of the host computer is now binded to the port 22 of the emulated system.

Now we can copy a file named source from the host computer to QEMU:

$ scp -P 2222 source user@localhost:.

After typing this command, the file source should be at the root of the user's root directory in the emulated Debian system.

As you can see, the utilization of this setup is a bit complicated. First it means distributing a +500Mb image to hundreds of students. Second it also means that the workflow is quite difficult: students have to write their code on their local computer before copying it in the QEMU image in order to compile and test it.

We can also add to the list of inconveniences the fact that for some reason, the emulated Debian system can't seem to properly shutdown. And finally, since we want to automate the correction, using such a setup would make things really complicated.

That is why the second solution seems like the best one.

QEMU as an userspace emulator

QEMU usually comes in two flavors: qemu-system-* are system emulators (able to run entire operating systems as seen in the previous section), while qemu-* are userspace emulators (only able to run userspace applications).

QEMU as an userspace emulator is thus able to directly execute a SPARC application, by emulating the syscalls that the application requests.

Among the greatest features of this approach are:

QEMU really just acts as a wrapper around the application, as time or nice do.

The only complicated thing you have to do in this approach is to compile a cross-toolchain for SPARC, so SPARC programs can be compiled on the host computer. Such a cross-toolchain can be generated by using the fabulous crosstool-ng.

Let's assume here that you were able to generate a SPARC cross-toolchain with uCLibc support: sparc-unknown-linux-uclibc-*.

The first thing is to set the following environment variable, otherwise QEMU will not be able to find the SPARC standard libraries:

$ export QEMU_LD_PREFIX=/pathtocrosstoolchain/sparc-unknown-linux-uclibc/sparc-unknown-linux-uclibc

The detailed explanation is that the cross-compiler compiles and links SPARC applications as if they were to be executed on a real system (i.e. with standard libraries being in /lib, etc.). This environment variable thus tells QEMU not to look for the SPARC standard libraries in the regular locations since the regular locations on the host computer contain only the libraries for the host computer (e.g. for the x86 architecture).

Another option is to start QEMU with the -L option and give the path to the SPARC libraries directly on the command line.

The path to the SPARC libraries is the folder that contains the following files:

$ ll /pathtocrosstoolchain/sparc-unknown-linux-uclibc/sparc-unknown-linux-uclibc
dr-xr-xr-x 2 user users 4096 2014-11-24 13:09 bin
dr-xr-xr-x 3 user users 4096 2014-11-24 13:09 debug-root
lrwxrwxrwx 1 user users   11 2014-11-24 12:49 lib -> sysroot/lib
lrwxrwxrwx 1 user users    3 2014-11-24 12:49 lib32 -> lib
lrwxrwxrwx 1 user users    3 2014-11-24 12:49 lib64 -> lib
dr-xr-xr-x 4 user users 4096 2014-11-24 12:49 sysroot

Now you can easily compile and test SPARC programs:

$ sparc-unknown-linux-uclibc-gcc -o hello hello.c
$ qemu-sparc ./hello joel
hello joel!
$

Note that it is quite likely that QEMU will display a warning, mentioning something wrong with /etc/ld.so.cache. It is because the dynamic loader of the SPARC cross-toolchain (ld-uClibc.so.0) refers to /etc/ld.so.cache. But obviously, the ld.so.cache on the host computer does not correspond to what the SPARC dynamic loader expects.

So in order to avoid having an annoying warning each time we start an application, we have to edit the file ld-uClibc.so.0 (located in /pathtocrosstoolchain/sparc-unknown-linux-uclibc/sparc-unknown-linux-uclibc/lib/). Locate the string /etc/ld.so.cache in the binary (no need to use xxd or any other hexadecimal editor, vim is perfectly adequate for the task) and just replace etc by something else (e.g. xxx). Save and that's it, you can now rerun without any warning!