从静态可执行文件中剥离未使用的库函数/死代码
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
是正确的,但问题是提供 malloc
和 free
的目标文件是在没有它的情况下构建的(LPC11xx_handlers.o
, LPC1xxx_startup.o
或 libaeabi-cortexm0.a
中的一些目标文件)。在这种情况下,链接器只能包含包含您需要的函数的整个目标文件(或 -Wl,--gc-sections
整个部分)。
函数在目标文件和节中的布局才是真正重要的,而不是哪个函数与另一个函数定义在同一个头文件中。
因此,要解决您的问题,请使用 -ffunction-sections -fdata-sections
重建您的标准库文件。
我正在使用 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
是正确的,但问题是提供 malloc
和 free
的目标文件是在没有它的情况下构建的(LPC11xx_handlers.o
, LPC1xxx_startup.o
或 libaeabi-cortexm0.a
中的一些目标文件)。在这种情况下,链接器只能包含包含您需要的函数的整个目标文件(或 -Wl,--gc-sections
整个部分)。
函数在目标文件和节中的布局才是真正重要的,而不是哪个函数与另一个函数定义在同一个头文件中。
因此,要解决您的问题,请使用 -ffunction-sections -fdata-sections
重建您的标准库文件。