Day 15 - ARM Assembly

🦾🦾🦾
10 May 2025

Loading and Storing

To load the value stored in r0 into r1, we do this:

ldr r1, r0

But to load the data in the address stored in r0, we can do this instead.

ldr r1, [r0]

The square brackets indicate that we access the value at the address stored.

To store a value from r2 to the address in r3, we can do this.

str r2, [r3]

Offsets

Very often you will want to access a location that is at a fixed distance from a base pointer or that is computed from another register. ARM gives you several addressing modes for this.

Immediate offsets 

str r2, [r1, #2]   @ offset: [r1+2] = r2 (r1 unchanged)
str r2, [r1, #4]!  @ pre-indexed: [r1+4] = r2 (r1 = r1+4)
ldr r3, [r1], #4   @ post-indexed: r3 = [r1]   (r1 = r1+4)

Register offsets

str r2, [r1, r3]    @ address = r1 + r3

Scaled register offsets

str r2, [r1, r3, LSL #2]    @ offset = r3 << 2 (multiply by 4)
str r2, [r1, r3, LSL #2]!   @ pre-indexed (updates r1)
ldr r4, [r1], r3, LSL #2    @ post-indexed

Multiple Read and Writes

You can also use the instructions ldm and stm to load/store multiple values to registers at the same time. ldmia increments after the first is loaded, but ldmib increments before. ldmda and ldmdb do the same but decrement.

ldmia r0, {r3-r6}    @ load four words: r3 r4 r5 r6 to [r0  … r0+12]
stmdb r1, {r2-r4}    @ store three words: r2 r3 r4 to [r1-12 … r1-4]                           and r1 = r1-12

Stack Handling

The push instruction decreases the sp by 4 bytes, before storing the info to the new address.

push {r0}

pop is the reverse, as the value in the SP address is loaded to a register, and the sp increases by 4 bytes.

pop {r0}

Conditional execution

The cmp code subtracts its second operand from the first, discards the result, and updates the CPSR flags. These flags can then be used by condition codes to provide conditional execution, such as loops using the b code.

CodeMeaningTrigger
eqequal / zeroZ = 1
nenot equalZ = 0
cs / hscarry set / unsigned ≥C = 1
cc / locarry clear / unsigned <C = 0
miminusN = 1
plplusN = 0
vsoverflow setV = 1
vcoverflow clearV = 0
loop:
    ldr r0, [r1], #4
    cmp r0, #0          @ set Z if element == 0
    beq done            @ branch equal → element was zero
    b   loop            @ otherwise keep scanning
done: