Compiling C code for MIPS and running it on x8610. Dec '13

So you want to compile a piece of C code for your MIPS64-based computer architectures lab? In that case you're in need of a cross-compiler toolchain 1 2. On your PC you probably have Intel's 32-bit processor, which is commonly abbrevated as x86 or it's 64-bit counterpart amd64. On your Ubuntu box you may run apt-get install gcc but as you've probably already guessed - it produces binaries which are compatible with x86 or amd64 architectures.

Your router probably runs MIPS32 architecure based processor and for that you need what is called a cross-compiler toolchain. Creating such toolchain is a tedious task because you need to compile bunch of tools: GCC capable of producing binaries for MIPS, binutils to compile assembly code and link MIPS binaries, GNU C Library for MIPS and many more.

The easy way out is to use OpenWrt and let it compile the toolchain for you. OpenWrt is a commonly used software for routers. First make sure you have all the bells and whistles installed on your Ubuntu box:

sudo apt-get install libncurses5-dev gawk flex build-essential qemu-user

You can start off by checking out the Git repository of OpenWrt:

git clone git://git.openwrt.org/openwrt.git

Next enter the freshly created directory and fire up the OpenWrt configuration interface:

cd openwrt
make menuconfig

By default it compiles the firmware for Atheros AR7xxx SoC based routers, which incidenly are based on MIPS processors, so there isn't really much to configure. Exit the menuconfig and go make yourself a cup of coffee while the toolchain are firmware are being built:

nice make -j16

If you're lucky enough to not run into trouble by getting an obscure error, you may find the produced cross-compiler toolchain under staging_dir/ directory. Now to make it even more compilcated - OpenWrt relies on your host machine as less as possible, therefore in the staging_dir/ directory there should be three directories:

  • host - Required tools and libraries to be run on the host machine (x86/amd64)

  • toolchain-mips_34kc_gcc-4.6-linaro_uClibc-0.9.33.2 - Toolchain that runs on the host machine and which produces binaries for the target architecture (mips32)

  • target-mips_34kc_uClibc-0.9.33.2 - Libraries and files of the target architecture

What you probably want to do it so include the cross compiler binaries in your $PATH:

export STAGING_DIR=/path/to/openwrt/staging_dir/toolchain-mips_34kc_gcc-4.6-linaro_uClibc-0.9.33.2
export PATH=$PATH:$STAGING_DIR/bin

You may want to put down those lines to a file let's say loadenv.sh, so you may easily load such environment by issuing:

source loadenv.sh

Assuming that everything went as planned you should be able to run the C cross-compiler:

mips-openwrt-linux-gcc hello.c -o hello -static

Note that we ran the C compiler with -static directive so we won't have to mess around with dynamic linking issues later when we try to run that program. This also means that your binary will run on any binary-compatible machine regardless of C library version etc.

Now of course you can't run that binary on your x86 machine:

localhost ~ # ./hello
-bash: ./hello: cannot execute binary file

If you paid attention to the apt-get command issued earlier in this article you should have installed QEMU on your Ubuntu box by now. QEMU is an awesome piece of software which besides traditional virtualization is capable of running bare binaries on completely different architecture:

localhost ~ # qemu-mips hello
Hello World

To compile binaries for MIPS64 architecture you just need to have additional architecture directive which tells the compiler to enable MIPS64 specific instructions:

mips-openwrt-linux-gcc hello.c -o hello-mips64 -static -march=mips64r2

You may use file command to identify your binaries:

localhost ~ # file hello
hello: ELF 32-bit MSB  executable, MIPS, MIPS32 rel2 version 1, statically linked, not stripped
localhost ~ # file hello-mips64
hello-mips64: ELF 32-bit MSB  executable, MIPS, MIPS64 rel2 version 1, statically linked, not stripped

And now finally we get to the most interesting part! With the -S directive you can tell the GNU C compiler to produce assembly for the target architecture:

mips-openwrt-linux-gcc hello.c  -S -o hello.s
1

Cross compiler

2

Cross-Compiled Linux From Scratch

QEMU computer architecture MIPS OpenWrt cross-compiling git gcc TU Berlin