armv7a
+keywords: arm, armv7, abi
+-
+
- ISA type:
RISC
+ - Endianness:
little
,big
+
Registers
+General purpose registers
+bytes
+[3:0] alt desc
+---------------------------------------------
+r0-r12 general purpose registers
+r11 fp
+r13 sp stack pointer
+r14 lr link register
+r15 pc program counter
+
+Special registers
+bytes
+[3:0] desc
+---------------------------------------------
+cpsr current program status register
+
+CPSR register
+cpsr
+bits desc
+-----------------------------
+ [31] N negative flag
+ [30] Z zero flag
+ [29] C carry flag
+ [28] V overflow flag
+ [27] Q cummulative saturation (sticky)
+ [9] E load/store endianness
+ [8] A disable asynchronous aborts
+ [7] I disable IRQ
+ [6] F disable FIQ
+ [5] T indicate Thumb state
+[4:0] M process mode (USR, FIQ, IRQ, SVC, ABT, UND, SYS)
+
+Instructions cheatsheet
+Accessing system registers
+Reading from system registers:
+mrs r0, cpsr // move cpsr into r0
+
+Writing to system registers:
+msr cpsr, r0 // move r0 into cpsr
+
+Control Flow
+b <lable> // relative forward/back branch
+bl <lable> // relative forward/back branch & link return addr in r14 (LR)
+
+// branch & exchange (can change between ARM & Thumb instruction set)
+// bit Rm[0] == 0 -> ARM
+// bit Rm[0] == 1 -> Thumb
+bx <Rm> // absolute branch to address in register Rm
+blx <Rm> // absolute branch to address in register Rm &
+ // link return addr in r14 (LR)
+
+Load/Store
+Different addressing modes.
+str r1, [r0] // [r0]=r1
+str r1, [r0, #4] // [r0+4]=r1
+str r1, [r0, #4]! // r0+=4; [r0]=r1
+str r1, [r0], 4 // [r0]=r1; r0+=4
+
+Load/store multiple registers full-descending.
+stmfd r0!, {r1-r2, r5} // r0-=4; [r0]=r5
+ // r0-=4; [r0]=r2
+ // r0-=4; [r0]=r1
+ldmfd r0!, {r1-r2, r5} // r1=[r0]; r0+=4
+ // r2=[r0]; r0+=4
+ // r5=[r0]; r0+=4
+
++++
!
is optional but has the effect to update the base pointer registerr0
here.
Push/Pop
+push {r0-r2} // effectively stmfd sp!, {r0-r2}
+pop {r0-r2} // effectively ldmfd sp!, {r0-r2}
+
+Procedure Call Standard ARM (aapcs32
)
+Passing arguments to functions
+-
+
- integer/pointer arguments
+
+reg arg +----------- +r0 1 +.. .. +r3 4 +
+ - a double word (64bit) is passed in two consecutive registers (eg
r1+r2
)
+ - additional arguments are passed on the stack. Arguments are pushed
+
right-to-left (RTL)
, meaning next arguments are closer to currentsp
. +
+void take(..., int a5, int a6); + | | | ... | Hi + | +-->| a6 | | + +---------->| a5 | <-SP | + +-----+ v + | ... | Lo +
+
Return values from functions
+-
+
- integer/pointer return values
+
+reg size +----------------- +r0 32 bit +r0+r1 64 bit +
+
Callee saved registers
+-
+
r4
-r11
+sp
+
Stack
+-
+
- full descending
+
-
+
- full:
sp
points to the last used location (valid item)
+ - descending: stack grows downwards +
+ - full:
sp
must be 4byte aligned (word boundary) at all time
+sp
must be 8byte aligned on public interface interfaces
+
Frame chain
+-
+
- not strictly required by each platform +
- linked list of stack-frames +
- each frame links to the frame of its caller by a
frame record
+-
+
- a frame record is described as a
(FP,LR)
pair (2x32bit)
+
+ - a frame record is described as a
r11 (FP)
must point to the frame record of the current stack-frame +
++------+ Hi + | 0 | frame0 | + +->| 0 | | + | | ... | | + | +------+ | + | | LR | frame1 | + +--| FP |<-+ | + | ... | | | + +------+ | | + | LR | | current | +r11 ->| FP |--+ frame v + | ... | Lo +
+- end of the frame chain is indicated by following frame record
(0,-)
+ - location of the frame record in the stack frame is not specified +
r11
is not updated before the new frame record is fully constructed
+
Function prologue & epilogue
+-
+
- prologue
+
+push {fp, lr} +mov fp, sp // FP points to frame record +
+ - epilogue
+
+pop {fp, pc} // pop LR directly into PC +
+
ASM skeleton
+Small assembler skeleton, ready to use with following properties:
+-
+
- use raw Linux syscalls (
man 2 syscall
for ABI)
+ - no
C runtime (crt)
+ - gnu assembler
gas
+
// file: greet.S
+
+#include <asm/unistd.h> // syscall NRs
+
+ .arch armv7-a
+
+ .section .text, "ax"
+ .balign 4
+
+ // Emit `arm` instructions, same as `.arm` directive.
+ .code 32
+ .global _start
+_start:
+ // Branch with link and exchange instruction set.
+ blx _do_greet
+
+ mov r0, #0 // exit code
+ mov r7, #__NR_exit // exit(2) syscall
+ swi 0x0
+
+ // Emit `thumb` instructions, same as `.thumb` directive.
+ .code 16
+ .thumb_func
+_do_greet:
+ mov r0, #2 // fd
+ ldr r1, =greeting // buf
+ ldr r2, =greeting_len // &len
+ ldr r2, [r2] // len
+ mov r7, #__NR_write // write(2) syscall
+ swi 0x0
+
+ // Branch and exchange instruction set.
+ bx lr
+
+ .balign 8 // align data on 8byte boundary
+ .section .rodata, "a"
+greeting:
+ .asciz "Hi ASM-World!\n"
+greeting_len:
+ .int .-greeting
+
+++man gcc:
+file.S
assembler code that must be preprocessed.
To cross-compile and run:
+> arm-linux-gnueabi-gcc -o greet greet.S -nostartfiles -nostdlib \
+ -Wl,--dynamic-linker=/usr/arm-linux-gnueabi/lib/ld-linux.so.3 \
+ && qemu-arm ./greet
+Hi ASM-World!
+
+++Cross-compiling on
+Ubuntu 20.04 (x86_64)
, paths might differ on other +distributions. Explicitly specifying the dynamic linker should not be +required when compiling natively on arm.