ARM GCC+Cortex-M4:如何强制用BL而非BLX调用地址函数?
我为Cortex-M4 CPU构建了一款小型操作系统,它可通过UART接收编译后的二进制文件并进行动态调度。我希望借助该特性搭建测试套件,让上传的测试程序无需通过SVC即可直接调用内存分配等OS函数。因此我需要将这些OS例程的固定地址转换为函数指针,但转换后调用生成的是BLX而非所需的BL指令,进而引发HardFault。
代码示例:
void (*functionPtr_addr)(void); functionPtr_addr = (void (*)()) (0x0800084C);
调用时生成的汇编代码:
8000838: 4b03 ldr r3, [pc, #12] ; (8000848 <idle+0x14>) 800083a: 681b ldr r3, [r3, #0] 800083c: 4798 blx r3
目前使用内联汇编可以实现需求,但我希望有更简洁的实现方式。编译链接选项包含-mcpu=cortex-m4 -mthumb,工具链版本为gcc version 12.2.0 (Arm GNU Toolchain 12.2.MPACBTI-Bet1 (Build arm-12-mpacbti.16))。请问是否有方法强制使用BL指令?
问题根源
Cortex-M系列仅支持Thumb指令集,但GCC默认会假设函数指针可能指向ARM/Thumb混合模式的代码,因此生成BLX指令(用于切换指令集)。当你直接使用物理地址(最低位为0)赋值给指针时,BLX会尝试切换到ARM模式,而Cortex-M不支持该模式,直接触发HardFault。
方法一:修正函数指针地址(添加Thumb模式标记)
Cortex-M中,Thumb函数的指针需要将最低位设为1(用于指示Thumb模式),只需给目标地址按位或1即可:
void (*functionPtr_addr)(void); functionPtr_addr = (void (*)()) (0x0800084C | 1);
此时GCC会识别这是Thumb函数,调用时要么生成BL指令,要么即使生成BLX,也会正确进入Thumb模式,不会触发异常。
方法二:用属性强制指定函数指针为Thumb模式
通过__attribute__((target("thumb")))修饰函数指针类型,明确告诉编译器该指针指向Thumb函数,无需切换指令集:
typedef void (*thumb_func_t)(void) __attribute__((target("thumb"))); thumb_func_t functionPtr_addr = (thumb_func_t)0x0800084C;
这种方式会让编译器直接生成BL指令调用目标函数,完全符合你的需求。
验证效果
使用上述两种方法后,调用生成的汇编会变为类似:
8000838: 4b03 ldr r3, [pc, #12] 800083a: 681b ldr r3, [r3, #0] 800083c: bl 800084C <target_function>
内容的提问来源于stack exchange,提问作者wolfbiker1

