This is a personal repository to help me learning Assembly.
This project contains notes and small program examples on Assembly programming for Apple ARM64.
- ARM 64 assembly STR and LDR instructions for Apple Silicon
- Hello World in ARM64 Assembly
- Apple M1 Assembly Language Hello World
- HelloSilicon: An introduction to assembly on Apple silicon Macs
- Writing ARM Assembly Programs(read this next)
- arm64 Syscall Examples
- ARMv8 AArch64/ARM64 Full Beginner's Assembly Tutorial
- Exploring Mach-O
- How to Read ARM64 Assembly Language
- Fundamentals of ARMv8-A
- arm64 notes
- How hello world for arm64 assembly really works (apple silicon)
- Assembly no macOS M1/ARM64 (BR Portuguese)
- You can learn assembly FAST with this technique (arm64 breakdown)
- Overview of ARM64 Architecture and Instruction Sets
- ARM Assembly
- Practical ARM Assembly Tutorial Series
- ARM64 assembly.
- Apple Syscall table
- Data definition directives
- Writing ARM64 code for Apple platforms
- Getting Started with Arm Assembly Language
- A64 - Base Instructions (alphabetic order)
- A64 general instructions in alphabetical order
- A64 floating-point instructions in alphabetical order
- Arm A-profile A64 Instruction Set Architecture
- Mac OS X ABI Mach-O File Format Reference, also available on this Github repository.
- ARMv8-A A64 ISA Overview
- Armv8-A Instruction Set Architecture
- ARM Directives
- armclang Integrated Assembler
- Arm Compiler Migration and Compatibility Guide
- The basics of Arm64 Assembly
- Exploring AArch64 assembler
- Introduction to ARM AArch64 Architecture and Low-level Programming
- Migrating code from ARM to ARM64
- Integer and floating-point conversions
- RISC-V Assembler Reference
- ARM-32 Assembly By Example
- Linux Syscall table
- GNU Assembler
- GNU Assembler Directives
- A Guide to ARM64 / AArch64 Assembly on Linux with Shellcodes and Cryptography
- Introduction to ARM Assembly Basics
- Programming with 64-Bit ARM Assembly Language
- Compiler Explorer - To have a similar assembly output from the ones we get locally with
objdump
, use it witharmv8-a clang
compiler with options-O2 -Wall
, example.
Most examples of Assembly programming on the internet use the GCC Assembler with GNU-Syntax which has a good documentation available on GNU-Syntax Arm Assembly Language Reference Guide and extensive list of resources about it. Also, they are based other CPUs than the one used by Apple (Apple silicon). That makes most of the program different then what we have here.
Since those options don't work for Apple development. We must use the Clang assembler with specific instruction set architecture for Apple processor. In this case my machine is running on Apple M1 (amr64) and has associated a "A64" instruction set .
Register | Size | Short Description |
---|---|---|
w0-w30 |
32-bit (4-bytes) | For 32-bit decimal data |
x0-x30 |
64-bit (8-bytes) | For 64-bit decimal data |
There is also a separate set of 32 registers used for floating point and vector operations, and other sizes:
Register | Size | Short Description |
---|---|---|
b0-b30 |
8-bit (1-byte) | For 8-bit decimal data |
h0-h30 |
16-bit (2-bytes) | For 16-bit decimal data |
s0-s30 |
32-bit (4-bytes) | For 32-bit single precision float number |
d0-d30 |
64-bit (8-bytes) | For 64-bit double precision float number |
q0-q30 |
128-bit (16-bytes) | For 128-bit decimal data |
More details:
x0-x7
: These are general purpose registers used as input/output parameters for functions calls. If a function has more than 8 arguments, the rest of the arguments are passed through the stack.x8
: Used as an indirect result location register.x9-x15
: Temporary registers. Can be used freely within a function.x16-x17
: Used as intra-procedure-call scratch registers (temporary).x18
: Reserved by Apple to its own use. We must not use it on our programs.x19-x28
: Callee-saved registers. Functions must save and restore these registers if used.fp
(x29
): Frame pointer, points to the stack base during a function call, to recover stack from calling function. It is used as base pointer to local variables on the stack per function. It won't change in a function scope and it will always hold the frame base pointer.lr
(x30
): Link register, saves the return address at a function call. It holds the address to return to when a subroutine call completes. It actually stores the address of the instruction to execute after the function call has been completed.pc
: Program counter, contains address of the next instruction to be executed. It is incremented for every single instruction it runs.sp
: Stack Pointer, used for dynamic memory allocation, points to the next available location on the stack. When the general purpose registers are not enough, we can use this to store data in the stack. It will be updated as the data is pushed and popped out of the stack.xzr
: Zero register, always contains the value zero. More details.
Just a summary of the available registers for quick reference.
Register 8 bytes | Register 4 bytes | Short Description |
---|---|---|
x0-x7 |
w0-w7 |
input/output parameters for function calls |
x29 (alias fp ) |
w29 |
frame pointer (FP) |
x30 (alias lr ) |
w30 |
link register (LR) |
sp |
wsp |
stack pointer (SP) |
pc |
program counter (PC) | |
xzr |
wzr |
zero register |
Less used registers, but still important to mention:
cpsr
: Current Program Status Register - doc.
Instruction | Description |
---|---|
b |
Branch the current execution into another label (function). |
bl |
Branch link, branch and save the current position in the link register. |
mov |
Move a value to a register |
fmov |
Move a float value to a float register |
stp |
Store pare of resgiers data into the stack memory |
strb |
Store a byte into the stack memory |
ldr |
Load data from memory to register |
Check out conditional execution for extensions it support such as beq, bneq, and etc.
Instruction | Description |
---|---|
add |
Add the value from 2 registers |
sub |
Subtract the value from 2 registers |
mul |
Multiply the value from 2 registers |
udiv |
Divides two unsigned values |
Instruction | Description | Absolute |
---|---|---|
.byte |
8-bits (1 byte) | Within the range [-128,255] only |
.hword (half word) |
16-bits (2 bytes) | Within the range [-0x8000,0xffff] only |
.word |
32-bits (4 bytes) | Within the range [-2^31,2^32-1] only |
.single , .float |
32-bits (4 bytes) | Fractional, within the range [+/- 1.17 x 10^-38 to +/- 3.4 x 10^38] only |
.double |
64-bits (8 bytes) | Fractional, within the range [+/- 2.23 x 10^-308 to +/- 1.80 x 10^308] only |
.quad , .dowrd (double word) |
64-bits (8 bytes) | Within the range [-2^63,2^64-1] only |
References:
Numeric data is represented as hexadecimal in assembly and some times we need to convert it to decimal in order to better understand what that value represents.
Probably the simplest option to convert values between decimal and hexadecimal is using the Apple Calculator app. It has a "Programmer Mode" which can be enabled on View → Programmer (⌘3).
Another option is using the terminal, here is a command to convert 1337 decimal value to hexadecimal:
printf '%x\n' 1337
// output: 539
And the command to convert it back to decimal:
printf '%d\n' 0x539
// output: 1337
Notes is a section with notes taken from different resources. Keeping them around as reference to be used on writing my own summary later.
Darwin
: Apple OS: macOS, iOS, etc.XNU
: short for X is not Unix. Is the kernel used by Darwin based on the Mach kernel.Mach-O
: short for Mach object file format. It determines the order which code and data in a binary file are read into memory. Programs compiled for Darwin will have this format.
Simplest explanation about page and pageoff directives https://stackoverflow.com/a/38730184/1050818