AArch64 assembly - part 1
Author: Carmelo C.
Published: Feb 27, 2025 (updated)assembly
arm64
aarch64
coding
AArch64
Index
Let’s break the ice
… or, let’s quickly generate some assembly code and run it.
Our very first program
Let’s write a small assembly program that does nothing but exits by leaving a specific return code.
Copy and paste the following code into a file named answer.s
.
/*
File: answer.s
Purpose: runs and, immediately, exits while leaving a return code that
can be displayed through the OS
Example:
$ ./answer
$ echo $?
42
*/
.text
.global _start
_start:
mov x0, #42 // x0 ← 42
mov x8, #93 // x8 ← 93 (__NR_exit)
svc #0 // syscall
The program can be assembled and linked with as
and ld
from binutils
:
$ as -g answer.s -o answer.o
$ ld answer.o -o answer
NOTE: option -g
in the first step is used to retain symbols in the code. It is optional but it can be used for debugging purposes.
Finally, as mentioned in the code, it can be run as follows:
$ ./answer
$ echo $?
42
Wut?
Oh! Wow! Indeed it works… and, apparently, it didn’t break anything. Good!
Let’s dig a bit deeper and look at what we’ve done.
Our file answer.s
is a tiny text file abiding to a specific syntax. A few elements can be identified:
/*
and*/
: multi-line comment, anything in between is ignored by the assembler (as
)//
: single-line comment, anything between the double forward slashes and the end of the line is ignored.text
: this statement marks the beginning of our code.global
: this statemenet is followed by a symbol (_start
) which is exposed to the linker (ld
); anything after_start
is our real codemov
: this is an AArch64 instruction whose aim is to move some data (#42
, decimal42
) tox0
(the first general-purpose register in ARMv8 processors)svc
: this instruction passes control back to the OS while invoking thesyscall
whose number has been stored inx8
Once the file has been saved it is assembled withas
and, finally, linked withld
. The resulting file can be run from the command line and its output can be read with theecho $?
command. Easy, huh!?!
NOTE: for more info on syscall
try man syscall
. Hint:
$ grep 93 /usr/include/asm-generic/unistd.h | head -n1
#define __NR_exit 93