ARM 寄存器

文章目录

ARM 寄存器介绍

Cortex A 系列的 ARM 处理器共有 40 个 32 位寄存器,其中 33 个为通用寄存器,7 个为状态寄存器。用户模式和系统模式共用同一组寄存器。

一、未分组寄存器 R0~R7

有些寄存器是所有运行模式共用的,如 R0~R7,它们被称为未分组寄存器。

在所有运行模式下,未分组寄存器都指向同一个物理寄存器,它们未被系统用作特殊用途。

在运行模式转换时,不同运行模式的处理器均使用相同的物理寄存器,可能造成寄存器中数据的覆盖。

二、分组寄存器 R8~R14

分组寄存器每一次访问的物理寄存器都与当前处理器的运行模式有关。

对 R8~R12 来说,每个寄存器对应 2 个不同的物理寄存器。当使用快速中断模式时,分组寄存器访问寄存器 R8_fiq ~ R12_fiq;当使用除快速中断模式以外的其他模式时,分组寄存器访问寄存器 R8_usr ~ R12_usr。

对 R13、R14 来说,每个寄存器对应 7 个不同的物理寄存器,其中一个为用户模式和系统模式共用,另外 6 个物理寄存器对应其它 6 种不同的运行模式,并采用以下记号来区分不同的物理寄存器。

R13_mode、R14_mode

其中 mode 可为 usr、fiq、irq、svc、abt、und、mon

① 寄存器 R13(SP)

寄存器 R13 在 ARM 指令集中常被用作堆栈指针,用户也可以使用其它寄存器作为堆栈指针,而在 Thumb 指令集中,某些指令强制要求使用寄存器 R13 作为堆栈指针。

处理器的每种运行模式均有自己独立的物理寄存器 R13,在用户应用程序初始化时,要初始化每种运行模式下的 R13 寄存器,使其指向该运行模式的栈空间。这样,当程序的运行进入异常模式时,可以将需要保护的寄存器中的数据保存至 R13 所指向的堆栈,而当程序从异常模式返回时,再从该堆栈中恢复数据,采用这种方式可以保证异常发生后程序也能正常执行。

② 寄存器 R14(LR)

当执行子程序调用指令(BL)时,R14 可得到 R15(程序计数器)的备份。

在每一种运行模式下,都可用 R14 保存子程序的返回地址,当用指令 BL 或 BLX 调用子程序时,将程序计数器的当前值复制给 R14,执行完子程序后,又将 R14 的值复制回程序计数器,即可完成子程序的调用返回。

三、程序计数寄存器 R15(PC)

寄存器 R15 用作程序计数器,在 ARM 状态下,bit[1:0] 为 0,bit[31:2] 用于保存 PC 值,在 Thumb 状态下,bit[0] 为 0,bit[31:1] 用于保存 PC 值。

例如,在 ARM 状态下,如果 PC 的值是 0x40008001,那么在寻址时,查找的地址为 0x40008000,低 2 位会自动被忽略掉。

四、当前程序状态寄存器 R16(CPSR)

ARM 包含一个当前程序状态寄存器 CPSR(R16)(Current Program Status Register)和 6 个备份的程序状态寄存器(SPSRs)。CPSR 在任何工作模式都可被访问,用来保存 ALU 中的当前操作信息、控制允许和禁止中断、设置处理器的工作模式等。

其中工作模式位(M[4:0])用来标识或设置处理器的工作模式。

下面,我们通过调试,看下管理模式和用户模式下 CPSR 的值,实际感受下

管理模式(SVC)

在内核代码中打上断点,断点命中后,CPU 停止运行,此时 cpsr 寄存器的值为 0x60000193,我们只看最低 5 bits,值为 10011b,对应上表中的 SVC 管理模式。

PS:Linux 内核代码大多数时候都是以 SVC 管理模式运行的,其中,软中断相关的调用是使用 SYS 系统模式运行的。而且,内核在特定的情况下可以主动从 SVC 模式切换到 SYS 模式去运行。

用户模式(USR)

在用户进程的 main 函数打上断点,断点命中后,CPU 停止运行,此时 cpsr 寄存器的值为 0x60080010,最低 5 bits 为 10000b,对应上表中的用户模式。

汇编里的寄存器名称

我们在看反汇编代码时,常常会看到 fp、lr 等寄存器名称,这些是指什么呢?

