14. LTO Support
14.1. Overview
ELD supports Link Time Optimization (LTO) using the LLVM LTO libraries. The linker can consume LLVM bitcode directly or use embedded bitcode inside ELF objects and drive Full LTO or ThinLTO code generation. This chapter describes the LTO model used by ELD and the linker switches that control it.
14.2. Background: LLVM LTO
LLVM LTO performs intermodular (whole program) optimization at link time. Compared to traditional per-object optimization, LTO enables cross-module inlining, dead code elimination, and whole-program analysis by merging or summarizing LLVM IR across inputs. The LLVM LTO design emphasizes transparency in the build system: compile with LTO enabled and link with an LTO-capable linker, and the linker handles optimization without special build steps.
ThinLTO is LLVM’s scalable LTO mode. It uses a summary index to avoid a full merge of all IR, supports parallel code generation, and allows caching of imported summaries or produced objects to speed up incremental builds. ELD provides knobs for ThinLTO parallelism and caching, alongside Full LTO support when modules are compiled for full LTO.
14.3. ELD LTO model
14.3.1. Inputs
ELD triggers LTO when it sees bitcode inputs or when it is instructed to use embedded bitcode sections in ELF files:
Bitcode inputs:
.bcinputs are always treated as LTO inputs.Embedded bitcode:
ELD recognizes
.llvmbcsections in ELF objects and can replace the native object with embedded bitcode when LTO input selection enables it.ELD also supports
.llvm.lto(SHT_LLVM_LTO) sections used by fat LTO objects when--fat-lto-objectsis enabled.
14.3.2. Selecting LTO inputs
LTO is enabled in two ways:
-fltoenables LTO if any bitcode input or embedded bitcode is present.--include-lto-filelistcan be used without-fltoto select which ELF inputs with embedded bitcode should be upgraded to LTO inputs.--fat-lto-objectsenables consuming embedded.llvm.ltosections from relocatable ELF inputs (alias:--ffat-lto-objects).
When -flto is used, embedded bitcode is used by default unless excluded using
--exclude-lto-filelist. When -flto is not used, only file patterns listed
in --include-lto-filelist are upgraded to LTO inputs.
By default, .llvm.lto sections are ignored. They are only consumed when
--fat-lto-objects (or --ffat-lto-objects) is specified.
File lists accept one glob pattern per line (wildcards *, ?, and [] are
supported). Patterns are matched against the input path as seen by the linker.
14.3.3. LTO phases in ELD
ELD performs LTO in distinct phases:
Pre-LTO: Inputs are read, symbols are collected, and linker scripts are evaluated. Bitcode inputs are registered for LTO.
LTO: LLVM performs symbol resolution across bitcode modules and emits native object files (Full LTO) or partitioned outputs (ThinLTO).
Post-LTO: The generated objects are inserted back into the link and linked like normal ELF objects. Map files can include pre-LTO and post-LTO details.
When --fat-lto-objects (or --ffat-lto-objects) selects embedded
.llvm.lto from a mixed object, the pre-LTO map input record for that file
is annotated with Fat LTO object selected.
14.3.4. Linker scripts and LTO
ELD supports LTO with linker scripts. When a script uses SECTIONS ordering,
ELD preserves input order for LTO-generated sections. If you need to disable
this ordering for performance or to match non-script ordering, use
--flto-options=disable-linkorder.
14.4. LTO switch reference
This section lists the LTO-related switches supported by ELD. Some switches
also accept --plugin-opt=... aliases for compatibility with LLVMgold and lld.
14.4.1. Core LTO enablement and input selection
-fltoor--fltoEnable LTO if a bitcode file or embedded bitcode section is present.--fat-lto-objects/--no-fat-lto-objectsEnable/disable use of.llvm.ltoembedded bitcode sections from fat LTO relocatable objects. Aliases:--ffat-lto-objects,--fno-fat-lto-objects.--include-lto-filelist=<list>Use this list to select which ELF inputs with embedded bitcode should be used for LTO when-fltois not present.--exclude-lto-filelist=<list>Use this list to exclude embedded bitcode inputs when-fltois present.
14.4.2. LTO output control and artifacts
--save-tempsSave intermediate LTO artifacts. Temporary files use the prefix<output>.llvm-lto.*.--save-temps=<dir>Save LTO temporary files under the specified directory.--lto-emit-asmRun LTO and emit assembly only. No final link is performed. Output files use the prefix<output>.llvm-lto.<task>.s. Alias:--plugin-opt=emit-asm.--lto-emit-llvmRun LTO and emit LLVM bitcode to the final output file (-o). No final link is performed. Alias:--plugin-opt=emit-llvm.--lto-obj-path=<prefix>Prefix for LTO-generated object files. When provided, output objects are not deleted after LTO. Alias:--plugin-opt=obj-path=.--flto-options=lto-asm-file=<file[,file2,...]>Use pre-generated LTO assembly files as inputs to the external assembler.--flto-options=lto-output-file=<file[,file2,...]>Use pre-generated LTO object files as outputs (bypasses LTO code generation).
14.4.3. LTO optimization control
--lto-O=<level>Set the LTO optimization level (0-4). Alias:--plugin-opt=O.--lto-partitions=<number>Set the number of code generation partitions. Alias:--plugin-opt=lto-partitions=.--thinlto-jobs=<number>Set the number of ThinLTO backend jobs. Overrides--threads=for ThinLTO. Alias:--plugin-opt=jobs=.--lto-sample-profile=<file>Provide a sample PGO profile for LTO. Alias:--plugin-opt=sample-profile=.--lto-cs-profile-generateEnable context-sensitive PGO instrumentation during LTO. Alias:--plugin-opt=cs-profile-generate.--lto-cs-profile-file=<file>Provide a context-sensitive profile for LTO. Alias:--plugin-opt=cs-profile-path=.--lto-debug-pass-managerEnable debug output for the new pass manager. Alias:--plugin-opt=debug-pass-manager.--disable-verifyDisable the LLVM IR verifier in the LTO pipeline. Alias:--plugin-opt=disable-verify.--dwodir=<dir>Directory for split DWARF.dwofiles generated during LTO.
14.4.4. LLVM option passthrough
--plugin-opt=-<llvm-option>Pass a raw LLVM option to LTO (LLVMgold compatibility). For example,--plugin-opt=-debug-pass-manager.--flto-options=codegen=<llvm-arg>Pass LLVM codegen options to LTO (supports-O,-mcpu=,-mattr=, and arbitrary LLVM options).--flto-options=<string>Passes additional LTO plugin options through. For example, tests use--flto-options=no-merge-modulesand--flto-options=codegen=-split-lto-cg.
14.4.5. Assembler control
--flto-use-asUse the external assembler instead of the integrated assembler for LTO.--flto-options=asmopts=<arg>Extra arguments passed to the external assembler during LTO.
14.4.6. LTO caching
--flto-options=cacheEnable ThinLTO caching. By default, cache output is written to<output>.ltocache.--flto-options=cache=<dir>Enable ThinLTO caching using the specified directory.
14.4.7. Symbol preservation and ordering
--flto-options=preserveallPreserve all bitcode symbols during LTO.--flto-options=preserve-sym=<sym1,sym2,...>Preserve the specified symbols in LTO.--flto-options=preserve-file=<file>Preserve the symbols listed in the given file (one symbol per line).--flto-options=disable-linkorderDisable link order enforcement when linker scripts are present.--flto-options=verboseEnable verbose LTO diagnostics and trace output.
14.4.8. Diagnostics and tracing
--trace-ltoTrace LTO stages and emit additional diagnostics.--opt-record-fileEmit LTO optimization remarks. ELD writes-LTO.opt.yamlalongside the output file.--display-hotnessDisplay hotness information with optimization remarks.--print-timing-stats,--emit-timing-statsEmit or print timing stats, including LTO phases.
14.5. Examples
Full LTO with embedded bitcode:
clang -flto -c foo.c -o foo.o
clang -flto -c bar.c -o bar.o
ld.eld -flto foo.o bar.o -o app.elf
ThinLTO with parallel backends and cache:
clang -flto=thin -c foo.c -o foo.o
clang -flto=thin -c bar.c -o bar.o
ld.eld -flto --thinlto-jobs=8 --flto-options=cache=thinlto.cache \
foo.o bar.o -o app.elf
Selective LTO on a subset of objects:
# lto_list.txt contains glob patterns like:
# libfoo/*.o
# *vector_math*.o
ld.eld --include-lto-filelist=lto_list.txt foo.o bar.o -o app.elf
Emit LTO assembly for inspection:
ld.eld -flto --lto-emit-asm foo.o bar.o -o app.elf
# Output files: app.elf.llvm-lto.0.s, app.elf.llvm-lto.1.s, ...
Use .llvm.lto from fat LTO objects:
# foo.fat.o carries native code plus a .llvm.lto section.
ld.eld --fat-lto-objects foo.fat.o bar.bc -o app.elf
14.6. References
LLVM Link Time Optimization: Design and Implementation (
https://llvm.org/docs/LinkTimeOptimization.html)