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 指向栈顶,低地址

lr 是 link 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/and 与 ORR/orr 或 EOR/eor 异或

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

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

寻址

  • L 开头为取,如 ldr,ldp
  • S 开头为存,如 str,stp

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就周到了这一行

参考