ARM寄存器结构小记

ARM处理器共有37个寄存器,被分为若干个组,这些寄存器包括:

  • 31个通用寄存器,包括未分组寄存器R0-R7、分组寄存器R8-R14和程序计数器( PC 指针),均为32位的寄存器。
  • 6个状态寄存器,包括程序状态寄存器 CPSR 和5个物理状态寄存器 SPSR (用以异常发生时保存 CPSR 的值,异常退出时恢复 CPSR )。 这些状态寄存器用以标识 CPU 的工作状态及程序的运行状态,均为32位。

具体如下表所示:

用户模式 usr 系统模式 sys 特权模式 svc 中止模式 abt 未定义指令模式 und 外部中断模式 irq 快速中断模式 fiq
R0 R0 R0 R0 R0 R0 R0
R1 R1 R1 R1 R1 R1 R1
R2 R2 R2 R2 R2 R2 R2
R3 R3 R3 R3 R3 R3 R3
R4 R4 R4 R4 R4 R4 R4
R5 R5 R5 R5 R5 R5 R5
R6 R6 R6 R6 R6 R6 R6
R8 R8 R8 R8 R8 R8 R8_fiq
R9 R9 R9 R9 R9 R9 R9_fiq
R10 R10 R10 R10 R10 R10 R10_fiq
R11 R11 R11 R11 R11 R11 R11_fiq
R12 R12 R12 R12 R12 R12 R12_fiq
R13(SP) R13 R13_svc R13_abt R13_und R13_inq R13_fiq
R14(LR) R14 R14_svc R14_abt R14_und R14_inq R14_fiq
PC(R15) PC PC PC PC PC PC
CPSR CPSR CPSR CPSR CPSR CPSR CPSR
SPSR_svc SPSR_abt SPSR_und SPSR_inq SPSR_fiq

1. 未分组寄存器 R0 - R7

对于未分组寄存器,它们没有被系统用于特别的用途,因此任何可采用通用寄存器的应用场合都可以使用未分组寄存器。
但需要注意一点,未分组寄存器不会因为处理器模式的改变而更改指向的寄存器,因此在所有的处理器模式下未分组寄存器都指向同一个寄存器,当中断或异常处理造成处理器模式转换的时候,由于不同的处理器模式使用了相同的物理寄存器,这就有可能造成寄存器中的数据被破坏。

2. 分组寄存器 R8 - R14

对于分组寄存器,它们每一次所访问的物理寄存器和处理器当前的运行模式有关。例如在快速中断模式 fiq下R8-R12访问寄存器 R8_fiq-R12_fiq ;而在其他模式下又访问 R8_usr-R12_usr 。因此它们每个对应着两个不同的寄存器。

对于R13(SP)、R14(LR)来说,每个寄存器对应着6个不同的物理寄存器,其中的一个是用户模式与系统模式共用,另外5个物理寄存器对应于其他5种不同的运行模式。采用以下的记号来区分不同的物理寄存器:
R13_< mode >
R14_< mode >
其中,mode为以下几种模式之一:usr、fiq、irq、svc、abt、und。

2.1 R13(SP)

寄存器 R13 在 ARM 指令还有着一个非常重要的作用,通常他被用作堆栈指针,当然这只是一种习惯用法,用户也可以使用其他的寄存器作为堆栈指针,但在Thumb指令集中,某些指令强制性地要求使用R13作为堆栈指针。

由于处理器的每种运行模式均有自己福利的物理寄存器R13,使其指向该运行模式下的栈空间,这样,当程序的运行进入异常模式时,可以将需要保护的寄存器放入R13所指向的堆栈,而当程序从异常模式返回时,则从对应的堆栈恢复,采用这种方式可以保证异常发生后程序的正常执行。

2.2 R14(LR)

R14 也称作子程序连接寄存器(Subroutine Link Register)或连接寄存器 LR 。当执行 BL 子程序调用指令时,R14 中得到 R15 (程序计数器PC)的备份。

1
2
3
0x00008d68 <+44>: bl 0x8cd4 <func>
0x00008d6c <+48>: ...
0x00008d70 <+52>: ...123

通常情况下,在汇编代码中不会出现 R14 中产生 PC 备份的指令语句。可以简单的理解为在执行调用的同时,将当前 PC 的指向的值 0x00008d70 减去一条指令的长度,这里是ARM工作状态,指令长度为 0x00000004,并交由R14保存。减去一条指令的原因很简单,不减的话返回的时候中间 0x00008d6c 处的那条指令就被跳过了。

