Learning ARM assembly basics
Before writing more ARM code, I learned it in Internet.
STMFD = store multiple registers full descendent = stmdb (decrement before)
LDMFD = load multiple registers full descendent = ldmia (increment after)
if ! is specified, the result will be written back.
STMFD:
pre: r1 = 0x1 r2 = 0x2 r13 = 0x00008000 stmfd !r13, {r1, r2} post: r1 = 0x1 r2 = 0x2 r13 = 0x00007ff8 mem[0x00007ff8] = 0x00000001 mem[0x00008000] = 0x00000002
LDMFD:
pre: r1 = 0x0 r2 = 0x0 r13 = 0x00008000 mem[0x00008000] = 0x00000001 mem[0x00008004] = 0x00000002 ldmfd !r13, {r1, r2} post: r1 = 0x00000001 r2 = 0x00000002 r13 = 0x0000800c
And some more info.
R0-R3: scratch registers, don’t need to save
R4-R12: callee saved
R13=SP (Stack Pointer) stack
R14=LR (Link Register) to store return address of function call
R15=PC (Program Counter) instruction pointer
If you want to do like this x86,
push 1 push 2 call hoge // result in EAX
It’ll be like this in ARM.
mov r0, #1 mov r1, #2 bl hoge // set LR=next instruction pointer and branch to hoge // result in r0
startup.s:
@ startup .align .global _start _start: ldr r0, =0x000000d3 msr cpsr, r0 ldr sp, =0x06400000 bl main b . .global _add _add: add r0, r0, r1 mov pc, lr .global _sub _sub: sub r0, r0, r1 mov pc, lr .global _fib _fib: stmfd r13!,{r8, r9, lr} // same as stmdb (decrement before) or push, ! means write back in r13 // return 0 if fib(0) mov r8, #0 cmp r0, #0 beq _fib_end // return 1 if fib(1) mov r8, #1 cmp r0, #2 ble _fib_end // store arg-1 and arg-2 in r0 and r9 sub r0, r0, #1 // arg-1 sub r9, r0, #1 // arg-2 // call fib(arg-1) mov r8, #0 bl _fib add r8, r0, r8 // call fib(arg-2) mov r0, r9 bl _fib add r8, r0, r8 _fib_end: mov r0, r8 ldmfd r13!,{r8, r9, lr} // same as ldmia (increment after) or pop, ! means write back in r13 mov pc, lr
hoge.c:
static const int kA = 3; static const int kB = 4; int _add(int a, int b); int _sub(int a, int b); int _fib(int a); int main(int argc, char const* argv[]) { int a = kA; int b = kB; int result; result = _add(a, b); result = _sub(a, b); result = _fib(0); result = _fib(1); result = _fib(2); result = _fib(6); result = _fib(10); }
And tested it with gdb+ARM sim.
$cat startup.gdb target sim file hoge load hoge b main run $arm-unknown-eabi-gdb --command=startup.gdb ... 15 result = _fib(0); (gdb) n 16 result = _fib(1); (gdb) p result $1 = 0 (gdb) n 17 result = _fib(2); (gdb) p result $2 = 1 (gdb) n 18 result = _fib(6); (gdb) p result $3 = 1 (gdb) n 19 result = _fib(10); (gdb) p result $4 = 8 (gdb) n 20 } (gdb) p result $5 = 55