ARM 架构中,R14链接寄存器(LR)是什么?
本文来自于我关于 Arm Cortex-M 编程模型的系列文章。欢迎阅读、点评与交流~
1、Arm Cortex-M 处理器的编程模型
2、ARM 架构中,R13栈指针(SP)是什么?
3、ARM 架构中,R14链接寄存器(LR)是什么?
核心定义
R14,即链接寄存器(全称:Link Register) ,是 ARM 处理器 16 个通用寄存器(R0-R15)中的一个。它的主要职责是 存储子程序或函数调用的返回地址。
当程序使用 BL(Branch with Link)或 BLX 指令调用一个子程序(函数)时,处理器在跳转到目标地址执行之前,会自动将下一条指令的地址(即返回地址)保存到 LR(R14)中。子程序执行完毕后,通过将 LR 的值复制到程序计数器 PC(R15),即可返回到主调程序继续执行。
主要功能与用途
-
保存返回地址(核心功能)
-
这是 LR 最基本、最重要的作用。
-
示例:
assemblymain: ... BL subroutine ; 调用子程序。执行此指令时,下一行 MOV 指令的地址会被自动存入 LR MOV r0, #5 ; <-- 这是返回地址,被保存在 LR 中 ... subroutine: ... ; 子程序代码 BX LR ; 将 LR 的值载入 PC,从而返回到 main 的 MOV 指令处
-
-
异常处理时的状态保存
- 当发生异常(如中断、系统调用)时,处理器在进入异常模式前,会将当前模式的返回地址保存到异常模式下的 LR (例如
LR_irq,LR_svc)。 - 这确保了异常处理程序完成后,能正确返回到被中断的程序点。
- 注意: 此时的 LR 保存的值可能与正常函数返回地址略有不同(例如会进行自动偏移校正),这取决于具体的异常类型和 ARM 架构版本。
- 当发生异常(如中断、系统调用)时,处理器在进入异常模式前,会将当前模式的返回地址保存到异常模式下的 LR (例如
-
作为临时通用寄存器
- 在函数内部,一旦返回地址被安全地保存到栈上 (通常在函数开头通过
PUSH {LR}或STR LR, [sp, #-4]!),LR 就可以在后续代码中作为一个普通的临时寄存器(相当于 R14)使用,以增加寄存器资源的灵活性。
- 在函数内部,一旦返回地址被安全地保存到栈上 (通常在函数开头通过
关键特性与注意事项
-
调用嵌套与栈保存
LR 是单副本寄存器。如果一个函数(A)内部又调用了另一个函数(B),那么在调用 B 之前,函数 A 的返回地址(保存在 LR 中)会被 B 的调用覆盖。
-
解决方案: 在非叶子函数(即那些还会调用其他函数的函数)的开头,必须先将 LR 的值压入内存栈进行保存,在函数结束前再从栈中恢复。
-
标准序言/尾声:
assemblymy_function: PUSH {LR} ; 将返回地址保存到栈 ... ; 函数体,可以安全地调用其他函数 BL another_func ... POP {PC} ; 从栈中弹出之前保存的地址,直接载入 PC 以实现返回 ; 这是一种常见的优化技巧
-
-
与 PC(R15)的关系
LR 和 PC 紧密协作。
BL指令完成LR = PC + offset的写入,而BX LR或MOV PC, LR则完成从子程序返回的操作。 -
在 ARM 操作模式和 Banked Registers
ARM 有多种处理器模式(User, FIQ, IRQ, SVC, Abort 等)。不同模式拥有自己独立的 R14 物理副本(称为"分组寄存器")。
- 例如,当在 User 模式下执行
BL指令时,返回地址保存在 User 模式的 LR 中。 - 当发生 IRQ 中断时,处理器自动切换到 IRQ 模式,并将返回地址保存到
LR_irq(IRQ 模式专用的 R14),而 User 模式的 LR 值保持不变,不受影响。 - 这为不同模式提供了独立的调用返回链,是硬件上下文切换的关键部分。
- 例如,当在 User 模式下执行
-
架构差异
- 在 ARMv7-A/R 和更早的架构中,LR 就是 R14。
- 在 64位的 ARMv8-A 架构中,寄存器文件扩展为 31 个 64 位通用寄存器(X0-X30)。X30 寄存器承担了链接寄存器的角色,其功能和原理与 ARM32 下的 R14 完全相同。
总结
| 特性 | 描述 |
|---|---|
| 名称 | R14 / 链接寄存器 / Link Register / LR |
| 核心目的 | 存储函数调用(BL指令)后的返回地址 |
| 关键操作 | 由 BL/BLX 指令自动写入;通过 BX LR 或 MOV PC, LR 返回 |
| 嵌套调用 | 必须在调用其他函数前,将其值压入栈保存,否则会被覆盖 |
| 异常处理 | 各异常模式有自己的分组 LR,用于保存异常返回地址 |
| 临时使用 | 在保存好返回地址后,可临时作为通用寄存器使用 |
简单来说,LR 是函数调用的"书签",它告诉程序"你从哪儿来的,执行完了就该回哪儿去"。它是实现结构化编程和子程序调用的硬件基础。