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.

ldr r1, [r0]                // r1 = [r0]
ldr r1, [r0, #4]            // r1 = [r0+4]

ldr r1, [r0, #4]!           // pre-inc : r0+=4; r1 = [r0]
ldr r1, [r0], #4            // post-inc: [r0] = r1; r0+=4

ldr r0, [r1, r2, lsl #3]    // r0 = [r1 + (r2<<3)]

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 register r0 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 current sp.
    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
  • 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)
  • 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.

References