函数嵌套时以及异常响应时,寄存器LR的作用存在显著区别,理解这个问题对于理解freeRTOS底层代码的实现大有帮助,具体使用过程如下:
一 函数嵌套时的LR使用的具体过程
在ARM架构(特别是M0处理器)中,函数嵌套调用时LR(Link Register)寄存器的处理过程如下:
1 基本调用机制
当使用BL指令调用函数时,处理器在进行跳转之前,会将当前函数的下一条地址,即(PC+4)的地址,存入LR寄存器,
被调函数执行完毕函数返回时,通过MOV pc,lr 指令加载LR寄存器的值到PC寄存器,实现函数返回。
2 函数嵌套时的处理过程
每次BL调用时LR都会被新的返回值覆盖,
内层函数调用前需要对原LR值进行保存,通常压栈。以下是一个具体示例:
main:
BL outer_func
B .
outer_func:
PUSH {LR} ; 保存返回地址
BL inner_func
POP {LR} ; 恢复LR
BX LR
inner_func:
; 函数体
BX LR
从以上红色字体可以看出,最后一层函数在返回时,是先执行BX lr指令返回,然后再执行出栈操作恢复包括上一层函数返回地址寄存器LR在内的所有栈内容。
二 异常发生时,LR的使用机制
以FreeRTOS操作系统为例,LR工作在异常返回机制状态下:
1. LR寄存器(R14)的作用
- ARM Cortex-M架构中,LR寄存器在触发异常(如SVC)时会被自动设置为特殊的
EXC_RETURN
值。该值包含两部分信息:- 异常返回模式:标识返回后使用MSP(主栈指针)还是PSP(进程栈指针);
- 栈帧类型:指示硬件需要恢复的寄存器集合。
- 在FreeRTOS任务切换场景中,
EXC_RETURN
通常设置为使用PSP,并触发硬件自动从任务栈恢复上下文。
2. BX R14的执行逻辑
中断返回时,BX R14的执行逻辑,通常不是直接将LR寄存器的值赋值给PC寄存器,而是通过EXC_RETURN
触发异常返回流程,此时处理器会:
- 根据
EXC_RETURN
确定使用PSP作为栈指针; - 从PSP指向的任务栈中弹出保存的寄存器(包括R0-R3、R12、LR、PC、xPSR);
- 将PC设置为任务入口地址(即任务函数指针)。
以下为freeRTOS代码示例:
SVC异常:
PendSV异常: