ARM处理器有37个寄存器,包括31个通用寄存器,和6个状态寄存器。
通用寄存器是31个从x0-x30,31个数量是比较奇怪的,其实还有一个是Zero Register是wzr。如果是使用寄存器中的32位,就是w0-w30了。类型X86中的rax和eax寄存器,一个64位一个32位。
ARM处理器共有7种不同的处理器模式,在每一种处理器模式中有一组响应的寄存器组。
在AArch64时使用X30作为子函数调用时使用的link register
在AArch32时始终使用LR作为link register。
后续主要都是ARM64架构了,所以这里以arm64例。
Register |
Volatile? |
Role |
x0 |
Volatile |
Parameter/scratch register 1, result register |
x1-x7 |
Volatile |
Parameter/scratch register 2-8 |
x8-x15 |
Volatile |
Scratch registers |
x16-x17 |
Volatile |
Intra-procedure-call scratch registers |
x18 |
Non-volatile |
Platform register: in kernel mode, points to KPCR for the current processor; in user mode, points to TEB |
x19-x28 |
Non-volatile |
Scratch registers |
x29/fp |
Non-volatile |
Frame pointer |
x30/lr |
Non-volatile |
Link registers |
|
|
|
可以通过w0 ~ w30来访问这31个64位寄存器的低32位,写入时会将高32位清零。
也是有32个浮点寄存器。
每个寄存器都可以作为完整的128位值(通过v0-v31或q0-q31)进行访问。 可以以64位值(通过d0-d31),32位值(通过s0-s31),16位值(通过h0-h31)或8位值进行访问 (通过b0-b31)。 小于128位的访问仅访问整个128位寄存器的低位。 除非另有说明,否则它们保持其余位不变。 (AArch64与AArch32不同,在AArch32中,较小的寄存器封装在较大的寄存器的顶部。)
Register |
Volatile? |
Role |
v0 |
Volatile |
Parameter/scratch register 1, result register |
v1-v7 |
Volatile |
Parameter/scratch registers 2-8 |
v8-v15 |
Non-volatile |
Scratch registers (only the low 64 bits are non-volatile) |
v16-v31 |
Volatile |
Scratch registers |
浮点控制寄存器(FPCR)对其中的各个位字段有某些要求:
Bits |
Meaning |
Volatile? |
Role |
26 |
AHP |
Non-Volatile |
Alternative half-precision control. |
25 |
DN |
Non-Volatile |
Default NaN mode control. |
24 |
FZ |
Non-volatile |
Flush-to-zero mode control. |
23-22 |
RMode |
Non-volatile |
Rounding mode control. |
15,12-8 |
IDE/IXE/etc |
Non-Volatile |
Exception trap enable bits, must always be 0. |
浮点寄存器的单精度命名为s0至s31,双精度命名为d0至d15。
这些寄存器分为4个存储区:s0–s7(d0–d3),s8–s15(d4–d7),s16–s23(d8–d11)和s24–s31(d12–d15)。
(存储体0,s0–s7,d0–d3)称为标量存储体,而其余三个是矢量存储体
Vector Floating-point v2
可以通过软件来实现VFPv2当然相比硬件,其性能会更差。
VFPv2提供了三个控制寄存器,其中一个称为fpscr, 该寄存器与cpsr相似,保留了通常的比较标志N,Z,C和V。它还存储了两个非常有用的字段len和stride。 这两个字段控制浮点指令的行为。
大多数VFPv2指令的格式为vname Rdest,Rsource1,Rsource2或fname Rdest,Rsource1。 它们具有三种操作模式。
示例
|
单精度是:vldr
/vstr
加载/存储的地址必须已经在通用寄存器中
|
可以Load/store多个寄存器:
vldm indexing-mode precision Rbase{!}, floating-point-register-set
vstm indexing-mode precision Rbase{!}, floating-point-register-set
|
32位中还有vpush
|
指令是vmov.
在一个通用寄存器和一个单精度寄存器之间vmov,数据不会转换。 只有位会被复制,因此不要将浮点值与整数指令混合使用,反之亦然。
|
单精度转换为整型的时候丢失精度是必然的的,是多少问题。
指令:
vcvt
两个寄存器都必须是浮点寄存器。浮点寄存器将包含一个不是IEEE 754值的值。
|
设置了len和stride的特殊寄存器fpscr无法直接修改。
必须使用vmrs指令将fpscr加载到通用寄存器中。 然后使用vmsr指令对寄存器进行操作,并将其移回fpscr。
len的值存储在fpscr的第16至18位中。 len的值不直接存储在这些位中。这是因为len不能为0(操作0个浮点数没有意义)。 这样,这些位中的值000表示len = 1,001表示len = 2,…,111表示len =8。以下是将len设置为8的代码。
|
stride存储在fpscr的20至21位中。 与len相似,这些位中的值00表示1,01表示 2,10表示 3,11表示 4。
https://developer.arm.com/docs/ddi0595/d/aarch32-system-registers/fpscr
该寄存器中的命名字段映射到AArch64 FPCR和FPSR中的等效字段。
寄存器FPEXC中,EN表示NEON和VFP是否使能。清零是关闭
要使能,将EN置1。
注意有关可变参数函数(例如printf):不能将单精度浮点传递给此类函数之一。 只能通过双精度。 需要将单精度值转换为双精度值。 还要注意,通常使用整数寄存器(r0–r3),因此您最多只能传递2个双精度值,其余的必须在堆栈上传递。 特别是对于printf,因为r0包含字符串格式的地址,所以您只能在{r2,r3}中传递双精度。
要将标志-mfpu = vfpv2传递给as,否则将无法识别VFPv2指令。
VMRS/VMSR在ARM寄存器与NEON和VFP系统寄存器之间传输内容。
fmrx/fmxr在ARM寄存器和VFP系统寄存器之间传输内容。
Fmrs/fmsr 在ARM寄存器和浮点寄存器之间传输内容。
与AArch32一样,AArch64规范提供了三个系统控制的“线程ID”寄存器:
Register |
Role |
TPIDR_EL0 |
Reserved. |
TPIDRRO_EL0 |
Contains CPU number for current processor. |
TPIDR_EL1 |
Points to KPCR structure for current processor. |
程序计数器
pc,保存着当前CPU执行指令的地址。不能用作算数指令的源或目的地以及用作加载或存储指令。
堆栈指针
sp,即x31,指向堆栈的顶部。sp不能被大多数指令引用, 但一些算术指令,例如ADD指令,可以读写当前的堆栈指针来调整函数中的堆栈指针。每个异常级别都有一个专用的SP寄存器。
fp,即x29,帧指针,指向当前frame的栈底,也就是高地址。
链接寄存器
lr,即x30,存储着函数的返回地址。
程序状态寄存器
在汇编中通过状态寄存器来控制分支的执行。
cpsr:与其他寄存器不太一样,其他寄存器用来存储数据的,但是这个寄存器是,按位起作用的,每一位都有专门的含义。
spsr:当发生异常时,cpsr会存入spsr直到异常恢复再复制回cpsr。
ARM处理器支持7种运行模式,分别是:
各种处理器模式下的,通用寄存器
还有两个工作模式:
hyp:用于虚拟化扩展。
monitor:用于Security扩展。
ARM状态:执行32位字对齐的ARM指令。
Thumb状态:执行16位字对齐的ARM指令。
Thumb状态下的寄存器的命名与ARM有部分差异,它们的对应关系如下所示:
Thumb状态下的R0~R7与ARM状态下的R0~R7相同。
Thumb状态下的CPSR与ARM状态下的CPSR相同。
Thumb状态下的FP与ARM状态下的R11相同。
Thumb状态下的IP与ARM状态下的R12相同。
Thumb状态下的SP与ARM状态下的R13相同。
Thumb状态下的LR与ARM状态下的R14相同。
Thumb状态下的PC与ARM状态下的R15相同。
CPSR(当前程序状态寄存器)可以在任何处理器模式下被访问。
如果写入到寄存器PC中的值是非字对齐的,要么指令执行的结果不可预知,要么地址值中最低两位被忽略。