This Time Self-Hosted
dark mode light mode Search

How to avoid unused functions to creep into final binaries

I already wrote about using ld --gc-sections to identify unused code but I didn’t go much into the details on how to use that knowledge to avoid unused code to creep into your binaries.

Of course this is one possible solution, I’m sure there are more solution to this, but I find this pretty nice and easy to deal with. It relies a bit on the linker being smart enough to kill unused units, but if the linker you’re using can’t even get to this point, I’d sincerely suggest looking for a better one. GNU ld need to be told to make the right optimisation, but should work fine afterward.

Also this trick relies on hiding the internal symbols, so either you have updated your package to properly use visibility, or you could look into linker scripts and similar tools.

The trick is actually easy. Take as an example a software like xine-ui (where I’m applying this trick as I write), that has some optional feature. One of this is, for instance, the download of skins from the server; it’s an optional feature, and it defines its set of functions that are used only if the feature is enabled.

Up till I a few days ago, these functions were always built, as just the initialisation one was removed by #ifdef. As most of them were static, luckily they would have been optimised out by the compiler already. Unfortunately this is not always reliable, so some of them were still built.

What I did was actually simple, I took the functions used to download the data and moved all of them on their own unit. When the support for downloadable skins is disabled, the whole file is not built, and the functions will not be defined. On the two places where the two entrypoints of that code, I used #ifdef.

Up to now there is nothing really important about unused functions. As I said, the functions were mostly static, so most of them would have been removed already, with the exclusion of the two entrypoints, and one more function that was called by the closing entrypoint.

The unused functions start to appear now. There are two functions inside the “xine toolkit” (don’t get me started with that, please) that are used just by the skin downloader dialog. If the skin downloader support is not built, they become unused. How to solve this? Adding an #ifdef inside the xitk code for a feature of xine-ui proper is not a good design, so what?

It just requires to know that xitk is built as an archive library (static library, .a), and that even without any further option, ld does not link objects found in archives if there is no symbol needed from them. Move the two functions out on their own file, they will not be requested if the skin downloader is not used, so they won’t be linked in the final file. 1KB of code gone.

When you’re not linking through an archive file, though, you need to do something more: add --gc-sections. Don’t add other flags like -ffunction-section and -fdata-section, they’ll create too much overhead; without those the sections will be split per-file, and then collapsed altogether; that will allow you to discard the unused units’ data even if you’re linking the object file explicitly.

The problem is usually that you find yourself with a huge amount of files this way; but this is not necessarily a bad thing, if you don’t overdesign stuff like xine-ui, where almost all the source units for X11 frontend re-declare the gGui global pointer explicitly, rather than leaving that in the common include file…

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.