目录
[4.ARMv8 registers](#4.ARMv8 registers)
[4.1 AArch64 特殊寄存器](#4.1 AArch64 特殊寄存器)
[4.1.1 Zero register](#4.1.1 Zero register)
[4.1.2 Stack pointer (SP)](#4.1.2 Stack pointer (SP))
[4.1.3 Program Counter (PC)](#4.1.3 Program Counter (PC))
[4.1.4 Exception Link Register(ELR)](#4.1.4 Exception Link Register(ELR))
[4.1.5 Saved Process Status Register (SPSR)](#4.1.5 Saved Process Status Register (SPSR))
[4.2 Processor state](#4.2 Processor state)
[4.3 System registers](#4.3 System registers)
[4.3.1 The system control register](#4.3.1 The system control register)
4.ARMv8 registers
在ARMv8架构的AArch64执行状态中,提供了31个64位的通用寄存器,这些寄存器在所有异常级别(Exception Levels, EL)上始终可访问。这些寄存器通常被称为X0到X30。
每个AArch64 64bit的寄存器X0-X30也有一个32bit的格式。
在ARMv8架构的AArch64执行状态中,每个64位通用寄存器X0到X30都有一个对应的32位宽的低半部分寄存器,称为W0到W30。以下是关于W寄存器的一些关键点:
-
W寄存器是X寄存器的低32位:例如,W0是X0的低32位,W1是X1的低32位。
-
读取W寄存器:当读取一个W寄存器时,只有对应的X寄存器的低32位被读取,高32位被忽略,并且保持不变。这意味着即使X寄存器的高32位包含数据,读取W寄存器也不会影响它们。
-
写入W寄存器:向W寄存器写入数据时,只修改对应X寄存器的低32位,而将高32位设置为零。例如,如果向W0写入0xFFFFFFFF,则X0将变为0x00000000FFFFFFFF,其中高32位被清零,低32位设置为写入的值。
-
W寄存器的用途:W寄存器可以用于32位的计算和操作,这在与32位操作系统或应用程序交互时特别有用。
-
兼容性:这种设计允许AArch64状态的处理器向后兼容32位代码,因为32位的值可以被存储在64位寄存器的低半部分,而不影响高半部分。
-
优化:在某些情况下,使用W寄存器可以优化代码,因为它允许32位的操作在不牺牲64位寄存器宽度的情况下进行。
-
寄存器对的使用:在AArch64中,寄存器通常成对使用,这意味着在进行某些操作时,可能会同时影响一个寄存器的X部分和W部分。
4.1 AArch64 特殊寄存器
除了31个core寄存器外,也有一些特殊寄存器。
在ARMv8架构的AArch64执行状态中,有一些特殊的寄存器规则和约定需要注意:
-
零寄存器(Zero Register):不存在名为X31或W31的寄存器。在许多指令中,数字31代表零寄存器(ZR),它有两种形式:WZR(32位宽的零寄存器)和XZR(64位宽的零寄存器)。
-
指令编码:在指令编码中,数字31被用来表示零寄存器,这样编码是为了节省空间和提高效率。
-
栈指针(Stack Pointer):在一组受限的指令中,数字31代表栈指针(Stack Pointer, SP)。与零寄存器不同,当指令中使用数字31来引用栈指针时,它指的是实际的栈指针寄存器。
-
零寄存器的访问:
- 写入零寄存器的所有操作都会被忽略,因为零寄存器始终为零。
- 从零寄存器读取的值总是0,无论之前是否有写入操作。
-
栈指针的特殊性:栈指针是一个特殊的寄存器,用于指向当前线程的栈顶。在64位模式下,栈指针通常不使用前缀X来表示,即直接使用SP而不是XSP。
-
寄存器使用:程序员在使用寄存器时应意识到这些规则,以避免混淆或错误地使用寄存器。
-
编码效率:通过使用数字31来表示零寄存器和栈指针,指令编码更加紧凑,这有助于提高指令解码的效率。
-
兼容性和向后兼容性:这种设计保持了与旧版ARM架构的兼容性,同时也为AArch64状态提供了新的功能和优化。
在ARMv8架构中,当在AArch64执行状态时,异常返回状态由每个异常级别(Exception Level, EL)的专用寄存器保存:
-
异常链接寄存器(Exception Link Register, ELR):
- 这个寄存器用于保存异常处理程序的返回地址。当处理器响应异常并跳转到异常处理程序时,它会将异常发生时的程序计数器(PC)保存到相应的ELR。
- 当异常处理完成,处理器使用异常返回(Exception Return, ERET)指令从ELR恢复执行,返回到异常发生前的代码位置。
-
保存的处理器状态寄存器(Saved Processor State Register, SPSR):
- SPSR用于保存异常发生时的某些处理器状态信息。这包括程序状态寄存器(Program Status Register, PSR)的某些字段,如条件标志、中断使能位等。
- 每个异常级别都有自己的SPSR,例如SPSR_EL1、SPSR_EL2和SPSR_EL3,它们分别保存在该异常级别上发生异常时的处理器状态。
-
专用栈指针(Stack Pointer, SP):
- 虽然每个异常级别都有一个专用的栈指针,但它们不用于保存异常返回状态。栈指针用于管理该异常级别的栈,而异常返回地址和状态由ELR和SPSR保存。
-
异常处理流程:
- 当异常发生时,处理器将当前的程序计数器和其他状态信息保存到ELR和SPSR中,然后跳转到对应的异常处理程序。
- 异常处理程序执行完毕后,处理器使用ERET指令从ELR恢复程序计数器,并从SPSR恢复其他状态信息,然后继续执行。
-
设计目的:
- 这种设计允许处理器在不同异常级别之间进行清晰的异常处理和返回,同时保持异常发生时的上下文不变。
-
异常级别的栈:
- 每个异常级别的栈用于存储该级别上的上下文信息,如寄存器内容,但在异常返回时,不通过栈来恢复程序计数器和状态信息。
4.1.1 Zero register
零寄存器(Zero Register)在ARMv8架构的AArch64执行状态中扮演着特殊的角色,以下是它的一些特性和使用方式:
-
读取始终为零:当零寄存器(通常表示为WZR或XZR)被用作源寄存器时,它总是提供零值作为操作数。
-
写入被忽略:当零寄存器被用作目的寄存器时,对它的写入操作会被忽略,即不会影响寄存器的值,它始终保持为零。
-
广泛使用:零寄存器可以在大多数指令中使用,特别是在需要一个零常数的算术或逻辑操作中,使用零寄存器可以提高编码效率和性能。
-
限制使用:尽管零寄存器在很多指令中可用,但并非所有指令都支持使用零寄存器。例如,某些特定的比较或移动指令可能不允许使用零寄存器。
-
优化代码:零寄存器的使用可以简化代码并减少指令大小,因为它避免了使用立即数零,特别是在条件执行的指令中。
-
寄存器别名:在AArch64中,零寄存器没有特定的寄存器编号,它通常被用作X0或W0寄存器的别名,但始终返回零。
-
与其他寄存器的区别:与普通的通用寄存器不同,零寄存器不保存任何状态,它仅作为一个特殊的寄存器,用于提供零或丢弃结果。
-
汇编编程中的考虑:在编写汇编代码时,程序员需要了解哪些指令支持零寄存器,以确保代码的正确性和效率。
4.1.2 Stack pointer (SP)
在ARMv8架构中,栈指针的使用在一定程度上与异常级别分离。默认情况下,触发异常时会为目标异常级别选择栈指针,例如,触发到EL1的异常会选择SP_EL1。每个异常级别都有自己的栈指针:SP_EL0、SP_EL1、SP_EL2和SP_EL3。
当处理器处于AArch64状态且不在EL0时,可以使用以下任一栈指针:
- 与该异常级别(SP_ELn)相关联的专用64位栈指针。
- 与EL0相关联的栈指针(SP_EL0)。
EL0只能访问SP_EL0。
"t"后缀表示选择了SP_EL0栈指针。"h"后缀表示选择了SP_ELn栈指针。 大多数指令不能引用SP。然而,某些形式的算术指令,例如,ADD指令,可以读取和写入当前栈指针,以调整函数中的栈指针。例如:
4.1.3 Program Counter (PC)
ARMv7指令集的一个特点是使用R15作为程序计数器(Program Counter, PC),它也被用作通用寄存器。PC使得一些巧妙的编程技巧成为可能,但也为编译器和复杂流水线的设计带来了复杂性。在ARMv8中移除对PC的直接访问使得返回预测变得更容易,并且简化了应用程序二进制接口(Application Binary Interface, ABI)的规范。PC永远不能作为一个命名寄存器被访问。它在某些指令中的使用是隐式的,比如PC相对的加载和地址生成。PC不能被指定为数据处理指令或加载指令的目的寄存器。
4.1.4 Exception Link Register(ELR)
用于储存异常返回地址。
4.1.5 Saved Process Status Register (SPSR)
在触发异常时,处理器状态被存储在相应的保存程序状态寄存器(Saved Program Status Register, SPSR)中,这与ARMv7中的当前程序状态寄存器(Current Program Status Register, CPSR)类似。SPSR保存了触发异常前的PSTATE值,并在执行异常返回时用于恢复PSTATE的值。
在ARMv8中,写入的SPSR(Saved Program Status Register)取决于触发异常的异常级别(Exception Level, EL)。具体如下:
- 如果异常是在EL1触发的,则使用SPSR_EL1。
- 如果异常是在EL2触发的,则使用SPSR_EL2。
- 如果异常是在EL3触发的,则使用SPSR_EL3。
当处理器触发异常时,它会将当前的PSTATE寄存器的值保存到对应的SPSR中。这个PSTATE值随后可以在执行异常返回操作时用来恢复处理器状态。每个异常级别都有自己的SPSR,以便在不同级别处理异常时保存和恢复状态。这种设计允许处理器在不同异常级别之间进行有效的状态管理和切换。
注意:与某个异常级别(Exception Level, EL)相关联的寄存器对ELR_ELn(Exception Link Register)和SPSR_ELn(Saved Program Status Register)在较低异常级别执行期间保留其状态。
4.2 Processor state
AArch64没有与ARMv7的当前程序状态寄存器(Current Program Status Register, CPSR)直接等价的寄存器。在AArch64中,传统CPSR的组件被提供为可以独立访问的字段。这些字段统称为处理器状态(Processor State, PSTATE)。AArch64的处理器状态或PSTATE字段具有以下定义:
-
条件标志(Condition Flags):类似于ARMv7的N(负数)、Z(零)、C(进位)、V(溢出)标志,这些标志基于上一次算术操作的结果。
-
控制位(Control Bits):包括模式(M)、中断使能位(I、F)、当前程序状态信息等,用于控制处理器的行为和状态。
-
状态位(State Bits):例如,是否处于异常级别、是否使能中断等。
-
异常级别(Exception Level, EL):指示当前执行的异常级别。
-
安全状态(Security State, SS):指示当前是处于安全状态还是非安全状态。
-
执行状态(Execution State, ES):指示是处于AArch64还是AArch32执行状态。
-
栈指针(Stack Pointer, SP):指示当前使用的栈指针,例如SP_EL0或SP_EL1。
-
程序计数器(Program Counter, PC):指向当前正在执行的指令的地址。
-
其他位:可能包括用于特定系统操作或模式的其他控制和状态位。
PSTATE字段的设计允许更细粒度的控制和访问,提高了AArch64在不同执行环境和上下文中的灵活性和效率。开发者可以根据需要独立地访问和修改这些状态字段,而不是作为一个整体的CPSR来处理。这种设计也简化了对处理器状态的管理和异常处理的实现。
在AArch64中,您可以通过执行ERET(Exception Return)指令来从异常返回,这会导致SPSR_ELn的内容被复制到PSTATE。这一操作会恢复算术逻辑单元(ALU)的标志位(N、Z、C、V)、执行状态、异常级别,并使处理器跳转到相应的地址。从这里开始,处理器会继续从ELR_ELn中的地址执行。
PSTATE中的{N, Z, C, V}字段可以在EL0(用户模式)下访问。所有其他的PSTATE字段可以在EL1或更高级别上执行,在EL0下是未定义(UNDEFINED)的。
4.3 System registers
在AArch64中,系统配置通过系统寄存器进行控制,并通过MSR(Move to System Register)和MRS(Move from System Register)指令来访问。这与ARMv7-A不同,在ARMv7-A中,这些寄存器通常是通过协处理器15(CP15)操作来访问的。寄存器的名称告诉您它可以从哪个最低的异常级别访问。
例如:
- TTBR0_EL1可以从EL1、EL2和EL3访问。
- TTBR0_EL2可以从EL2和EL3访问。
带有_ELn后缀的寄存器在某些或所有级别上都有单独的、银行化的副本,尽管通常不在EL0。很少有系统寄存器可以从EL0访问,尽管Cache Type Register(CTR_EL0)就是这样一个可以从EL0访问的例子。
访问系统寄存器的代码采用以下形式:
assembly
; 将值移至系统寄存器 MSR <system_register>, <register>
; 从系统寄存器移出值 MRS <register>, <system_register>
这里,<system_register>
是系统寄存器的名称,<register>
是通用寄存器的名称,用于存储要写入系统寄存器的值或从系统寄存器读取的值。
这种设计允许更细粒度的控制和更清晰的指令集,同时也简化了对系统寄存器的访问方式。通过MSR和MRS指令,开发者可以在不同的异常级别上安全地配置和查询系统状态。
表格显示了具有每个寄存器独立副本的异常级别。例如,辅助控制寄存器(Auxiliary Control Registers, ACTLRs)分别存在于ACTLR_EL1、ACTLR_EL2和ACTLR_EL3,每个都对应不同的异常级别。
4.3.1 The system control register
系统控制寄存器(System Control Register, SCTLR)是一个控制标准内存、系统设施,并为核心中实现的功能提供状态信息的寄存器。以下是SCTLLR的一些关键特性:
-
内存管理控制:SCTLR包含多个位字段,用于控制内存系统的各个方面,例如缓存的使能、页表的配置等。
-
系统特性控制:它还控制一些系统特性,如中断向量的位置、系统访问权限等。
-
状态信息提供:SCTLR可以指示当前的系统状态,如是否处于安全模式或非安全模式。
-
核心功能配置:SCTLR允许配置核心的某些功能,如分支预测、流水线行为等。
-
异常级别影响:SCTLR的某些位可能受到当前异常级别(Exception Level, EL)的影响,不同级别上的行为可能会有所不同。
-
系统稳定性:通过合理配置SCTLR,可以提高系统的稳定性和性能。
-
系统设计者和开发者使用:系统设计者和软件开发者需要了解SCTLR的配置,以确保系统按照预期运行。