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

时间:2015-07-09 20:31:12

标签: gcc arm ld compiler-optimization avr-gcc

我正在使用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将它们保存在可执行文件中。没有调用它们,这些符号在任何地方都没有引用。它实际上是死代码。

如何摆脱它们?一些额外的编译器/链接器标志?

修改

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

#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膨胀。

1 个答案:

答案 0 :(得分:2)

在这里使用-ffunction-sections是正确的,但问题是提供mallocfree的对象文件是在没有它的情况下构建的(LPC11xx_handlers.o,{{ 1}}或LPC1xxx_startup.o中的一些目标文件。在这种情况下,链接器只能包含整个目标文件(或libaeabi-cortexm0.a,整个部分),其中包含您需要的功能。

目标文件和部分中的函数布局是唯一真正重要的事情,而不是在与另一个函数相同的头文件中定义哪个函数。

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