bash 复制代码
liyongjun@Box:~/project/board/buildroot/override/Vexpress_2/test$ /home/liyongjun/project/board/buildroot/Vexpress_2/host/bin/arm-linux-objdump -d test.out 
...
000005b8 <main>:
 5b8:	e92d4800 	push	{fp, lr}
 5bc:	e28db004 	add	fp, sp, #4
 5c0:	e24dd008 	sub	sp, sp, #8
 5c4:	e3a03000 	mov	r3, #0
 5c8:	e50b3008 	str	r3, [fp, #-8]
 5cc:	ea000008 	b	5f4 <main+0x3c>
 5d0:	e59f3038 	ldr	r3, [pc, #56]	@ 610 <main+0x58>
 5d4:	e08f3003 	add	r3, pc, r3
 5d8:	e1a00003 	mov	r0, r3
 5dc:	ebffff92 	bl	42c <puts@plt>
 5e0:	e3a00001 	mov	r0, #1
 5e4:	ebffff8d 	bl	420 <sleep@plt>
 5e8:	e51b3008 	ldr	r3, [fp, #-8]
 5ec:	e2833001 	add	r3, r3, #1
 5f0:	e50b3008 	str	r3, [fp, #-8]
 5f4:	e51b3008 	ldr	r3, [fp, #-8]
 5f8:	e3530009 	cmp	r3, #9
 5fc:	dafffff3 	ble	5d0 <main+0x18>
 600:	e3a03000 	mov	r3, #0
 604:	e1a00003 	mov	r0, r3
 608:	e24bd004 	sub	sp, fp, #4
 60c:	e8bd8800 	pop	{fp, pc}
 610:	000000d4 	.word	0x000000d4
...

在解答疑问之前,我们先介绍一个概念:ATPCS

ATPCS

ATPCS(ARM-Thumb Produce Call Standard)是 ARM 程序和 Thumb 程序中调用的基本规则。这些基本规则包括子程序调用过程中寄存器的使用规则,数据栈的使用规则,参数的传递规则。

寄存器的使用规则

下表总结了在 ATPCS 中各寄存器的使用规则及其名称。这些名称在编译器和汇编器中都是预定义的。

寄存器的使用必须满足下面的规则。

  • 子程序间通过寄存器 R0~R3 来传递参数。这时,寄存器 R0~R3 可以记作 A0~A3。
  • 在子程序中使用寄存器 R4~R11 来保存局部变量。这时,寄存器 R4~R11 可以记作 V1~V8。如果在子程序中也使用到了寄存器 V1~V8,那么子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值。
  • 寄存器 R12 用作子程序间 scratch 寄存器,记作 IP,在子程序间的连接代码段中常有这种使用规则。
  • 寄存器 R13 用作堆栈指针,记作 SP,在子程序中寄存器 R13 不能用作其它用途。寄存器 SP 在进入子程序时的值和退出子程序时的值必须相等。
  • 寄存器 R14 称为连接寄存器,记作 LR。它用于保存子程序的返回地址。如果在子程序中保存了返回地址,寄存器 R14 则可以用作其它用途。
  • 寄存器 R15 是程序计数器,记作 PC。他不能用作其他用途。

通过以上介绍,我们就知道了 fp、lr 分别是寄存器 R11、R14 的别名。类似的寄存器别名还有 pc、sp、ip、sl 等。

相关推荐
森G37 分钟前
七、04ledc-sdk--------makefile有变化
linux·c语言·arm开发·c++·ubuntu
VekiSon4 小时前
Linux内核驱动——杂项设备驱动与内核模块编译
linux·c语言·arm开发·嵌入式硬件
AI+程序员在路上5 小时前
Nand Flash与EMMC区别及ARM开发板中的应用对比
arm开发
17(无规则自律)11 小时前
深入浅出 Linux 内核模块,写一个内核版的 Hello World
linux·arm开发·嵌入式硬件
梁洪飞1 天前
内核的schedule和SMP多核处理器启动协议
linux·arm开发·嵌入式硬件·arm
代码游侠1 天前
学习笔记——Linux字符设备驱动
linux·运维·arm开发·嵌入式硬件·学习·架构
syseptember2 天前
Linux网络基础
linux·网络·arm开发
代码游侠2 天前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
程序猿阿伟2 天前
《Apple Silicon与Windows on ARM:引擎原生构建与模拟层底层运作深度解析》
arm开发·windows
wkm9562 天前
在arm64 ubuntu系统安装Qt后编译时找不到Qt3DExtras头文件
开发语言·arm开发·qt