I need to optimize the size of my executable severely (ARM
development) and
I noticed that in my current build scheme (gcc
+ ld
) unuse
From the GCC 4.2.1 manual, section -fwhole-program
:
Assume that the current compilation unit represents whole program being compiled. All public functions and variables with the exception of
main
and those merged by attributeexternally_visible
become static functions and in a affect gets more aggressively optimized by interprocedural optimizers. While this option is equivalent to proper use ofstatic
keyword for programs consisting of single file, in combination with option--combine
this flag can be used to compile most of smaller scale C programs since the functions and variables become local for the whole combined compilation unit, not for the single source file itself.
While not strictly about symbols, if going for size - always compile with -Os
and -s
flags. -Os
optimizes the resulting code for minimum executable size and -s
removes the symbol table and relocation information from the executable.
Sometimes - if small size is desired - playing around with different optimization flags may - or may not - have significance. For example toggling -ffast-math
and/or -fomit-frame-pointer
may at times save you even dozens of bytes.
You'll want to check your docs for your version of gcc & ld:
However for me (OS X gcc 4.0.1) I find these for ld
-dead_strip
Remove functions and data that are unreachable by the entry point or exported symbols.
-dead_strip_dylibs
Remove dylibs that are unreachable by the entry point or exported symbols. That is, suppresses the generation of load command commands for dylibs which supplied no symbols during the link. This option should not be used when linking against a dylib which is required at runtime for some indirect reason such as the dylib has an important initializer.
And this helpful option
-why_live symbol_name
Logs a chain of references to symbol_name. Only applicable with
-dead_strip
. It can help debug why something that you think should be dead strip removed is not removed.
There's also a note in the gcc/g++ man that certain kinds of dead code elimination are only performed if optimization is enabled when compiling.
While these options/conditions may not hold for your compiler, I suggest you look for something similar in your docs.
Programming habits could help too; e.g. add static
to functions that are not accessed outside a specific file; use shorter names for symbols (can help a bit, likely not too much); use const char x[]
where possible; ... this paper, though it talks about dynamic shared objects, can contain suggestions that, if followed, can help to make your final binary output size smaller (if your target is ELF).
strip --strip-unneeded
only operates on the symbol table of your executable. It doesn't actually remove any executable code.
The standard libraries achieve the result you're after by splitting all of their functions into seperate object files, which are combined using ar
. If you then link the resultant archive as a library (ie. give the option -l your_library
to ld) then ld will only include the object files, and therefore the symbols, that are actually used.
You may also find some of the responses to this similar question of use.