ARM 汇编笔记

ARM 寄存器

R0~R30 x访问64位 w访问32位

r29 = fp (frame pointer)
r30 = lr (link register)

x31 = sp (用 sp/wsp 访问)
pc (program conter)

v0~v31 向量寄存器(浮点型寄存器) 128 位,可以通过 Bn(8) Hn(16) Sn(32) Dn(64) Qn(128) 访问

SPRs 状态寄存器 The Current Program Status Register (CPSR) The Saved Program Status Registers (SPSRs) FPSR浮点状态

栈从高地址往低地址生长,arm64 开始堆栈的操作是 16 字节对齐的,即拉伸栈空间一定是16的倍数,换句话说就是 0x10 最小,最后一位一定是 0

  • fp 指向当前 frame 的栈底,高地址
  • sp 指向栈顶,低地址

lrlink register,保存的是前一个函数的执行的最后一行指令的下一行,返回时就利用这个地址进行返回

传参

  • 一般 arm64 上 x0 - x7 分别存放方法的前 8 个参数
  • 超过的 8 个的,多余的放在栈上
  • 返回值放在 x0 上
  • 返回值是一个较大的数据结构时,结果糊存在 x8 执行的地址上

指令

运算

算术运算

1
2
3
4
5
add x0, x1, x2 ; x0 = x1 + x2
sub x0, x1, x2 ; x0 = x1 - x2
cmp x11, #4 ; 相当于 subs xzr, x11, #4 (subs 有符号减法,xzr 零寄存器)
; 如果 x11 - 4 == 0,那么状态寄存器的 NZCV.Z = 1
; 如果 x11 - 4 < 0, 那么 NZCV.N = 1

NZCV 是状态寄存器的几个状态值
N, negative condition flag 运算结果为负
Z, zero condition flag 运算结果为 0
C, carry condition flag 无符号运算有溢出时, C = 1
V, oVerflow condition flag 有符号运算

逻辑运算

  • LSL/lsl 逻辑左移 LSR/lsr 逻辑右移
  • ASR/asr 算术右移 ROR/ror 循环右移
  • AND/andORR/orrEOR/eor 异或

逻辑位移可以与算术运算一起用,如

1
add x14, x4, x27, lsl #1 ; x14 = x4 + (x27 << 1)

寻址

  • L 开头为取,如 ldrldp
  • S 开头为存,如 strstp

ldr 将内存数据存到寄存器中
ldp 一个变体,可以同时读写两个寄存器

例如:

1
2
3
4
5
ldr x0, [x1] ; 从 x1 指向的地址中区一个 64 为数据存入 x0
ldp x1, x2, [x10, #10] ; 从 x10+10 指向的地址中取 2 个 64 位的数,分别存入 x1, x2 低地址的存入 x1
str x5, [sp, #24] ; 将 x5 内容存入 sp+24 所指向的内存地址上
stp x29, x30, [sp, #-16]! ; 将 x29, x30 存到 sp-16 所指向的内存地址上,x29 在低地址,同时 sp = sp - 16 (感叹号的意思)
ldp x29, x30, [sp], #16 ; 从 sp 指向的内存地址中区两个 64 位数据存入 x29, x30 中,并且 sp += 16

寻址操作示例:

1
2
3
[x10, #0x10] // signed offset。 意思是从 x10 + 0x10的地址取值
[sp, #-16]! // pre-index。 意思是从 sp-16地址取值,取值完后在把 sp-16 writeback 回 sp
[sp], #16 // post-index。 意思是从 sp 地址取值,取值完后在把 sp+16 writeback 回 sp

跳转

跳转分为有返回跳转 bl 和无返回跳转 b,有返回会存 lr

1.存了LR也就意味着可以返回到本方法继续执行。一般用于不同方法直接的调用
2.B相关的跳转没有 LR,一般是本方法内的跳转,如while循环,if else等。

跳转可以依赖运算产生的标志位,即 NZCV 有一下可选情况:

1
2
3
4
5
cmp x2, 0
b.ne addr
0x1000d4ab0 bl testFuncA; // 跳转方法,这个时候 lr 设置为 0x1000d4ab4
0x1000d4ab4 orr x8, xzr, #0x1f00000000 // testFuncA执行完之后跳回lr就周到了这一行

参考