Limit GCC Link-Time Optimization Memory and Link Time in Cross-Compilation
Control GCC LTO memory and link time during cross-compilation by limiting LTO jobs and using the linker plugin, then verify with size and timing checks.
10 Oct 2026, 17:57 UTC

Problem: Link-Time Optimization Can Exhaust Builder Memory
GCC Link-Time Optimization (LTO) defers optimization until link time by embedding GIMPLE intermediate representation in object files. While this enables whole-program inlining and dead-code elimination, the link stage can consume several times the memory of a normal link and run for many minutes. On memory-constrained cross-compilation servers or embedded build agents, this often triggers out-of-memory kills or CI timeouts.
Prerequisites
- GCC 7 or later for fine-grained LTO job control (
-flto=n); GCC 4.5+ for basic-flto - The same GCC version used for every compilation and link step in the build
- GNU gold or LLVM lld linker if using
-fuse-linker-plugin - A build directory you can write to; normal user permissions are sufficient
Procedure: Bound LTO Resource Use
Run these commands on the build host in your cross-compilation shell. Replace arm-linux-gnueabihf-gcc with your actual target toolchain prefix, and main.o util.o with your object files.
1. Confirm the compiler version
arm-linux-gnueabihf-gcc --version | head -n 1
All objects and the final link must use this exact GCC release. Mixing versions produces incompatible GIMPLE sections and link errors.
2. Compile objects with LTO enabled
arm-linux-gnueabihf-gcc -flto -O2 -c main.c util.c
-flto tells GCC to write GIMPLE into the object file instead of only final machine code. -O2 sets the optimization level applied during the later LTO phase.
3. Link with a bounded number of LTO jobs
arm-linux-gnueabihf-gcc -flto=4 -O2 main.o util.o -o my_program
-flto=4 limits the link-time optimization stage to four parallel jobs. Use -flto=auto to let GCC base the count on available cores, or a fixed number such as -flto=2 on small builders. This does not limit compilation parallelism; it only throttles the LTO link step.
4. Optional: use the linker plugin
arm-linux-gnueabihf-gcc -flto=4 -fuse-linker-plugin -O2 main.o util.o -o my_program
-fuse-linker-plugin requires gold or lld and lets the linker read LTO sections directly, which can reduce memory and link time compared with the classic LTO object-file merge. If your target uses the default bfd linker, omit this flag.
Expected Checks
Verify LTO is active
arm-linux-gnueabihf-gcc -Q --help=optimizers | grep -i lto
Look for optimization names containing lto in the output. If nothing appears, the compiler may not support LTO or the flag was rejected.
Compare binary size and link time
# Non-LTO build for reference
arm-linux-gnueabihf-gcc -O2 -c main.c util.c
arm-linux-gnueabihf-gcc -O2 main.o util.o -o my_program_normal
time arm-linux-gnueabihf-gcc -O2 main.o util.o -o my_program_normal
# LTO build
arm-linux-gnueabihf-gcc -flto=4 -O2 -c main.c util.c
time arm-linux-gnueabihf-gcc -flto=4 -O2 main.o util.o -o my_program_lto
size my_program_normal my_program_lto
Run time in the build shell to capture wall-clock link duration. Run size to compare text, data, and bss sections. A smaller text section often indicates successful dead-code elimination or cross-module inlining.
Inspect object files for LTO sections
readelf -S main.o | grep -i lto
If LTO sections appear, the object contains GIMPLE. If the command returns nothing, recompile with -flto.
Risks and Limitations
- Mixed toolchain versions break LTO: Rebuild every object with the same GCC version if you see GIMPLE version mismatch errors.
- Memory still spikes: Even with
-flto=n, large programs can exhaust RAM during the LTO phase. Reducenor add swap if the linker is killed. - Debugging is harder: Functions may be inlined across files, so stack traces and variable inspection can be misleading. Keep a non-LTO build for debugging.
- Static libraries compiled without LTO do not participate in whole-program optimization. Rebuild archives with
gcc-ar -fltoor compile their objects with-fltobefore archiving. - Linker scripts may need adjustment: Plugin-based LTO can change symbol visibility or section layout; test with your target's linker script before releasing.
Practical Verification and Recovery
If the LTO binary is larger or slower than expected, or if linking fails with memory errors, revert to the non-LTO build by removing -flto and -fuse-linker-plugin from your compile and link commands. Rebuild all objects cleanly to avoid mixing LTO and non-LTO object files in the same binary.
Confirm the final artifact runs on the target hardware or emulator before deploying. LTO changes code layout, so timing-sensitive or position-dependent code should be retested after enabling optimization.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.