01.寄存器
寄存器是什么
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寄存器的值可以改变程序执行的流程 
 
1.1 通用寄存器
- x0-x7: 用于子程序调用时的参数传递,X0还用于返回值传递 
- x0 - x30是31个通用整形寄存器。每个寄存器可以存取一个64位大小的数。 当使用 r0 - r30访问时,它就是一个64位的数。当使用 w0 - w30访问时,访问的是这些寄存器的低32位,如图:

1.2 CPSR 状态寄存器
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栈开口向底地址,即开辟的地址是朝底地址方向的
2.01 SP 和 FP寄存器
- SP寄存器在任意时刻会保存栈顶的地址 
- FP寄存器也称为X29寄存器属于通用寄存器,但是在某些时候我们利用它保存栈底的地址 
注意:ARM64开始,取消了32位的LDM、STM、PUSH、POP指令,取而代之的是:ldr、ldp、str、stp。在ARM64中对栈的操作是16字节对齐的
2.02 编译器会根据编译情况开辟固定的栈空间
2.03 函数调用栈
常见函数调用开辟和恢复栈空间
- 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
2.03 内存读写指令
读写:数据都是往高地址读写的 即:一段数据一个字节无法完整保存的话,连续的多个地址进行保存,地址递增
- str 指令 store register - 将数据从寄存器中读出来,存到内存中 
 
- ldr 指令 load register - 将数据冲内存中读出来,存到寄存器中 
 
- ldp stp 可以一次性操作两个寄存器 
2.04 bl 和 ret 指令
- bl- 将下一条指令的地址放入 - lr(x30)寄存器
- 转到标号处执行指令 
 
- ret- 默认使用 - lr(x30)寄存器的值,通过底层指令提示CPU此处作为下条指令地址
 
- lr(x30)寄存器- 存放的是函数的返回地址,当 - ret指令执行时,回去寻找- lr(x30)寄存器保存的地址
- 在嵌套调用函数的时候需要将 x30 入栈
 
2.05 函数的参数和返回值
- ARM64下,函数的参数是放在- x0 ~ x7(- w0 ~ w7)这8个寄存器中。如果超过八个参数就会入栈。
- 函数的返回值会放在 - X0寄存器中的。
- 函数的局部变量是放在栈里面的 
Last updated
Was this helpful?