How to Remove Unused C/C++ Symbols With Gcc and Ld

How to remove unused C/C++ symbols with GCC and ld?

For GCC, this is accomplished in two stages:

First compile the data but tell the compiler to separate the code into separate sections within the translation unit. This will be done for functions, classes, and external variables by using the following two compiler flags:

-fdata-sections -ffunction-sections

Link the translation units together using the linker optimization flag (this causes the linker to discard unreferenced sections):

-Wl,--gc-sections

So if you had one file called test.cpp that had two functions declared in it, but one of them was unused, you could omit the unused one with the following command to gcc(g++):

gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections

(Note that -Os is an additional compiler flag that tells GCC to optimize for size)

discard unused functions in GCC

Yes, this is possible. To do this, add the following two flags when compiling your C source code to objects:

 -ffunction-sections -fdata-sections

This will generate bigger object files, but will add a lot of information for the linker.
When calling the linker add the following flag:

--gc-sections

The linker will now throw away all functions and sections that are not used. Note that this might incur a performance penalty:

Only use these options when there are significant benefits from doing
so. When you specify these options, the assembler and linker create
larger object and executable files and are also slower. These options
affect code generation. They prevent
optimizations by the compiler and assembler using relative locations inside a translation unit since the locations are unknown
until link time. An example of such an optimization is relaxing calls
to short call instructions.
(man gcc)

See also this question: Query on -ffunction-section & -fdata-sections options of gcc for more information.

When and why would the C linker exclude unused symbols?

It's mostly correct with the caveat that static-library linking doesn't really have per-symbol granularity. It has per-member-object-file granularity.

Example:

If the static library contains files:

a.o 
foo
bar
b.o
baz

and an undefined reference to foo needs to be resolved, a.o will be brought in, and with it the bar symbol as well.

You can get the effect of per symbol granularity when you compile with -ffunction-sections -fdata-sections and then link with -Wl,--gc-sections (gc stands for garbage-collect), but bear in mind that the compiler/linker options are gcc/clang-specific and that they have some minor performance/code-size cost.

-ffunction-sections puts each function in its own section (sort of like its own object file) and -fdata-sections does the same thing for externally visible global variables. -Wl,--gc-sections then causes a garbage collector to run after the object files are linked as usual, and the garbage collector removes all sections (=>symbols) that are unreachable.

(-ffunction-sections is also useful if you want size -A the_objectfile.o to give you function sizes and if you also want those functions sizes to
not slightly fluctuate based on the position of the functions (due to alignment requirements).)

gcc/ld: Allow Code Placement And Removal of Unused Functions

The compiler is just doing what it's told; you asked it to put that function in that section, so what else should it do?

The linker then sees all the functions in one section, and so garbage collection is not very helpful.

I've not tried this, but I would imagine that simply assigning different manual names to each function will solve the problem:

void CalledFunc(void) __attribute__ ((section (".text.myregion.CalledFunc")))
{
/* ... */
}
void UncalledFunc(void) __attribute__ ((section (".text.myregion.UncalledFunc")))
{
/* ... */
}

However, if that's a lot of typing (or if you use a macro to apply the attribute), then it might be better like this:

#define STRINGIFY(S) #S
#define TOSTRING(S) STRINGIFY(S)
#define NAME __FILE__ "." TOSTRING(__LINE__)
void CalledFunc(void) __attribute__ ((section (".text.myregion." NAME)))
{
/* ... */
}

That way you can do it with search-and-replace and still have each function have a unique section name. (It is necessary to use the macro because __LINE__ is an integer value, but we need a string here, and the # "stringify" operator is only available inside macros. The apparently pointless levels of indirection cause __LINE__ to be evaluated into the actual line number.)

It might be that the __FUNCTION__ macro works, but I'm not confident given that this is outside the function body.

How to remove *ALL* unused symbols from a shared library?

Compile with the flag -ffunction-sections. Then link with -Wl,--gc-sections. I think that this can also be achieved with LTO, I'm not sure of the details.

Note that all public symbols in a dylib are considered live. Only hidden symbols will be stripped this way.



Related Topics



Leave a reply



Submit