离久的小站

ARM汇编学习

2019/05/06 Share

http://infocenter.arm.com/help/index.jsp

ARM 寄存器

arm64有32个64bit长度的通用寄存器x0~x30,sp,可以只使用其中的32bit w0~w30
arm64有32个128bit SIMD寄存器v0~v31
arm32只有16个32bit的通用寄存器r0~r12, lr, pc, sp
arm32有16个128bit SIMD寄存器Q0~Q15,又可细分为32个64bit SIMD寄存器D0~D31

函数调用:

  • arm64前面8个参数都是通过寄存器来传递x0~x7,其他通过栈传递
  • arm32前面4个参数通过寄存器来传递r0~r3,其他通过栈传递

iOS中armv7以及arm64下的ABI:

  • armv7中,对于通用寄存器,自己写的过程中需要保护r4、r5、r6、r7、r8、r9、r10、r11以及r14寄存器;NEON寄存器需要保存Q4、Q5、Q6、Q7寄存器。
  • arm64模式下,通用寄存器x18、x30不能被使用。而需要被自己写的过程所保护的是:x19、x20、x21、x22、x23、x24、x25、x26、x27、x28、x29寄存器;而SIMD寄存器需要保护的是v8、v9、v10、v11、v12、v13、v14、v15。

arm汇编指令简介

常用寄存器

寄存器 位数 描述
x0-x30 64bit 64位通用寄存器
wO-w30 32bit 32位通用寄存器
fp(x29) 64bit 栈底指针
Lr(x30) 64bit 程序链接寄存器,保存跳转返回信息地址
sp 64bit 保存栈指针
pc 64bit 程序计数器,又称pc指针,指向下一条指令

通用寄存器名称

位数 通用 寄存器 栈指针
32bit wn wZr wsp
64bit xn xZr sp

通用寄存器用法

1
2
3
4
5
6
7
8
9
x0 - x7:用于传递子程序参数和结果,使用时不需要保存,多余参数采用堆栈传递,子程序返回结果写入到 x0
x8:用于保存子程序返回地址
x9 - x15:临时寄存器
x16 - x17:子程序内部调用寄存器
x18:平台寄存器,它的使用与平台相关
x19 - x28:临时寄存器
x29:帧指针寄存器 fp(栈底指针),用于连接栈帧
x30:链接寄存器 lr,保存了子程序返回的地址
x31:堆栈指针寄存器 sp

常用的汇编指令

汇编指令不区分大小写。即 mov 和 MOV 是一样的。
一条汇编指令是4字节大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
nop 什么也不做的指令,愣一下。没什么用途,但可以偏移指令地址。

mov x1, x0 ; 寄存器x0的值传给x1
add x0, x1, x2 ; 寄存器x1和x2的值相加后给x0
sub x0, x1, x2 ; 寄存器x1和x2的值相减后给x0

and x0, x0, #0xF ; x0和0xF相与后的值给x0
orr x0, x0, #0x10 ; x0和0x10相或后的值给x0
eor x0, x0, #0x11 ; x0和0x11相异或后的值给x0

ldr(ldur) x5, [x6, #0x8] ; x6寄存器的值(地址)加0x8的地址内的值给x5
str(stur) x0, [sp, #0x8] ; x0的值给(sp+0x8)地址指向的空间

stp x29, x30, [sp, #0x10] ; sp加0x10个字节的位置,存放 x29 和 x30
ldp x29, x30, [sp, #0x10] ; sp减0x10个字节的值取出来,赋值 x29 和 x30
L打头的基本都是取值指令,如 LDr LDP;
S打头的基本都是存值指令,如 STr STP;

寻址操作
[x10, #0x20] ;操作 x10 + 0x20 的地址。#0x20是立即数
[sp, #-16]! ;先将sp-16,然后操作sp指向地址
[sp], #16 ; 先操作sp指向地址,操作完后再把sp+16

cbz 比较,如果结果为0,就跳转到后面的指令
cbnz 比较,如果结果非0,就跳转到后面的指令

cmp 比较指令,结果影响cspr状态

br 跳转指令,直接跳转到指定地址,跳转完不返回.
bl 跳转命令,将 bl 的下一个指令地址保存到 lr 寄存器,然后跳转到指定地址,因为将下一个指令保存到 lr,所以返回的时候,可以从lr得到返回地址,从而跳回来
blr 可以用跳转到动态地址去,且会返回。比如 blr x8

ret 子程序返回,返回地址保存到lr(x30)

adrp 用来定位数据段中的数据, 因为ASLR会导致代码及数据的地址随机化, 用adrp来根据pc做辅助定位

其它

下面不作总结,简单说以下,方便查找。

.text

1
.text 用于声明以下是代码段。

.align

.align 用于将指令对齐到内存地址,对齐位置为参数的 2 的幂次方。 以 .align 10 举例,在没有添加对齐时:

1
2
3
4
func_1:
ret
func_2:
ret

得到的结果,两个指令构成了连续的地址,即指令之间相差

在 func_1 和 func_2 之间加入 .align 10:

1
2
3
4
5
.align 10
func_1:
ret
func_2:
ret

得到如下结果,如果 .align 只是个普通的指令,那 func_2 的 ret 对应地址应当为递增4字节后的 0x0000000100008060,这里却变成了 0x000000010000840,0x000000010000840刚好是 2^10 的倍数。

.rept 和 .endr

.rept 和 .endr 是一组循环伪指令。

1
2
3
4
5
func_1:
.rept 5
add x0, x0, x1
.endr
ret

生成了 5 个连续的 add 指令。

标签

如下代码:

1
2
label:
add x0, x0, x1

调用 label 就会执行 add x0, x0, x1 指令。

.globl

.globl 可以让一个标签对链接器可见,可以供其他链接对象模块使用。

如下代码:

1
.globl label

外部可以像 C 语言函数那样直接调用 label 标签方法。

CATALOG
  1. 1. ARM 寄存器
  2. 2. arm汇编指令简介
    1. 2.1. 常用寄存器
    2. 2.2. 通用寄存器名称
    3. 2.3. 通用寄存器用法
    4. 2.4. 常用的汇编指令
    5. 2.5. 其它
      1. 2.5.1. .text
      2. 2.5.2. .align
      3. 2.5.3. .rept 和 .endr
      4. 2.5.4. 标签
      5. 2.5.5. .globl