这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战。
CPU和寄存器
内部部件之间由总线连接,CPU除了有控制器、运算器还有寄存器。其中寄存器的作用就是进行数据的临时存储。
CPU的运算速度是非常快的,为了性能CPU在内部开辟一小块临时存储区域,并在进行运算时先将数据从内存复制到这一小块临时存储区域中,运算时就在这一小快临时存储区域内进行。我们称这一小块临时存储区域为寄存器。
对于arm64系的CPU来说,如果寄存器以x开头则表明的是一个64位的寄存器,如果以w开头则表明是一个32位的寄存器,在系统中没有提供16位和8位的寄存器供系统访问和使用。其中32位的寄存器是64位寄存器的低32位部分并不是独立存在的。对程序员来说,CPU中最主要的部件是寄存器,可以通过改变寄存器内容来实现对CPU的控制,不同的CPU,寄存器的个数和结构是不相同的。
浮点和向量寄存器
因为浮点数的存储以及其运算的特殊性,CPU中专门提供浮点数寄存器来处理浮点数。
- 浮点寄存器 64位:D0 - D31 32位:S0 - S31 现在的CPU支持向量运算。(向量运算在图形处理的领域用的非常多)为了支持向量计算,系统也提供了众多的向量寄存器
- 向量寄存器 128位:V0 - V31
通用寄存器
通用寄存器也称数据地址寄存器,通常用来做数据计算的临时存储、做累加、技术、地址保存等功能。定义这些寄存器的作用主要是用于在CPU指令中保存操作数,在CPU中当做一些常规变量来使用。
ARM64拥有32个64位的通用寄存器x0到x30,以及XZR(零寄存器),这些通用寄存器优势也有特定用途。
pc寄存器
pc寄存器为指令指针寄存器,它指示了CPU当前要读取指令的地址,在内存或磁盘上,指令和数据没有任何区别,都是二进制信息,CPU在工作的时候把有的信息看作指令,有的信息看做数据,为同样的信息赋予了不同的意义。比如 1110 0000 0000 0011 0000 1000 1010 1010,可以当做数据 0xE003008AA,也可以当做指令 mov x0, x8。CPU根据什么将内存中的信息看做指令?CPU将pc指向的内存单元的内容看做指令;如果内存中的某段内容曾被CPU执行过,那么它所在的内存单元必然被pc指向过。
栈
栈是一种具有特殊的访问方式的存储空间(后进先出,Last In Out First,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还可以操作两个寄存器。如下面这段指令
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寄存器里面的。
函数的局部变量
函数的局部变量是放在栈里面的!