One of the easiest ways to get started using ARM64 (also known as AARCH64) is with Docker or Virtual Box. While setting up a Raspberry Pi with an AArch64 OS is doable (particularly with OpenSUSE), it can be much faster to just emulate a linux box or image on an x86 based machine. This post assumes you already have docker installed and running.
Docker
First, start a Debian command line:
docker run -it debian /bin/bash
It’s as simple as that.
Hello AArch64
There are two main dependencies for working with AArch64: qemu and
aarch64-linux-gnu-gcc. The first emulates execution of AArch64 binaries
and the latter is a cross compiler to AArch64.
The following commands compiles and prints the classic “hello, world\n”
message: (Note, replace vim with your favorite editor i.e. emacs)
apt-get update
apt-get install -y qemu-user-static gcc-aarch64-linux-gnu vim
vim hello.c
aarch64-linux-gnu-gcc -static hello.c -o hello
qemu-aarch64-static hello
Where hello.c is:
#include <stdio.h>
int main(void) {
printf("hello, world\n");
return 0;
}
In Debian, running qemu-aarch64-static hello is the same as running
./hello for an AArch64 binary hello. This does not necessarily
happpen with other operating systems.
Examine the Binary
To inspect the binary, it will be easier to look at the non-statically compiled version, so re-run gcc:
aarch64-linux-gnu-gcc hello.c -o hello
aarch64-linux-gnu-objdump -d hello > hello.dmp
vim hello.dmp
And inspect the <main>: address to see the disassembly:
0000000000000828 <main>:
828: a9bf7bfd stp x29, x30, [sp, #-16]!
82c: 910003fd mov x29, sp
830: 90000000 adrp x0, 0 <_init-0x658>
834: 91238000 add x0, x0, #0x8e0
838: 97ffffa6 bl 6d0 <puts@plt>
83c: 52800000 mov w0, #0x0 // #0
840: a8c17bfd ldp x29, x30, [sp], #16
844: d65f03c0 ret
Another way of looking at the pre-linked assembly code is of course to
just ask GCC for it: aarch64-linux-gcc hello.c -S and then open
hello.s:
.arch armv8-a
.file "hello.c"
.section .rodata
.align 3
.LC0:
.string "hello, world"
.text
.align 2
.global main
.type main, %function
main:
stp x29, x30, [sp, -16]!
add x29, sp, 0
adrp x0, .LC0
add x0, x0, :lo12:.LC0
bl puts
mov w0, 0
ldp x29, x30, [sp], 16
ret
.size main, .-main
.ident "GCC: (Debian 6.3.0-18) 6.3.0 20170516"
.section .note.GNU-stack,"",@progbits
Examining the differences between these files can be interesting, for
example the add instruction below main: was changed to a mov
instruction in the actual binary.
Compile Dynamically-Linked Binary
Why is the -static flag needed for cross-compiling the AArch64 binaries?
Without it, you will see something like this message:
root@30941edc6d88:~# ./hello
/lib/ld-linux-aarch64.so.1: No such file or directory
See “Qemu AArch64 User-Space Emulation” on just the topic.