寄存器的补充
数据地址寄存器
数据地址寄存器通常用来做数据计算的临时存储、做累加、计数、地址保存等功能。定义这些寄存器的作用主要是用于在 CPU 指令中保存操作数,在 CPU 中当做一些常规变量来使用。
ARM64中
- 64 位:
X0-X30, XZR(零寄存器) - 32 位:
W0-W30, WZR(零寄存器)
需要注意的是,8086 汇编中有一种特殊的寄存器段寄存器:
CS, DS, SS, ES四个寄存器来保存这些段的基地址,这个属于Intel架构CPU中,在ARM中并没有。
浮点和向量寄存器
因为浮点数的存储以及其运算的特殊性,CPU 中专门提供浮点数寄存器来处理浮点数
- 浮点寄存器 64位: D0 - D31,32位: S0 - S31
现在的 CPU 支持向量运算,(向量运算在图形处理相关的领域用得非常的多)为了支持向量计算系统了也提供了众多的向量寄存器。
- 向量寄存器 128位:V0-V31
栈
- 栈:是一种具有特殊的访问方式的存储空间(后进先出,
Last In Out Firt,LIFO)
SP和FP寄存器
-
sp寄存器在任意时刻会保存我们栈顶的地址。 -
fp寄存器也称为x29寄存器属于通用寄存器,但是在某些时刻我们利用它保存栈底的地址!
注意:
ARM64开始,取消 32 位的LDM,STM,PUSH,POP指令! 取而代之的是ldr\ldp str\stp,ARM64里面,对栈的操作是 16 字节对齐的。
函数调用栈
常见的函数调用开辟和恢复的栈空间
sub sp, sp, #0x40 ; 拉伸0x40(64字节)空间
stp x29, x30, [sp, #0x30] ;x29\x30 寄存器入栈保护
add x29, sp, #0x30 ; x29指向栈帧的底部
...
ldp x29, x30, [sp, #0x30] ;恢复x29/x30 寄存器的值
add sp, sp, #0x40 ; 栈平衡
ret
关于内存读写指令
注意:读/写 数据是都是往高地址读/写
str(store register)指令
将数据从寄存器中读出来,存到内存中。
ldr(load register)指令
将数据从内存中读出来,存到寄存器中,ldr 和 str 的变种 ldp 和 stp 还可以操作2个寄存器。
堆栈操作练习
使用 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
bl和ret指令
bl标号
- 将下一条指令的地址放入
lr(x30)寄存器 - 转到标号处执行指令
ret
- 默认使用
lr(x30)寄存器的值,通过底层指令提示CPU此处作为下条指令地址。
ARM64平台的特色指令,它面向硬件做了优化处理的。
x30寄存器
x30 寄存器存放的是函数的返回地址,当 ret 指令执行时刻,会寻找 x30 寄存器保存的地址值。
注意:在函数嵌套调用的时候,需要将
x30入栈。
函数的参数和返回值
ARM64下,函数的参数是存放在 X0 到 X7(W0 到 W7) 这 8 个寄存器里面的,如果超过 8个参数,就会入栈。
函数的返回值是放在 X0 寄存器里面的。
函数的局部变量
函数的局部变量放在栈里面。