You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cortex-M0+平台GCC内联汇编BX跳转MYJUMP异常问题排查

问题:Cortex-M0+平台内联汇编BX跳转触发DefaultHandler异常

在Cortex-M0+平台开发中,需要保留MYCODE代码段用于后续跳转,通过全局变量x=false配合if(x) goto MYCODE的伪逻辑防止GCC优化移除该段代码。使用C语言goto MYJUMP跳转可正常执行,但采用内联汇编__asm volatile("BX %0" : : "r" (&&MYJUMP) : );跳转时,程序触发DefaultHandler崩溃。

生成的汇编显示BX指令已正确跳转到MYJUMP对应的地址0800286c(该地址为nop指令),但执行该nop后触发异常。


相关代码

bool x = false; // 全局定义

if (x) goto MYCODE; // 防止MYCODE被移除

//goto MYJUMP; // 此方式正常
__asm volatile("BX %0" : : "r" (&&MYJUMP) : ); // 此处崩溃!!!

MYCODE:

__asm volatile ("nop");
__asm volatile ("nop");
__asm volatile ("nop");

MYJUMP:
__asm volatile ("nop"); // 第一个NOP会崩溃!!!
__asm volatile ("nop");
__asm volatile ("nop");

生成的汇编代码

96           __asm volatile("BX %0" : : "r" (&&MYJUMP) : );
0800285e:   ldr     r3, [pc, #96]  
08002860:   bx      r3                    // 目标地址为0800286c

执行时的汇编代码

08002864:   nop     ; (mov r8, r8)
100         __asm volatile ("nop");
08002866:   nop     ; (mov r8, r8)
101         __asm volatile ("nop");
08002868:   nop     ; (mov r8, r8)
102         __asm volatile ("nop");
0800286a:   nop     ; (mov r8, r8)
105         __asm volatile ("nop");
0800286c:   nop     ; (mov r8, r8)       // 代码正常到达此处
106         __asm volatile ("nop");      // 执行此NOP时跳转到DefaultHandler
0800286e:   nop     ; (mov r8, r8)
107         __asm volatile ("nop");
08002870:   nop     ; (mov r8, r8)  

问题根源及解决方案

根源分析

Cortex-M0+是Thumb-only架构,所有指令必须在Thumb模式下执行。BX指令的最低位(LSB)用于控制模式切换:

  • LSB=1:切换到Thumb模式
  • LSB=0:切换到ARM模式(Cortex-M0+不支持ARM模式,触发异常)

GCC中&&MYJUMP获取的是标签的绝对地址,该地址的LSB为0(因为Thumb指令地址对齐到2字节,地址是偶数)。当BX指令跳转到这个地址时,会尝试切换到ARM模式,而Cortex-M0+不支持该模式,因此触发DefaultHandler异常。

而C语言的goto语句会自动处理Thumb模式的地址,生成的跳转指令会确保目标地址的LSB被置1,从而维持Thumb模式执行。

解决方案

  1. 手动置位地址最低位:在传递给BX的地址中强制设置LSB为1,告诉CPU保持Thumb模式:
    __asm volatile("BX %0" : : "r" ((uint32_t)&&MYJUMP | 1) : );
    
  2. 使用BLX指令或直接Thumb跳转指令:使用B指令配合"p"约束,让GCC自动处理Thumb地址的LSB置位:
    __asm volatile("B %0" : : "p" (MYJUMP) : );
    
  3. 更高效的代码段保留方式:用__attribute__((used))标记代码段,替代if(x) goto的伪逻辑,直接防止MYCODE被优化移除:
    void __attribute__((used)) my_code_section(void) {
        __asm volatile ("nop");
        __asm volatile ("nop");
        __asm volatile ("nop");
    MYJUMP:
        __asm volatile ("nop");
        __asm volatile ("nop");
        __asm volatile ("nop");
    }
    

内容的提问来源于stack exchange,提问作者yo3hcv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:35:24