Cross - Geek went Freak!

Cross

Ubuntu: Cross-compile baremetal Cortex-M assembly program

In this post, we will cross-compile a small baremetal program for ARM processor on an Ubuntu machine.

ARM cross-compile toolchain

First step is to install the ARM cross-compiler toolchain. Luckily Ubuntu already has it in its software repository. Execute the following command in the terminal to install ARM EABI compatible tool chain:

sudo apt install gcc-arm-none-eabi

Check the version of the installed compiler using the following command:

arm-none-eabi-gcc --version

Sample baremetal program

Now, we need a sample baremetal program to compile. I have choosen a very simple assembly program.

startup.S

.global _start
_start:
  B _reset /* Reset */
  B . /* Undefined */
  B . /* SWI */
  B . /* Prefetch Abort */
  B . /* Data Abort */
  B . /* reserved */
  B . /* IRQ */
  B . /* FIQ */

_reset:
  mov r1, #10
  ldr r0, =0x20000000
  str r1, [r0]
  ldr r2, [r0]
  B .

Assemble

Lets assemble the assembly file using GCC assembler.

arm-none-eabi-as -mcpu=cortex-m3 -g startup.S -o startup.out

Link

Finally lets link the object file startup.out generated by the assembler.

arm-none-eabi-ld -Ttext=0x0 -o startup.elf startup.out

Note: Since the program is very simple, I haven’t used any linker script here.

-Ttext=0x0 option instructs the linker to use 0x0 as the starting address of the instructions.

cross compiling for ARM - the LLVM way

I have never used a compiler other than gcc before to cross-compile c code for ARM. This is the first time I am straying outside gcc. All these days I have always heard all kinds of promising reviews on LLVM. So Let us try it out now. If you are using ubuntu, you can install llvm using apt,

apt-get install llvm clang

If you are using any other distribution, follow these instructions to compile llvm from source.

Its time to get our hands dirty. Here is the simple code we are going to compile,

#include
int main()
{
  printf("Hello World!");
  return 0;
}

The compiling process is like this, 1. compile c code into llvm assembly using clang 2. convert llvm assembly into ARM assembly using llc 3. convert ARM assembly code into binary/ELF using binutils

clang -emit-llvm hello.c -c -o hello.bc

-emit-llvm option instructs clang to generate llvm assembly. The generated llvm assembly, hello.bc can be executed using lli.

lli hello.bc

Let us convert this llvm assembly into ARM assembly,

llc -march=arm hello.bc -o hello.s

Now, we can binutils(as + ld) to assemble and link these generated ARM assembly files.

arm-elf-gcc hello.s -o hello.elf

You can use gdb to simulate the generated elf.

Update: Here is the single command which compiles, assembles and links the given c code,

clang -march=armv7-a -ccc-host-triple arm-elf -ccc-gcc-name arm-elf-gcc hello.c