//===- Driver.cpp ---------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // The driver drives the entire linking process. It is responsible for // parsing command line options and doing whatever it is instructed to do. // // One notable thing in the LLD's driver when compared to other linkers is // that the LLD's driver is agnostic on the host operating system. // Other linkers usually have implicit default values (such as a dynamic // linker path or library paths) for each host OS. // // I don't think implicit default values are useful because they are // usually explicitly specified by the compiler ctx.driver. They can even // be harmful when you are doing cross-linking. Therefore, in LLD, we // simply trust the compiler driver to pass all required options and // don't try to make effort on our side. // //===----------------------------------------------------------------------===// #include "Driver.h" #include "Config.h" #include "ICF.h" #include "InputFiles.h" #include "InputSection.h" #include "LTO.h" #include "LinkerScript.h" #include "MarkLive.h" #include "OutputSections.h" #include "ScriptParser.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" #include "lld/Common/Args.h" #include "lld/Common/CommonLinkerContext.h" #include "lld/Common/Driver.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Filesystem.h" #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "lld/Common/Version.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/Archive.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Remarks/HotnessThresholdParser.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/GlobPattern.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include <cstdlib> #include <tuple> #include <utility> usingnamespacellvm; usingnamespacellvm::ELF; usingnamespacellvm::object; usingnamespacellvm::sys; usingnamespacellvm::support; usingnamespacelld; usingnamespacelld::elf; ConfigWrapper elf::config; Ctx elf::ctx; static void setConfigs(opt::InputArgList &args); static void readConfigs(opt::InputArgList &args); void elf::errorOrWarn(const Twine &msg) { … } void Ctx::reset() { … } llvm::raw_fd_ostream Ctx::openAuxiliaryFile(llvm::StringRef filename, std::error_code &ec) { … } namespace lld { namespace elf { bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { … } } // namespace elf } // namespace lld // Parses a linker -m option. static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) { … } // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers( MemoryBufferRef mb) { … } static bool isBitcode(MemoryBufferRef mb) { … } bool LinkerDriver::tryAddFatLTOFile(MemoryBufferRef mb, StringRef archiveName, uint64_t offsetInArchive, bool lazy) { … } // Opens a file and create a file object. Path has to be resolved already. void LinkerDriver::addFile(StringRef path, bool withLOption) { … } // Add a given library by searching it from input search paths. void LinkerDriver::addLibrary(StringRef name) { … } // This function is called on startup. We need this for LTO since // LTO calls LLVM functions to compile bitcode files to native code. // Technically this can be delayed until we read bitcode files, but // we don't bother to do lazily because the initialization is fast. static void initLLVM() { … } // Some command line options or some combinations of them are not allowed. // This function checks for such errors. static void checkOptions() { … } static const char *getReproduceOption(opt::InputArgList &args) { … } static bool hasZOption(opt::InputArgList &args, StringRef key) { … } static bool getZFlag(opt::InputArgList &args, StringRef k1, StringRef k2, bool defaultValue) { … } static SeparateSegmentKind getZSeparate(opt::InputArgList &args) { … } static GnuStackKind getZGnuStack(opt::InputArgList &args) { … } static uint8_t getZStartStopVisibility(opt::InputArgList &args) { … } static GcsPolicy getZGcs(opt::InputArgList &args) { … } // Report a warning for an unknown -z option. static void checkZOptions(opt::InputArgList &args) { … } constexpr const char *saveTempsValues[] = …; void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { … } static std::string getRpath(opt::InputArgList &args) { … } // Determines what we should do if there are remaining unresolved // symbols after the name resolution. static void setUnresolvedSymbolPolicy(opt::InputArgList &args) { … } static Target2Policy getTarget2(opt::InputArgList &args) { … } static bool isOutputFormatBinary(opt::InputArgList &args) { … } static DiscardPolicy getDiscard(opt::InputArgList &args) { … } static StringRef getDynamicLinker(opt::InputArgList &args) { … } static int getMemtagMode(opt::InputArgList &args) { … } static ICFLevel getICF(opt::InputArgList &args) { … } static StripPolicy getStrip(opt::InputArgList &args) { … } static uint64_t parseSectionAddress(StringRef s, opt::InputArgList &args, const opt::Arg &arg) { … } static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &args) { … } static SortSectionPolicy getSortSection(opt::InputArgList &args) { … } static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &args) { … } // Parse --build-id or --build-id=<style>. We handle "tree" as a // synonym for "sha1" because all our hash functions including // --build-id=sha1 are actually tree hashes for performance reasons. static std::pair<BuildIdKind, SmallVector<uint8_t, 0>> getBuildId(opt::InputArgList &args) { … } static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &args) { … } static void readCallGraph(MemoryBufferRef mb) { … } // If SHT_LLVM_CALL_GRAPH_PROFILE and its relocation section exist, returns // true and populates cgProfile and symbolIndices. template <class ELFT> static bool processCallGraphRelocations(SmallVector<uint32_t, 32> &symbolIndices, ArrayRef<typename ELFT::CGProfile> &cgProfile, ObjFile<ELFT> *inputObj) { … } template <class ELFT> static void readCallGraphsFromObjectFiles() { … } template <class ELFT> static void ltoValidateAllVtablesHaveTypeInfos(opt::InputArgList &args) { … } static CGProfileSortKind getCGProfileSortKind(opt::InputArgList &args) { … } static DebugCompressionType getCompressionType(StringRef s, StringRef option) { … } static StringRef getAliasSpelling(opt::Arg *arg) { … } static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args, unsigned id) { … } // Parse options of the form "old;new[;extra]". static std::tuple<StringRef, StringRef, StringRef> getOldNewOptionsExtra(opt::InputArgList &args, unsigned id) { … } // Parse the symbol ordering file and warn for any duplicate entries. static SmallVector<StringRef, 0> getSymbolOrderingFile(MemoryBufferRef mb) { … } static bool getIsRela(opt::InputArgList &args) { … } static void parseClangOption(StringRef opt, const Twine &msg) { … } // Checks the parameter of the bti-report and cet-report options. static bool isValidReportString(StringRef arg) { … } // Process a remap pattern 'from-glob=to-file'. static bool remapInputs(StringRef line, const Twine &location) { … } // Initializes Config members by the command line options. static void readConfigs(opt::InputArgList &args) { … } // Some Config members do not directly correspond to any particular // command line options, but computed based on other Config values. // This function initialize such members. See Config.h for the details // of these values. static void setConfigs(opt::InputArgList &args) { … } static bool isFormatBinary(StringRef s) { … } void LinkerDriver::createFiles(opt::InputArgList &args) { … } // If -m <machine_type> was not given, infer it from object files. void LinkerDriver::inferMachineType() { … } // Parse -z max-page-size=<value>. The default value is defined by // each target. static uint64_t getMaxPageSize(opt::InputArgList &args) { … } // Parse -z common-page-size=<value>. The default value is defined by // each target. static uint64_t getCommonPageSize(opt::InputArgList &args) { … } // Parses --image-base option. static std::optional<uint64_t> getImageBase(opt::InputArgList &args) { … } // Parses `--exclude-libs=lib,lib,...`. // The library names may be delimited by commas or colons. static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &args) { … } // Handles the --exclude-libs option. If a static library file is specified // by the --exclude-libs option, all public symbols from the archive become // private unless otherwise specified by version scripts or something. // A special library name "ALL" means all archive files. // // This is not a popular option, but some programs such as bionic libc use it. static void excludeLibs(opt::InputArgList &args) { … } // Force Sym to be entered in the output. static void handleUndefined(Symbol *sym, const char *option) { … } // As an extension to GNU linkers, lld supports a variant of `-u` // which accepts wildcard patterns. All symbols that match a given // pattern are handled as if they were given by `-u`. static void handleUndefinedGlob(StringRef arg) { … } static void handleLibcall(StringRef name) { … } static void writeArchiveStats() { … } static void writeWhyExtract() { … } static void reportBackrefs() { … } // Handle --dependency-file=<path>. If that option is given, lld creates a // file at a given path with the following contents: // // <output-file>: <input-file> ... // // <input-file>: // // where <output-file> is a pathname of an output file and <input-file> // ... is a list of pathnames of all input files. `make` command can read a // file in the above format and interpret it as a dependency info. We write // phony targets for every <input-file> to avoid an error when that file is // removed. // // This option is useful if you want to make your final executable to depend // on all input files including system libraries. Here is why. // // When you write a Makefile, you usually write it so that the final // executable depends on all user-generated object files. Normally, you // don't make your executable to depend on system libraries (such as libc) // because you don't know the exact paths of libraries, even though system // libraries that are linked to your executable statically are technically a // part of your program. By using --dependency-file option, you can make // lld to dump dependency info so that you can maintain exact dependencies // easily. static void writeDependencyFile() { … } // Replaces common symbols with defined symbols reside in .bss sections. // This function is called after all symbol names are resolved. As a // result, the passes after the symbol resolution won't see any // symbols of type CommonSymbol. static void replaceCommonSymbols() { … } // The section referred to by `s` is considered address-significant. Set the // keepUnique flag on the section if appropriate. static void markAddrsig(Symbol *s) { … } // Record sections that define symbols mentioned in --keep-unique <symbol> // and symbols referred to by address-significance tables. These sections are // ineligible for ICF. template <class ELFT> static void findKeepUniqueSections(opt::InputArgList &args) { … } // This function reads a symbol partition specification section. These sections // are used to control which partition a symbol is allocated to. See // https://lld.llvm.org/Partitions.html for more details on partitions. template <typename ELFT> static void readSymbolPartitionSection(InputSectionBase *s) { … } static void markBuffersAsDontNeed(bool skipLinkedOutput) { … } // This function is where all the optimizations of link-time // optimization takes place. When LTO is in use, some input files are // not in native object file format but in the LLVM bitcode format. // This function compiles bitcode files into a few big native files // using LLVM functions and replaces bitcode symbols with the results. // Because all bitcode files that the program consists of are passed to // the compiler at once, it can do a whole-program optimization. template <class ELFT> void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) { … } // The --wrap option is a feature to rename symbols so that you can write // wrappers for existing functions. If you pass `--wrap=foo`, all // occurrences of symbol `foo` are resolved to `__wrap_foo` (so, you are // expected to write `__wrap_foo` function as a wrapper). The original // symbol becomes accessible as `__real_foo`, so you can call that from your // wrapper. // // This data structure is instantiated for each --wrap option. struct WrappedSymbol { … }; // Handles --wrap option. // // This function instantiates wrapper symbols. At this point, they seem // like they are not being used at all, so we explicitly set some flags so // that LTO won't eliminate them. static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) { … } static void combineVersionedSymbol(Symbol &sym, DenseMap<Symbol *, Symbol *> &map) { … } // Do renaming for --wrap and foo@v1 by updating pointers to symbols. // // When this function is executed, only InputFiles and symbol table // contain pointers to symbol objects. We visit them to replace pointers, // so that wrapped symbols are swapped as instructed by the command line. static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) { … } static void reportMissingFeature(StringRef config, const Twine &report) { … } static void checkAndReportMissingFeature(StringRef config, uint32_t features, uint32_t mask, const Twine &report) { … } // To enable CET (x86's hardware-assisted control flow enforcement), each // source file must be compiled with -fcf-protection. Object files compiled // with the flag contain feature flags indicating that they are compatible // with CET. We enable the feature only when all object files are compatible // with CET. // // This is also the case with AARCH64's BTI and PAC which use the similar // GNU_PROPERTY_AARCH64_FEATURE_1_AND mechanism. // // For AArch64 PAuth-enabled object files, the core info of all of them must // match. Missing info for some object files with matching info for remaining // ones can be allowed (see -z pauth-report). static void readSecurityNotes() { … } static void initSectionsAndLocalSyms(ELFFileBase *file, bool ignoreComdats) { … } static void postParseObjectFile(ELFFileBase *file) { … } // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { … }