01.寄存器
Last updated
Last updated
CPU除了有控制器、运算器还有寄存器。其中寄存器的作用是进行数据的临时存储
CPU的运算速度非常快,为了性能CPU在内部开辟一小块零食存储区域,并在进行运算时先将数据从内存复制到这一小块临时区域中,运算时就在这一小块临时存储区域内进行。
高速缓存
CPU每执行一条指令前都要从内存中将指令读取到CPU内执行。而寄存器的运行速度相比内存读写要快很多,为了性能,CPU还集成了一个高速缓存存储区域当程序在运行时,先将需要执行的指令代码以及数据复制到高速缓存中去(由操作系统完成),CPU直接从高速缓存中依次读取指令来执行。
ARM64一个寄存器64位,8个字节
浮点寄存器
因为浮点数的存储以及运算的特殊性,CPU中专门提供浮点寄存器来处理浮点数
浮点寄存器64位:D0-D31 32位:S0-S31
向量寄存器
先在很多CPU支持向量运算(图形处理用的很多),为了支持向量计算而提供
向量寄存器:128位 V0-V31
异常状态寄存器
通用寄存器(数据地址寄存器)
ARM64拥有32个64位的通用寄存器X0-X30以及XZR(零寄存器)
为了兼容32位,所以ARM64拥有W0-W30和WZR30个32位寄存器
32位寄存器并不是独立存在的。如:W0是X0的低32位
PC寄存器:指令指针寄存器
PC寄存器里面的值就是保存的CPU接下来需要执行的指令地址
改变PC寄存器的值可以改变程序执行的流程
x0-x7: 用于子程序调用时的参数传递,X0还用于返回值传递
x0 - x30
是31个通用整形寄存器。每个寄存器可以存取一个64位大小的数。 当使用 r0 - r30访问时,它就是一个64位的数。当使用 w0 - w30访问时,访问的是这些寄存器的低32位,如图:
Current Program State Register
状态寄存器是32位的
CPSR的低8位(包括I、F、T和M[4:0])称为控制位,程序无法修改,除非CPU运行于特权模式
下,程序才能修改控制位
N、Z、C、V
均为条件码标志位
。它们的内容可被算术或逻辑运算
的结果所改变,并且可以决定某条指令是否被执行,意义重大
NZCV是状态寄存器的条件标志位,分别代表运算过程中产生的状态,其中:
N, negative condition flag
,一般代表运算结果是负数
1 代表结果为负数
0 代表结果为非负数
Z, zero condition flag
, 指令结果为0时Z=1,否则Z=0
C, carry condition flag
, 一般情况下进行无符号数的运算
加法运算
当运算结果产生了进位(无符号溢出)C=1否则C=0
减法运算(包括CMP)
当运算是产生了借位时(无符号溢出)则C=0,否则C=1
对于位数为N的无符号数来说其对应的二进制的最高位,即第N-1位就是他的最高有效位,而假想存在的第N位就是相对于最高有效位的更高位。
进位
我们知道,当两个数相加的时候,有可能从最高有效位向更高位进位。比如两个32位数据:0xaaaaaaaa
+ 0xaaaaaaaa
,将会产生进位。但由于进位值在32位中无法保存,我们就只是简单的说这个进位值丢失了。其实CPU在运算的时候并不会丢弃这个进位值,而是记录在一个特殊的寄存器的某一位上。ARM上就用C为来记录这个进位值。
借位
当两个数据做减法的时候,有可能向更高位。比如:0x00000000
- 0x000000ff
,将产生借位,借位后相当于计算0x100000000
- 0x000000ff
= 0xffffff01
,由于借了一位,所以C位用来标记借位。
V, oVerflow condition flag
有符号运算有溢出时,V=1
正数 + 正数 = 负数 则 溢出
负数 + 负数 = 正数 则 溢出
正数 + 负数 不可能溢出
后进先出 ARM64栈开口向底地址,即开辟的地址是朝底地址方向的
SP寄存器在任意时刻会保存栈顶的地址
FP寄存器也称为X29寄存器属于通用寄存器,但是在某些时候我们利用它保存栈底的地址
注意:ARM64开始,取消了32位的LDM、STM、PUSH、POP指令,取而代之的是:ldr、ldp、str、stp。在ARM64中对栈的操作是16字节对齐的
常见函数调用开辟和恢复栈空间
sub sp, sp, #0x40
拉伸0x40(64字节)空间
即sp寄存器地址减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
将数据冲内存中读出来,存到寄存器中
ldp stp 可以一次性操作两个寄存器
bl
将下一条指令的地址放入lr(x30)
寄存器
转到标号处执行指令
ret
默认使用lr(x30)
寄存器的值,通过底层指令提示CPU此处作为下条指令地址
lr(x30)
寄存器
存放的是函数的返回地址,当ret
指令执行时,回去寻找lr(x30)
寄存器保存的地址
在嵌套调用函数的时候需要将 x30 入栈
ARM64
下,函数的参数是放在x0 ~ x7
(w0 ~ w7
)这8个寄存器中。如果超过八个参数就会入栈。
函数的返回值会放在X0
寄存器中的。
函数的局部变量是放在栈里面的