Introduction to Arm64 Assembly on Raspberry Pi¶
Introduction¶
Arm64 assembly language, also known as AArch64, is the native instruction set for modern Raspberry Pi models (Raspberry Pi 3, 4, and 5 with 64-bit OS). Understanding assembly language provides direct control over the processor, enables performance-critical optimizations, and deepens your understanding of how high-level languages like C++ are translated into machine code.
Learning Arm64 assembly on Raspberry Pi is particularly valuable because:
- Direct Hardware Control: Access GPIO, memory-mapped peripherals, and system resources without abstraction layers
- Performance Optimization: Write critical code sections that execute faster than compiler-generated code
- Deeper Understanding: Gain insight into how processors execute instructions, manage memory, and handle function calls
- Embedded Systems Development: Essential knowledge for bare-metal programming and operating system development
- Debugging Skills: Better understand crashes, stack traces, and low-level behavior of your programs
This guide assumes you're familiar with C++ programming and basic computer architecture concepts. We'll start with setting up the development environment and writing our first assembly program.
What is Arm64/AArch64?¶
Arm64, officially called AArch64, is the 64-bit execution state of the Armv8-A architecture. Key differences from 32-bit Arm include:
- 64-bit Registers: 31 general-purpose 64-bit registers (x0-x30) plus special registers
- Larger Address Space: Can address up to 2^64 bytes of memory (16 exabytes)
- Simplified Instruction Set: Removed some legacy 32-bit instructions, added new powerful instructions
- Better Performance: More registers reduce memory access, improved SIMD (NEON) capabilities
- Uniform Instruction Encoding: All instructions are 32-bits wide, simplifying instruction fetch
Development Environment Setup¶
Required Tools¶
Raspberry Pi OS (64-bit) includes all necessary tools for assembly development:
Output:
Creating Your First Assembly Project¶
Let's create a dedicated directory for assembly projects:
Hello World in Arm64 Assembly¶
Our first program will print "Hello, Arm64!\n" to the console using Linux system calls.
Create a file named hello.s:
Understanding the Code¶
Let's break down each section:
Directives:
- .global _start: Makes _start visible to the linker as the program entry point
- .section .data: Defines the data section for initialized variables
- .section .text: Defines the text section for executable code
Data Section:
- msg: .ascii "Hello, Arm64!\n": Declares a string without null termination
- len = . - msg: Calculates message length (current position minus message start)
Registers Used:
- x0 - x7: Used for passing arguments to system calls and functions
- x8: System call number
- Other registers will be explained in detail in the next tutorial
System Calls:
- write(fd, buffer, count): Syscall 64 writes data to a file descriptor
- x0: File descriptor (1 = stdout)
- x1: Pointer to buffer
- x2: Number of bytes to write
- x8: Syscall number
- svc #0: Supervisor call instruction
exit(status): Syscall 93 terminates the programx0: Exit status codex8: Syscall number
Assembling and Linking¶
Output:
Verifying the Binary¶
You can inspect the generated binary:
Output:
Basic Instructions Overview¶
Here are a few basic instructions to get started (detailed coverage in the next tutorial):
Data Movement¶
Arithmetic Operations¶
Comments¶
A More Complex Example: Sum of Numbers¶
Let's write a program that calculates the sum of numbers from 1 to 10:
Create sum.s:
Build and run:
Output:
This example demonstrates:
- Loop structures with conditional branching (b.lt)
- Function calls using bl (branch with link)
- Comparison using cmp
- Conditional branches for control flow
- More complex register usage
The details of these instructions and control flow will be covered in later tutorials.
Debugging Assembly Programs¶
GDB (GNU Debugger) is invaluable for assembly development:
Useful GDB Commands:
Example Debug Session:
Makefile for Assembly Projects¶
Create a Makefile to simplify building:
Usage:
System Call Reference¶
Here are the most common system calls you'll use in assembly programming:
| Syscall | Number | Arguments | Description |
|---|---|---|---|
read |
63 | x0=fd, x1=buf, x2=count |
Read from file descriptor |
write |
64 | x0=fd, x1=buf, x2=count |
Write to file descriptor |
open |
56 | x0=filename, x1=flags, x2=mode |
Open file |
close |
57 | x0=fd |
Close file descriptor |
exit |
93 | x0=status |
Terminate process |
brk |
214 | x0=addr |
Change data segment size |
For a complete list, see /usr/include/asm-generic/unistd.h or search for "Linux arm64 syscall table".
Next Steps¶
Now that you have your development environment set up and understand basic assembly program structure, the next tutorial will cover:
- Registers in Detail: Complete explanation of all 31 general-purpose registers (x0-x30)
- Special Registers: SP, LR, PC, XZR and their purposes
- Register Naming: Understanding x vs w registers, when to use each
- AAPCS64 Calling Convention: How registers are used for function calls
- SIMD/FP Registers: v0-v31 for floating-point and vector operations
- Data Movement Instructions: mov, movz, movk, movn with immediate encoding
- Arithmetic Operations: add, sub, mul, div, and their variants
- Logical Operations: and, orr, eor, bic, shifts and rotations
- Memory Access Instructions: ldr, str, ldp, stp with addressing modes
Conclusion¶
You've learned how to set up an Arm64 assembly development environment on Raspberry Pi and written your first assembly programs. We covered:
- What Arm64/AArch64 is and why it's important for Raspberry Pi
- Installing and verifying development tools (assembler, linker, debugger)
- Basic program structure with sections (.data, .bss, .text)
- System calls for I/O operations (write, exit)
- Assembly and linking process
- Simple loop and function call examples
- Debugging with GDB
- Building with Makefiles
Assembly language provides unprecedented control over the processor and is essential for understanding computer architecture at a fundamental level. While modern compilers generate excellent code, knowing assembly enables you to optimize critical sections, debug complex issues, and work on systems programming projects.
In the next tutorial, we'll dive deep into the Arm64 register architecture and explore the instruction set with comprehensive examples.