EE3220 System-on-Chip Design
Tutorial 6: Basic Compiler Workflow
Objectives
In this tutorial, you will:
Learn basic ARM assembly instructions and compiler workflow
Use QEMU-USER to emulate around ARM assembly
Learn the transformation among C code, ARM assembly and binary
In system-on-chip, the software program is converted to assembly code, and then it transforms to
machine-code. Therefore, it is important to understand the basic ARM instructions and compiler
workflow. In this tutorial, we will learn a new tool called QEMU with user mode to emulate around
ARM assembly on x86_64 architecture. And we also will learn the transformation among C code,
ARM assembly and binary: C code to binary, assembly to binary and Disassembly.
Linux Introduction
An operating system (OS) is system software that manages computer hardware and software
resources, and provides common services for computer programs.
Linux is a family of Unix-like computer operating systems assembled under the model of free and
open-source software development and distribution. Unix is a multi-user operating system that
has been originally written in the programming language C, and is therefore a classical platform
for C-programs. Unix contains well suited environments for program development (C, C++, Java,
...). Unix is originally command-line oriented, but can be used via a graphical user interface.
Ubuntu is a specific Linux distribution composed mostly of free and open-source software.
1
C Code to Binary
We use this Ubuntu LTS version of virtual machine based on Intel Core as the host platform in
tutorial 6. Firstly we learn how to transform C code to machine-code by cross-compiler.
Statically Linked ARM64 Binary
Steps:
1. Install following packages.
ee3220@ee3220-virtual-machine:~$ sudo apt update -y && sudo apt upgrade -y
ee3220@ee3220-virtual-machine:~$ sudo apt install qemu-user qemu-user-static gcc-
aarch64-linux-gnu binutils-aarch64-linux-gnu binutils-aarch64-linux-gnu-dbg
build-essential
2. Write a easy C code for the test. We create a helloworld.c, and write following code:
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0;
}
3. We compile helloworld.c to static executable file helloworld64 with compiler aarch64-linux-
gnu-gcc and static tag.
ee3220@ee3220-virtual-machine:~$ aarch64-linux-gnu-gcc -static -o helloworld64
helloworld.c
4. Check the host and binary information. Then we execute the file.
ee3220@ee3220-virtual-machine:~$ uname -a
ee3220@ee3220-virtual-machine:~$ file helloworld64
ee3220@ee3220-virtual-machine:~$ ./helloworld64
2
We can still run the ARM binary on x86_64 architecture with the help of qemu-user-static.
Dynamically Linked ARM64 Binary
Steps:
1. We compile helloworld.c to dynamic executable file helloworld64dyn with compiler aarch64-
linux-gnu-gcc without static tag.
2. Use qemu-aarch64 and add the -L flag to support the aarch64 libraries.
ee3220@ee3220-virtual-machine:~$ aarch64-linux-gnu-gcc -o helloworld64dyn
helloworld.c
ee3220@ee3220-virtual-machine:~$ qemu-aarch64 -L /usr/aarch64-linux-gnu
./helloworld64dyn
Comment
If you want to convert C code to assembly without command lines above, please access online
compile tool https://godbolt.org/ for reference.
Assembly to Binary
We attempt to convert assembly to binary.
Steps:
1. Please copy following code to a new assembly file newhello.s
.section .text
.global _start
_start:
/* syscall write(int fd, const void *buf, size_t count) */
mov x0, #1
ldr x1, =msg
ldr x2, =len
mov w8, #64
svc #0
/* syscall exit(int status) */
mov x0, #0
mov w8, #93
3
svc #0
msg:
.ascii "This is ARM64 architecture!\n"
len = . - msg
2. It's necessary to choose proper cross-assembler and linker to identify instructions. We can
get newhello.o and binary newhello, then execute it.
ee3220@ee3220-virtual-machine:~$ aarch64-linux-gnu-as newhello.s -o newhello.o
ee3220@ee3220-virtual-machine:~$ aarch64-linux-gnu-ld newhello.o -o newhello
ee3220@ee3220-virtual-machine:~$ ./newhello
Disassembly: Binary to Assembly
In this section, we use objdump tool to implement disassembly. We can use tool arm-linux-
gnueabihf-objdump to transform ARM32 binary to assembly.
C Code to ARM32 Binary
Steps:
1. Install following packages.
ee3220@ee3220-virtual-machine:~$ sudo apt install gcc-arm-linux-gnueabihf
binutils-arm-linux-gnueabihf binutils-arm-linux-gnueabihf-dbg
2. a) Compile helloworld.c to static ARM32 binary helloworld32 and execute it.
ee3220@ee3220-virtual-machine:~$ arm-linux-gnueabihf-gcc -static -o helloworld32
helloworld.c
ee3220@ee3220-virtual-machine:~$ ./helloworld32
b) Compile helloworld.c to dynamic ARM32 binary helloworld32dyh and execute it.
ee3220@ee3220-virtual-machine:~$ arm-linux-gnueabihf-gcc -o helloworld32dyh
helloworld.c
4
ee3220@ee3220-virtual-machine:~$ qemu-arm -L /usr/arm-linux-gnueabihf
./helloworld32dyh
ARM32 Disassembly
Steps:
ee3220@ee3220-virtual-machine:~$ arm-linux-gnueabihf-objdump -d helloworld32dyh
Reference
1. https://azeria-labs.com/arm-on-x86-qemu-user/
2. https://en.wikipedia.org/wiki/Operating_system
3. https://www.bu.edu/tech/files/2018/05/2018-Summer-Tutorial-Intro-to-Linux.pdf
4. https://www.usm.uni-muenchen.de/people/puls/lessons/intro_general/Linux/Linux_for_begi
nners.pdf
5. https://en.wikipedia.org/wiki/Linux
6. https://en.wikipedia.org/wiki/Ubuntu
7. https://en.wikipedia.org/wiki/%22Hello,_World!%22_program
8. https://godbolt.org/