从静态可执行文件中剥离未使用的库函数/死代码

Stripping unused library functions / dead code from a static executable

我正在使用 GCC arm-none-eabi-g++ (4.8.3) 为 ARM Cortex-M0 mcu 编译代码。 一切都很好,但我注意到当我包含和使用 cstdlib 中的任何函数时,该文件中的所有函数也被包含在内。如何摆脱它们?

我只调用了 malloc()free(),但是生成的 ELF 也有 system()isatty() 机器码。

MCU 只有 32kB 闪存,所以 ~0.7kB 镇流器很重要,特别是如果其他接头继续发生这种情况。

现在我用-ffunction-sections -fdata-sections编译,-Wl,--gc-sections -Wl,--static链接,如下:

arm-none-eabi-g++ -c --std=c++11 -Os -I. -Ilpc1xxx -Idrivers -Wall -mthumb \
  -ffunction-sections -fdata-sections -fmessage-length=0 -mcpu=cortex-m0 \
  -DTARGET=LPC11xx -fno-builtin -flto -fno-exceptions -o main.o main.cpp
arm-none-eabi-gcc -c --std=c11   -Os -I. -Ilpc1xxx -Idrivers -Wall -mthumb \
  -ffunction-sections -fdata-sections -fmessage-length=0 -mcpu=cortex-m0 \
  -DTARGET=LPC11xx -fno-builtin -flto  -o core_cm0.o lpc1xxx/nxp/core_cm0.c
arm-none-eabi-gcc -nostartfiles -mcpu=cortex-m0 -mthumb -Wl,--gc-sections -flto \
  -Os -Wl,--static -T lpc1xxx/memory.ld -o firmware.elf main.o core_cm0.o  \
  libaeabi-cortexm0/libaeabi-cortexm0.a LPC11xx_handlers.o LPC1xxx_startup.o

编辑:警告:我示例中的 -flto 标志是错误的——它以某种方式丢弃了中断例程。

结果是,当我执行 arm-none-eabi-objdump -t firmware.elf 时,我得到了:

00000fbc g     F .text  0000002c _isatty
00001798 g     F .text  00000018 fclose
00000e4c g     F .text  00000030 _kill
00000e7c g     F .text  00000018 _exit
00000fe8 g     F .text  00000050 _system

这些函数显然是多余的(在 mcu 上根本没用),但 GCC 将它们保留在可执行文件中。没有对它们的调用,这些符号在任何地方都没有被引用。它实际上是死代码。

如何摆脱它们?一些额外的 compiler/linker 标志?


编辑:

重现我的问题的最少代码:

#include <cstdlib>
int main(){
    [[gnu::unused]] volatile void * x = malloc(1);
    return 0;
}

用于编译的命令:

arm-none-eabi-g++ --std=c++11 -Os -Wall -mthumb -ffunction-sections 
  -fdata-sections -fmessage-length=0 -mcpu=cortex-m0 -fno-builtin -flto
  -fno-exceptions -Wl,--static -Wl,--gc-sections -o main.elf main.cpp

并且 main.elf 文件仍然有所有 stdlib 膨胀。


在这里使用 -ffunction-sections 是正确的,但问题是提供 mallocfree 的目标文件是在没有它的情况下构建的(LPC11xx_handlers.oLPC1xxx_startup.olibaeabi-cortexm0.a 中的一些目标文件)。在这种情况下,链接器只能包含包含您需要的函数的整个目标文件(或 -Wl,--gc-sections 整个部分)。

函数在目标文件和节中的布局才是真正重要的,而不是哪个函数与另一个函数定义在同一个头文件中。

因此,要解决您的问题,请使用 -ffunction-sections -fdata-sections 重建您的标准库文件。