| name | linkers-lto |
| description | Linker and Link-Time Optimisation (LTO) skill. Use when configuring GNU ld, gold, or lld linker flags, diagnosing link-order issues or undefined symbols at link time, enabling LTO safely in real projects, or understanding inter-module optimisation trade-offs. Activates on queries about linker flags, -flto, thin LTO, LTCG, --gc-sections, link order errors, weak symbols, or linker scripts. |
Linkers and LTO
Purpose
Guide agents through linker selection, common linker flags, link-order issues, LTO setup, and symbol-visibility management.
Triggers
- "I'm getting
undefined reference at link time"
- "How do I enable LTO for a real project?"
- "Which linker should I use: ld, gold, or lld?"
- "How do I reduce binary size with
--gc-sections?"
- "How do I write or understand a linker script?"
- "I have duplicate symbol or weak symbol issues"
Workflow
1. Linker selection
| Linker | Invocation | Strengths |
|---|
| GNU ld (BFD) | default on Linux | Universal, stable |
| gold | -fuse-ld=gold | Faster than ld for C++; supports LTO plugins |
| lld (LLVM) | -fuse-ld=lld | Fastest, parallel, required for Clang LTO |
gcc -fuse-ld=lld -o prog ...
clang -fuse-ld=lld -o prog ...
gcc -v -o prog main.c 2>&1 | grep 'Invoking'
2. Essential linker flags
gcc main.c -o prog \
-Wl,-rpath,/opt/mylibs/lib \
-Wl,--as-needed \
-Wl,--gc-sections \
-Wl,-z,relro \
-Wl,-z,now \
-L/opt/mylibs/lib -lfoo
3. Link order matters (GNU ld)
GNU ld processes archives left-to-right. A library must come after the objects that need it.
gcc main.o -lfoo libdep.a -o prog
gcc main.o -lfoo -ldep -o prog
gcc main.o -Wl,--start-group -lfoo -lbar -Wl,--end-group -o prog
4. LTO with GCC
gcc -O2 -flto -ffunction-sections -fdata-sections -c foo.c -o foo.o
gcc -O2 -flto -ffunction-sections -fdata-sections -c bar.c -o bar.o
gcc -O2 -flto -Wl,--gc-sections foo.o bar.o -o prog
gcc-ar rcs libfoo.a foo.o
gcc-ranlib libfoo.a
Parallel LTO:
gcc -O2 -flto=auto foo.o bar.o -o prog
gcc -O2 -flto=4 foo.o bar.o -o prog
5. LTO with Clang / lld
clang -O2 -flto -fuse-ld=lld foo.c bar.c -o prog
clang -O2 -flto=thin -fuse-ld=lld foo.c bar.c -o prog
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
ThinLTO caches work: subsequent builds that reuse unchanged modules are faster.
Cache location: specify with -Wl,--thinlto-cache-dir=/tmp/thinlto-cache.
6. Dead-code stripping
gcc -O2 -ffunction-sections -fdata-sections -c foo.c -o foo.o
gcc -Wl,--gc-sections foo.o -o prog
gcc -Wl,--gc-sections -Wl,--print-gc-sections foo.o -o prog 2>&1 | head -20
On macOS, the linker strips dead code by default (-dead_strip).
7. Symbol visibility
Controlling visibility reduces DSO size and enables better LTO:
gcc -fvisibility=hidden -O2 -shared -fPIC foo.c -o libfoo.so
__attribute__((visibility("default"))) int my_public_function(void);
Or use a version script:
# foo.ver
{
global: my_public_function; my_other_public;
local: *;
};
gcc -Wl,--version-script=foo.ver -shared -fPIC -o libfoo.so foo.o
8. Common linker errors
| Error | Cause | Fix |
|---|
undefined reference to 'foo' | Missing library or wrong order | Add -lfoo; move after the object that needs it |
multiple definition of 'foo' | Symbol defined in two TUs | Remove duplicate; use static or extern |
cannot find -lfoo | Library not in search path | Add -L/path/to/lib; install dev package |
relocation truncated | Address overflow in relocation | Use -mcmodel=large; restructure image |
version 'GLIBC_2.33' not found | Binary needs newer glibc | Link statically or rebuild on older host |
circular reference | Archives mutually depend | Use --start-group/--end-group |
9. Linker map file
gcc -Wl,-Map=prog.map -o prog foo.o bar.o
less prog.map
Useful for debugging binary size and symbol placement.
For a comprehensive linker and LTO flags reference, see references/flags.md.
Related skills
- Use
skills/binaries/elf-inspection for examining the resulting binary
- Use
skills/compilers/gcc or skills/compilers/clang for compile-phase LTO flags
- Use
skills/binaries/binutils for ar, strip, objcopy