函数的本质
1.寄存器
CPU除了有控制器、运算器还有寄存器。其中寄存器的作用就是临时存储数据。
CPU的运算速度是非常快的,为了性能CPU在内部开辟一小块临时存储区域,并在进行运算时先将数据从内存复制到这一小块临时存储区域中,运算时就在这一小块的临时存储区域内进行。我们称这一小块临时存储区域为寄存器。
对于 arm64 系的 CPU 来说,如果寄存器以 x 开头则表明的是一个 64 位的寄存器,如果以 w 开头则表明是一个 32 位的寄存器,在系统中没有提供 16 位和 8 位的寄存器供访问和使用。其中 32 位的寄存器是 64 位寄存器的低 32 位部分并不是独立存在的。
1.1 SP 寄存器
SP 寄存器是保存栈顶地址
1.2 FP 寄存器
FP 寄存器 也称为 x29 寄存器属于通用寄存器,但是在某些时候会利用它保存栈底地址
1.3 LR寄存器
LR寄存器 也称为 x30 寄存器, 保存的要执行的下一条指令的地址
1.4 浮点和向量寄存器
因为浮点数的存储以及其运算的特殊性, CPU 中专门提供浮点数寄存器来处理浮点数
- 浮点寄存器 64位: D0 - D31 32位: S0 - S31
现在的CPU支持向量运算.(向量运算在图形处理相关的领域用得非常的多)为了支持向量计算系统了也提供了众多的向量寄存器.
- 向量寄存器 128位: V0 - V31
2 高速缓存
iPhoneX 上搭载的 ARM 处理器 A11 它的 1 级缓存的容量是 64KB,2 级缓存的容量 8M.
CPU 每执行一条指令前都需要从内存中将指令读取到 CPU 内并执行。而寄存器的运行速度相比内存读写要快很多,为了性能, CPU 还集成了一个高速缓存存储区域. 当程序在运行时,先将要执行的指令代码以及数据复制到高速缓存中去(由操作系统完成). CPU 直接从高速缓存依次读取指令来执行.
1.4.3 bl指令
CPU 从何处执行指令是由 pc 中的内容决定的,我们可以通过改变pc的内容来控制CPU执行目标指令
-
ARM64 提供了一个 mov 指令(传送指令),可以用来修改大部分寄存器的值,比如
- mov x0,#10、mov x1,#20
但是,mov 指令不能用于设置 pc 的值,ARM64 没有提供这样的功能
ARM64 提供了另外的指令来修改 PC 的值,这些指令统称为转移指令,最简单的是 bl 指令
3 栈
栈: 是一种具有特殊的访问方式的存储空间(先进后出)
- 栈与堆有什么区别?
- 在内存中,栈操作是从高地址到低地址,然而堆是从低地址到高地址
在 ARM64 中, 栈操作都是以16字节(0x10)对齐的, 换句话说就是栈拉伸空间时都是以16字节为倍数.
3.1 关于内存读写的指令
读/写数据都是往高地址读/写
3.1.1 STR 指令
STR 是 store from a register into mermory 的缩写,意思就是将数据从寄存器中读取出来,然后再存到内存中去.
3.1.2 LDR 指令
- LDR* 是 load from mermory into a registe 的缩写,意思就是将数据从内存中读取出来,写入寄存器中去.
STP 和 LDP 指令是用来操作两个寄存器的, 而上面两条指令只能操作一个寄存器.
来个栗子
使用32个字节空间作为这段程序的栈空间,然后利用栈将 x0 和 x1 的值进行交换.
sub sp, sp, #0x20 ;拉伸栈空间32个字节
stp x0, x1, [sp, #0x10] ;sp往上加16个字节,存放x0 和 x1
ldp x1, x0, [sp, #0x10] ;将sp偏移16个字节的值取出来,放入x1 和 x0
3.2 BL 指令
BL 指令的作用:
- 将下一条指令的地址放入 x30(LR) 寄存器中去
- 跳转到标号处执行指令
思考:
现在有两段代码, 假设程序先执行A,请写出指令执行顺序.最终寄存器x0的值是多少?
_A:
mov x0,#0xa0
mov x1,#0x00
add x1, x0, #0x14
mov x0,x1
bl _B
mov x0,#0x0
ret
_B:
add x0, x0, #0x10
ret
3.3 RET指令
RET 指令会默认使用存放在 x30(LR) 寄存器中的值
ARM64 平台的特色指令,它面向硬件做了优化处理的.
4 函数
4.1 函数的参数和返回值
ARM64 下, 函数的参数是存放在 x0 到 x7 (w0 到 w7)这8个寄存器里面的.如果超过8个参数,就会入栈.
函数的返回值是放在 x0 寄存器里面的.
4.2 函数的局部变量和全局变量
函数的局部变量放在栈里面!