ARM64 Assembly
All development is being done on a Linux based system (Debian), I am making use of scanf and printf to handle user input and output.
While the more correct way to load an address for a variable is:
adrp x0, variable
add x0, x0, :lo12:variable
I will be using:
ldr x0, =variable
1. Hello World
// hello_world.s
.global main
.extern printf
.data
message:
.asciz "Hello World!\n"
.text
main:
// prolog // Used to store the current frame pointer and return addr before prog runs
stp x29, x30, [sp, -16]! // Store the frame pointer and the return addr to the stack
mov x29, sp // Load the frame pointer with the new stack pointer
// main code
ldr x0, =message // Load x0 with the address of the string
bl printf // Print the string
// cleanup
mov x0, #0 // Load x0 with an exit code. Zero for clean exit
ldp x29, x30, [sp], 16 // Restore the original frame pointer and return addr
RET // Return from our programme
This, very simple, application demonstrates the structure of the code as it will be demonstrated throughout this tutorial.
It also demonstrates some practices that will be required to ensure that running these apps does not clobber the OS as a whole.
Code layout
The exact order of the code elements is not, generally, critical. Code in this tutorial will be laid out in the following way:
- A comment repeating the name of the source file.
- The global declaration of the entry point and any external libraries that will be required such as printf and scanf.
- The data section. While this section could be divided into .data and .rodata (read only data), only .data will be used for simplicity.
- The text section or main code section. This will, generally, have the following sections within:
- The prologue. This pushes the frame pointer and link register to the stack so they can be restored after the code has run.
- The main code.
- The cleanup. This moves an exit code into x0 and restores the frame pointer and link register.
- Any internal functions.
Code explanation
At the top of the code is:
// hello_world.s
This is a comment. Any text following a double forward slash is ignored by the assembler.
Below that are the following lines:
.global main
.extern printf
The .global main tells the assembler how to find the start of the application when it runs.
The .extern printf tells the assembler to include a link to the C printf function as it will be used in the code.
Below that are the following lines:
.data
message:
.asciz "Hello World!\n"
This section declares variables that will be used by the code. Memory is allocation on the heap for the variables.
In this case, a string of ascii values is stored. The base address of the string will be pointed to by the "message" variable.
Below that are the following lines.
.text
main:
// prolog // Used to store the current frame pointer and return addr before prog runs
stp x29, x30, [sp, -16]! // Store the frame pointer and the return addr to the stack
mov x29, sp // Load the frame pointer with the new stack pointer
// main code
ldr x0, =message // Load x0 with the address of the string
bl printf // Print the string
// cleanup
mov x0, #0 // Load x0 with an exit code. Zero for clean exit
ldp x29, x30, [sp], 16 // Restore the original frame pointer and return addr
RET // Return from our programme
The code is commented so no further commentary is required.