Compile - Geek went Freak!


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.


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

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


Lets assemble the assembly file using GCC assembler.

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


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.

Modelsim: compile and simulate VHDL from command line

Modelsim has a pretty clumsy and ugly user interface(atleast in linux). Moreover, command line gives more control and makes automation easier. Lets see how we can simulate VHDL project using modelsim command line tools. Before starting, make sure you have modelsim’s bin directory in your PATH. To demonstrate, I will reuse the fileio example. Lets assume you have the above vhdl files in a project directory. In the command line, change to the project directory.

First we have to create a work library:

vlib work

Now, compile the VHDL files:

vcom fileio.vhd gen.vhd

Note: The files should be listed in hierarchical order.

To simulate using GUI:

vsim fileio

Note: vsim takes the name of the top level module to be simulated, not the name of the top level module’s VHDL file.

Adding the -c option starts the simulator in command line interactive mode.

vsim -c fileio

You should be in VSIM’s prompt. From here you can type commands to add signal to the wave, run simulation, write to vcd file, etc.

Show available signals

The VSIM command to list all available signals

show -all

You can also list all available signals in an instance

show fileio
show gen_inst

To unambiguously show signals of an instances down the hierarchy

show /fileio/gen_inst

Adding signals to wave

add wave i_a

You can also add signals of an instance down the hierarchy

add wave /fileio/gen_inst/a_i

Run the simulation

To run the complete simulation

run -all

To run for a specified time


Follow this blog post to generate VCD waveform from command line.

Automate simulation

The best thing is you don’t have to type these commands every time you launch vsim. You can automate the process by specifying the .do in the vsim command. The .do should contain the list of commands you want to execute to run the simulation.

Here is the updated command to lauch fileio example:

vsim -c -do fileio

compiling systemc TLM examples

SystemC TLM is available for download from here. To compile TLM examples, you must have systemC installed. Install systemC libraries. Extract the TLM archive you downloaded and set $TLM_HOME pointing to top-level directory where you extracted TLM archive. Add these lines to ~/.bashrc,

export SYSTEMC_HOME=/usr/local/systemc-2.2/
export TLM_HOME=/home/sairam/Public/TLM-2009-07-15

Replace the above paths with where you installed your systemc and TLM respectively. In TLM directory, navigate to examples/tlm/build-unix/ and comment out the following line in Makefile.config,


From build-unix directory, in the terminal, execute the following to compile and run TLM examples,

make run

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,

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