5

I'm trying to reduce the size of my elf executable. I'm compiling with -ffunction-sections -fdata-sections and linking with -gc-sections, but it appears some of the symbols that I believe are unused are not being discarded.

Is there some command in the GNU toolchain I can run to find out which symbols are being used and where?

  • Toolchain: GNU arm-none-eabi
  • Platform: Cortex-M4
  • Language: C++

Here are my typical build flags:

Compilation: arm-none-eabi-g++.exe -Wall -O3 -mthumb -std=c++11 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -fsingle-precision-constant -ffunction-sections -fdata-sections

Link: arm-none-eabi-g++.exe -static -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -Wl,-gc-sections -Wl,-T"LinkerScript.ld

Thanks for the help.

Verax
  • 1,959
  • 3
  • 22
  • 38

3 Answers3

5

I wasn't able to find a command that showed the symbol dependencies. However, I was able to get the information I needed by using the following technique:

  • Add the symbol in question to the /DISCARD/ section of the linker script. This will output an error message revealing which symbol is using it. It looks something like this: <symbol0>' referenced in section '<symbol1>' of <lib0.a file path>(<object0 file path>): defined in discarded section '<symbol0>' of <lib1.a file path>(object1 file path>)
  • Continue to add symbols from these messages up the call stack to the /DISCARD/ section until you find the root of the problem.

The root of the problem for me was having a class that inherited from another. This created a virtual table, and the compiler cannot remove dead code that is referenced in a virtual table.

Lesson learned: if you want to reduce code size and still use C++, don't use inheritance. The GNU toolchain used to have a -fvtable-gc switch to help with this, but it was removed some time ago. I will refactor my code to address my specific problem.

Verax
  • 1,959
  • 3
  • 22
  • 38
  • Hi @Verax, your approach looks very promising. I have problems applying it how does this section definition have to look like? – Torsten Robitzki Jul 24 '15 at 08:51
  • 1
    @TorstenRobitzki Example: `/DISCARD/ : { *(.ARM.extab*) *(.ARM.exidx*) }` – Verax Nov 18 '15 at 22:27
  • Use `--verbose` or `-Wl,--verbose` in order to retrieve the default linker script, use it with `-T` and add your `/DISCARD/` directive on top, otherwise it may not work. – NorbertM May 23 '19 at 23:15
5

You can try the linker option -Wl,--trace-symbol=<symbol_name>. It will display in the output where the symbol is defined, and where the symbol is used.

sdive
  • 1,747
  • 1
  • 18
  • 19
4

Create a linker map file with cross-reference output:

-Wl,-Map=output.map -Wl,--cref

Clifford
  • 76,825
  • 12
  • 79
  • 145
  • Thanks, this is helpful, but doesn't quite give me what I was expecting. It cross-references symbols to object files, but doesn't give me an actual symbol-to-symbol cross-reference. I'm trying to figure out why some of my functions are not discarded when there is no hope of them ever being called. Any suggestions? – Verax Jul 10 '14 at 05:23
  • 1
    Linkers vary, but I think that is as good as it gets in GNU ld. If an unused function is defined in an object module that includes symbols that are used, the entire object module is necessarily linked. Some linkers can use cross-module optimisation to remove unused code from object modules - I am not sure about the GNU linker. – Clifford Jul 10 '14 at 08:39
  • As suggested on the linked thread, have you tried `-dead-strip` and `-why-live=*name*` ? – M.M Jul 11 '14 at 01:41
  • @MattMcNabb I checked for those, and they don't exist in my toolchain. They are Mac-only features. – Verax Jul 11 '14 at 09:18