[译] ARMv8-A架构基础之寄存器

ARMv8-A提供了31个64位的通用寄存器,始终可以访问,并且可以在所有异常级别访问。 在AArch64执行状态下,每个寄存器(X0-X30)都是64位宽度。 宽度增加有助于减少大部分应用程序中的寄存器压力。

每个64位通用寄存器(X0 - X30)也有一个32位的格式(W0 - W30)。

64bit_register.png

32位W寄存器构成相应的64位X寄存器的下半部分。 即W0形成X0的低位字,W1形成X1的低位字。

从W寄存器中读取时,忽略对应的X寄存器的高32位并且保持他们不变。 写入W寄存器将X寄存器的高32位设置为零。 因此,将0xFFFFFFFF写入W0会将X0设置为0x00000000FFFFFFFF。

注意
有时Rn用来指定一个ARMv8-A寄存器。 这意味着寄存器可以是Xn或Wn。

特殊寄存器

除了31个(X0到X30)个ARMv8-A核心寄存器之外,还有几个特殊的寄存器。

special_registers.png

注意
没有名为X31或W31的寄存器。 一些指令被编码了,以使数字31代表零寄存器ZR(WZR / XZR)。 还有一组受限制的指令,其中一个或多个参数被编码,以使数字31代表堆栈指针(SP)。

名字 大小 描述
WZR 32 bits 零寄存器
XZR 64 bits 零寄存器
WSP 32 bits 当前栈指针
SP 64 bits 当前栈指针
PC 64 bits 程序计数器

注意
64位格式的堆栈指针不使用X前缀。

在AArch64中执行时,对于每个异常级别,异常返回状态将保存在以下专用寄存器中:

  • 异常链接寄存器(ELR)。
  • 保存的处理器状态寄存器(SPSR)。

下表按异常级别标识特殊寄存器:

EL0 EL1 EL2 EL3
栈指针 (SP) SP_EL0 SP_EL1 SP_EL2 SP_EL3
异常链接寄存器 (ELR) - ELR_EL1 ELR_EL2 ELR_EL3
保存的处理器状态寄存器 (SPSR) - SPSR_EL1 SPSR_EL2 SPSR_EL3

异常级别的特殊寄存器

程序调用标准(PCS)还定义了一个专用的帧指针(FP),通过可靠地展开堆栈,它使调试和调用关系图分析变得更加容易。

零寄存器

零寄存器的名字暗示着什么。

零寄存器忽略所有对它的写操作,并且所有对它的读操作都返回0.您可以在大多数(但不是全部)指令中使用零寄存器。

堆栈指针

堆栈指针(SP)是一个指向堆栈顶部的寄存器。 选择使用的堆栈指针在某种程度上与“异常”级别是分开的。 默认情况下,发生异常时会为目标异常级别选择堆栈指针(SP_ELn)。 例如,发生EL1异常时选择SP_EL1。 每个异常级别都有自己的堆栈指针。

但是,当在AArch64中,异常级别的不是E0时,处理器可以使用下面中的任何一种:

  • 与该异常级别(SP_ELn)关联的64位堆栈指针,或者,
  • 与EL0(SP_EL0)关联的堆栈指针。 EL0只能访问SP_EL0。

SP不能被大多数指令引用。 但是,一些算术指令,例如ADD指令,可以读写当前的堆栈指针来调整函数中的堆栈指针。 例如:

ADD SP, SP, #0x10          // 将SP调整为当前值之前的0x10字节
ADD SP, SP, #256           // SP = SP + 256

程序计数器

程序计数器(PC)保存当前的程序地址。 它不能被数字引用(就像通用寄存器文件的一部分一样),因此不能用作算术指令的源或目的地,或作为加载和存储指令的基址,索引或转移寄存器。

那些可以读取PC的指令是那些具有计算PC相对地址功能的指令(ADR,ADRP,字面加载和直接分支),以及在链接寄存器中存储返回地址的“分支并链接”指令(BL和BLR)。 修改程序计数器的唯一方法是使用分支,异常生成和异常返回指令。

使用计算PC相对地址的指令读取PC时,读取的PC值是该指令的地址。 与ARMv7-A不同,不存在4或8字节的隐含偏移量。

异常链接寄存器(ELR)

异常链接寄存器保存要在异常后返回的地址。


原文

https://developer.arm.com/products/architecture/a-profile/docs/100878/latest/registers

推荐阅读更多精彩内容