My notes for where ARM differs from IA32 in the Assembly Primer video Part 6 — Moving Data.
(There is no separate part 5 post for ARM — apart from the instructions, it’s identical to IA32. There’s even support for the .bss section, unlike SPU and PPC)
Moving Data
We’ll look at MovDemo.s for ARM. First, the storage:
.data
HelloWorld:
.ascii "Hello World!"
ByteLocation:
.byte 10
Int32:
.int 2
Int16:
.short 3
Float:
.float 10.23
IntegerArray:
.int 10,20,30,40,50
It’s the same as for IA32, PPC and SPU. Like the first two, ARM will cope with the unnatural alignment.
1. Immediate value to register
.text
.globl _start
_start:
@movl $10, %eax
mov r0, #10
Move the value 10 into register r0.
Something to note: the ARM assembly syntax has some slightly differences. Where others use # to mark the start of a comment, ARM has @ (although # works at the start of a line). Literal values are prefixed with #, which confuses the default syntax highlighting in vim.
2. Immediate value to memory
@movw $50, Int16
mov r1, #50
movw r0, #:lower16:Int16
movt r0, #:upper16:Int16
strh r1, [r0, #0]
We need to load the immediate value in a register (r1), the address in a register (r0) and then perform the write. To quote the Architecture Reference Manual:
The ARM architecture … incorporates … a load/store architecture, where data processing operations only operate on register contents, not directly on memory contents.
which is like PPC and SPU, and unlike IA32 — and so we’ll see similarly verbose alternatives to the IA32 examples from the video.
I’m using movw, movt sequence to load the address, rather than ldr (as mentioned in the previous installment).
strh is, in this case, Store Register Halfword (immediate) — writes the value in r1 to the address computed from the sum of the contents of r0 and the immediate value of 0.
3. Register to register
@movl %eax, %ebx
mov r1,r0
mov (Move) copies the value from r0 to r1.
4. Memory to register
@movl Int32, %eax
movw r0, #:lower16:Int32
movt r0, #:upper16:Int32
ldr r1, [r0, #0]
Load the address into r0, load from the address r0+0. Here ldr is Load Register (immediate).
5. Register to memory
@movb $3, %al
@movb %al, ByteLocation
mov r0, #3
movw r1, #:lower16:ByteLocation
movt r1, #:upper16:ByteLocation
strb r0, [r1, #0]
Once again the same kind of thing — load 3 into r0, the address of ByteLocation into r1, perform the store.
6. Register to indexed memory location
@movl $0, %ecx
@movl $2, %edi
@movl $22, IntegerArray(%ecx, %edi, 4)
movw r0, #:lower16:IntegerArray
movt r0, #:upper16:IntegerArray
mov r1, #2
mov r2, #22
str r2, [r0, r1, lsl #2]
A little more interesting — here str is Store Register (register) which accepts two registers and an optional shift operation and amount. Here lsl is logical shift left, effectively multiplying r1 by 4 — the size of the array elements.
(GCC puts asl here. Presumably identical to logical shift left, but there’s no mention of asl in the Architecture Reference Manual. Update: ASL is referenced in the list of errors here as an obsolete name for LSL)
Two source registers and a shift is still shy of IA32’s support for an calculating an address from a base address, two registers and a multiply.
7. Indirect addressing
@movl $Int32, %eax
@movl (%eax), %ebx
movw r0, #:lower16:Int32
movt r0, #:upper16:Int32
ldr r1, [r0, #0]
@movl $9, (%eax)
mov r2, #9
str r2, [r0, #0]
More of the same.
Concluding thoughts
In addition to the cases above, ARM has a number of other interesting addressing modes that I shall consider in more detail in the future — logical operations, auto-{increment, decrement} and multiples. Combined with conditional execution, there are some very interesting possibilities.