Clang+CMake交叉编译ARM Cortex M4固件启用C++异常失效且生成.got段问题
修复方案
1. 消除不必要的GOT段
你遇到的GOT段自动插入问题,本质是Clang默认启用了位置无关代码(PIC)生成,静态链接的裸机固件完全不需要该特性。在CMAKE_CXX_FLAGS_INIT和CMAKE_EXE_LINKER_FLAGS_INIT中添加以下编译参数,即可彻底关闭PIC相关逻辑,不再生成GOT段:
-fno-pic -fno-pie -fno-plt
添加后不需要再手动修改链接脚本插入.got段配置,也不会再出现全局变量地址偏移错误的问题。
2. 匹配异常处理模型
Clang针对ARM Cortex-M裸机目标,需要显式指定与GCC libgcc兼容的异常处理和调用约定,在CMAKE_CXX_FLAGS_INIT中补充以下参数:
-funwind-tables -fasynchronous-unwind-tables -mabi=aapcs
上述参数会强制Clang生成符合ARM AAPCS标准的调用栈,以及GCC libgcc可识别的unwind栈信息,用于异常抛出后的栈展开。
3. 调整链接库顺序
链接器按照从左到右的顺序解析符号依赖,你当前的链接库顺序不符合C++异常处理的依赖关系,将CMAKE_EXE_LINKER_FLAGS_INIT最后的库参数调整为:
-lstdc++ -lgcc -lc -lm -lnosys -lgcc
调整逻辑是:libstdc++的异常实现依赖libgcc的unwind功能,libc依赖libgcc的内置函数,末尾重复添加-lgcc用于解决libgcc和libc之间的循环依赖问题。
4. 兼容性排查
如果完成上述配置后异常仍然无法捕获,按以下步骤排查:
- 临时删除编译和链接参数中的
-flto选项测试,LLVM 13的LTO实现与GCC 10的libgcc存在已知的unwind符号兼容问题,关闭LTO后如果异常正常工作,可升级LLVM到15及以上版本,或添加LTO参数-Wl,-plugin-opt=-emulated-tls解决兼容问题。 - 使用
arm-none-eabi-readelf -u 编译生成的elf文件命令验证unwind段是否正常生成,如果没有输出unwind信息,回到第二步确认编译参数是否正确添加。 - 在HardFault_Handler中添加断点,查看故障触发时的调用栈,确认是否是
__cxa_throw函数执行过程中触发的异常,如果是则检查链接的libgcc是否是对应Cortex-M4硬浮点版本的库。
内容的提问来源于stack exchange,提问作者K. Koovalsky
相关产品推荐
相关产品推荐

