LD.LLD(1)
π NAME π
ld.lld β the ELF linker from the LLVM project β¨
π SYNOPSIS π
ld.lld [options] objfile ...
π¦ DESCRIPTION π¦
okay so bestie, imagine you've got a whole pile of object files, archives and libraries just sitting there like, completely unlinked, tragic, no cap π. A linker takes all of them and combines them into one single output file β could be an executable, could be a shared library, could be another object file, whatever you're feeling that day. It relocates code and data from the input files and resolves the symbol references between them. That's the whole job. Iconic behaviour honestly. π
ld.lld is a drop-in replacement for the GNU BFD and gold linkers. It accepts most of the same command line arguments and linker scripts as GNU linkers. So if you're switching over, lowkey everything you already know still works. π
ld.lld currently supports i386, x86-64, ARM, AArch64, LoongArch, PowerPC32, PowerPC64, MIPS32, MIPS64, RISC-V, AMDGPU, Hexagon and SPARC V9 targets. And get this β ld.lld acts as a Microsoft link.exe-compatible linker if invoked as lld-link, and as macOS's ld if invoked as ld.ld64. Not me having main character energy in every flavour ππ«Ά
All these targets are always supported howeverld.lldwas built, so you can always useld.lldas a native linker as well as a cross linker. fr fr, no build-config drama.
β¨ OPTIONS β¨
So many of these have both a single-letter and a long form, which is giving "why not both" energy. Here's the tea on the long forms: when you use a long form option other than those beginning with the letter o, you may specify it using either one or two dashes preceding the option name. But long options beginning with o require two dashes, to avoid confusion with the -o path option. iykyk π
--allow-multiple-definitionβ Do not error if a symbol is defined multiple times. The first definition will be used.--allow-shlib-undefinedβ Allow unresolved references in shared libraries. This option is enabled by default when linking a shared library.--apply-dynamic-relocsβ Apply link-time values for dynamic relocations.--as-neededβ Only setDT_NEEDEDfor shared libraries if used.--auxiliary=valueβ Set theDT_AUXILIARYfield to the specified name.--Bdynamic,--dyβ Link against shared libraries.--Bstatic,--static,--dnβ Do not link against shared libraries.-Bno-symbolicβ Don't bind default visibility defined symbols locally for-shared(default).-Bsymbolicβ Bind default visibility defined symbols locally for-shared. Also set theDF_SYMBOLICflag.-Bsymbolic-non-weakβ Bind default visibility definedSTB_GLOBALsymbols locally for-shared.-Bsymbolic-functionsβ Bind default visibility defined function symbols locally for-shared.-Bsymbolic-non-weak-functionsβ Bind default visibility definedSTB_GLOBALfunction symbols locally for-shared.--be8β Write a Big Endian ELF File using BE8 format (AArch32 only).--branch-to-branchβ Enable the branch-to-branch optimizations: a branch whose target is another branch instruction is rewritten to point to the latter branch target (AArch64 and X86_64 only). Enabled by default at-O2.--build-id=valueβ Generate a build ID note.valuemay be one offast,md5,sha1,tree,uuid,0xhex-string, andnone.treeis an alias forsha1. Build-IDs of typefast,md5,sha1, andtreeare calculated from the object contents.fastis not intended to be cryptographically secure.--build-idβ Synonym for--build-id=sha1.--call-graph-profile-sort=algorithmβalgorithmmay be:noneβ Ignore call graph profile.hfsortβ Use hfsort.cdsortβ Use cdsort (default).
--color-diagnostics=valueβ Use colors in diagnostics.valuemay be one ofalways,auto, andnever.autoenables color if and only if output is to a terminal.--color-diagnosticsβ Alias for--color-diagnostics=auto.--compress-debug-sections=valueβ Compress DWARF debug sections. The sections remain uncompressed if compressed content would be larger.valuemay benoneβ No compression.zlibβ The default compression level is 1 (fastest) as the debug info usually compresses well at that level.zstdβ Use the default compression level in zstd.
--compress-sections=section-glob={none,zlib,zstd}[:level]β Compress output sections that match the glob and do not have theSHF_ALLOCflag. The matched sections remain uncompressed if compressed content would be larger. The compression level islevel(if specified) or a default speed-focused level. This is like a generalized--compress-debug-sections. It's giving "but make it customizable" π--crefβ Output cross reference table. If-Mapis specified, print to the map file.--debug-namesβ Generate a merged.debug_namessection.--default-script=file,-dT fileβ In the absence of--script, read this default linker script.--defsym=symbol=expressionβ Define a symbol alias.expressionmay be another symbol or a linker script expression. For example,--defsym=foo=baror--defsym=foo=bar+0x100.--demangleβ Demangle symbol names. (because reading mangled names is not the vibe π)--disable-new-dtagsβ Disable new dynamic tags.--discard-all,-xβ Delete all local symbols.--discard-locals,-Xβ Delete temporary local symbols.--discard-noneβ Keep all symbols in the symbol table.--dynamic-linker=valueβ Specify the dynamic linker to be used for a dynamically linked executable. This is recorded in an ELF segment of typePT_INTERP.--dynamic-list=fileβ Similar to--export-dynamic-symbol-list. When creating a shared object, implies-Bsymbolicbut does not setDF_SYMBOLIC.--EBβ Select the big-endian format in theOUTPUT_FORMATcommand.--ELβ Select the little-endian format in theOUTPUT_FORMATcommand.--eh-frame-hdrβ Request creation of.eh_frame_hdrsection andPT_GNU_EH_FRAMEsegment header.--emit-relocs,-qβ Generate relocations in the output.--enable-new-dtagsβ Enable new dynamic tags.--enable-non-contiguous-regionsβ Spill input sections to later matching output sections to avoid memory region overflow.--end-libβ End a grouping of objects that should be treated as if they were together in an archive.--entry=entryβ Name of entry point symbol.--error-limit=valueβ Maximum number of errors to emit before stopping. A value of zero indicates that there is no limit.--error-unresolved-symbolsβ Report unresolved symbols as errors.--error-handing-script=script_pathβ Call scriptscript_pathupon some error, withtagas first argument, and an extra parameter as second argument. The script is expected to return0on success. Any other value is considered a generic error.tagmay bemissing-libfollowed by the name of the missing library.undefined-symbolfollowed by the name of the undefined symbol.--execute-onlyβ Mark executable sections unreadable. This option is currently only supported on AArch64.--exclude-libs=valueβ Exclude static libraries from automatic export.--export-dynamic,-Eβ Put symbols in the dynamic symbol table.--export-dynamic-symbol=globβ (executable) Put matched non-local defined symbols to the dynamic symbol table. (shared object) References to matched non-localSTV_DEFAULTsymbols shouldn't be bound to definitions within the shared object even if they would otherwise be due to-Bsymbolic,-Bsymbolic-functionsor--dynamic-list.--export-dynamic-symbol-list=fileβ Read a list of dynamic symbol patterns fromfile. Apply--export-dynamic-symbolon each pattern.--fatal-warningsβ Treat warnings as errors. No more "it's just a warning bestie" π--filter=value,-F valueβ Set theDT_FILTERfield to the specified value.--fini=symbolβ Specify a finalizer function.--force-group-allocationβ Only meaningful for-r. Section groups are discarded. If two section group members are placed to the same output section, combine their relocations as well.--format=input-format,-b input-formatβ Specify the format of the inputs following this option.input-formatmay be one ofbinary,elf, anddefault.defaultis a synonym forelf.--gc-sectionsβ Enable garbage collection of unused sections. bye bye unused sections, you will not be missed ποΈβ¨--gdb-indexβ Generate.gdb_indexsection.--hash-style=valueβ Specify hash style.valuemay besysv,gnu, orboth.bothis the default.--helpβ Print a help message.--icf=allβ Enable identical code folding.--icf=safeβ Enable safe identical code folding.--icf=noneβ Disable identical code folding.--ignore-data-address-equalityβ Ignore address equality of data. C/C++ requires each data to have a unique address. This option allows lld to do unsafe optimization that breaks the requirement: create copies of read-only data or merge two or more read-only data that happen to have the same value.
β οΈ okay this one is literally called unsafe in the description, so like, read the whole thing before you go turning it on bestie.
--ignore-function-address-equalityβ Ignore address equality of functions. This option allows non-PIC calls to a function with non-default visibility in a shared object. The function may have different addresses within the executable and within the shared object.--image-base=valueβ Set the base address tovalue.--init=symbolβ Specify an initializer function.--keep-unique=symbolβ Do not foldsymbolduring ICF.-l libName,--library=libNameβ Root name of library to use.-L dir,--library-path=dirβ Add a directory to the library search path.--lto-aa-pipeline=valueβ AA pipeline to run during LTO. Used in conjunction with--lto-newpm-passes.--lto-newpm-passes=valueβ Passes to run during LTO.--lto-Oopt-levelβ Optimization level for LTO.--lto-partitions=valueβ Number of LTO codegen partitions.-m valueβ Set target emulation.--Map=file,-M fileβ Print a link map tofile.--nmagic,-nβ Do not page align sections, link against static libraries.--no-allow-shlib-undefinedβ Do not allow unresolved references in shared libraries. This option is enabled by default when linking an executable.--no-as-neededβ Always setDT_NEEDEDfor shared libraries.
πΈ more parts coming, bestie β don't go anywhere πΈ
--no-color-diagnosticsβ pls no rainbow in my error messages, bestie. Diagnostics come out plain. π«π--no-demangleβ leave those symbol names in their raw, un-glammed-up form. No name decoding. π--no-dynamic-linkerβ don't emit an.interpsection at all. Like, that whole "which loader am I" thing? Skipped. β¨--no-fortran-commonβ stop digging through archive members looking for definitions to overrideCOMMONsymbols. Not today. π--no-gc-sectionsβ turn OFF garbage collection of unused sections. Nothing gets yeeted. Everything stays, even the flops. π--no-gnu-uniqueβ disableSTB_GNU_UNIQUEsymbol binding. Yeah, that one. It's off now. π¦--no-merge-exidx-entriesβ stop merging.ARM.exidxentries. They stay separate, individually iconic. β¨--no-nmagicβ page align sections. That's the whole vibe. π--no-omagicβ do NOT make the text/data sections writable, but DO page align sections. π--no-relaxβ disable target-specific relaxations. Lowkey important detail: for x86-64 this turns off theR_X86_64_GOTPCRELXandR_X86_64_REX_GOTPCRELXGOT optimization. No chill, no relaxing. π€--no-rosegmentβ don't give read-only non-executable sections their own separate segment. They can share, it's fine. π«Ά--undefined-versionβ don't come for version scripts that reference undefined symbols. Let them live. π--no-undefinedβ report unresolved symbols even when the linker is out here building a shared library. Yes, even then. Snitches get... reported. π₯--no-warn-mismatchβ unknown section types? Not rejected. We move. π--no-warn-symbol-orderingβ don't nag about problems with the symbol ordering file or the call graph profile. Silence is golden. β¨--no-warnings,-wβ suppress warnings AND cancel--fatal-warnings. Full mute mode. π€«--no-whole-archiveβ restores the default behavior of loading archive members. The classic, the original recipe. π--no-pie,--no-pic-executableβ do not create a position independent executable. Fixed-address era. π--noinhibit-execβ keep the executable output file whenever it's still usable, even if stuff went sideways. Salvage the queen. π--nostdlibβ only search the directories you named on the command line. Nowhere else. Rude but efficient. π-o pathβ write the output executable, library, or object to path. No path given? Thena.outis the default, periodt. π-Ovalueβ optimize the output file. value can be:0β disable string merging.1β enable string merging.2β enable string tail merging and branch-to-branch optimization.
-O1 is the default. So if you don't say anything, you get the level-1 slay. π₯
--oformat=formatβ pick the format for the output object file. The ONLY supported format isbinary, which gives you output with no ELF header at all. Raw. Unfiltered. π--omagic,-Nβ set the text and data sections to be readable AND writable, do NOT page align sections, and link against static libraries. Chaotic good energy. π--opt-remarks-filename fileβ write optimization remarks in YAML format to file. π--opt-remarks-passes pass-regexβ filter those optimization remarks by only allowing the passes matching pass-regex. Picky, and we love that. π―--opt-remarks-with-hotnessβ include hotness info in the optimization remarks file. Spicy metrics. π₯--orphan-handling=modeβ control how orphan sections get handled. An orphan section is one that's not specifically mentioned in a linker script. (Yes, they exist, and they need a home.) mode can be:placeβ place orphan sections in suitable output sections.warnβ place orphan sections as forplace, and also report a warning.errorβ place orphan sections as forplace, and also report an error.
place is the default. π
--pack-dyn-relocs=formatβ pack dynamic relocations in the given format. format can be:noneβ do not pack. Dynamic relocations are encoded inSHT_REL(A).androidβ pack dynamic relocations inSHT_ANDROID_REL(A).relrβ pack relative relocations inSHT_RELR, and the rest of dynamic relocations inSHT_REL(A).android+relrβ pack relative relocations inSHT_RELR, and the rest of dynamic relocations inSHT_ANDROID_REL(A).
none is the default. Also important: if --use-android-relr-tags is specified, use SHT_ANDROID_RELR instead of SHT_RELR. π§
--package-metadataβ emit a percent-encoded string to the.note.packagesection. Example so you get it:%25decodes to a single%. β¨--pic-veneerβ always generate position independent thunks. No exceptions, bestie. π--pie,--pic-executableβ create a position independent executable. It's giving modern. π--power10-stubs=modeβ whether to use Power10 instructions in call stubs forR_PPC64_REL24_NOTOCand TOC/NOTOC interworking. mode can be:yesβ (default) Use.autoβ currently the same asyes.noβ don't use.
π
--print-gc-sectionsβ list the removed unused sections. Show me what got cut. βοΈ--print-gc-sections=fileβ same energy, but list the removed unused sections to the specified file. π--print-icf-sectionsβ list identical folded sections. Twin reveal. π―--print-mapβ print a link map to the standard output. πΊοΈ--print-archive-stats=fileβ write archive usage statistics to the specified file. Prints the numbers of members and fetched members for each archive. Receipts, basically. π§Ύ--push-stateβ save the current state of--as-needed,--static, and--whole-archive. Bookmark it. π--pop-stateβ restore the states saved by--push-state. And we're back. βͺ--randomize-section-padding=seedβ randomly insert padding between input sections and at the start of each segment using the given seed. Padding goes into output sections whose names match these patterns:.bss,.data,.data.rel.ro,.lbss,.ldata,.lrodata,.ltext,.rodataand.text*. Chaos, but make it deterministic. π²---relax-gpβ enable global pointer relaxation for RISC-V. (Yes, that's THREE dashes. Type it exactly, bestie, I'm not playing.) πΈ--relocatable,-rβ create a relocatable object file. π§©--remap-inputs=from-glob=to-fileβ input files matching from-glob get mapped to to-file. Want to ignore an input file entirely? Use/dev/null. Bye. π--remap-inputs-file=fileβ remap input files based on patterns in file. Each line in the remap file is of the formatfrom-glob=to-file, or a comment starting with#. π--reproduce=pathβ write a tar file to path, containing all the input files needed to reproduce the link, a text file calledresponse.txtwith the command line options, and a text file calledversion.txtcontaining the output ofld.lld --version. Once unpacked, that archive can re-run the linker with the same options and input files. It's a time capsule. π°οΈβ¨--retain-symbols-file=fileβ retain ONLY the symbols listed in file. Everyone else? Gone. π--rpath=value,-R valueβ add aDT_RUNPATHto the output. π£οΈ--rsp-quoting=valueβ quoting style for response files. The supported *value*s arewindowsandposix. πͺπ§--script=file,-T fileβ read the linker script from file. If multiple linker scripts are given, they're processed as if they were concatenated in the order they appeared on the command line. Order matters, always. π--section-start=section=addressβ set the address of section. π--shared,--Bsharableβ build a shared object. (Yes, it's spelled--Bsharable. Copy it exactly, I beg.) π«Ά--shuffle-sections=seedβ shuffle matched sections using the given seed before mapping them to the output sections. If-1, reverse the section order. If0, use a random seed. π°--soname=value,-h valueβ setDT_SONAMEto value. Name your child. π--sort-commonβ this option is ignored for GNU compatibility. Yeah. It just sits there. It does nothing and I respect it. π--sort-section=valueβ specifies the sections sorting rule when a linkerscript is used. ποΈ--start-libβ start a grouping of objects that should be treated as if they were together in an archive. Squad formation. π§βπ€βπ§--strip-all,-sβ strip ALL symbols. Implies--strip-debug. Nothing left but vibes. βοΈβ¨--strip-debug,-Sβ strip debugging information. The bug-hunting breadcrumbs? Deleted. πβ‘οΈπ«--symbol-ordering-file=fileβ lay out sections in the order specified by file. Lineup, in formation. π--sysroot=valueβ set the system root. π³--target1-absβ interpretR_ARM_TARGET1asR_ARM_ABS32. π―--target1-relβ interpretR_ARM_TARGET1asR_ARM_REL32. π―--target2=typeβ interpretR_ARM_TARGET2as type, where type is one ofrel,abs, orgot-rel. π--Tbss=valueβ same as--section-startwith.bssas the sectionname. π«§--Tdata=valueβ same as--section-startwith.dataas the sectionname. π--Ttext=valueβ same as--section-startwith.textas the sectionname. π--thinlto-cache-dir=valueβ path to the ThinLTO cached object file directory. ποΈ--thinlto-cache-policy=valueβ pruning policy for the ThinLTO cache. Spring cleaning, but for object files. π§Ή--thinlto-jobs=valueβ number of ThinLTO jobs. π·--threads=Nβ number of threads.all(the default) means all of the concurrent threads supported.1disables multi-threading. Go forth and parallelize. πββοΈπ¨--fat-lto-objectsβ use the.llvm.ltosection, which contains LLVM bitcode, in fat LTO object files to perform LTO. π--no-fat-lto-objectsβ ignore the.llvm.ltosection in relocatable object files (default). π«π--time-traceβ record time trace. Where did the seconds go? Now you'll know. β±οΈ--time-trace-file=fileβ write time trace output to file. π--time-trace-granularity=valueβ minimum time granularity (in microseconds) traced by the time profiler. π§--traceβ print the names of the input files. Narration mode: ON. π£οΈ--trace-symbol=symbol,-y symbolβ trace references to symbol. Following it everywhere like a detective. π--undefined=symbol,-u symbolβ if symbol is not defined after symbol resolution, and there's a static library that contains an object file defining the symbol, load the member to include that object file in the output file. Summoned from the archives. πβ¨--undefined-glob=patternβ synonym for--undefined, except it takes a glob pattern. In a glob pattern,*matches zero or more characters,?matches any single character, and[...]matches the characters within brackets. All symbols that match a given pattern are handled as if they were given as arguments of--undefined. Fancy. π--uniqueβ creates a separate output section for EVERY orphan input section. Everyone gets their own room. πͺ--unresolved-symbols=valueβ determine how to handle unresolved symbols. value may be:report-allβ report unresolved symbols (default).ignore-in-object-filesβ only report unresolved symbols contained in shared libraries.ignore-in-shared-libsβ only report unresolved symbols contained in object files.ignore-allβ do not report unresolved symbols.
Pick your level of awareness, bestie. π
--use-android-relr-tagsβ useSHT_ANDROID_RELR/DT_ANDROID_RELR*tags instead ofSHT_RELR/DT_RELR*. π§β¨
-v,-Vβ shows the version number, and then keeps going with the linking if you actually passed it some object files π--versionβ shows the version number and dips. That's it, that's the whole job π--verboseβ verbose mode, bestie. It tells you stuff. Lots of stuff. β¨--version-script=fileβ reads the version script in from file π--warn-backrefsβ yells at you about reverse or cyclic dependencies to or between static archives. Lowkey a vibe-check for your link order β use it if you want your linker invocation to stay compatible with traditional Unix-like linkers π«Ά--warn-backrefs-exclude=globβ a glob describing an archive (or an object file inside--start-lib) that should be ignored for--warn-backrefs. Like a do-not-disturb sign for one specific archive π--warn-commonβ warns you when common symbols are duplicated π―--warn-ifunc-textrelβ warns about using ifunc symbols together with text relocations. So here's the lore: older versions of the glibc library (2.28and earlier) have a bug that makes the segment containing ifunc symbols get marked as not executable once they're relocated. Meaning: the program compiles and links just fine, and then gives you a segmentation fault the moment the instruction pointer reaches an ifunc symbol π Use-warn-ifunc-textrelto let lld give you a warning if your code may include ifunc symbols, may do text relocations, and is getting linked against an older glibc version. Otherwise there's genuinely no need for it, because the default value does not give a warning. Heads up: this flag showed up in late 2018, has no counterpart in the ld and gold linkers, and may be removed in the future π--warn-unresolved-symbolsβ unresolved symbols get reported as warnings instead of errors π’--whole-archiveβ force-loads every member of a static library. No skips, no cuts, the whole archive eats π½οΈ--why-extract=fileβ prints out, into a file, why archive members are getting extracted. Receipts, basically π§Ύ--why-live=globβ reports a chain of references that's preventing garbage collection, for every symbol matching the glob βοΈ--wrap=symbolβ redirects references to symbol over to__wrap_symbol, and references to__real_symbolover to symbol. Iconic little switcheroo π-z optionβ linker option extensions. The main-character list of extras:dead-reloc-in-nonalloc=section_glob=valueβ resolves a relocation in a matched non-SHF_ALLOCsection that references a discarded symbol, replacing it with value. It accepts globs, and if a section matches more than one option, the last option takes precedence. An order of least specific to most specific match is recommended πΈexecstackβ makes the main stack executable. Stack permissions get recorded in thePT_GNU_STACKsegment.bti-report=[none|warning|error]β specifies how to report the missingGNU_PROPERTY_AARCH64_FEATURE_1_BTIproperty.noneis the default, so the linker won't report the missing property at all; otherwise it gets reported as a warning or an error.cet-report=[none|warning|error]β specifies how to report the missingGNU_PROPERTY_X86_FEATURE_1_IBTorGNU_PROPERTY_X86_FEATURE_1_SHSTKproperties.noneis the default, so the linker won't report the missing property; otherwise it's reported as a warning or an error.gcs-report=[none|warning|error]β specifies how to report the missingGNU_PROPERTY_AARCH64_FEATURE_1_GCSproperty.GNU_PROPERTY_AARCH64_FEATURE_1_GCSindicates object file support for the Guarded Control Stack security feature.noneis the default, so the linker won't report the missing property; otherwise it's reported as a warning or an error.dynamic-undefined-weakβ makes undefined weak symbols dynamic when the dynamic symbol table is present, if they're referenced from relocatable object files and not forced local by symbol visibility or versioning. They don't get made dynamic whennodynamic-undefined-weakis specified.dynamic-undefined-weakis the default when building a shared object, or when an input shared object is present.pauth-report=[none|warning|error]β specifies how to report the missingGNU_PROPERTY_AARCH64_FEATURE_PAUTHproperty.noneis the default, so the linker won't report the missing property; otherwise it's reported as a warning or an error.force-btiβ force-enables the AArch64 BTI instruction in the PLT, and warns if an input ELF file doesn't have theGNU_PROPERTY_AARCH64_FEATURE_1_BTIproperty.force-ibtβ force-enables Intel Indirect Branch Tracking in the PLT, and warns if an input ELF file doesn't have theGNU_PROPERTY_X86_FEATURE_1_IBTproperty.globalβ sets theDF_1_GLOBALflag in theDYNAMICsection. Different loaders can decide how to handle this flag on their own π€·ifunc-nopltβ doesn't emit PLT entries for ifunc symbols. Instead it emits text relocations referencing the resolver. This is an experimental optimization and only suitable for standalone environments where text relocations don't have the usual drawbacks. It must be combined with the-z notextoption β οΈinitfirstβ sets theDF_1_INITFIRSTflag to indicate the module should be initialized first π₯interposeβ sets theDF_1_INTERPOSEflag to tell the runtime linker that the object is an interposer. During symbol resolution, interposers get searched after the application but before other dependencies.lrodata-after-bssβ places.lrodataafter.bss.muldefsβ doesn't error out if a symbol is defined multiple times; the first definition gets used. This is a synonym for--allow-multiple-definition.nocombrelocβ disables combining and sorting multiple relocation sections.nocopyrelocβ disables the creation of copy relocations.nodefaultlibβ sets theDF_1_NODEFLIBflag to indicate that default library search paths should be ignored.nodeleteβ sets theDF_1_NODELETEflag to indicate that the object cannot be unloaded from a process.nodlopenβ sets theDF_1_NOOPENflag to indicate that the object may not be opened bydlopen(3).nognustackβ doesn't emit thePT_GNU_STACKsegment.norelroβ doesn't indicate that portions of the object should be mapped read-only after initial relocation processing. The object will omit thePT_GNU_RELROsegment.nosectionheaderβ doesn't generate the section header table.notextβ allows relocations against read-only segments. Sets theDT_TEXTRELflag in theDYNAMICsection.nowβ sets theDF_BIND_NOWflag to indicate that the run-time loader should perform all relocation processing as part of object initialization. By default, relocations may be performed on demand.originβ sets theDF_ORIGINflag to indicate that the object requires$ORIGINprocessing.pac-pltβ AArch64 only, uses pointer authentication in the PLT.pack-relative-relocsβ similar to-pack-dyn-relocs=relr, except it synthesizes theGLIBC_ABI_DT_RELRversion dependency if there's aGLIBC_2.*version dependency. glibc'sld.sorejects loading a dynamically linked object that doesn't have theGLIBC_ABI_DT_RELRversion dependency.relβ uses the REL format for dynamic relocations.relaβ uses the RELA format for dynamic relocations.retpolinepltβ emits retpoline format PLT entries as a mitigation for CVE-2017-5715 π‘οΈrodynamicβ makes the.dynamicsection read-only. TheDT_DEBUGtag will not be emitted.separate-loadable-segments,separate-code,noseparate-codeβ these three specify whether two adjacentPT_LOADsegments are allowed to overlap in pages.noseparate-code(the default) allows overlap.separate-codeallows overlap between two executable segments, or between two non-executable segments.separate-loadable-segmentsdisallows overlap entirely.shstkβ x86 only, uses shadow stack.gcs=[implicit|never|always]β specifies how theGNU_PROPERTY_AARCH64_FEATURE_1_GCSbit is set in the output ELF file. When set, it indicates support for the Guarded Control Stack (GCS) security feature.implicit(the default): the GCS feature bit is set if all input relocatable files have a.note.gnu.propertysection containing theGNU_PROPERTY_AARCH64_FEATURE_1_GCSbit.never: clears the GCS feature bit regardless of input relocatable files' markings.always: sets the GCS feature bit regardless of input object markings.stack-size=sizeβ sets the main thread's stack size to size. The stack size is recorded as the size of thePT_GNU_STACKprogram segment.start-stop-gcβ doesn't let__start_/__stop_references retain the associated C identifier name sections (this is the default).nostart-stop-gcβ lets__start_/__stop_references retain the associated C identifier name sections.textβ doesn't allow relocations against read-only segments. This is the default.nobtcfiβ creates aPT_OPENBSD_NOBTCFIsegment.wxneededβ creates aPT_OPENBSD_WXNEEDEDsegment.
πΈ ENVIRONMENT VARIABLES πΈ
okay bestie these are the env vars ld.lld actually looks at, and there are literally only two, so this is a chill section π
LLD_REPRODUCEβ set this and ld.lld will make a reproduce tarball with whatever filename you gave it. and yes, the lore matters here: if you also passed--reproduceon the command line, then--reproducewins and takes precedence, no cap. so the flag beats the env var, periodt. πLLD_VERSIONβ sold.lldcreates a section named.commentthat contains the LLD version string, right? and this env var can override that string. why would you even want that? because it's useful to eliminate differences in the binary caused by LLD version number differences β like when you're diffing two builds and the only thing wigging out is the version number π« . setLLD_VERSIONand boom, those diffs are gone.
π¦ IMPLEMENTATION NOTES π¦
okay so this is the part where ld.lld lowkey does its own thing and you need to know about it before you come for it. sit down, grab a snack π
π how ld.lld treats archives (the whole vibe)
ld.lld's handing of archive files (those with a .a file extension) is different from traditional linkers used on Unix-like systems.
so let's talk about how the traditional girlies do it, because it's a whole different energy:
Traditional linkers maintain a set of undefined symbols during linking. The linker processes each file in the order in which it appears on the command line, until the set of undefined symbols becomes empty. An object file is linked into the output object when it is encountered, with its undefined symbols added to the set. Upon encountering an archive file a traditional linker searches the objects contained therein, and processes those that satisfy symbols in the unresolved set.
translation bestie: it's one pass, in order, first-come-first-served and if your symbol's already been passed, sorry babe, too late π
π΅π« the mutually dependent archive problem
Handling mutually dependent archives may be awkward when using a traditional linker. Archive files may have to be specified multiple times, or the special command line options --start-group and --end-group may be used to have the linker loop over the files in the group until no new symbols are added to the set.
yeah. you literally have to list the same archive over and over, OR wrap it all in --start-group / --end-group so the linker just keeps looping over the files in the group until no new symbols are added to the set. it's giving "just keep trying until it works" π iconic behavior honestly
β¨ how ld.lld does it instead
ld.lld records all symbols found in objects and archives as it iterates over command line arguments. When ld.lld encounters an undefined symbol that can be resolved by an object file contained in a previously processed archive file, it immediately extracts and links it into the output object.
okay so the glow-up here is that it remembers everything as it iterates over command line arguments. and then β plot twist β when it hits an undefined symbol that could be resolved by an object file inside an archive it already processed? it goes back and immediately extracts and links it into the output object. like it never even left π§β¨. no --start-group gymnastics required.
π«Ά the honest disclaimer
With certain archive inputs ld.lld may produce different results compared to traditional linkers. In practice, large bodies of third party software have been linked with ld.lld without material issues.
so like, yes, with certain archive inputs it may produce different results compared to traditional linkers. but fr fr β in practice, large bodies of third party software have been linked with ld.lld without material issues. so it's fine. it's slaying even π
if you're nervous about whether your linker invocation might be incompatible with traditional Unix-like linker behavior, the --warn-backrefs option may be used to identify a linker invocation that may be incompatible with traditional Unix-like linker behavior. it's literally built for exactly this vibe check π
and that's the whole page, bestie!! πβ¨ this one came from the Debian crew, dated Jul 25, 2023 β so if you're citing it, that's the source and the date, no cap ππ. now go link something iconic. mwah π π
π¦ where this page comes from
- centos-stream 10: lld 22.1.8-1.el10 Β· Apache-2.0 WITH LLVM-exception OR NCSA
- debian trixie: lld-22 1:22.1.8-1~deb13u4 Β· APACHE-2-LLVM-EXCEPTIONS
- fedora 44: lld 22.1.1-2.fc44 Β· Apache-2.0 WITH LLVM-exception OR NCSA
- fedora 44: lld 22.1.1-2.fc44 Β· Apache-2.0 WITH LLVM-exception OR NCSA
- fedora 44: lld 22.1.8-4.fc44 Β· Apache-2.0 WITH LLVM-exception OR NCSA
- fedora 44: lld 22.1.8-4.fc44 Β· Apache-2.0 WITH LLVM-exception OR NCSA
- ubuntu resolute: lld-22 1:22.1.2-1ubuntu1 Β· APACHE-2-LLVM-EXCEPTIONS
- ubuntu stonking: lld-22 1:22.1.8-1ubuntu1 Β· APACHE-2-LLVM-EXCEPTIONS
- π the page's license: Apache-2.0 WITH LLVM-exception
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms