ARM v7(QEMU树莓派模拟)中断处理:是否需跳回故障指令?
ARM v7异常处理返回地址说明
先直接给结论:返回地址取决于异常类型,不是所有异常都要回到故障指令,分情况明确:
同步异常(未定义指令、软中断、预取中止、数据中止)
这类异常由指令执行直接触发,返回逻辑需按异常类型区分:
- 未定义指令、预取中止:进入异常时,LR已指向故障指令的下一条指令(ARM状态下偏移+4字节)。如果你的处理逻辑是修复故障后重新执行这条指令,给LR减4是合理的;如果不需要重试(比如直接跳过故障指令),则无需调整LR。你代码里这部分的处理是正确的。
- 软中断(SWI):进入异常时,LR已经指向SWI指令的下一条指令——这才是正确的返回地址。你当前代码里给LR减4会导致返回后重复执行SWI指令,直接触发无限循环,必须去掉
sub lr, #4这一行。 - 数据中止:进入异常时,LR指向故障指令的下下条指令(ARM状态下偏移+8字节),这是ARM流水线特性导致的。如果要重新执行故障指令,给LR减8是正确的,你代码里这部分没问题。
异步异常(IRQ、FIQ)
这类异常由外部触发(比如外设中断),触发时当前正在执行的指令已经完成,LR已指向原本要执行的下一条指令,这就是正确的返回地址。你代码里给IRQ的LR减8、FIQ的LR减4都是错误的,会导致回到之前的指令重复执行,直接去掉这些sub lr, #x操作即可。
另外,你用LDMIA sp!, {r0-r12,pc}^完成返回是正确的,这个指令会自动把SPSR的值恢复到CPSR,同时跳转到指定地址,符合ARM异常返回的规范。
修正后的关键代码片段
software_interrupt: ; 移除sub lr, #4,LR已是正确返回地址 stmfd sp!, {r0-r12,lr} mov r0, sp bl software_interrupt_C LDMIA sp!, {r0-r12,pc}^ irq: ; 移除sub lr, #8 stmfd sp!, {r0-r12,lr} mov r0, sp bl irq_C LDMIA sp!, {r0-r12,pc}^ fiq: ; 移除sub lr, #4 stmfd sp!, {r0-r12,lr} mov r0, sp bl fiq_C LDMIA sp!, {r0-r12,pc}^
内容的提问来源于stack exchange,提问作者user25858014
相关产品推荐
相关产品推荐

