Jan K
Jan K

Reputation: 108

Stripping unused library functions / dead code from a static executable

I'm compiling code for an ARM Cortex-M0 mcu with GCC arm-none-eabi-g++ (4.8.3). All is fine, but I noticed that when I include and use any function from cstdlib, all functions from that file are included as well. How to get rid of them?

I'm calling malloc() and free() only, but the resulting ELF has system() and isatty() machine code as well.

The mcu has only 32kB flash, so ~0.7kB ballast matters, especially if this keeps happening for other headers.

Right now I use -ffunction-sections -fdata-sections for compiling and -Wl,--gc-sections -Wl,--static while linking, as follows:

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

Edit: Warning: The -flto flag in my example is wrong – somehow it discards interrupt routines.

The result is that when I do arm-none-eabi-objdump -t firmware.elf, I get among others:

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

These functions are clearly redundant (and quite useless on mcu at all), yet GCC keeps them in the executable. There are no calls to them, these symbols are not referenced anywhere. It's effectively dead code.

How to get rid of them? Some extra compiler/linker flags?


Edit:

Minimal code to reproduce my problem:

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

Command used to compile that:

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

And the main.elf file still has all stdlib bloat.


Upvotes: 3

Views: 2173

Answers (1)

mstorsjo
mstorsjo

Reputation: 13317

Using -ffunction-sections is the right thing here, but the issue is that the object file that provides malloc and free is built without it (either LPC11xx_handlers.o, LPC1xxx_startup.o or some of the object files within libaeabi-cortexm0.a). In that case, the linker can only include the whole object file (or with -Wl,--gc-sections, the whole section) that contain functions you need.

The layout of functions in object files and sections is the only thing that actually matters, not which function is defined in the same header as another function.

So to fix your issue, rebuild your standard library files with -ffunction-sections -fdata-sections.

Upvotes: 3

Related Questions