异常不适用于 arm cortex m4 的 clang 和 cmake 交叉编译,并生成“got”部分
Posted
技术标签:
【中文标题】异常不适用于 arm cortex m4 的 clang 和 cmake 交叉编译,并生成“got”部分【英文标题】:exceptions not working cross compiling with clang and cmake for arm cortex m4, and "got" section is generated 【发布时间】:2021-12-28 06:23:44 【问题描述】:我最近一直在尝试用 Clang 和 CMake 编译固件,使用工具链文件,用于 C++。我可以让它正常工作,没有例外。当我使用异常时出现问题。
LLVM 版本:13.0.0 CMake 版本:3.21.3 CPU:STM32L432KC,ARM Cortex M4
为了成功编译固件,我使用预编译的libc
、libm
、libgcc
和 libstdc++
与 ARM GNU GCC 工具链,版本 10.3.2021-10 捆绑在一起。
我不会把整个工具链文件放在这里。相信我,CMAKE_C_COMPILER
、CMAKE_CXX_COMPILER
、CMAKE_ASM_COMPILER
和 CMAKE_LINKER
的路径都很好。
CMAKE_CXX_FLAGS_INIT
,定义了 C 语言的初始编译标志,定义如下:
-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16
-nodefaultlibs
--sysroot=$ARM_GNU_TOOLCHAIN_PATH/arm-none-eabi
-flto
-fdata-sections -ffunction-sections
# For <iostream>, <string>, ...
-isystem "$ARM_GNU_TOOLCHAIN_PATH/arm-none-eabi/include/c++/$ARM_GNU_TOOLCHAIN_GCC_VERSION/"
# For <bits/*>, ...
-isystem "$ARM_GNU_TOOLCHAIN_PATH/arm-none-eabi/include/c++/$ARM_GNU_TOOLCHAIN_GCC_VERSION/arm-none-eabi/thumb/v7e-m+fp/hard/"
-fexceptions
ARM_GNU_TOOLCHAIN_PATH
是上述 ARM GNU GCC 工具链的根路径。 ARM_GNU_TOOLCHAIN_GCC_VERSION
等于 10.3.1
。
链接器标志,定义为CMAKE_EXE_LINKER_FLAGS_INIT
:
-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16
-nodefaultlibs
--sysroot=$ARM_GNU_TOOLCHAIN_PATH/arm-none-eabi
-flto
-fdata-sections -ffunction-sections
-Wl,--gc-sections
-flto
-fexceptions
# Path to standard libraries: libc, libm, ...
-L"$ARM_GNU_TOOLCHAIN_PATH/arm-none-eabi/lib/thumb/v7e-m+fp/hard/"
# Path to libgcc
-L"$ARM_GNU_TOOLCHAIN_PATH/lib/gcc/arm-none-eabi/$ARM_GNU_TOOLCHAIN_GCC_VERSION/thumb/v7e-m+fp/hard/"
-lc -lm -lnosys -lstdc++ -lgcc")
如果二进制文件中没有,try ... catch
块。一切都编译得很好,但如果至少有一个块:
try
throw std::runtime_error"Some error!";
catch (const std::exception&e)
printf("Error: %s\r\n", e.what());
链接器在.data
部分之前输入.got
部分,而没有在链接描述文件中得到指示。 RAM 起始地址为 0x20000000。 objdump
输出:
...
Contents of section .got:
20000000 848f0108 ....
Contents of section .data:
20000004 00000000 00000000 08000020 08000020 ........... ...
20000014 10000020 10000020 18000020 18000020 ... ... ... ...
20000024 20000020 20000020 28000020 28000020 .. .. (.. (..
20000034 30000020 30000020 38000020 38000020 0.. 0.. 8.. 8..
...
由 CubeMX 生成的我的链接器脚本有 LMA .data
部分,应该是 RAM 中的第一个部分。:
.fini_array :
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
>FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
>RAM AT> FLASH
正如您在评论中看到的,_sdata
将被启动代码用于在 RAM 中初始化 data
。问题是_sdata
将设置为 0x20000000,而不是第一个全局变量所在的 0x20000008。这意味着所有的全局变量都会有错误的值。
作为一种解决方法,我添加了一个 .got
部分,它使用了所有 got*
输入部分:
...
.fini_array :
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
>FLASH
.got :
. = ALIGN(8);
*(.got)
*(.got*)
. = ALIGN(8);
>RAM AT> FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
...
由于.got
部分与动态符号解析有关,我对它不是很熟悉。我只使用静态库来编译固件,因为我编写了针对每个项目一个二进制文件的裸机程序。
主要问题是异常不能正常工作。在上面的try ... catch ...
块中没有发现异常。固件在Default_Handler
内结束。
我猜这与 clang 生成的 .got
部分有关。 Clang 无法正确链接来自 libgcc
的编译器内置函数以处理异常。
您能帮我调试和修复它吗?
【问题讨论】:
与问题无关,但编译 C++ 代码时可能不应该涉及C_FLAGS
。
@user7860670 你的意思是只用isystem
标志和fexceptions
编译C++?
不,我的意思是在编译 C++ 代码时会忽略 C_FLAGS
,因此更改它们是没有意义的,您应该改用 CXX_FLAGS
。
哦,是的,也许我不够清楚。我将删除提及 C 标志,因为它们在这里无关紧要。
【参考方案1】:
编译时使用-Wl,--target2=rel
标志。
我在 llvm-dev 邮件列表上创建了一个帖子,可以在 here 找到。 Peter Smith 帮助解决了问题并指出了解决方案。
【讨论】:
以上是关于异常不适用于 arm cortex m4 的 clang 和 cmake 交叉编译,并生成“got”部分的主要内容,如果未能解决你的问题,请参考以下文章
ARM Cortex-M3/M4/M7 Hardfault异常分析
东芝推出TXZ+TM族高级系列中用于高速数据处理基于Arm(R) Cortex(R)-M4的新款M4G组微控制器