Embedded Code Space Optimization
These days we rarely have to worry about the amount of code space we are using. It’s all demand loaded, unused code never gets loaded, and disk space is cheap. However, back when I started writing embedded code, back when photosynthesis was still a recent innovation looked on with skepticism by the establishment, every byte that went into your EPROM had to be accounted for; your CPU may have had 64KB of address space, but no-one made EPROMs that big, and even if they did you couldn’t afford them anyway.
When processing a static library .a file, the C linker only uses object .o files from within the library .a file that actually define symbols referenced by the program. So, when implementing a static library of code, to be used in an embedded program, it was important that the user of the library only linked code from the library that was actually used, and didn’t link in any library code that wasn’t used.
The problem comes when you are implementing a bunch of related functions, such as the <string.h> portion of the Standard C Library. If an object .o file contained definitions of both the memcpy and memmove functions, but the program only used the memcpy function, unused code (memmove) would also be included. There are two traditional ways to avoid this wasted code space.
1. The first is to sprinkle the library source code with #ifdef directives used to select which pieces of the library to omit or include. This pretty much defeats the point of having a library, making it project specific. You may as well just include the source code in your project instead. It’s also tedious when you decide to use another function already in the library, you have to find and fix the necessary #ifdef. And when you stop using one, you have to remember to turn off the #ifdef.
2. The second way is to put every (non-static) function definition and variable definition in its own source .c file, and then in its own object .o file, within the library .a file. The linker will then, without change, only pull in library functions and global variables from the library .a file that the program actually uses.
This tends to make the compilation of the library slower, because there are so many invocations of the C compiler for very small C functions. This cost is amortized over the much larger number of times the library .a file is linked to, compared to the cost of compiling it once.
3. Times have changed, and photosynthesis is pretty well established in the ecosystem. The GNU C compiler now provides a third way, if you are using the ELF object file format, and a modern-ish version of gcc. There are two compiler options and a linker option you need to understand.
The gcc -ffunction-sections and -fdata-sections options place each function or data item into its own section in the output file if the target supports arbitrary sections, as ELF format object files do. The name of the function or the name of the data item determines the section’s name in the object .o file. The GNU ld –gc-sections option (or gcc -Wl,–gc-sections from the gcc command line) is used to ignore sections in object .o files if they are not referenced by the program. The result of combining these two options means that, effectively, if you were to implement all of <string.h> in a single source file, only the functions actually used will appear in the final executable.
These features were introduced in gcc and binutils in 1999. And, yes, some Windows compilers and linkers had functionally equivalent features 15 years earlier.
Most recently, I came across this using an Arduino board, but any embedded SoC (MIPS, ARM, AVR, etc) will benefit. This also helps when C++ code generates numerous functions, especially with templates, and not all of them are actually used.

