A variant of the modern kernel built with Clang ThinLTO on top of everything from Phase 2 (kCFI, hardening, modern features).
Link-Time Optimization lets the compiler optimize across translation-unit
boundaries — inlining, devirtualization and dead-code elimination that a
per-file compile can't see, because at -c time each .o is compiled blind to
the others. ThinLTO does this with a lightweight per-module summary instead
of merging the whole program into one giant module (Full LTO), so it links far
faster and uses far less memory while keeping most of the benefit. On the kernel
it also tightens kCFI (CFI + LTO let the compiler prove more call targets).
Start from the exact modern .config, then:
cp build-modern/.config build-modern-lto/.config
scripts/config --file build-modern-lto/.config \
-e LTO_CLANG_THIN \ # Clang ThinLTO
-d DEBUG_INFO_BTF \ # drop BTF...
-e DEBUG_INFO_NONE \ # ...and DWARF, to bound the LTO link's memory
--set-str LOCALVERSION "-modern-lto"
make LLVM=1 O=build-modern-lto olddefconfig
make LLVM=1 O=build-modern-lto -j$(nproc) bzImageWhy drop BTF/debug-info for the LTO build? ThinLTO defers code generation to
link time and holds the bitcode for the whole vmlinux in memory at once; piling
full DWARF5 + a BTF pahole pass on top of that is what pushes a 15 GiB box toward
swap. Dropping debug info kept the peak RSS at ~6 GiB (vs. 7.7 GiB for the
non-LTO modern build with BTF). The main modern kernel keeps BTF; this LTO
variant trades it for a comfortable link. ThinLTO requires lld (we use
LLVM=1), which x86-64 supports (ARCH_SUPPORTS_LTO_CLANG_THIN).
| Metric | Modern (Phase 2) | Modern + ThinLTO (Phase 5) |
|---|---|---|
CONFIG_LTO_CLANG_THIN |
off | y |
CONFIG_CFI (kCFI) |
y | y |
| Debug info / BTF | DWARF5 + BTF | none (dropped for the link) |
| Build time | 18 m 55 s | 21 m 25 s |
| Peak build RAM | 7.7 GiB | 6.0 GiB |
bzImage |
20 MB | 18 MB |
| Boots in QEMU | ✅ | ✅ rc=0 |
Linux version 7.1.0-modern-lto … clang 18.1.3 … LLD 18.1.3 … #1 SMP PREEMPT_DYNAMIC
SMP alternatives: CFI: Using rehashed retpoline kCFI <-- kCFI still live under LTO
landlock: Up and running.
Run /init as init process
reboot: Power down <-- clean poweroff
The ThinLTO + kCFI kernel boots cleanly and powers off. The bzImage is slightly
smaller than the non-LTO modern build (cross-module dead-code elimination, and no
debug info), and kCFI remains active — LTO and CFI compose.
Full LTO (
CONFIG_LTO_CLANG_FULL) would optimize harder but merges the whole program into one module at link — much slower and far more memory-hungry. On a 15 GiB box, ThinLTO is the right call; Full LTO would risk swapping.