G ++不使用-O0编译我的源代码,但使用-O2 -DNDEBUG编译,我该如何解决?

时间:2012-01-12 09:02:52

标签: c++ compiler-construction embedded arm

我正在为ARM微控制器编写固件。我已经构建了没有系统调用的交叉编译器,实际上我的RTOS(ChibiOS)提供了一个简单的系统调用实现。

我的所有代码都是用C语言编写的,除了我只使用C ++链接Eigen库(线性代数的C ++模板库,它只是标题)。

如果我使用-O2 -DNDEBUG编译我的源代码示例代码(据我所知,使用NDEBUG代码将不需要assert()),所有内容编译都很好并且固件可以工作。

如果我用-O0编译源代码示例代码,我有以下内容:

Linking build/ch.elf
/home/noether/workspace/tool-chains/arm-none-eabi-4.6.2/lib/gcc/arm-none-eabi/4.6.2    /../../../../arm-none-eabi/lib/thumb/cortex-m4/libc.a(lib_a-abort.o): In function `abort':
/home/noether/workspace/tool-chains/summon-arm-toolchain/build/arm-none-eabi/thumb /cortex-m4/newlib/libc/stdlib/../../../../../../../gcc-4.6.2/newlib/libc/stdlib  /abort.c:63: undefined reference to `_exit'
/home/noether/workspace/tool-chains/arm-none-eabi-4.6.2/lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib/thumb/cortex-m4/libc.a(lib_a-signalr.o): In function `_kill_r':
/home/noether/workspace/tool-chains/summon-arm-toolchain/build/arm-none-eabi/thumb/cortex-m4/newlib/libc/reent/../../../../../../../gcc-4.6.2/newlib/libc/reent/signalr.c:61: undefined reference to `_kill'
/home/noether/workspace/tool-chains/arm-none-eabi-4.6.2/lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib/thumb/cortex-m4/libc.a(lib_a-signalr.o): In function `_getpid_r':
/home/noether/workspace/tool-chains/summon-arm-toolchain/build/arm-none-eabi/thumb/cortex-m4/newlib/libc/reent/../../../../../../../gcc-4.6.2/newlib/libc/reent/signalr.c:96: undefined reference to `_getpid'
collect2: ld returned 1 exit status
make: *** [build/ch.elf] Error 1

如果我放-DNDEBUG并不重要,我有相同的输出。 我也在使用这些标志,-fno-exceptions和fno-rtti。 如果我不使用/链接Eigen库(唯一的C ++东西),g ++甚至可以使用-O0编译源代码。

实际上,我实现了一个简单的_kill _getpid和_exit函数,代码编译,但代码从13KB到130KB,它崩溃了(也许我没写好这些函数)。

我想要的是从我的代码中删除这些东西(中止等),如果我使用-O0,因为它(我猜)用-O2完成。

非常感谢你。如果您需要更多信息,请与我们联系。

2 个答案:

答案 0 :(得分:5)

这些引用几乎肯定是由于使用assert();这将在失败时调用abort(),这反过来会尝试发出一个信号(使用此实现中的kill()系统调用)来中止该过程。显然,如果你不能进行系统调用,这是不可能的。

使用-DNDEBUG构建(就像在优化版中一样)将解决此问题;它导致assert()宏不生成代码,因此不会引用abort()。优化级别本身不应该有任何区别。

或者,如果要保留断言,可以实现自己的assert()宏,不需要任何系统调用。

答案 1 :(得分:1)

您可以简单地为缺少的系统调用实现存根,并将它们链接到您的代码。这将保持链接器安静,但您可能会使存根做一些明智或有用的事情。 exit()可能会禁用中断并无限循环或强制重置。 _kill()可能会挂钩到你的RTOS来终止一个线程,或者只是调用_exit(),而_getpid()可能会返回一些虚拟值或一个RTOS线程ID。