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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:01:19