(当前执行的是 0x00008d68 处的指令,0x00008d6c 处的指令处于译码阶段,0x00008d70 的指令处于取指阶段,PC总是指向取指阶段的指令。关于 ARM 处理器的流水线机制和 PC 指向的值 详见下文。)

其他情况下,R14 也可以用作通用寄存器。与之类似,当发生中断或异常时,对应的分组寄存器 R14_svc、R14_irq、R14_fiq、R14_abt 和 R14_und 用来保存 R15 的返回值。

每一种处理器模式在自己的物理 R14 中存放当前子程序的返回地址。当通过BL、BX 等指令调用子程序时,R14就被设置成该子程序的返回地址。例如有汇编指令如下:

  • 执行以下任意一条指令:
1
2
MOV PC,LR
BX LR12
  • 在子程序入口处使用以下指令将R14存入堆栈:
1
STMFD SP!,{<Regs>,LR}1
  • 对应的,使用以下指令可以完成子程序返回:
1
LDMFD SP!,{<Regs>,PC}1

当发生异常中断的时候,该模式下的特定物理R14被设置成该异常模式将要返回的地址。

2.3 R15(PC)

介绍R15之前先简单了解一下 ARM 处理器的是流水线机制。 ARM7 处理器采用3级流水线来增加处理器指令流的速度,能提供 0.9MIPS/MHz 的指令处理速度。

ARM7 的流水线有3个阶段,因此指令分3个阶段执行。
⑴ 取指从存储器装载一条指令
⑵ 译码识别将要被执行的指令
⑶ 执行处理指令并将结果写会寄存器

对于x86处理器来说,只有完成一条指令的读取和执行后,才会执行下一条指令。这样, PC 始终指向的正在“执行”的指令。
而对于 ARM7 来说因为是3级流水线,所以把指令的处理分为了上面所述的3个阶段。所以处理时实际是这样的: ARM 正在执行第1条指令的同时对第2条指令进行译码,并将第3条指令从存储器中取出。因此 ARM7 流水线只有在取第4条指令时,第1条指令才算完成执行。继而 ARM 的 PC 寄存器永远指向当前执行的指令后的第二条指令,即处于取指阶段的指令。

另外,在ARM状态下,最低的两位[1:0]为0,其他位[31:2]用于保存PC;在Thumb状态下,最低位[0]为0,其他位 [31:1]用于保存PC;所以 R15(PC)虽然可以用作通用寄存器,但是有一些指令在使用R15时有一些特殊限制,当违反了这些限制时,程序的执行结果是未知的。

2.4 R16(CPSR)

寄存器R16用作当前程序状态寄存器 CPSR (Current Program Status Register),可在任何运行模式下被访问,它包括条件标志位、中断禁止位、当前处理器模式标志位,以及其他一些相关的控制和状态位。

每一种运行模式下又都有一个专用的物理状态寄存器,称为备份的程序状态寄存器 SPSR (Saved Program Status Register),当异常发生时, SPSR 用于保存 CPSR 的当前值,从异常退出时则可由 SPSR 来恢复 CPSR 。

由于用户模式和系统模式不属于异常模式,他们没有 SPSR ,当在这两种模式下访问 SPSR ,结果是未知的。

2.5 执行条件标志位

ARM 的执行条件与 x86 下面的标志位有些类似,系统通过对这些标志位的判断来确定是否满足执行条件。几乎所有的 ARM 指令都包含一个4位的条件码,位于指令的最高4位。条件码共有16种,每种条件码可用两个字符表示,这两个字符可以添加在指令助记符的后面和指令同时使用。

例如,跳转指令 B 可以加上后缀 EQ 变成 BEQ 表示“相同则跳转”,即当 CPSR 中的Z标志置位时发生跳转。在16种条件标志码中,只有15种可以使用,如下表所示。第十六种(1111)为系统保留,暂时不能使用。

编 码 条件助记符 标志位 含 义
0000 EQ Z=1 相等
0001 NE Z=0 不相等
0010 CS C=1 无符号大于或等于
0011 CC C=0 无符号小于
0100 MI N=1 负值
0101 PL N=0 正值或 0
0110 VS V=1 溢出
0111 VC V=0 无溢出
1000 HI C=1 且 Z=0 无符号大于
1001 LS C=0 且 Z=1 无符号小于或等于
1010 GE N 和 V 相同 有符号大于或等于
1011 LT N 和 V 不相同 有符号小于
1100 GT Z=0 且 N 等于 V 有符号大于
1101 LE Z=1 且 N 不等于 V 有符号小于或等于
1110 AL 任意 无条件执行(不推荐使用)
1111 NV 任意 从不执行(不要使用)