1.2 AArch64寄存器堆
作为RISC架构,AArch64提供了大量的通用寄存器。除通用寄存器之外,本节还会介绍特殊寄存器、系统控制寄存器、处理器状态、函数调用标准。
1.2.1 通用寄存器
通用寄存器分为两类。其中一类寄存器包括X0~X30,用于普通的指令集,每个寄存器都有64位(Xn)和32位(Wn)两种表示形式。其中32位的表示形式是64位表示形式的低32位。另一类寄存器包括V0~V31,用于浮点运算、SIMD、crypto等领域。每个寄存器长度都是128位(Qn),它们有64位(Dn)、32位(Sn)、16位(Hn)、8位(Bn)这4种表示形式。
以X0和V0为例,X0是64位寄存器,它的低32位是W0。V0也称为Q0,Q0是一个128位的寄存器,它的低64位称为D0,它的低32位称为S0,它的低16位称为H0,它的低8位称为B0,如图1.1所示。
图1.1 寄存器的表示形式
1.2.2 特殊寄存器
XZR和WZR分别对应64位与32位的零寄存器。对这些寄存器进行读操作,将会获取到0;对这些寄存器进行的写操作将会被处理器忽略。与ARM的32位架构不同,PC寄存器已经不再是一个通用寄存器,无法直接访问。ARM指令的长度是4字节,因此对于ARMv8上的纯ARM指令来说,PC寄存器是按字节对齐的。SP寄存器也不再是一个通用寄存器,SP寄存器强制按16字节对齐。
1.2.3 系统控制寄存器
ARM的系统控制寄存器都以“_ELx”为后缀,其中“x”表示某异常级别(Exception Level,EL)的一个数字,如SCTLR_EL1。后缀的数字意味着能够访问该寄存器的最低异常级别,ARM的系统控制寄存器如表1.1所示。
表1.1 ARM的系统控制寄存器
MRS和MSR指令用于读写系统控制寄存器,示例代码如下。
MRS X0, SCTLR_EL1 // X0 = SCTLR_EL1 MSR SCTLR_EL1, X0 // SCTLR_EL1 = X0
常用的系统控制寄存器及其功能如表1.2所示。
表1.2 常用的系统控制寄存器及其功能
ARM的系统控制寄存器数量庞大,详细的介绍可以参考文档DDI0487F_b_ARMv8_arm.pdf。
1.2.4 处理器状态
AArch64通过PSTATE(process state)的标志位来保存处理器的状态,处理器执行指令的时候,可以读取和设置这些标志位。这些标志位既可以通过mrs/msr指令进行访问,也可以通过DAIFSet、DAIFClr、SPSel、PAN、UAO等指令直接访问。PSTATE寄存器的标志位如表1.3所示。
表1.3 PSTATE寄存器的标志位
1.2.5 函数调用标准
1.AArch64基本指令集函数调用规则
AArch64提供了31个64位的通用寄存器X0~X30,SP寄存器已经变成了一个专用寄存器。这些寄存器的描述如表1.4所示。
表1.4 AArch64寄存器的描述
值得注意的是,X16和X17寄存器在动态链接的时候,可能会被某些链接器用于实现特殊功能。X18寄存器在Darwin和Windows平台上会保留作为平台寄存器使用。在代码优化的时候,这3个寄存器要谨慎使用。
2.AArch64 NEON指令集函数调用规则
AArch64提供了32个128位的寄存器(V0~31),可以用来进行SIMD和浮点运算。
其中,V0~V7这8个寄存器用来传递参数和函数返回值,V8~V15这8个寄存器需要由被调函数保存(只需要保存这些寄存器的低64位即可)。
D8~D15是V8~V15寄存器的低64位,因此通过如下的代码片段保存D8~D15的内容,就可以在函数中使用V0~V31这32个寄存器了。
stp d8, d9, [sp, -192]! stp d10, d11, [sp, 16] stp d12, d13, [sp, 32] stp d14, d15, [sp, 48]
3.AArch64 SVE指令集函数调用规则
如果平台支持SVE扩展,那么AArch64会提供32个可变长的向量寄存器Z0~Z31。每个寄存器都可以用来进行SIMD和浮点运算,其中Z0~Z7用来传递参数和函数返回值。Z8~Z15这8个寄存器需要由被调函数保存(只需要保存这些寄存器的低64位即可)。
AArch64还为SVE提供了16个断言寄存器P0~P15,其中P0~P3这4个寄存器用来传递参数和函数返回值。