g++ arm-none-eabi 从 4.9 升级到 gcc 8.2。生成的二进制文件不再适合闪存

Posted

技术标签:

【中文标题】g++ arm-none-eabi 从 4.9 升级到 gcc 8.2。生成的二进制文件不再适合闪存【英文标题】:g++ arm-none-eabi upgrade from 4.9 to gcc 8.2. Generated binary do not fit any more in flash 【发布时间】:2019-01-04 16:15:12 【问题描述】:

我最近将我的 Linux 笔记本电脑从 Ubuntu 16.04 更新到了 18.04。

我有一个基于 STM32 (Cortex-M4) Makefile 的项目,该项目使用 Ubuntu 提供的 arm-none-eabi g++ 版本正确编译。生成的文件在 .text 部分中需要 47620 字节。

通过 Ubuntu 升级,我还安装了最新版本的 gcc(来自 ARM website)。版本是 8.2.1。

当我编译同一个项目(make clean && make)时,生成的二进制文件不适合闪存(需要 97424 字节,超过两倍!)。项目完全相同(源代码、链接脚本、启动文件、Makefile)。

编译器选项是:-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -DSTM32F303x8 -DARMCM4 -O0 -g -Wall -fexceptions -Wno-deprecated

链接器选项是-mthumb -mcpu=cortex-m4 -Tstm32f303K8.ld -mfloat-abi=hard -mfpu=fpv4-sp-d16 --specs=nosys.specs -lm -Wl,--start-group -lm -Wl,--end-group -Wl,--gc-sections -Lsys -Xlinker -Map=test.elf.map

当我查看 .Map 生成的文件时,所有用户函数的大小大致相同(新版本节省了 8 个字节!)。但之后,它包括 C++ 特定部分,其中一个超过 26Kb(来自映射文件): .text 0x00000000080079e8 0x683c /usr/local/gcc-arm-none-eabi-8-2018-q4-major/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libstdc++.a(cp-demangle.o) 0x000000000800e13c __cxa_demangle

注意:只有 C 项目没有问题,只有 C++。包含的库是相同的(gcc 4.9.3 -> armv7e-m/fpu,和 gcc 8.2.1 -> thumb/v7e-m+fp/hard): libm.a libstdc++.a libc.a libnosys.a libgcc.a

有没有办法摆脱它,以便我可以编译和刷新我的(不太旧的)项目?

问候,

【问题讨论】:

你试过剥离可执行文件吗? 你为什么使用-O0而不是显而易见的-Os 我在第一种方法中没有使用任何优化。然后,我打开它(-O3 -funroll-loops -fomit-frame-pointer -fno-strict-aliasing -pipe -ffast-math -fexceptions)。但是这两个二进制文件是使用相同的标志编译的。 (它也不适合我的 STM32 优化...... @user3582893 如果您想回复特定用户,请使用@user 以便通知他们。此外,-O3 -funroll-loops 可能会显着恶化代码大小。我推荐-Os 感谢 Mathieu 的提示。我刚试过-Wl,--strip-all,但它不适合:arm-none-eabi-g++ -o test.elf build/main.o build/mcp23s17.o build/Print.o build/Adafruit_GFX.o build/Adafruit_SPITFT.o build/Adafruit_ST7735.o build/Adafruit_ST77xx.o build/spi.o build/timer.o build/button.o build/adc.o build/codeur.o build/startup_ARMCM4.o build/startup_clock.o -mthumb -mcpu=cortex-m4 -Tstm32f303K8.ld -mfloat-abi=hard -mfpu=fpv4-sp-d16 --specs=nosys.specs -lm -Wl,--start-group -lm -Wl,--end-group -Wl,--gc-sections -Wl,--strip-all -Lsys -Xlinker -Map=test.elf.map 【参考方案1】:

我找到了使用libstdc++_nano(而不是隐式 libstc++)的解决方案。这样,代码大小从 84kb 减少到 26kb!

LDFLAGS += -lstdc++_nano

它只是工作。感谢@Henrik、@Matthieu 和@EOF 的支持!

【讨论】:

【参考方案2】:

它可能与异常处理有关,因为与异常一起使用的 std::terminate() 可能会调用解组例程。如果您不需要异常,请尝试使用-fno-exceptions 禁用它们,如here 所述。

另一种解决方案可能是查看 GCC headers:

拆解例程。 C++ 运行时库中 ABI 强制的入口点,用于解组。 [...] 返回一个指向以 NUL 结尾的 demangled 开头的指针 名称,或 NULL 如果拆解失败。来电者是 负责使用 free 释放此内存。

原型是:

  char*
  __cxa_demangle(const char* __mangled_name, char* __output_buffer,
         size_t* __length, int* __status);
因此,您可能只提供自己的返回 NULL 的虚拟函数(假设所有库函数都很弱,并且可以被覆盖)。不过,我建议您先查看反汇编代码,并首先找出调用它的方式和原因,因为它可能会改变行为以丢弃功能)。

他们还在This forum post 中提供其他建议,这也可能对您有用:

使用-Os 而不是-O0 优化大小(如果您更喜欢易于调试的代码,则可以添加-Og 选项,它通常比-O0 更小更快)。 在编译和链接时使用-flto 在链接时进行优化。 如果不使用,可能会禁用 RTTI。

【讨论】:

谢谢亨利克。我尝试使用 -Os、-fno-exceptions、-flto 和 -fno-rtti。代码显着减少。但是,它还不适合我的 MCU(减少了 14kb,但仍有 19kb 需要删除以适合闪存:/) 好的@user3582893 我想你应该再看看列表。可能已经添加了一些其他库函数。 尝试寻找 malloc 或类似的。你能以某种方式得到一堆吗?

以上是关于g++ arm-none-eabi 从 4.9 升级到 gcc 8.2。生成的二进制文件不再适合闪存的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式在 g++ 4.9 下匹配,但在 g++-5.3.1 下失败

(原)ubuntu14.04中安装gcc4.9和g++4.9

如何设置gcc5.0与gcc4.9的优先级

用arm-none-eabi进行交叉编译

arm gcc 工具链作为 arm-elf 或 arm-none-eabi,有啥区别?

arm-none-eabi 和 arm-linux-gnueabi 之间的区别?