异常栈:PC、LR 与 EXC_RETURN
2026/9/29大约 2 分钟
Cortex-M 异常栈:PC、LR 与 EXC_RETURN
1. 异常发生时,硬件自动压栈
Cortex-M 异常进入时,硬件自动保存:
R0
R1
R2
R3
R12
LR
PC
xPSR形成标准异常栈帧。
stack[0] → R0
stack[1] → R1
stack[2] → R2
stack[3] → R3
stack[4] → R12
stack[5] → LR
stack[6] → PC
stack[7] → xPSR2. PC 和 LR 分别干什么?
PC
保存异常发生时的程序执行位置。
因此故障分析首先关注:
PC → 异常现场位置但 PC 是否精确指向真正的故障指令,要结合具体 Fault 类型判断。
LR
保存异常发生前程序中的 LR:
LR → 原程序的返回地址它可以辅助分析函数调用关系。
所以:
PC → 异常现场
LR → 调用/返回关系不要把两者混为一谈。
3. 异常 Handler 里的 LR 又不一样
进入异常 Handler 后,CPU 会把特殊值装入 LR:
EXC_RETURN它不是普通函数意义上的返回地址。
例如:
0xFFFFFFF9
0xFFFFFFFD这些值告诉 Cortex-M:
异常返回时使用 MSP 还是 PSP
返回到 Thread mode 还是 Handler mode
是否存在浮点寄存器栈帧所以看到:
LR = 0xFFFFFFFD不要把它当成普通代码地址。
两个LR不一样

4. 为什么 HardFault 常用汇编先处理?
因为进入 Handler 后,LR 已经变成了 EXC_RETURN。
可以通过:
TST LR, #4判断异常现场使用的是哪个栈:
LR bit2 = 0 → MSP
LR bit2 = 1 → PSP然后:
MRSEQ R0, MSP
MRSNE R0, PSP把对应的异常栈地址传给 C。
5. 整个关系
异常发生
↓
硬件自动压栈
↓
R0 R1 R2 R3 R12 LR PC xPSR
↓
进入 Handler
↓
LR 被设置为 EXC_RETURN
↓
根据 EXC_RETURN 找到异常栈
↓
分析 PC / LR / xPSR这里最容易混淆的是:
异常栈中的 LR
≠
Handler 当前的 LR前者是被中断程序的 LR,后者是EXC_RETURN。
6. 一句话记忆
异常栈里的 PC/LR 属于被中断程序;Handler 里的 LR 是 EXC_RETURN。

