Some time ago I wrote about using --gc-sections
to avoid unused functions to creep into final code. Today instead I’d like to show how that can be quite a problem if it was used indiscriminately.
I’m still using at least for some projects the diagnostic of --gc-sections
to identify stuff that is unused but still kept around. Today I noticed one bad thing with it and pulseaudio:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.2/../../../../x86_64-pc-linux-gnu/bin/ld: Removing unused section '.data.__padsp_disabled__' in file 'pulseaudio-main.o'
The __padsp_disabled__
symbol is declared in main.c
to avoid pulseaudio’s access to OSS devices to be wrapped around by the padsp
script. When I first have seen this, I thought the problem was a missing #ifdef
directive: if I didn’t ask for the wrapper, it might still have declared the (unused) symbol. That was not the case.
Looking at the code, I found what the problem was: the symbol is (obviously) never used by pulseaudio itself; it is, rather, checked through dlsym()
by the DSP wrapper library. For this reason, for compiler and linker, the symbol looks pretty much unused, and when asking for it to be dropped explicitly, it is. Since the symbol is loaded via the runtime linker, neither building nor executing pulseaudio will have any problem. And indeed, the only problem would be when running pulseaudio as a children of padsp
, and using the OSS output module (so not on most Linux systems).
This shows how just using -fdata-sections -ffunction-sections -Wl,--gc-sections
is not safe at all and why you shouldn’t get excited about GCC and ld optimisations without understanding how they work in detail.
In particular, even I thought that it would be easier to work around than it actually seem to be: while GCC provides a used
attribute that allows to declare a variable (or a function) as used even though the compiler can’t tell that by itself (it’s often used together with inline hand-written ASM the compiler doesn’t check for), this does not propagate to the linker, so it won’t save the section from being emitted. The only solution I can think of is adding one instruction that sets the variable to itself, but that’s probably going to be optimised away. Or giving a way for gcc to explicit that the section is used.
Isn’t that method exported? If it is exported, why is it removed in the first place? I would say that it is never save to remove exported symbols, even when unused in the code base as you can never know who might be calling it. And if it isn’t exported how can it be used at runtime?Just wondering.