ARMv7-M架构下PC加载异常及Usage Fault相关技术问询
关于ARM Cortex-M架构中PC加载异常的问题解答
问题1:当指令将格式错误的地址加载到PC时,会发生什么?
首先得明确“格式错误的地址”在ARM Cortex-M架构里的常见场景:
- 地址最低位为0:Cortex-M强制运行在Thumb/Thumb-2指令集模式,PC的最低位用来标记指令集(1=Thumb,0=ARM),加载最低位为0的地址到PC会被判定为无效状态。
- 地址未对齐:比如32位Thumb-2指令要求地址对齐到4字节(最低两位为0),不符合对齐要求的地址会触发对齐错误。
- 地址落在非可执行区域:默认配置下SRAM是不可执行的,把SRAM地址加载到PC后,处理器尝试取指时会触发错误。
针对不同错误类型,处理器的反应略有不同:
- 如果是无效状态(比如最低位为0):会立即触发Usage Fault,处理器暂停当前指令执行,进入故障处理流程,同时自动把故障发生时的上下文(R0-R3、R12、LR、PC、xPSR)压入栈中,方便后续调试。
- 如果是非可执行区域取指:会触发Bus Fault(取指错误类型),同样会进入故障处理流程并保存现场上下文。
- 如果是地址对齐错误:取决于处理器的配置(比如是否启用对齐检查),可能触发Usage Fault或Bus Fault。
简单来说,这类操作几乎都会触发处理器的故障异常,中断正常执行流程,保存现场以便定位问题。
问题2:POP指令返回触发Usage Fault的细节疑问
子问题2.1:POP返回时栈中PC是SRAM地址而非Flash地址
这种情况大概率是栈被破坏了:函数调用时会把返回地址(Flash中的指令地址)压入栈,但如果出现栈溢出、越界写操作(比如数组越界、指针错误),这个返回地址会被覆盖成SRAM的地址。当执行POP {PC}时,处理器把这个SRAM地址加载到PC,随后尝试去SRAM中取指执行——而默认配置下SRAM是不可执行区域,因此触发了故障(可能是Bus Fault,也可能是配置归类后的Usage Fault)。
你看到的“被压入栈中的PC(故障栈帧里的PC)是SRAM地址”,说明这条POP指令已经完成了加载PC的操作,处理器在尝试执行SRAM中的“指令”时触发了故障,此时故障栈帧里的PC就是那个错误的SRAM地址。
子问题2.2:加载PC时地址第0位未置位,故障触发时机
这个场景属于无效状态错误,触发时机是指令执行过程中,而非执行完毕后。具体来说:
当你执行POP {PC}或BX LR这类指令时,如果要加载到PC的地址最低位为0,处理器在尝试更新PC的瞬间就会检测到错误,不会完成这条指令的执行——也就是说,PC不会被设置成那个错误的地址,栈指针也不会完成POP对应的递增操作(如果是POP指令的话)。
此时,故障栈帧中保存的PC值是这条触发故障的指令的下一条指令的地址(也就是如果指令执行成功,本该继续执行的地址),而不是错误的目标地址,也不是触发故障的指令本身的地址。
内容的提问来源于stack exchange,提问作者user299582




