ARM Assembly Programming: Complete Beginner's Course
Part 1: Understanding ARM Architecture
What is ARM?
ARM (Advanced RISC Machine) is a family of processor architectures based on RISC (Reduced
Instruction Set Computing) principles. Unlike x86 processors, ARM uses simpler instructions
that execute faster.
Key characteristics:
• Load/Store architecture: you can only manipulate data in registers, not directly in
memory
• 16 general-purpose registers (R0-R15)
• Fixed-width instructions (32-bit in ARM, 16-bit in Thumb mode)
• Conditional execution on almost every instruction
ARM Registers
General Purpose Registers (R0-R12):
• R0-R12: Used for general data manipulation
• R0-R3: Often used for function arguments and return values
• R4-R11: Preserved across function calls (callee-saved)
Special Purpose Registers:
• R13 (SP): Stack Pointer - points to the top of the stack
• R14 (LR): Link Register - stores return addresses for functions
• R15 (PC): Program Counter - points to the next instruction
• CPSR: Current Program Status Register - holds condition flags (N, Z, C, V)
Part 2: Basic ARM Instruction Set
Data Movement Instructions
assembly
MOV r0, #5 ; Move immediate value 5 into r0
MOV r1, r0 ; Copy r0 into r1
MVN r2, #0 ; Move NOT: r2 = ~0 (all bits set)
Arithmetic Instructions
assembly
ADD r0, r1, r2 ; r0 = r1 + r2
SUB r0, r1, r2 ; r0 = r1 - r2
MUL r0, r1, r2 ; r0 = r1 * r2
ADD r0, r1, #10 ; r0 = r1 + 10 (immediate value)
Logical Instructions
assembly
AND r0, r1, r2 ; r0 = r1 AND r2
ORR r0, r1, r2 ; r0 = r1 OR r2
EOR r0, r1, r2 ; r0 = r1 XOR r2
BIC r0, r1, r2 ; r0 = r1 AND NOT r2 (bit clear)
Comparison Instructions
assembly
CMP r0, r1 ; Compare r0 and r1, set flags
CMP r0, #5 ; Compare r0 with 5
TST r0, r1 ; Test (AND without storing result)
TEQ r0, r1 ; Test equivalence (XOR without storing)
Memory Access Instructions
assembly
LDR r0, [r1] ; Load word from memory address in r1 into r0
STR r0, [r1] ; Store r0 to memory address in r1
LDR r0, [r1, #4] ; Load from address (r1 + 4)
STR r0, [r1, #4]! ; Store to (r1+4) and update r1 (pre-indexed)
LDR r0, [r1], #4 ; Load from r1, then r1 = r1 + 4 (post-indexed)
Branch Instructions
assembly
B label ; Unconditional branch to label
BL function ; Branch with Link (call function)
BX lr ; Branch and exchange (return from function)
Part 3: Conditional Execution
ARM allows conditional execution using suffix codes:
Condition codes:
• EQ: Equal (Z flag set)
• NE: Not Equal (Z flag clear)
• GT: Greater Than (signed)
• LT: Less Than (signed)
• GE: Greater or Equal (signed)
• LE: Less or Equal (signed)
• HI: Higher (unsigned)
• LS: Lower or Same (unsigned)
• AL: Always (default)
Examples:
assembly
CMP r0, r1
ADDEQ r2, r3, r4 ; Only execute if r0 == r1
MOVNE r5, #0 ; Only execute if r0 != r1
BGT label ; Branch if r0 > r1
Part 4: Program Structure
A complete ARM assembly program has this structure:
assembly
.global _start @ Make _start visible to linker
.section .text @ Code section
_start:
@ Your code here
MOV r0, #1 @ Example instruction
@ Exit program (Linux syscall)
MOV r7, #1 @ Syscall number for exit
SWI 0 @ Software interrupt
.section .data @ Data section
variable: .word 42 @ Define a 32-bit variable
Part 5: Basic Programming Examples
Example 1: Add Two Numbers
assembly
.global _start
.section .text
_start:
MOV r0, #10 @ First number
MOV r1, #20 @ Second number
ADD r2, r0, r1 @ r2 = r0 + r1 = 30
@ Exit
MOV r7, #1
SWI 0
Example 2: Simple Loop (Count from 1 to 10)
assembly
.global _start
.section .text
_start:
MOV r0, #1 @ Counter
MOV r1, #10 @ Limit
loop:
ADD r0, r0, #1 @ Increment counter
CMP r0, r1 @ Compare with limit
BLE loop @ Branch if r0 <= r1
@ Exit
MOV r7, #1
SWI 0
Example 3: Conditional Logic (Maximum of Two Numbers)
assembly
.global _start
.section .text
_start:
MOV r0, #15 @ First number
MOV r1, #23 @ Second number
CMP r0, r1 @ Compare r0 and r1
MOVGT r2, r0 @ If r0 > r1, r2 = r0
MOVLE r2, r1 @ If r0 <= r1, r2 = r1
@ r2 now contains the maximum
@ Exit
MOV r7, #1
SWI 0
Example 4: Array Sum
assembly
.global _start
.section .text
_start:
LDR r0, =array @ Load address of array
MOV r1, #5 @ Number of elements
MOV r2, #0 @ Sum accumulator
sum_loop:
LDR r3, [r0], #4 @ Load element, increment pointer
ADD r2, r2, r3 @ Add to sum
SUBS r1, r1, #1 @ Decrement counter, set flags
BNE sum_loop @ Continue if not zero
@ r2 now contains the sum
@ Exit
MOV r7, #1
SWI 0
.section .data
array: .word 1, 2, 3, 4, 5
Example 5: Function Call Example
assembly
.global _start
.section .text
_start:
MOV r0, #5 @ First argument
MOV r1, #7 @ Second argument
BL multiply @ Call function
@ Result is in r0
@ Exit
MOV r7, #1
SWI 0
multiply:
MUL r0, r0, r1 @ r0 = r0 * r1
BX lr @ Return
Part 6: Assembling and Linking
Step 1: Write Your Code
Save your code in a file, e.g., program.s
Step 2: Assemble
The assembler converts assembly to object code:
bash
as -o program.o program.s
For ARM on a non-ARM machine:
bash
arm-linux-gnueabi-as -o program.o program.s
Step 3: Link
The linker creates the executable:
bash
ld -o program program.o
For ARM cross-compilation:
bash
arm-linux-gnueabi-ld -o program program.o
Step 4: Run
bash
./program
For ARM on non-ARM:
bash
qemu-arm ./program
Alternative: Using GCC
You can also use GCC which handles both steps:
bash
gcc -o program program.s
Or for ARM:
bash
arm-linux-gnueabi-gcc -static -o program program.s
Part 7: Common Patterns and Idioms
Clearing a Register
assembly
MOV r0, #0 @ Simple way
EOR r0, r0, r0 @ XOR with itself (faster)
Setting All Bits
assembly
MVN r0, #0 @ Move NOT 0
Multiplying by Powers of 2
assembly
LSL r0, r0, #3 @ Multiply r0 by 8 (shift left 3)
Dividing by Powers of 2
assembly
LSR r0, r0, #2 @ Divide r0 by 4 (logical shift right)
ASR r0, r0, #2 @ Signed divide by 4 (arithmetic shift)
Stack Operations
assembly
PUSH {r0-r3, lr} @ Save registers to stack
@ ... your code ...
POP {r0-r3, pc} @ Restore and return (pc = lr)
Part 8: Debugging Tips
1. Use comments extensively - ARM assembly can get confusing quickly
2. Check your condition codes - Make sure CMP comes before conditional branches
3. Watch your register usage - Keep track of what's in each register
4. Remember addressing modes - Pre-indexed vs post-indexed addressing
5. Mind the stack - Always balance PUSH and POP
Quick Reference Card
Common Instructions:
• MOV - Move data
• ADD/SUB - Arithmetic
• LDR/STR - Memory access
• CMP - Compare
• B/BL - Branch
• PUSH/POP - Stack operations
Condition Suffixes:
• EQ - Equal
• NE - Not equal
• GT/LT - Greater/Less (signed)
• GE/LE - Greater or equal/Less or equal (signed)
Registers:
• R0-R3: Arguments/results
• R4-R11: Variables
• R13 (SP): Stack pointer
• R14 (LR): Return address
• R15 (PC): Program counter
Practice Exercise
Try writing a program that finds the factorial of 5. Start with r0 = 5, and compute 5! = 120.
Hint: Use a loop that multiplies r0 by decreasing values until you reach 1.