diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2021-12-17 14:47:15 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2021-12-17 14:47:15 +0000 |
commit | 85441880e8b445d58571a3bb2446a3bd1846c848 (patch) | |
tree | b1f340cd667e6ca70ae89a44e42a0e2b54943d9d /gnu/llvm/lld | |
parent | b46545b801f382e6ea8682095cd6bc75963b5866 (diff) |
Merge LLVM 13.0.0.
Diffstat (limited to 'gnu/llvm/lld')
-rw-r--r-- | gnu/llvm/lld/ELF/Arch/PPC.cpp | 10 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/Config.h | 37 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/Driver.cpp | 624 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/DriverUtils.cpp | 14 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/InputSection.cpp | 156 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/LinkerScript.cpp | 336 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/Options.td | 130 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/Relocations.cpp | 288 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/Symbols.cpp | 88 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/Symbols.h | 23 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/SyntheticSections.cpp | 268 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/Writer.cpp | 487 | ||||
-rw-r--r-- | gnu/llvm/lld/MachO/MergedOutputSection.cpp | 74 | ||||
-rw-r--r-- | gnu/llvm/lld/MachO/MergedOutputSection.h | 56 | ||||
-rw-r--r-- | gnu/llvm/lld/docs/ld.lld.1 | 121 | ||||
-rw-r--r-- | gnu/llvm/lld/tools/lld/lld.cpp | 112 | ||||
-rw-r--r-- | gnu/llvm/lld/wasm/InputEvent.h | 62 | ||||
-rw-r--r-- | gnu/llvm/lld/wasm/InputGlobal.h | 55 |
18 files changed, 1896 insertions, 1045 deletions
diff --git a/gnu/llvm/lld/ELF/Arch/PPC.cpp b/gnu/llvm/lld/ELF/Arch/PPC.cpp index 90329315a37..aaecef6ee94 100644 --- a/gnu/llvm/lld/ELF/Arch/PPC.cpp +++ b/gnu/llvm/lld/ELF/Arch/PPC.cpp @@ -45,8 +45,7 @@ public: bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; - RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const override; + RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override; int getTlsGdRelaxSkip(RelType type) const override; void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const override; @@ -261,7 +260,7 @@ RelExpr PPC::getRelExpr(RelType type, const Symbol &s, case R_PPC_TPREL16_HA: case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: - return R_TLS; + return R_TPREL; default: error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + ") against symbol " + toString(s)); @@ -347,8 +346,8 @@ void PPC::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { write32(loc, (read32(loc) & ~mask) | (val & mask)); break; } - case R_PPC_REL24: case R_PPC_ADDR24: + case R_PPC_REL24: case R_PPC_LOCAL24PC: case R_PPC_PLTREL24: { uint32_t mask = 0x03FFFFFC; @@ -362,8 +361,7 @@ void PPC::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { } } -RelExpr PPC::adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const { +RelExpr PPC::adjustTlsExpr(RelType type, RelExpr expr) const { if (expr == R_RELAX_TLS_GD_TO_IE) return R_RELAX_TLS_GD_TO_IE_GOT_OFF; if (expr == R_RELAX_TLS_LD_TO_LE) diff --git a/gnu/llvm/lld/ELF/Config.h b/gnu/llvm/lld/ELF/Config.h index 941dc2455a4..e61c698e146 100644 --- a/gnu/llvm/lld/ELF/Config.h +++ b/gnu/llvm/lld/ELF/Config.h @@ -10,7 +10,9 @@ #define LLD_ELF_CONFIG_H #include "lld/Common/ErrorHandler.h" +#include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/ELF.h" @@ -18,6 +20,7 @@ #include "llvm/Support/CodeGen.h" #include "llvm/Support/Endian.h" #include "llvm/Support/GlobPattern.h" +#include "llvm/Support/PrettyStackTrace.h" #include <atomic> #include <vector> @@ -35,6 +38,10 @@ enum ELFKind { ELF64BEKind }; +// For -Bno-symbolic, -Bsymbolic-non-weak-functions, -Bsymbolic-functions, +// -Bsymbolic. +enum class BsymbolicKind { None, NonWeakFunctions, Functions, All }; + // For --build-id. enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; @@ -79,7 +86,8 @@ struct SymbolVersion { struct VersionDefinition { llvm::StringRef name; uint16_t id; - std::vector<SymbolVersion> patterns; + std::vector<SymbolVersion> nonLocalPatterns; + std::vector<SymbolVersion> localPatterns; }; // This struct contains the global configuration for the linker. @@ -90,11 +98,13 @@ struct Configuration { uint8_t osabi = 0; uint32_t andFeatures = 0; llvm::CachePruningPolicy thinLTOCachePolicy; + llvm::SetVector<llvm::CachedHashString> dependencyFiles; // for --dependency-file llvm::StringMap<uint64_t> sectionStartMap; llvm::StringRef bfdname; llvm::StringRef chroot; - llvm::StringRef dynamicLinker; + llvm::StringRef dependencyFile; llvm::StringRef dwoDir; + llvm::StringRef dynamicLinker; llvm::StringRef entry; llvm::StringRef emulation; llvm::StringRef fini; @@ -107,6 +117,7 @@ struct Configuration { llvm::StringRef mapFile; llvm::StringRef outputFile; llvm::StringRef optRemarksFilename; + llvm::Optional<uint64_t> optRemarksHotnessThreshold = 0; llvm::StringRef optRemarksPasses; llvm::StringRef optRemarksFormat; llvm::StringRef progName; @@ -133,16 +144,15 @@ struct Configuration { uint64_t> callGraphProfile; bool allowMultipleDefinition; - bool allowShlibUndefined; bool androidPackDynRelocs; bool armHasBlx = false; bool armHasMovtMovw = false; bool armJ1J2BranchEncoding = false; bool asNeeded = false; - bool bsymbolic; - bool bsymbolicFunctions; + BsymbolicKind bsymbolic = BsymbolicKind::None; bool callGraphProfileSort; bool checkSections; + bool checkDynamicRelocs; bool compressDebugSections; bool cref; std::vector<std::pair<llvm::GlobPattern, uint64_t>> deadRelocInNonAlloc; @@ -159,6 +169,7 @@ struct Configuration { bool fixCortexA53Errata843419; bool fixCortexA8; bool formatBinary = false; + bool fortranCommon; bool gcSections; bool gdbIndex; bool gnuHash = false; @@ -170,6 +181,7 @@ struct Configuration { bool ltoDebugPassManager; bool ltoEmitAsm; bool ltoNewPassManager; + bool ltoPseudoProbeForProfiling; bool ltoUniqueBasicBlockSectionNames; bool ltoWholeProgramVisibility; bool mergeArmExidx; @@ -181,6 +193,8 @@ struct Configuration { bool nostdlib; bool oFormatBinary; bool omagic; + bool optEB = false; + bool optEL = false; bool optimizeBBJumps; bool optRemarksWithHotness; bool picThunk; @@ -190,7 +204,7 @@ struct Configuration { bool relocatable; bool relrPackDynRelocs; bool saveTemps; - llvm::Optional<uint32_t> shuffleSectionSeed; + std::vector<std::pair<llvm::GlobPattern, uint32_t>> shuffleSections; bool singleRoRx; bool shared; bool symbolic; @@ -202,13 +216,13 @@ struct Configuration { bool thinLTOIndexOnly; bool timeTraceEnabled; bool tocOptimize; + bool pcRelOptimize; bool undefinedVersion; bool unique; bool useAndroidRelrTags = false; bool warnBackrefs; std::vector<llvm::GlobPattern> warnBackrefsExclude; bool warnCommon; - bool warnIfuncTextrel; bool warnMissingEntry; bool warnSymbolOrdering; bool writeAddends; @@ -231,6 +245,7 @@ struct Configuration { bool zRelro; bool zRodynamic; bool zShstk; + bool zStartStopGC; uint8_t zStartStopVisibility; bool zText; bool zRetpolineplt; @@ -242,7 +257,9 @@ struct Configuration { SortSectionPolicy sortSection; StripPolicy strip; UnresolvedPolicy unresolvedSymbols; + UnresolvedPolicy unresolvedSymbolsInShlib; Target2Policy target2; + bool Power10Stub; ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default; BuildIdKind buildId = BuildIdKind::None; SeparateSegmentKind zSeparate; @@ -350,6 +367,12 @@ static inline void errorOrWarn(const Twine &msg) { else warn(msg); } + +static inline void internalLinkerError(StringRef loc, const Twine &msg) { + errorOrWarn(loc + "internal linker error: " + msg + "\n" + + llvm::getBugReportMsg()); +} + } // namespace elf } // namespace lld diff --git a/gnu/llvm/lld/ELF/Driver.cpp b/gnu/llvm/lld/ELF/Driver.cpp index dc06998cc37..633cc3d5143 100644 --- a/gnu/llvm/lld/ELF/Driver.cpp +++ b/gnu/llvm/lld/ELF/Driver.cpp @@ -47,7 +47,9 @@ #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/Remarks/HotnessThresholdParser.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/GlobPattern.h" @@ -80,6 +82,27 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly, lld::stdoutOS = &stdoutOS; lld::stderrOS = &stderrOS; + errorHandler().cleanupCallback = []() { + freeArena(); + + inputSections.clear(); + outputSections.clear(); + archiveFiles.clear(); + binaryFiles.clear(); + bitcodeFiles.clear(); + lazyObjFiles.clear(); + objectFiles.clear(); + sharedFiles.clear(); + backwardReferences.clear(); + + tar = nullptr; + memset(&in, 0, sizeof(in)); + + partitions = {Partition()}; + + SharedFile::vernauxNum = 0; + }; + errorHandler().logName = args::getFilenameWithoutExe(args[0]); errorHandler().errorLimitExceededMsg = "too many errors emitted, stopping now (use " @@ -87,31 +110,16 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly, errorHandler().exitEarly = canExitEarly; stderrOS.enable_colors(stderrOS.has_colors()); - inputSections.clear(); - outputSections.clear(); - archiveFiles.clear(); - binaryFiles.clear(); - bitcodeFiles.clear(); - lazyObjFiles.clear(); - objectFiles.clear(); - sharedFiles.clear(); - backwardReferences.clear(); - config = make<Configuration>(); driver = make<LinkerDriver>(); script = make<LinkerScript>(); symtab = make<SymbolTable>(); - tar = nullptr; - memset(&in, 0, sizeof(in)); - partitions = {Partition()}; - SharedFile::vernauxNum = 0; - config->progName = args[0]; - driver->main(args); + driver->linkerMain(args); // Exit immediately if we don't need to return to the caller. // This saves time because the overhead of calling destructors @@ -119,8 +127,10 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly, if (canExitEarly) exitLld(errorCount() ? 1 : 0); - freeArena(); - return !errorCount(); + bool ret = errorCount() == 0; + if (!canExitEarly) + errorHandler().reset(); + return ret; } // Parses a linker -m option. @@ -134,14 +144,15 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) { std::pair<ELFKind, uint16_t> ret = StringSwitch<std::pair<ELFKind, uint16_t>>(s) - .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec", - {ELF64LEKind, EM_AARCH64}) + .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) + .Cases("aarch64elfb", "aarch64linuxb", {ELF64BEKind, EM_AARCH64}) .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS}) .Case("elf32lriscv", {ELF32LEKind, EM_RISCV}) .Cases("elf32ppc", "elf32ppclinux", {ELF32BEKind, EM_PPC}) + .Cases("elf32lppc", "elf32lppclinux", {ELF32LEKind, EM_PPC}) .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) .Case("elf64lriscv", {ELF64LEKind, EM_RISCV}) @@ -151,10 +162,13 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) { .Case("elf_i386", {ELF32LEKind, EM_386}) .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) .Case("elf64_sparc", {ELF64BEKind, EM_SPARCV9}) + .Case("msp430elf", {ELF32LEKind, EM_MSP430}) .Default({ELFNoneKind, EM_NONE}); if (ret.first == ELFNoneKind) error("unknown emulation: " + emul); + if (ret.second == EM_MSP430) + osabi = ELFOSABI_STANDALONE; return std::make_tuple(ret.first, ret.second, osabi); } @@ -278,7 +292,7 @@ void LinkerDriver::addLibrary(StringRef name) { if (Optional<std::string> path = searchLibrary(name)) addFile(*path, /*withLOption=*/true); else - error("unable to find library -l" + name); + error("unable to find library -l" + name, ErrorTag::LibNotFound, {name}); } // This function is called on startup. We need this for LTO since @@ -307,7 +321,10 @@ static void checkOptions() { error("--fix-cortex-a8 is only supported on ARM targets"); if (config->tocOptimize && config->emachine != EM_PPC64) - error("--toc-optimize is only supported on the PowerPC64 target"); + error("--toc-optimize is only supported on PowerPC64 targets"); + + if (config->pcRelOptimize && config->emachine != EM_PPC64) + error("--pcrel-optimize is only supported on PowerPC64 targets"); if (config->pie && config->shared) error("-shared and -pie may not be used together"); @@ -330,8 +347,6 @@ static void checkOptions() { if (config->relocatable) { if (config->shared) error("-r and -shared may not be used together"); - if (config->gcSections) - error("-r and --gc-sections may not be used together"); if (config->gdbIndex) error("-r and --gdb-index may not be used together"); if (config->icf != ICFLevel::None) @@ -436,11 +451,12 @@ static bool isKnownZFlag(StringRef s) { s == "initfirst" || s == "interpose" || s == "keep-text-section-prefix" || s == "lazy" || s == "muldefs" || s == "separate-code" || s == "separate-loadable-segments" || - s == "nocombreloc" || s == "nocopyreloc" || s == "nodefaultlib" || - s == "nodelete" || s == "nodlopen" || s == "noexecstack" || - s == "nognustack" || s == "nokeep-text-section-prefix" || - s == "norelro" || s == "noretpolineplt" || - s == "noseparate-code" || s == "notext" || + s == "start-stop-gc" || s == "nocombreloc" || s == "nocopyreloc" || + s == "nodefaultlib" || s == "nodelete" || s == "nodlopen" || + s == "noexecstack" || s == "nognustack" || + s == "nokeep-text-section-prefix" || s == "norelro" || + s == "noretpolineplt" || + s == "noseparate-code" || s == "nostart-stop-gc" || s == "notext" || s == "now" || s == "origin" || s == "pac-plt" || s == "rel" || s == "rela" || s == "relro" || s == "retpolineplt" || s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" || @@ -457,7 +473,7 @@ static void checkZOptions(opt::InputArgList &args) { error("unknown -z value: " + StringRef(arg->getValue())); } -void LinkerDriver::main(ArrayRef<const char *> argsArr) { +void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { ELFOptTable parser; opt::InputArgList args = parser.parse(argsArr.slice(1)); @@ -498,6 +514,9 @@ void LinkerDriver::main(ArrayRef<const char *> argsArr) { tar = std::move(*errOrWriter); tar->append("response.txt", createResponseFile(args)); tar->append("version.txt", getLLDVersion() + "\n"); + StringRef ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile); + if (!ltoSampleProfile.empty()) + readFile(ltoSampleProfile); } else { error("--reproduce: " + toString(errOrWriter.takeError())); } @@ -573,40 +592,58 @@ static std::string getRpath(opt::InputArgList &args) { // Determines what we should do if there are remaining unresolved // symbols after the name resolution. -static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) { +static void setUnresolvedSymbolPolicy(opt::InputArgList &args) { UnresolvedPolicy errorOrWarn = args.hasFlag(OPT_error_unresolved_symbols, OPT_warn_unresolved_symbols, true) ? UnresolvedPolicy::ReportError : UnresolvedPolicy::Warn; + // -shared implies -unresolved-symbols=ignore-all because missing + // symbols are likely to be resolved at runtime. + bool diagRegular = !config->shared, diagShlib = false; - // Process the last of -unresolved-symbols, -no-undefined or -z defs. - for (auto *arg : llvm::reverse(args)) { + for (const opt::Arg *arg : args) { switch (arg->getOption().getID()) { case OPT_unresolved_symbols: { StringRef s = arg->getValue(); - if (s == "ignore-all" || s == "ignore-in-object-files") - return UnresolvedPolicy::Ignore; - if (s == "ignore-in-shared-libs" || s == "report-all") - return errorOrWarn; - error("unknown --unresolved-symbols value: " + s); - continue; + if (s == "ignore-all") { + diagRegular = false; + diagShlib = false; + } else if (s == "ignore-in-object-files") { + diagRegular = false; + diagShlib = true; + } else if (s == "ignore-in-shared-libs") { + diagRegular = true; + diagShlib = false; + } else if (s == "report-all") { + diagRegular = true; + diagShlib = true; + } else { + error("unknown --unresolved-symbols value: " + s); + } + break; } case OPT_no_undefined: - return errorOrWarn; + diagRegular = true; + break; case OPT_z: if (StringRef(arg->getValue()) == "defs") - return errorOrWarn; - if (StringRef(arg->getValue()) == "undefs") - return UnresolvedPolicy::Ignore; - continue; + diagRegular = true; + else if (StringRef(arg->getValue()) == "undefs") + diagRegular = false; + break; + case OPT_allow_shlib_undefined: + diagShlib = false; + break; + case OPT_no_allow_shlib_undefined: + diagShlib = true; + break; } } - // -shared implies -unresolved-symbols=ignore-all because missing - // symbols are likely to be resolved at runtime using other DSOs. - if (config->shared) - return UnresolvedPolicy::Ignore; - return errorOrWarn; + config->unresolvedSymbols = + diagRegular ? errorOrWarn : UnresolvedPolicy::Ignore; + config->unresolvedSymbolsInShlib = + diagShlib ? errorOrWarn : UnresolvedPolicy::Ignore; } static Target2Policy getTarget2(opt::InputArgList &args) { @@ -725,6 +762,20 @@ static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &args) { return OrphanHandlingPolicy::Place; } +// Parses --power10-stubs= flags, to disable or enable Power 10 +// instructions in stubs. +static bool getP10StubOpt(opt::InputArgList &args) { + + if (args.getLastArgValue(OPT_power10_stubs_eq)== "no") + return false; + + if (!args.hasArg(OPT_power10_stubs_eq) && + args.hasArg(OPT_no_power10_stubs)) + return false; + + return true; +} + // 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. @@ -805,13 +856,66 @@ 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) { + symbolIndices.clear(); + const ELFFile<ELFT> &obj = inputObj->getObj(); + ArrayRef<Elf_Shdr_Impl<ELFT>> objSections = + CHECK(obj.sections(), "could not retrieve object sections"); + + if (inputObj->cgProfileSectionIndex == SHN_UNDEF) + return false; + + cgProfile = + check(obj.template getSectionContentsAsArray<typename ELFT::CGProfile>( + objSections[inputObj->cgProfileSectionIndex])); + + for (size_t i = 0, e = objSections.size(); i < e; ++i) { + const Elf_Shdr_Impl<ELFT> &sec = objSections[i]; + if (sec.sh_info == inputObj->cgProfileSectionIndex) { + if (sec.sh_type == SHT_RELA) { + ArrayRef<typename ELFT::Rela> relas = + CHECK(obj.relas(sec), "could not retrieve cg profile rela section"); + for (const typename ELFT::Rela &rel : relas) + symbolIndices.push_back(rel.getSymbol(config->isMips64EL)); + break; + } + if (sec.sh_type == SHT_REL) { + ArrayRef<typename ELFT::Rel> rels = + CHECK(obj.rels(sec), "could not retrieve cg profile rel section"); + for (const typename ELFT::Rel &rel : rels) + symbolIndices.push_back(rel.getSymbol(config->isMips64EL)); + break; + } + } + } + if (symbolIndices.empty()) + warn("SHT_LLVM_CALL_GRAPH_PROFILE exists, but relocation section doesn't"); + return !symbolIndices.empty(); +} + template <class ELFT> static void readCallGraphsFromObjectFiles() { + SmallVector<uint32_t, 32> symbolIndices; + ArrayRef<typename ELFT::CGProfile> cgProfile; for (auto file : objectFiles) { auto *obj = cast<ObjFile<ELFT>>(file); + if (!processCallGraphRelocations(symbolIndices, cgProfile, obj)) + continue; + + if (symbolIndices.size() != cgProfile.size() * 2) + fatal("number of relocations doesn't match Weights"); - for (const Elf_CGProfile_Impl<ELFT> &cgpe : obj->cgProfile) { - auto *fromSym = dyn_cast<Defined>(&obj->getSymbol(cgpe.cgp_from)); - auto *toSym = dyn_cast<Defined>(&obj->getSymbol(cgpe.cgp_to)); + for (uint32_t i = 0, size = cgProfile.size(); i < size; ++i) { + const Elf_CGProfile_Impl<ELFT> &cgpe = cgProfile[i]; + uint32_t fromIndex = symbolIndices[i * 2]; + uint32_t toIndex = symbolIndices[i * 2 + 1]; + auto *fromSym = dyn_cast<Defined>(&obj->getSymbol(fromIndex)); + auto *toSym = dyn_cast<Defined>(&obj->getSymbol(toIndex)); if (!fromSym || !toSym) continue; @@ -902,22 +1006,28 @@ static void readConfigs(opt::InputArgList &args) { args.hasFlag(OPT_allow_multiple_definition, OPT_no_allow_multiple_definition, false) || hasZOption(args, "muldefs"); - config->allowShlibUndefined = - args.hasFlag(OPT_allow_shlib_undefined, OPT_no_allow_shlib_undefined, - args.hasArg(OPT_shared)); config->auxiliaryList = args::getStrings(args, OPT_auxiliary); - config->bsymbolic = args.hasArg(OPT_Bsymbolic); - config->bsymbolicFunctions = args.hasArg(OPT_Bsymbolic_functions); + if (opt::Arg *arg = + args.getLastArg(OPT_Bno_symbolic, OPT_Bsymbolic_non_weak_functions, + OPT_Bsymbolic_functions, OPT_Bsymbolic)) { + if (arg->getOption().matches(OPT_Bsymbolic_non_weak_functions)) + config->bsymbolic = BsymbolicKind::NonWeakFunctions; + else if (arg->getOption().matches(OPT_Bsymbolic_functions)) + config->bsymbolic = BsymbolicKind::Functions; + else if (arg->getOption().matches(OPT_Bsymbolic)) + config->bsymbolic = BsymbolicKind::All; + } config->checkSections = args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); config->chroot = args.getLastArgValue(OPT_chroot); config->compressDebugSections = getCompressDebugSections(args); - config->cref = args.hasFlag(OPT_cref, OPT_no_cref, false); + config->cref = args.hasArg(OPT_cref); config->defineCommon = args.hasFlag(OPT_define_common, OPT_no_define_common, !args.hasArg(OPT_relocatable)); config->optimizeBBJumps = args.hasFlag(OPT_optimize_bb_jumps, OPT_no_optimize_bb_jumps, false); config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true); + config->dependencyFile = args.getLastArgValue(OPT_dependency_file); config->dependentLibraries = args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true); config->disableVerify = args.hasArg(OPT_disable_verify); config->discard = getDiscard(args); @@ -932,6 +1042,10 @@ static void readConfigs(opt::InputArgList &args) { config->enableNewDtags = args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true); config->entry = args.getLastArgValue(OPT_entry); + + errorHandler().errorHandlingScript = + args.getLastArgValue(OPT_error_handling_script); + config->executeOnly = args.hasFlag(OPT_execute_only, OPT_no_execute_only, false); config->exportDynamic = @@ -942,6 +1056,8 @@ static void readConfigs(opt::InputArgList &args) { !args.hasArg(OPT_relocatable); config->fixCortexA8 = args.hasArg(OPT_fix_cortex_a8) && !args.hasArg(OPT_relocatable); + config->fortranCommon = + args.hasFlag(OPT_fortran_common, OPT_no_fortran_common, true); config->gcSections = args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); config->gnuUnique = args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true); config->gdbIndex = args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); @@ -957,19 +1073,24 @@ static void readConfigs(opt::InputArgList &args) { config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager); config->ltoEmitAsm = args.hasArg(OPT_lto_emit_asm); - config->ltoNewPassManager = args.hasArg(OPT_lto_new_pass_manager); + config->ltoNewPassManager = + args.hasFlag(OPT_no_lto_legacy_pass_manager, OPT_lto_legacy_pass_manager, + LLVM_ENABLE_NEW_PASS_MANAGER); config->ltoNewPmPasses = args.getLastArgValue(OPT_lto_newpm_passes); config->ltoWholeProgramVisibility = - args.hasArg(OPT_lto_whole_program_visibility); + args.hasFlag(OPT_lto_whole_program_visibility, + OPT_no_lto_whole_program_visibility, false); config->ltoo = args::getInteger(args, OPT_lto_O, 2); config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq); config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); + config->ltoPseudoProbeForProfiling = + args.hasArg(OPT_lto_pseudo_probe_for_profiling); config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile); config->ltoBasicBlockSections = - args.getLastArgValue(OPT_lto_basicblock_sections); + args.getLastArgValue(OPT_lto_basic_block_sections); config->ltoUniqueBasicBlockSectionNames = - args.hasFlag(OPT_lto_unique_bb_section_names, - OPT_no_lto_unique_bb_section_names, false); + args.hasFlag(OPT_lto_unique_basic_block_section_names, + OPT_no_lto_unique_basic_block_section_names, false); config->mapFile = args.getLastArgValue(OPT_Map); config->mipsGotSize = args::getInteger(args, OPT_mips_got_size, 0xfff0); config->mergeArmExidx = @@ -982,6 +1103,17 @@ static void readConfigs(opt::InputArgList &args) { config->oFormatBinary = isOutputFormatBinary(args); config->omagic = args.hasFlag(OPT_omagic, OPT_no_omagic, false); config->optRemarksFilename = args.getLastArgValue(OPT_opt_remarks_filename); + + // Parse remarks hotness threshold. Valid value is either integer or 'auto'. + if (auto *arg = args.getLastArg(OPT_opt_remarks_hotness_threshold)) { + auto resultOrErr = remarks::parseHotnessThresholdOption(arg->getValue()); + if (!resultOrErr) + error(arg->getSpelling() + ": invalid argument '" + arg->getValue() + + "', only integer or 'auto' is supported"); + else + config->optRemarksHotnessThreshold = *resultOrErr; + } + config->optRemarksPasses = args.getLastArgValue(OPT_opt_remarks_passes); config->optRemarksWithHotness = args.hasArg(OPT_opt_remarks_with_hotness); config->optRemarksFormat = args.getLastArgValue(OPT_opt_remarks_format); @@ -1004,8 +1136,6 @@ static void readConfigs(opt::InputArgList &args) { config->rpath = getRpath(args); config->relocatable = args.hasArg(OPT_relocatable); config->saveTemps = args.hasArg(OPT_save_temps); - if (args.hasArg(OPT_shuffle_sections)) - config->shuffleSectionSeed = args::getInteger(args, OPT_shuffle_sections, 0); config->searchPaths = args::getStrings(args, OPT_library_path); config->sectionStartMap = getSectionStartMap(args); config->shared = args.hasArg(OPT_shared); @@ -1041,12 +1171,9 @@ static void readConfigs(opt::InputArgList &args) { config->unique = args.hasArg(OPT_unique); config->useAndroidRelrTags = args.hasFlag( OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false); - config->unresolvedSymbols = getUnresolvedSymbolPolicy(args); config->warnBackrefs = args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); config->warnCommon = args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); - config->warnIfuncTextrel = - args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false); config->warnSymbolOrdering = args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); config->zCombreloc = getZFlag(args, "combreloc", "nocombreloc", true); @@ -1077,9 +1204,38 @@ static void readConfigs(opt::InputArgList &args) { config->zSeparate = getZSeparate(args); config->zShstk = hasZOption(args, "shstk"); config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0); + config->zStartStopGC = + getZFlag(args, "start-stop-gc", "nostart-stop-gc", true); config->zStartStopVisibility = getZStartStopVisibility(args); config->zText = getZFlag(args, "text", "notext", true); config->zWxneeded = hasZOption(args, "wxneeded"); + setUnresolvedSymbolPolicy(args); + config->Power10Stub = getP10StubOpt(args); + + if (opt::Arg *arg = args.getLastArg(OPT_eb, OPT_el)) { + if (arg->getOption().matches(OPT_eb)) + config->optEB = true; + else + config->optEL = true; + } + + for (opt::Arg *arg : args.filtered(OPT_shuffle_sections)) { + constexpr StringRef errPrefix = "--shuffle-sections=: "; + std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('='); + if (kv.first.empty() || kv.second.empty()) { + error(errPrefix + "expected <section_glob>=<seed>, but got '" + + arg->getValue() + "'"); + continue; + } + // Signed so that <section_glob>=-1 is allowed. + int64_t v; + if (!to_integer(kv.second, v)) + error(errPrefix + "expected an integer, but got '" + kv.second + "'"); + else if (Expected<GlobPattern> pat = GlobPattern::create(kv.first)) + config->shuffleSections.emplace_back(std::move(*pat), uint32_t(v)); + else + error(errPrefix + toString(pat.takeError())); + } for (opt::Arg *arg : args.filtered(OPT_z)) { std::pair<StringRef, StringRef> option = @@ -1102,6 +1258,8 @@ static void readConfigs(opt::InputArgList &args) { error(errPrefix + toString(pat.takeError())); } + cl::ResetAllOptionOccurrences(); + // Parse LTO options. if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq)) parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())), @@ -1204,18 +1362,19 @@ static void readConfigs(opt::InputArgList &args) { } assert(config->versionDefinitions.empty()); - config->versionDefinitions.push_back({"local", (uint16_t)VER_NDX_LOCAL, {}}); config->versionDefinitions.push_back( - {"global", (uint16_t)VER_NDX_GLOBAL, {}}); + {"local", (uint16_t)VER_NDX_LOCAL, {}, {}}); + config->versionDefinitions.push_back( + {"global", (uint16_t)VER_NDX_GLOBAL, {}, {}}); // If --retain-symbol-file is used, we'll keep only the symbols listed in // the file and discard all others. if (auto *arg = args.getLastArg(OPT_retain_symbols_file)) { - config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back( + config->versionDefinitions[VER_NDX_LOCAL].nonLocalPatterns.push_back( {"*", /*isExternCpp=*/false, /*hasWildcard=*/true}); if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())) for (StringRef s : args::getLines(*buffer)) - config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back( + config->versionDefinitions[VER_NDX_GLOBAL].nonLocalPatterns.push_back( {s, /*isExternCpp=*/false, /*hasWildcard=*/false}); } @@ -1228,10 +1387,10 @@ static void readConfigs(opt::InputArgList &args) { } // When producing an executable, --dynamic-list specifies non-local defined - // symbols whith are required to be exported. When producing a shared object, + // symbols which are required to be exported. When producing a shared object, // symbols not specified by --dynamic-list are non-preemptible. config->symbolic = - args.hasArg(OPT_Bsymbolic) || args.hasArg(OPT_dynamic_list); + config->bsymbolic == BsymbolicKind::All || args.hasArg(OPT_dynamic_list); for (auto *arg : args.filtered(OPT_dynamic_list)) if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())) readDynamicList(*buffer); @@ -1294,9 +1453,23 @@ static void setConfigs(opt::InputArgList &args) { config->writeAddends = args.hasFlag(OPT_apply_dynamic_relocs, OPT_no_apply_dynamic_relocs, false) || !config->isRela; - + // Validation of dynamic relocation addends is on by default for assertions + // builds (for supported targets) and disabled otherwise. Ideally we would + // enable the debug checks for all targets, but currently not all targets + // have support for reading Elf_Rel addends, so we only enable for a subset. +#ifndef NDEBUG + bool checkDynamicRelocsDefault = m == EM_ARM || m == EM_386 || m == EM_MIPS || + m == EM_X86_64 || m == EM_RISCV; +#else + bool checkDynamicRelocsDefault = false; +#endif + config->checkDynamicRelocs = + args.hasFlag(OPT_check_dynamic_relocations, + OPT_no_check_dynamic_relocations, checkDynamicRelocsDefault); config->tocOptimize = args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, m == EM_PPC64); + config->pcRelOptimize = + args.hasFlag(OPT_pcrel_optimize, OPT_no_pcrel_optimize, m == EM_PPC64); } // Returns a value of "-format" option. @@ -1311,10 +1484,12 @@ static bool isFormatBinary(StringRef s) { } void LinkerDriver::createFiles(opt::InputArgList &args) { + llvm::TimeTraceScope timeScope("Load input files"); // For --{push,pop}-state. std::vector<std::tuple<bool, bool, bool>> stack; // Iterate over argv to process input files and positional arguments. + InputFile::isInGroup = false; for (auto *arg : args) { switch (arg->getOption().getID()) { case OPT_library: @@ -1584,11 +1759,81 @@ static void handleLibcall(StringRef name) { sym->fetch(); } +// 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() { + std::error_code ec; + raw_fd_ostream os(config->dependencyFile, ec, sys::fs::OF_None); + if (ec) { + error("cannot open " + config->dependencyFile + ": " + ec.message()); + return; + } + + // We use the same escape rules as Clang/GCC which are accepted by Make/Ninja: + // * A space is escaped by a backslash which itself must be escaped. + // * A hash sign is escaped by a single backslash. + // * $ is escapes as $$. + auto printFilename = [](raw_fd_ostream &os, StringRef filename) { + llvm::SmallString<256> nativePath; + llvm::sys::path::native(filename.str(), nativePath); + llvm::sys::path::remove_dots(nativePath, /*remove_dot_dot=*/true); + for (unsigned i = 0, e = nativePath.size(); i != e; ++i) { + if (nativePath[i] == '#') { + os << '\\'; + } else if (nativePath[i] == ' ') { + os << '\\'; + unsigned j = i; + while (j > 0 && nativePath[--j] == '\\') + os << '\\'; + } else if (nativePath[i] == '$') { + os << '$'; + } + os << nativePath[i]; + } + }; + + os << config->outputFile << ":"; + for (StringRef path : config->dependencyFiles) { + os << " \\\n "; + printFilename(os, path); + } + os << "\n"; + + for (StringRef path : config->dependencyFiles) { + os << "\n"; + printFilename(os, path); + os << ":\n"; + } +} + // 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() { + llvm::TimeTraceScope timeScope("Replace common symbols"); for (Symbol *sym : symtab->symbols()) { auto *s = dyn_cast<CommonSymbol>(sym); if (!s) @@ -1608,6 +1853,7 @@ static void replaceCommonSymbols() { // created from the DSO. Otherwise, they become dangling references // that point to a non-existent DSO. static void demoteSharedSymbols() { + llvm::TimeTraceScope timeScope("Demote shared symbols"); for (Symbol *sym : symtab->symbols()) { auto *s = dyn_cast<SharedSymbol>(sym); if (!s || s->getFile().isNeeded) @@ -1663,7 +1909,7 @@ static void findKeepUniqueSections(opt::InputArgList &args) { ArrayRef<Symbol *> syms = obj->getSymbols(); if (obj->addrsigSec) { ArrayRef<uint8_t> contents = - check(obj->getObj().getSectionContents(obj->addrsigSec)); + check(obj->getObj().getSectionContents(*obj->addrsigSec)); const uint8_t *cur = contents.begin(); while (cur != contents.end()) { unsigned size; @@ -1737,8 +1983,9 @@ static Symbol *addUndefined(StringRef name) { Undefined{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0}); } -static Symbol *addUnusedUndefined(StringRef name) { - Undefined sym{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0}; +static Symbol *addUnusedUndefined(StringRef name, + uint8_t binding = STB_GLOBAL) { + Undefined sym{nullptr, name, binding, STV_DEFAULT, 0}; sym.isUsedInRegularObj = false; return symtab->addSymbol(sym); } @@ -1771,9 +2018,9 @@ template <class ELFT> void LinkerDriver::compileBitcodeFiles() { // 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 +// 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. @@ -1801,8 +2048,9 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) { if (!sym) continue; - Symbol *real = addUndefined(saver.save("__real_" + name)); - Symbol *wrap = addUndefined(saver.save("__wrap_" + name)); + Symbol *real = addUnusedUndefined(saver.save("__real_" + name)); + Symbol *wrap = + addUnusedUndefined(saver.save("__wrap_" + name), sym->binding); v.push_back({sym, real, wrap}); // We want to tell LTO not to inline symbols to be overwritten @@ -1812,22 +2060,72 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) { // Tell LTO not to eliminate these symbols. sym->isUsedInRegularObj = true; - wrap->isUsedInRegularObj = true; + // If sym is referenced in any object file, bitcode file or shared object, + // retain wrap which is the redirection target of sym. If the object file + // defining sym has sym references, we cannot easily distinguish the case + // from cases where sym is not referenced. Retain wrap because we choose to + // wrap sym references regardless of whether sym is defined + // (https://sourceware.org/bugzilla/show_bug.cgi?id=26358). + if (sym->referenced || sym->isDefined()) + wrap->isUsedInRegularObj = true; } return v; } -// Do renaming for -wrap by updating pointers to symbols. +// 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 wrapSymbols(ArrayRef<WrappedSymbol> wrapped) { +static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) { + llvm::TimeTraceScope timeScope("Redirect symbols"); DenseMap<Symbol *, Symbol *> map; for (const WrappedSymbol &w : wrapped) { map[w.sym] = w.wrap; map[w.real] = w.sym; } + for (Symbol *sym : symtab->symbols()) { + // Enumerate symbols with a non-default version (foo@v1). + StringRef name = sym->getName(); + const char *suffix1 = sym->getVersionSuffix(); + if (suffix1[0] != '@' || suffix1[1] == '@') + continue; + + // Check the existing symbol foo. We have two special cases to handle: + // + // * There is a definition of foo@v1 and foo@@v1. + // * There is a definition of foo@v1 and foo. + Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find(name)); + if (!sym2) + continue; + const char *suffix2 = sym2->getVersionSuffix(); + if (suffix2[0] == '@' && suffix2[1] == '@' && + strcmp(suffix1 + 1, suffix2 + 2) == 0) { + // foo@v1 and foo@@v1 should be merged, so redirect foo@v1 to foo@@v1. + map.try_emplace(sym, sym2); + // If both foo@v1 and foo@@v1 are defined and non-weak, report a duplicate + // definition error. + sym2->resolve(*sym); + // Eliminate foo@v1 from the symbol table. + sym->symbolKind = Symbol::PlaceholderKind; + } else if (auto *sym1 = dyn_cast<Defined>(sym)) { + if (sym2->versionId > VER_NDX_GLOBAL + ? config->versionDefinitions[sym2->versionId].name == suffix1 + 1 + : sym1->section == sym2->section && sym1->value == sym2->value) { + // Due to an assembler design flaw, if foo is defined, .symver foo, + // foo@v1 defines both foo and foo@v1. Unless foo is bound to a + // different version, GNU ld makes foo@v1 canonical and elimiates foo. + // Emulate its behavior, otherwise we would have foo or foo@@v1 beside + // foo@v1. foo@v1 and foo combining does not apply if they are not + // defined in the same place. + map.try_emplace(sym2, sym); + sym2->symbolKind = Symbol::PlaceholderKind; + } + } + } + + if (map.empty()) + return; // Update pointers in input files. parallelForEach(objectFiles, [&](InputFile *file) { @@ -1903,10 +2201,14 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // Fail early if the output file or map file is not writable. If a user has a // long link, e.g. due to a large LTO link, they do not wish to run it and // find that it failed because there was a mistake in their command-line. - if (auto e = tryCreateFile(config->outputFile)) - error("cannot open output file " + config->outputFile + ": " + e.message()); - if (auto e = tryCreateFile(config->mapFile)) - error("cannot open map file " + config->mapFile + ": " + e.message()); + { + llvm::TimeTraceScope timeScope("Create output files"); + if (auto e = tryCreateFile(config->outputFile)) + error("cannot open output file " + config->outputFile + ": " + + e.message()); + if (auto e = tryCreateFile(config->mapFile)) + error("cannot open map file " + config->mapFile + ": " + e.message()); + } if (errorCount()) return; @@ -1925,7 +2227,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // Handle -u/--undefined before input files. If both a.a and b.so define foo, // -u foo a.a b.so will fetch a.a. for (StringRef name : config->undefined) - addUnusedUndefined(name); + addUnusedUndefined(name)->referenced = true; // Add all files to the symbol table. This will add almost all // symbols that we need to the symbol table. This process might @@ -1933,8 +2235,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // appended to the Files vector. { llvm::TimeTraceScope timeScope("Parse input files"); - for (size_t i = 0; i < files.size(); ++i) + for (size_t i = 0; i < files.size(); ++i) { + llvm::TimeTraceScope timeScope("Parse input files", files[i]->getName()); parseFile(files[i]); + } } // Now that we have every file, we can decide if we will need a @@ -2000,7 +2304,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // They also might be exported if referenced by DSOs. script->declareSymbols(); - // Handle the -exclude-libs option. + // Handle --exclude-libs. This is before scanVersionScript() due to a + // workaround for Android ndk: for a defined versioned symbol in an archive + // without a version node in the version script, Android does not expect a + // 'has undefined version' error in -shared --exclude-libs=ALL mode (PR36295). + // GNU ld errors in this case. if (args.hasArg(OPT_exclude_libs)) excludeLibs(args); @@ -2021,8 +2329,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // For a relocatable output, version scripts don't make sense, and // parsing a symbol version string (e.g. dropping "@ver1" from a symbol // name "foo@ver1") rather do harm, so we don't call this if -r is given. - if (!config->relocatable) + if (!config->relocatable) { + llvm::TimeTraceScope timeScope("Process symbol versions"); symtab->scanVersionScript(); + } // Do link-time optimization if given files are LLVM bitcode files. // This compiles bitcode files into real object files. @@ -2031,6 +2341,12 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // except a few linker-synthesized ones will be added to the symbol table. compileBitcodeFiles<ELFT>(); + // Handle --exclude-libs again because lto.tmp may reference additional + // libcalls symbols defined in an excluded archive. This may override + // versionId set by scanVersionScript(). + if (args.hasArg(OPT_exclude_libs)) + excludeLibs(args); + // Symbol resolution finished. Report backward reference problems. reportBackrefs(); if (errorCount()) @@ -2041,48 +2357,58 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // in addCombinedLTOObject, so we are done if that's the case. // Likewise, --plugin-opt=emit-llvm and --plugin-opt=emit-asm are the // options to create output files in bitcode or assembly code - // repsectively. No object files are generated. + // respectively. No object files are generated. // Also bail out here when only certain thinLTO modules are specified for // compilation. The intermediate object file are the expected output. if (config->thinLTOIndexOnly || config->emitLLVM || config->ltoEmitAsm || !config->thinLTOModulesToCompile.empty()) return; - // Apply symbol renames for -wrap. - if (!wrapped.empty()) - wrapSymbols(wrapped); - - // Now that we have a complete list of input files. - // Beyond this point, no new files are added. - // Aggregate all input sections into one place. - for (InputFile *f : objectFiles) - for (InputSectionBase *s : f->getSections()) - if (s && s != &InputSection::discarded) - inputSections.push_back(s); - for (BinaryFile *f : binaryFiles) - for (InputSectionBase *s : f->getSections()) - inputSections.push_back(cast<InputSection>(s)); - - llvm::erase_if(inputSections, [](InputSectionBase *s) { - if (s->type == SHT_LLVM_SYMPART) { - readSymbolPartitionSection<ELFT>(s); - return true; - } + // Apply symbol renames for -wrap and combine foo@v1 and foo@@v1. + redirectSymbols(wrapped); - // We do not want to emit debug sections if --strip-all - // or -strip-debug are given. - if (config->strip == StripPolicy::None) - return false; + { + llvm::TimeTraceScope timeScope("Aggregate sections"); + // Now that we have a complete list of input files. + // Beyond this point, no new files are added. + // Aggregate all input sections into one place. + for (InputFile *f : objectFiles) + for (InputSectionBase *s : f->getSections()) + if (s && s != &InputSection::discarded) + inputSections.push_back(s); + for (BinaryFile *f : binaryFiles) + for (InputSectionBase *s : f->getSections()) + inputSections.push_back(cast<InputSection>(s)); + } - if (isDebugSection(*s)) - return true; - if (auto *isec = dyn_cast<InputSection>(s)) - if (InputSectionBase *rel = isec->getRelocatedSection()) - if (isDebugSection(*rel)) - return true; + { + llvm::TimeTraceScope timeScope("Strip sections"); + llvm::erase_if(inputSections, [](InputSectionBase *s) { + if (s->type == SHT_LLVM_SYMPART) { + readSymbolPartitionSection<ELFT>(s); + return true; + } - return false; - }); + // We do not want to emit debug sections if --strip-all + // or -strip-debug are given. + if (config->strip == StripPolicy::None) + return false; + + if (isDebugSection(*s)) + return true; + if (auto *isec = dyn_cast<InputSection>(s)) + if (InputSectionBase *rel = isec->getRelocatedSection()) + if (isDebugSection(*rel)) + return true; + + return false; + }); + } + + // Since we now have a complete set of input files, we can create + // a .d file to record build dependencies. + if (!config->dependencyFile.empty()) + writeDependencyFile(); // Now that the number of partitions is fixed, save a pointer to the main // partition. @@ -2154,23 +2480,33 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { if (!config->relocatable) combineEhSections(); - // Create output sections described by SECTIONS commands. - script->processSectionCommands(); - - // Linker scripts control how input sections are assigned to output sections. - // Input sections that were not handled by scripts are called "orphans", and - // they are assigned to output sections by the default rule. Process that. - script->addOrphanSections(); - - // Migrate InputSectionDescription::sectionBases to sections. This includes - // merging MergeInputSections into a single MergeSyntheticSection. From this - // point onwards InputSectionDescription::sections should be used instead of - // sectionBases. - for (BaseCommand *base : script->sectionCommands) - if (auto *sec = dyn_cast<OutputSection>(base)) - sec->finalizeInputSections(); - llvm::erase_if(inputSections, - [](InputSectionBase *s) { return isa<MergeInputSection>(s); }); + { + llvm::TimeTraceScope timeScope("Assign sections"); + + // Create output sections described by SECTIONS commands. + script->processSectionCommands(); + + // Linker scripts control how input sections are assigned to output + // sections. Input sections that were not handled by scripts are called + // "orphans", and they are assigned to output sections by the default rule. + // Process that. + script->addOrphanSections(); + } + + { + llvm::TimeTraceScope timeScope("Merge/finalize input sections"); + + // Migrate InputSectionDescription::sectionBases to sections. This includes + // merging MergeInputSections into a single MergeSyntheticSection. From this + // point onwards InputSectionDescription::sections should be used instead of + // sectionBases. + for (BaseCommand *base : script->sectionCommands) + if (auto *sec = dyn_cast<OutputSection>(base)) + sec->finalizeInputSections(); + llvm::erase_if(inputSections, [](InputSectionBase *s) { + return isa<MergeInputSection>(s); + }); + } // Two input sections with different output sections should not be folded. // ICF runs after processSectionCommands() so that we know the output sections. diff --git a/gnu/llvm/lld/ELF/DriverUtils.cpp b/gnu/llvm/lld/ELF/DriverUtils.cpp index c9b00c6a625..6b164e30677 100644 --- a/gnu/llvm/lld/ELF/DriverUtils.cpp +++ b/gnu/llvm/lld/ELF/DriverUtils.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/TimeProfiler.h" using namespace llvm; using namespace llvm::sys; @@ -132,7 +133,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) { if (missingCount) error(Twine(args.getArgString(missingIndex)) + ": missing argument"); - for (auto *arg : args.filtered(OPT_UNKNOWN)) { + for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) { std::string nearest; if (findNearest(arg->getAsString(args), nearest) > 1) error("unknown argument '" + arg->getAsString(args) + "'"); @@ -144,7 +145,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) { } void elf::printHelp() { - ELFOptTable().PrintHelp( + ELFOptTable().printHelp( lld::outs(), (config->progName + " [options] file...").str().c_str(), "lld", false /*ShowHidden*/, true /*ShowAllAliases*/); lld::outs() << "\n"; @@ -183,10 +184,16 @@ std::string elf::createResponseFile(const opt::InputArgList &args) { // fail because the archive we are creating doesn't contain empty // directories for the output path (-o doesn't create directories). // Strip directories to prevent the issue. - os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n"; + os << "-o " << quote(path::filename(arg->getValue())) << "\n"; break; + case OPT_lto_sample_profile: + os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << "\n"; + break; + case OPT_call_graph_ordering_file: case OPT_dynamic_list: + case OPT_just_symbols: case OPT_library_path: + case OPT_retain_symbols_file: case OPT_rpath: case OPT_script: case OPT_symbol_ordering_file: @@ -265,6 +272,7 @@ Optional<std::string> elf::searchLibraryBaseName(StringRef name) { // This is for -l<namespec>. Optional<std::string> elf::searchLibrary(StringRef name) { + llvm::TimeTraceScope timeScope("Locate library", name); if (name.startswith(":")) return findFromSearchPaths(name.substr(1)); return searchLibraryBaseName(name); diff --git a/gnu/llvm/lld/ELF/InputSection.cpp b/gnu/llvm/lld/ELF/InputSection.cpp index 9e341a6ae67..7d952e9037f 100644 --- a/gnu/llvm/lld/ELF/InputSection.cpp +++ b/gnu/llvm/lld/ELF/InputSection.cpp @@ -28,6 +28,7 @@ #include <algorithm> #include <mutex> #include <set> +#include <unordered_set> #include <vector> using namespace llvm; @@ -52,7 +53,7 @@ static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &file, const typename ELFT::Shdr &hdr) { if (hdr.sh_type == SHT_NOBITS) return makeArrayRef<uint8_t>(nullptr, hdr.sh_size); - return check(file.getObj().getSectionContents(&hdr)); + return check(file.getObj().getSectionContents(hdr)); } InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags, @@ -87,7 +88,22 @@ InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags, if (!zlib::isAvailable()) error(toString(file) + ": contains a compressed section, " + "but zlib is not available"); - parseCompressedHeader(); + switch (config->ekind) { + case ELF32LEKind: + parseCompressedHeader<ELF32LE>(); + break; + case ELF32BEKind: + parseCompressedHeader<ELF32BE>(); + break; + case ELF64LEKind: + parseCompressedHeader<ELF64LE>(); + break; + case ELF64BEKind: + parseCompressedHeader<ELF64BE>(); + break; + default: + llvm_unreachable("unknown ELFT"); + } } } @@ -209,10 +225,7 @@ OutputSection *SectionBase::getOutputSection() { // When a section is compressed, `rawData` consists with a header followed // by zlib-compressed data. This function parses a header to initialize // `uncompressedSize` member and remove the header from `rawData`. -void InputSectionBase::parseCompressedHeader() { - using Chdr64 = typename ELF64LE::Chdr; - using Chdr32 = typename ELF32LE::Chdr; - +template <typename ELFT> void InputSectionBase::parseCompressedHeader() { // Old-style header if (name.startswith(".zdebug")) { if (!toStringRef(rawData).startswith("ZLIB")) { @@ -238,32 +251,13 @@ void InputSectionBase::parseCompressedHeader() { assert(flags & SHF_COMPRESSED); flags &= ~(uint64_t)SHF_COMPRESSED; - // New-style 64-bit header - if (config->is64) { - if (rawData.size() < sizeof(Chdr64)) { - error(toString(this) + ": corrupted compressed section"); - return; - } - - auto *hdr = reinterpret_cast<const Chdr64 *>(rawData.data()); - if (hdr->ch_type != ELFCOMPRESS_ZLIB) { - error(toString(this) + ": unsupported compression type"); - return; - } - - uncompressedSize = hdr->ch_size; - alignment = std::max<uint32_t>(hdr->ch_addralign, 1); - rawData = rawData.slice(sizeof(*hdr)); - return; - } - - // New-style 32-bit header - if (rawData.size() < sizeof(Chdr32)) { + // New-style header + if (rawData.size() < sizeof(typename ELFT::Chdr)) { error(toString(this) + ": corrupted compressed section"); return; } - auto *hdr = reinterpret_cast<const Chdr32 *>(rawData.data()); + auto *hdr = reinterpret_cast<const typename ELFT::Chdr *>(rawData.data()); if (hdr->ch_type != ELFCOMPRESS_ZLIB) { error(toString(this) + ": unsupported compression type"); return; @@ -275,8 +269,9 @@ void InputSectionBase::parseCompressedHeader() { } InputSection *InputSectionBase::getLinkOrderDep() const { - assert(link); assert(flags & SHF_LINK_ORDER); + if (!link) + return nullptr; return cast<InputSection>(file->getSections()[link]); } @@ -389,11 +384,16 @@ template <class ELFT> void InputSection::copyShtGroup(uint8_t *buf) { // The first entry is not a section number but a flag. *to++ = from[0]; - // Adjust section numbers because section numbers in an input object - // files are different in the output. + // Adjust section numbers because section numbers in an input object files are + // different in the output. We also need to handle combined or discarded + // members. ArrayRef<InputSectionBase *> sections = file->getSections(); - for (uint32_t idx : from.slice(1)) - *to++ = sections[idx]->getOutputSection()->sectionIndex; + std::unordered_set<uint32_t> seen; + for (uint32_t idx : from.slice(1)) { + OutputSection *osec = sections[idx]->getOutputSection(); + if (osec && seen.insert(osec->sectionIndex).second) + *to++ = osec->sectionIndex; + } } InputSectionBase *InputSection::getRelocatedSection() const { @@ -449,7 +449,7 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) { Elf_Shdr_Impl<ELFT> sec = CHECK(file->getObj().sections(), file)[secIdx]; warn("relocation refers to a discarded section: " + - CHECK(file->getObj().getSectionName(&sec), file) + + CHECK(file->getObj().getSectionName(sec), file) + "\n>>> referenced by " + getObjMsg(p->r_offset)); } p->setSymbolAndType(0, 0, false); @@ -540,8 +540,7 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a, } // The comment above getARMUndefinedRelativeWeakVA applies to this function. -static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a, - uint64_t p) { +static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t p) { switch (type) { // Unresolved branch relocations to weak references resolve to next // instruction, this is 4 bytes on from P. @@ -549,7 +548,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a, case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: - return p + 4 + a; + return p + 4; // Unresolved non branch pc-relative relocations case R_AARCH64_PREL16: case R_AARCH64_PREL32: @@ -557,11 +556,25 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a, case R_AARCH64_ADR_PREL_LO21: case R_AARCH64_LD_PREL_LO19: case R_AARCH64_PLT32: - return p + a; + return p; } llvm_unreachable("AArch64 pc-relative relocation expected\n"); } +static uint64_t getRISCVUndefinedRelativeWeakVA(uint64_t type, uint64_t p) { + switch (type) { + case R_RISCV_BRANCH: + case R_RISCV_JAL: + case R_RISCV_CALL: + case R_RISCV_CALL_PLT: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: + return p; + default: + return 0; + } +} + // ARM SBREL relocations are of the form S + A - B where B is the static base // The ARM ABI defines base to be "addressing origin of the output segment // defining the symbol S". We defined the "addressing origin"/static base to be @@ -698,6 +711,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, case R_AARCH64_GOT_PAGE_PC: case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC: return getAArch64Page(sym.getGotVA() + a) - getAArch64Page(p); + case R_AARCH64_GOT_PAGE: + return sym.getGotVA() + a - getAArch64Page(in.got->getVA()); case R_GOT_PC: case R_RELAX_TLS_GD_TO_IE: return sym.getGotVA() + a - p; @@ -756,14 +771,18 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, // Some PC relative ARM (Thumb) relocations align down the place. p = p & 0xfffffffc; if (sym.isUndefWeak()) { - // On ARM and AArch64 a branch to an undefined weak resolves to the - // next instruction, otherwise the place. + // On ARM and AArch64 a branch to an undefined weak resolves to the next + // instruction, otherwise the place. On RISCV, resolve an undefined weak + // to the same instruction to cause an infinite loop (making the user + // aware of the issue) while ensuring no overflow. if (config->emachine == EM_ARM) dest = getARMUndefinedRelativeWeakVA(type, a, p); else if (config->emachine == EM_AARCH64) - dest = getAArch64UndefinedRelativeWeakVA(type, a, p); + dest = getAArch64UndefinedRelativeWeakVA(type, p) + a; else if (config->emachine == EM_PPC) dest = p; + else if (config->emachine == EM_RISCV) + dest = getRISCVUndefinedRelativeWeakVA(type, p) + a; else dest = sym.getVA(a); } else { @@ -800,11 +819,12 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, case R_PPC64_TOCBASE: return getPPC64TocBase() + a; case R_RELAX_GOT_PC: + case R_PPC64_RELAX_GOT_PC: return sym.getVA(a) - p; case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_LD_TO_LE: - case R_TLS: + case R_TPREL: // It is not very clear what to return if the symbol is undefined. With // --noinhibit-exec, even a non-weak undefined reference may reach here. // Just return A, which matches R_ABS, and the behavior of some dynamic @@ -813,7 +833,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, return a; return getTlsTpOffset(sym) + a; case R_RELAX_TLS_GD_TO_LE_NEG: - case R_NEG_TLS: + case R_TPREL_NEG: if (sym.isUndefined()) return a; return -getTlsTpOffset(sym) + a; @@ -829,7 +849,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, case R_TLSGD_GOT: return in.got->getGlobalDynOffset(sym) + a; case R_TLSGD_GOTPLT: - return in.got->getVA() + in.got->getGlobalDynOffset(sym) + a - in.gotPlt->getVA(); + return in.got->getGlobalDynAddr(sym) + a - in.gotPlt->getVA(); case R_TLSGD_PC: return in.got->getGlobalDynAddr(sym) + a - p; case R_TLSLD_GOTPLT: @@ -874,7 +894,7 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) { if (config->emachine == EM_386 && type == R_386_GOTPC) continue; - uint64_t offset = getOffset(rel.r_offset); + uint64_t offset = rel.r_offset; uint8_t *bufLoc = buf + offset; int64_t addend = getAddend<ELFT>(rel); if (!RelTy::IsRela) @@ -911,8 +931,9 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) { // address 0. For bug-compatibilty, we accept them with warnings. We // know Steel Bank Common Lisp as of 2018 have this bug. warn(msg); - target->relocateNoSym(bufLoc, type, - SignExtend64<bits>(sym.getVA(addend - offset))); + target->relocateNoSym( + bufLoc, type, + SignExtend64<bits>(sym.getVA(addend - offset - outSecOff))); continue; } @@ -971,7 +992,7 @@ static void relocateNonAllocForRelocatable(InputSection *sec, uint8_t *buf) { for (const Relocation &rel : sec->relocations) { // InputSection::copyRelocations() adds only R_ABS relocations. assert(rel.expr == R_ABS); - uint8_t *bufLoc = buf + rel.offset + sec->outSecOff; + uint8_t *bufLoc = buf + rel.offset; uint64_t targetVA = SignExtend64(rel.sym->getVA(rel.addend), bits); target->relocate(bufLoc, rel, targetVA); } @@ -999,17 +1020,18 @@ void InputSectionBase::relocate(uint8_t *buf, uint8_t *bufEnd) { void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { assert(flags & SHF_ALLOC); const unsigned bits = config->wordsize * 8; + uint64_t lastPPCRelaxedRelocOff = UINT64_C(-1); for (const Relocation &rel : relocations) { if (rel.expr == R_NONE) continue; uint64_t offset = rel.offset; - if (auto *sec = dyn_cast<InputSection>(this)) - offset += sec->outSecOff; uint8_t *bufLoc = buf + offset; RelType type = rel.type; uint64_t addrLoc = getOutputSection()->addr + offset; + if (auto *sec = dyn_cast<InputSection>(this)) + addrLoc += sec->outSecOff; RelExpr expr = rel.expr; uint64_t targetVA = SignExtend64( getRelocTargetVA(file, type, rel.addend, addrLoc, *rel.sym, expr), @@ -1020,6 +1042,20 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { case R_RELAX_GOT_PC_NOPIC: target->relaxGot(bufLoc, rel, targetVA); break; + case R_PPC64_RELAX_GOT_PC: { + // The R_PPC64_PCREL_OPT relocation must appear immediately after + // R_PPC64_GOT_PCREL34 in the relocations table at the same offset. + // We can only relax R_PPC64_PCREL_OPT if we have also relaxed + // the associated R_PPC64_GOT_PCREL34 since only the latter has an + // associated symbol. So save the offset when relaxing R_PPC64_GOT_PCREL34 + // and only relax the other if the saved offset matches. + if (type == R_PPC64_GOT_PCREL34) + lastPPCRelaxedRelocOff = offset; + if (type == R_PPC64_PCREL_OPT && offset != lastPPCRelaxedRelocOff) + break; + target->relaxGot(bufLoc, rel, targetVA); + break; + } case R_PPC64_RELAX_TOC: // rel.sym refers to the STT_SECTION symbol associated to the .toc input // section. If an R_PPC64_TOC16_LO (.toc + addend) references the TOC @@ -1083,9 +1119,9 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { // a jmp insn must be modified to shrink the jmp insn or to flip the jmp // insn. This is primarily used to relax and optimize jumps created with // basic block sections. - if (auto *sec = dyn_cast<InputSection>(this)) { + if (isa<InputSection>(this)) { for (const JumpInstrMod &jumpMod : jumpInstrMods) { - uint64_t offset = jumpMod.offset + sec->outSecOff; + uint64_t offset = jumpMod.offset; uint8_t *bufLoc = buf + offset; target->applyJumpInstrMod(bufLoc, jumpMod.original, jumpMod.size); } @@ -1183,8 +1219,8 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *buf, if (Defined *f = getEnclosingFunction<ELFT>(rel.offset)) { prologues.insert(f); - if (target->adjustPrologueForCrossSplitStack(buf + getOffset(f->value), - end, f->stOther)) + if (target->adjustPrologueForCrossSplitStack(buf + f->value, end, + f->stOther)) continue; if (!getFile<ELFT>()->someNoSplitStack) error(lld::toString(this) + ": " + f->getName() + @@ -1232,7 +1268,7 @@ template <class ELFT> void InputSection::writeTo(uint8_t *buf) { fatal(toString(this) + ": uncompress failed: " + llvm::toString(std::move(e))); uint8_t *bufEnd = buf + outSecOff + size; - relocate<ELFT>(buf, bufEnd); + relocate<ELFT>(buf + outSecOff, bufEnd); return; } @@ -1240,7 +1276,7 @@ template <class ELFT> void InputSection::writeTo(uint8_t *buf) { // and then apply relocations. memcpy(buf + outSecOff, data().data(), data().size()); uint8_t *bufEnd = buf + outSecOff + data().size(); - relocate<ELFT>(buf, bufEnd); + relocate<ELFT>(buf + outSecOff, bufEnd); } void InputSection::replace(InputSection *other) { @@ -1300,6 +1336,11 @@ template <class ELFT> void EhInputSection::split() { template <class ELFT, class RelTy> void EhInputSection::split(ArrayRef<RelTy> rels) { + // getReloc expects the relocations to be sorted by r_offset. See the comment + // in scanRelocs. + SmallVector<RelTy, 0> storage; + rels = sortRels(rels, storage); + unsigned relI = 0; for (size_t off = 0, end = data().size(); off != end;) { size_t size = readEhRecordSize(this, off); @@ -1403,8 +1444,7 @@ SectionPiece *MergeInputSection::getSectionPiece(uint64_t offset) { uint64_t MergeInputSection::getParentOffset(uint64_t offset) const { // If Offset is not at beginning of a section piece, it is not in the map. // In that case we need to search from the original section piece vector. - const SectionPiece &piece = - *(const_cast<MergeInputSection *>(this)->getSectionPiece (offset)); + const SectionPiece &piece = *getSectionPiece(offset); uint64_t addend = offset - piece.inputOff; return piece.outputOff + addend; } diff --git a/gnu/llvm/lld/ELF/LinkerScript.cpp b/gnu/llvm/lld/ELF/LinkerScript.cpp index 032cd4b6f02..d362cfc0919 100644 --- a/gnu/llvm/lld/ELF/LinkerScript.cpp +++ b/gnu/llvm/lld/ELF/LinkerScript.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TimeProfiler.h" #include <algorithm> #include <cassert> #include <cstddef> @@ -250,26 +251,34 @@ getChangedSymbolAssignment(const SymbolAssignmentMap &oldValues) { // Process INSERT [AFTER|BEFORE] commands. For each command, we move the // specified output section to the designated place. void LinkerScript::processInsertCommands() { + std::vector<OutputSection *> moves; for (const InsertCommand &cmd : insertCommands) { - // If cmd.os is empty, it may have been discarded by - // adjustSectionsBeforeSorting(). We do not handle such output sections. - auto from = llvm::find(sectionCommands, cmd.os); - if (from == sectionCommands.end()) - continue; - sectionCommands.erase(from); + for (StringRef name : cmd.names) { + // If base is empty, it may have been discarded by + // adjustSectionsBeforeSorting(). We do not handle such output sections. + auto from = llvm::find_if(sectionCommands, [&](BaseCommand *base) { + return isa<OutputSection>(base) && + cast<OutputSection>(base)->name == name; + }); + if (from == sectionCommands.end()) + continue; + moves.push_back(cast<OutputSection>(*from)); + sectionCommands.erase(from); + } auto insertPos = llvm::find_if(sectionCommands, [&cmd](BaseCommand *base) { auto *to = dyn_cast<OutputSection>(base); return to != nullptr && to->name == cmd.where; }); if (insertPos == sectionCommands.end()) { - error("unable to insert " + cmd.os->name + + error("unable to insert " + cmd.names[0] + (cmd.isAfter ? " after " : " before ") + cmd.where); } else { if (cmd.isAfter) ++insertPos; - sectionCommands.insert(insertPos, cmd.os); + sectionCommands.insert(insertPos, moves.begin(), moves.end()); } + moves.clear(); } } @@ -320,20 +329,33 @@ void LinkerScript::assignSymbol(SymbolAssignment *cmd, bool inSec) { cmd->sym->type = v.type; } -static std::string getFilename(InputFile *file) { - if (!file) - return ""; - if (file->archiveName.empty()) - return std::string(file->getName()); - return (file->archiveName + ':' + file->getName()).str(); +static inline StringRef getFilename(const InputFile *file) { + return file ? file->getNameForScript() : StringRef(); } -bool LinkerScript::shouldKeep(InputSectionBase *s) { - if (keptSections.empty()) +bool InputSectionDescription::matchesFile(const InputFile *file) const { + if (filePat.isTrivialMatchAll()) + return true; + + if (!matchesFileCache || matchesFileCache->first != file) + matchesFileCache.emplace(file, filePat.match(getFilename(file))); + + return matchesFileCache->second; +} + +bool SectionPattern::excludesFile(const InputFile *file) const { + if (excludedFilePat.empty()) return false; - std::string filename = getFilename(s->file); + + if (!excludesFileCache || excludesFileCache->first != file) + excludesFileCache.emplace(file, excludedFilePat.match(getFilename(file))); + + return excludesFileCache->second; +} + +bool LinkerScript::shouldKeep(InputSectionBase *s) { for (InputSectionDescription *id : keptSections) - if (id->filePat.match(filename)) + if (id->matchesFile(s->file)) for (SectionPattern &p : id->sectionPatterns) if (p.sectionPat.match(s->name) && (s->flags & id->withFlags) == id->withFlags && @@ -395,15 +417,16 @@ static void sortSections(MutableArrayRef<InputSectionBase *> vec, // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. // 4. If no SORT command is given, sort according to --sort-section. static void sortInputSections(MutableArrayRef<InputSectionBase *> vec, - const SectionPattern &pat) { - if (pat.sortOuter == SortSectionPolicy::None) + SortSectionPolicy outer, + SortSectionPolicy inner) { + if (outer == SortSectionPolicy::None) return; - if (pat.sortInner == SortSectionPolicy::Default) + if (inner == SortSectionPolicy::Default) sortSections(vec, config->sortSection); else - sortSections(vec, pat.sortInner); - sortSections(vec, pat.sortOuter); + sortSections(vec, inner); + sortSections(vec, outer); } // Compute and remember which sections the InputSectionDescription matches. @@ -411,13 +434,27 @@ std::vector<InputSectionBase *> LinkerScript::computeInputSections(const InputSectionDescription *cmd, ArrayRef<InputSectionBase *> sections) { std::vector<InputSectionBase *> ret; + std::vector<size_t> indexes; + DenseSet<size_t> seen; + auto sortByPositionThenCommandLine = [&](size_t begin, size_t end) { + llvm::sort(MutableArrayRef<size_t>(indexes).slice(begin, end - begin)); + for (size_t i = begin; i != end; ++i) + ret[i] = sections[indexes[i]]; + sortInputSections( + MutableArrayRef<InputSectionBase *>(ret).slice(begin, end - begin), + config->sortSection, SortSectionPolicy::None); + }; // Collects all sections that satisfy constraints of Cmd. + size_t sizeAfterPrevSort = 0; for (const SectionPattern &pat : cmd->sectionPatterns) { - size_t sizeBefore = ret.size(); + size_t sizeBeforeCurrPat = ret.size(); - for (InputSectionBase *sec : sections) { - if (!sec->isLive() || sec->parent) + for (size_t i = 0, e = sections.size(); i != e; ++i) { + // Skip if the section is dead or has been matched by a previous input + // section description or a previous pattern. + InputSectionBase *sec = sections[i]; + if (!sec->isLive() || sec->parent || seen.contains(i)) continue; // For -emit-relocs we have to ignore entries like @@ -433,19 +470,37 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd, if (!pat.sectionPat.match(sec->name)) continue; - std::string filename = getFilename(sec->file); - if (!cmd->filePat.match(filename) || - pat.excludedFilePat.match(filename) || + if (!cmd->matchesFile(sec->file) || pat.excludesFile(sec->file) || (sec->flags & cmd->withFlags) != cmd->withFlags || (sec->flags & cmd->withoutFlags) != 0) continue; ret.push_back(sec); + indexes.push_back(i); + seen.insert(i); } + if (pat.sortOuter == SortSectionPolicy::Default) + continue; + + // Matched sections are ordered by radix sort with the keys being (SORT*, + // --sort-section, input order), where SORT* (if present) is most + // significant. + // + // Matched sections between the previous SORT* and this SORT* are sorted by + // (--sort-alignment, input order). + sortByPositionThenCommandLine(sizeAfterPrevSort, sizeBeforeCurrPat); + // Matched sections by this SORT* pattern are sorted using all 3 keys. + // ret[sizeBeforeCurrPat,ret.size()) are already in the input order, so we + // just sort by sortOuter and sortInner. sortInputSections( - MutableArrayRef<InputSectionBase *>(ret).slice(sizeBefore), pat); + MutableArrayRef<InputSectionBase *>(ret).slice(sizeBeforeCurrPat), + pat.sortOuter, pat.sortInner); + sizeAfterPrevSort = ret.size(); } + // Matched sections after the last SORT* are sorted by (--sort-alignment, + // input order). + sortByPositionThenCommandLine(sizeAfterPrevSort, ret.size()); return ret; } @@ -500,52 +555,73 @@ LinkerScript::createInputSectionList(OutputSection &outCmd) { // Create output sections described by SECTIONS commands. void LinkerScript::processSectionCommands() { - size_t i = 0; - for (BaseCommand *base : sectionCommands) { - if (auto *sec = dyn_cast<OutputSection>(base)) { - std::vector<InputSectionBase *> v = createInputSectionList(*sec); - - // The output section name `/DISCARD/' is special. - // Any input section assigned to it is discarded. - if (sec->name == "/DISCARD/") { - for (InputSectionBase *s : v) - discard(s); - discardSynthetic(*sec); - sec->sectionCommands.clear(); - continue; - } + auto process = [this](OutputSection *osec) { + std::vector<InputSectionBase *> v = createInputSectionList(*osec); + + // The output section name `/DISCARD/' is special. + // Any input section assigned to it is discarded. + if (osec->name == "/DISCARD/") { + for (InputSectionBase *s : v) + discard(s); + discardSynthetic(*osec); + osec->sectionCommands.clear(); + return false; + } - // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive - // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input - // sections satisfy a given constraint. If not, a directive is handled - // as if it wasn't present from the beginning. - // - // Because we'll iterate over SectionCommands many more times, the easy - // way to "make it as if it wasn't present" is to make it empty. - if (!matchConstraints(v, sec->constraint)) { - for (InputSectionBase *s : v) - s->parent = nullptr; - sec->sectionCommands.clear(); - continue; - } + // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive + // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input + // sections satisfy a given constraint. If not, a directive is handled + // as if it wasn't present from the beginning. + // + // Because we'll iterate over SectionCommands many more times, the easy + // way to "make it as if it wasn't present" is to make it empty. + if (!matchConstraints(v, osec->constraint)) { + for (InputSectionBase *s : v) + s->parent = nullptr; + osec->sectionCommands.clear(); + return false; + } - // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign - // is given, input sections are aligned to that value, whether the - // given value is larger or smaller than the original section alignment. - if (sec->subalignExpr) { - uint32_t subalign = sec->subalignExpr().getValue(); - for (InputSectionBase *s : v) - s->alignment = subalign; - } + // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign + // is given, input sections are aligned to that value, whether the + // given value is larger or smaller than the original section alignment. + if (osec->subalignExpr) { + uint32_t subalign = osec->subalignExpr().getValue(); + for (InputSectionBase *s : v) + s->alignment = subalign; + } - // Set the partition field the same way OutputSection::recordSection() - // does. Partitions cannot be used with the SECTIONS command, so this is - // always 1. - sec->partition = 1; + // Set the partition field the same way OutputSection::recordSection() + // does. Partitions cannot be used with the SECTIONS command, so this is + // always 1. + osec->partition = 1; + return true; + }; - sec->sectionIndex = i++; + // Process OVERWRITE_SECTIONS first so that it can overwrite the main script + // or orphans. + DenseMap<StringRef, OutputSection *> map; + size_t i = 0; + for (OutputSection *osec : overwriteSections) + if (process(osec) && !map.try_emplace(osec->name, osec).second) + warn("OVERWRITE_SECTIONS specifies duplicate " + osec->name); + for (BaseCommand *&base : sectionCommands) + if (auto *osec = dyn_cast<OutputSection>(base)) { + if (OutputSection *overwrite = map.lookup(osec->name)) { + log(overwrite->location + " overwrites " + osec->name); + overwrite->sectionIndex = i++; + base = overwrite; + } else if (process(osec)) { + osec->sectionIndex = i++; + } } - } + + // If an OVERWRITE_SECTIONS specified output section is not in + // sectionCommands, append it to the end. The section will be inserted by + // orphan placement. + for (OutputSection *osec : overwriteSections) + if (osec->partition == 1 && osec->sectionIndex == UINT32_MAX) + sectionCommands.push_back(osec); } void LinkerScript::processSymbolAssignments() { @@ -725,7 +801,7 @@ void LinkerScript::addOrphanSections() { add(depSec); }; - // For futher --emit-reloc handling code we need target output section + // For further --emit-reloc handling code we need target output section // to be created before we create relocation output section, so we want // to create target sections first. We do not want priority handling // for synthetic sections because them are special. @@ -754,6 +830,9 @@ void LinkerScript::addOrphanSections() { } void LinkerScript::diagnoseOrphanHandling() const { + llvm::TimeTraceScope timeScope("Diagnose orphan sections"); + if (config->orphanHandling == OrphanHandlingPolicy::Place) + return; for (const InputSectionBase *sec : orphanSections) { // Input SHT_REL[A] retained by --emit-relocs are ignored by // computeInputSections(). Don't warn/error. @@ -764,23 +843,14 @@ void LinkerScript::diagnoseOrphanHandling() const { StringRef name = getOutputSectionName(sec); if (config->orphanHandling == OrphanHandlingPolicy::Error) error(toString(sec) + " is being placed in '" + name + "'"); - else if (config->orphanHandling == OrphanHandlingPolicy::Warn) + else warn(toString(sec) + " is being placed in '" + name + "'"); } } uint64_t LinkerScript::advance(uint64_t size, unsigned alignment) { - bool isTbss = - (ctx->outSec->flags & SHF_TLS) && ctx->outSec->type == SHT_NOBITS; - uint64_t start = isTbss ? dot + ctx->threadBssOffset : dot; - start = alignTo(start, alignment); - uint64_t end = start + size; - - if (isTbss) - ctx->threadBssOffset = end - dot; - else - dot = end; - return end; + dot = alignTo(dot, alignment) + size; + return dot; } void LinkerScript::output(InputSection *s) { @@ -852,26 +922,37 @@ static OutputSection *findFirstSection(PhdrEntry *load) { // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). void LinkerScript::assignOffsets(OutputSection *sec) { - if (!(sec->flags & SHF_ALLOC)) - dot = 0; - + const bool isTbss = (sec->flags & SHF_TLS) && sec->type == SHT_NOBITS; const bool sameMemRegion = ctx->memRegion == sec->memRegion; const bool prevLMARegionIsDefault = ctx->lmaRegion == nullptr; + const uint64_t savedDot = dot; ctx->memRegion = sec->memRegion; ctx->lmaRegion = sec->lmaRegion; - if (ctx->memRegion) - dot = ctx->memRegion->curPos; - if ((sec->flags & SHF_ALLOC) && sec->addrExpr) - setDot(sec->addrExpr, sec->location, false); - - // If the address of the section has been moved forward by an explicit - // expression so that it now starts past the current curPos of the enclosing - // region, we need to expand the current region to account for the space - // between the previous section, if any, and the start of this section. - if (ctx->memRegion && ctx->memRegion->curPos < dot) - expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos, - ctx->memRegion->name, sec->name); + if (!(sec->flags & SHF_ALLOC)) { + // Non-SHF_ALLOC sections have zero addresses. + dot = 0; + } else if (isTbss) { + // Allow consecutive SHF_TLS SHT_NOBITS output sections. The address range + // starts from the end address of the previous tbss section. + if (ctx->tbssAddr == 0) + ctx->tbssAddr = dot; + else + dot = ctx->tbssAddr; + } else { + if (ctx->memRegion) + dot = ctx->memRegion->curPos; + if (sec->addrExpr) + setDot(sec->addrExpr, sec->location, false); + + // If the address of the section has been moved forward by an explicit + // expression so that it now starts past the current curPos of the enclosing + // region, we need to expand the current region to account for the space + // between the previous section, if any, and the start of this section. + if (ctx->memRegion && ctx->memRegion->curPos < dot) + expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos, + ctx->memRegion->name, sec->name); + } // ctx->lmaOffset is LMA minus VMA. If LMA is explicitly specified via AT() or @@ -924,17 +1005,22 @@ void LinkerScript::assignOffsets(OutputSection *sec) { for (InputSection *sec : cast<InputSectionDescription>(base)->sections) output(sec); } + + // Non-SHF_ALLOC sections do not affect the addresses of other OutputSections + // as they are not part of the process image. + if (!(sec->flags & SHF_ALLOC)) { + dot = savedDot; + } else if (isTbss) { + // NOBITS TLS sections are similar. Additionally save the end address. + ctx->tbssAddr = dot; + dot = savedDot; + } } static bool isDiscardable(OutputSection &sec) { if (sec.name == "/DISCARD/") return true; - // We do not remove empty sections that are explicitly - // assigned to any segment. - if (!sec.phdrs.empty()) - return false; - // We do not want to remove OutputSections with expressions that reference // symbols even if the OutputSection is empty. We want to ensure that the // expressions can be evaluated and report an error if they cannot. @@ -960,6 +1046,18 @@ static bool isDiscardable(OutputSection &sec) { return true; } +static void maybePropagatePhdrs(OutputSection &sec, + std::vector<StringRef> &phdrs) { + if (sec.phdrs.empty()) { + // To match the bfd linker script behaviour, only propagate program + // headers to sections that are allocated. + if (sec.flags & SHF_ALLOC) + sec.phdrs = phdrs; + } else { + phdrs = sec.phdrs; + } +} + void LinkerScript::adjustSectionsBeforeSorting() { // If the output section contains only symbol assignments, create a // corresponding output section. The issue is what to do with linker script @@ -983,6 +1081,7 @@ void LinkerScript::adjustSectionsBeforeSorting() { // the previous sections. Only a few flags are needed to keep the impact low. uint64_t flags = SHF_ALLOC; + std::vector<StringRef> defPhdrs; for (BaseCommand *&cmd : sectionCommands) { auto *sec = dyn_cast<OutputSection>(cmd); if (!sec) @@ -1005,6 +1104,18 @@ void LinkerScript::adjustSectionsBeforeSorting() { sec->flags = flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) | SHF_WRITE | SHF_EXECINSTR); + // The code below may remove empty output sections. We should save the + // specified program headers (if exist) and propagate them to subsequent + // sections which do not specify program headers. + // An example of such a linker script is: + // SECTIONS { .empty : { *(.empty) } :rw + // .foo : { *(.foo) } } + // Note: at this point the order of output sections has not been finalized, + // because orphans have not been inserted into their expected positions. We + // will handle them in adjustSectionsAfterSorting(). + if (sec->sectionIndex != UINT32_MAX) + maybePropagatePhdrs(*sec, defPhdrs); + if (isEmpty && isDiscardable(*sec)) { sec->markDead(); cmd = nullptr; @@ -1049,20 +1160,9 @@ void LinkerScript::adjustSectionsAfterSorting() { // Walk the commands and propagate the program headers to commands that don't // explicitly specify them. - for (BaseCommand *base : sectionCommands) { - auto *sec = dyn_cast<OutputSection>(base); - if (!sec) - continue; - - if (sec->phdrs.empty()) { - // To match the bfd linker script behaviour, only propagate program - // headers to sections that are allocated. - if (sec->flags & SHF_ALLOC) - sec->phdrs = defPhdrs; - } else { - defPhdrs = sec->phdrs; - } - } + for (BaseCommand *base : sectionCommands) + if (auto *sec = dyn_cast<OutputSection>(base)) + maybePropagatePhdrs(*sec, defPhdrs); } static uint64_t computeBase(uint64_t min, bool allocateHeaders) { diff --git a/gnu/llvm/lld/ELF/Options.td b/gnu/llvm/lld/ELF/Options.td index 470e92ab7aa..b13e0c50cc3 100644 --- a/gnu/llvm/lld/ELF/Options.td +++ b/gnu/llvm/lld/ELF/Options.td @@ -36,10 +36,15 @@ multiclass B<string name, string help1, string help2> { defm auxiliary: Eq<"auxiliary", "Set DT_AUXILIARY field to the specified name">; -def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">; +def Bno_symbolic: F<"Bno-symbolic">, HelpText<"Don't bind default visibility defined symbols locally for -shared (default)">; + +def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind default visibility defined symbols locally for -shared">; def Bsymbolic_functions: F<"Bsymbolic-functions">, - HelpText<"Bind defined function symbols locally">; + HelpText<"Bind default visibility defined function symbols locally for -shared">; + +def Bsymbolic_non_weak_functions: F<"Bsymbolic-non-weak-functions">, + HelpText<"Bind default visibility defined STB_GLOBAL function symbols locally for -shared">; def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">; @@ -64,6 +69,10 @@ defm optimize_bb_jumps: BB<"optimize-bb-jumps", "Remove direct jumps at the end to the next basic block", "Do not remove any direct jumps at the end to the next basic block (default)">; +defm fortran_common : BB<"fortran-common", + "Search archive members for definitions to override COMMON symbols (default)", + "Do not search archive members for definitions to override COMMON symbols">; + defm split_stack_adjust_size : Eq<"split-stack-adjust-size", "Specify adjustment to stack size when a split-stack function calls a " @@ -113,16 +122,14 @@ defm call_graph_profile_sort: BB<"call-graph-profile-sort", // -chroot doesn't have a help text because it is an internal option. def chroot: Separate<["--", "-"], "chroot">; -def color_diagnostics: F<"color-diagnostics">, - HelpText<"Alias for --color-diagnostics=always">; - +defm color_diagnostics: B<"color-diagnostics", + "Alias for --color-diagnostics=always", + "Alias for --color-diagnostics=never">; def color_diagnostics_eq: J<"color-diagnostics=">, - HelpText<"Use colors in diagnostics">, + HelpText<"Use colors in diagnostics (default: auto)">, MetaVarName<"[auto,always,never]">; -defm cref: B<"cref", - "Output cross reference table", - "Do not output cross reference table">; +def cref: FF<"cref">, HelpText<"Output cross reference table">; defm define_common: B<"define-common", "Assign space to common symbols", @@ -132,6 +139,9 @@ defm demangle: B<"demangle", "Demangle symbol names (default)", "Do not demangle symbol names">; +defm dependency_file: EEq<"dependency-file", "Write a dependency file">, + MetaVarName<"<file>">; + def disable_new_dtags: F<"disable-new-dtags">, HelpText<"Disable new dynamic tags">; @@ -152,6 +162,9 @@ defm dynamic_list : Eq<"dynamic-list", "shared object. Implies -Bsymbolic but does not set DF_SYMBOLIC">, MetaVarName<"<file>">; +def eb: F<"EB">, HelpText<"Select the big-endian format in OUTPUT_FORMAT">; +def el: F<"EL">, HelpText<"Select the little-endian format in OUTPUT_FORMAT">; + defm eh_frame_hdr: B<"eh-frame-hdr", "Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header", "Do not create .eh_frame_hdr section">; @@ -176,6 +189,9 @@ defm error_limit: def error_unresolved_symbols: F<"error-unresolved-symbols">, HelpText<"Report unresolved symbols as errors">; +defm error_handling_script: EEq<"error-handling-script", + "Specify an error handling script">; + defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">; defm execute_only: BB<"execute-only", @@ -269,9 +285,6 @@ def nmagic: F<"nmagic">, MetaVarName<"<magic>">, def nostdlib: F<"nostdlib">, HelpText<"Only search directories specified on the command line">; -def no_color_diagnostics: F<"no-color-diagnostics">, - HelpText<"Do not use colors in diagnostics">; - def no_dynamic_linker: F<"no-dynamic-linker">, HelpText<"Inhibit output of .interp section">; @@ -338,7 +351,9 @@ def push_state: F<"push-state">, def print_map: F<"print-map">, HelpText<"Print a link map to the standard output">; -defm reproduce: Eq<"reproduce", "Write a tar file containing input files and command line options to reproduce link">; +defm reproduce: + Eq<"reproduce", + "Write tar file containing inputs and command to reproduce link">; defm rosegment: BB<"rosegment", "Put read-only non-executable sections in their own segment (default)", @@ -370,7 +385,7 @@ def start_group: F<"start-group">, def start_lib: F<"start-lib">, HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">; -def strip_all: F<"strip-all">, HelpText<"Strip all symbols">; +def strip_all: F<"strip-all">, HelpText<"Strip all symbols. Implies --strip-debug">; def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; @@ -392,16 +407,20 @@ defm threads "Number of threads. '1' disables multi-threading. By default all " "available hardware threads are used">; -def time_trace: F<"time-trace">, HelpText<"Record time trace">; -def time_trace_file_eq: J<"time-trace-file=">, HelpText<"Specify time trace output file">; +def time_trace: FF<"time-trace">, HelpText<"Record time trace">; +def time_trace_file_eq: JJ<"time-trace-file=">, HelpText<"Specify time trace output file">; -defm time_trace_granularity: Eq<"time-trace-granularity", +defm time_trace_granularity: EEq<"time-trace-granularity", "Minimum time granularity (in microseconds) traced by time profiler">; -defm toc_optimize : B<"toc-optimize", +defm toc_optimize : BB<"toc-optimize", "(PowerPC64) Enable TOC related optimizations (default)", "(PowerPC64) Disable TOC related optimizations">; +defm pcrel_optimize : BB<"pcrel-optimize", + "(PowerPC64) Enable PC-relative optimizations (default)", + "(PowerPC64) Disable PC-relative optimizations">; + def trace: F<"trace">, HelpText<"Print the names of the input files">; defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">; @@ -409,7 +428,7 @@ defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">; defm undefined: Eq<"undefined", "Force undefined symbol during linking">, MetaVarName<"<symbol>">; -defm undefined_glob: Eq<"undefined-glob", "Force undefined symbol during linking">, +defm undefined_glob: EEq<"undefined-glob", "Force undefined symbol during linking">, MetaVarName<"<pattern>">; def unique: F<"unique">, HelpText<"Creates a separate output section for every orphan input section">; @@ -430,6 +449,17 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">; def version: F<"version">, HelpText<"Display the version number and exit">; +def power10_stubs: F<"power10-stubs">, HelpText<"Alias for --power10-stubs=auto">; + +def no_power10_stubs: F<"no-power10-stubs">, HelpText<"Alias for --power10-stubs=no">; + +def power10_stubs_eq: + J<"power10-stubs=">, HelpText< + "Enables Power10 instructions in all stubs without options, " + "options override previous flags." + "auto: Allow Power10 instructions in stubs if applicable." + "no: No Power10 instructions in stubs.">; + defm version_script: Eq<"version-script", "Read a version script">; defm warn_backrefs: BB<"warn-backrefs", @@ -461,8 +491,9 @@ defm whole_archive: B<"whole-archive", "Force load of all members in a static library", "Do not force load of all members in a static library (default)">; -defm wrap: Eq<"wrap", "Use wrapper functions for symbol">, - MetaVarName<"<symbol>=<symbol>">; +defm wrap : Eq<"wrap", "Redirect symbol references to __wrap_symbol and " + "__real_symbol references to symbol">, + MetaVarName<"<symbol>">; def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, HelpText<"Linker option extensions">; @@ -519,8 +550,9 @@ def lto_debug_pass_manager: FF<"lto-debug-pass-manager">, HelpText<"Debug new pass manager">; def lto_emit_asm: FF<"lto-emit-asm">, HelpText<"Emit assembly code">; -def lto_new_pass_manager: FF<"lto-new-pass-manager">, - HelpText<"Use new pass manager">; +defm lto_legacy_pass_manager: BB<"lto-legacy-pass-manager", + "Use the legacy pass manager in LLVM", + "Use the new pass manager in LLVM">; def lto_newpm_passes: JJ<"lto-newpm-passes=">, HelpText<"Passes to run during LTO">; def lto_O: JJ<"lto-O">, MetaVarName<"<opt-level>">, @@ -534,26 +566,35 @@ def lto_cs_profile_file: JJ<"lto-cs-profile-file=">, def lto_obj_path_eq: JJ<"lto-obj-path=">; def lto_sample_profile: JJ<"lto-sample-profile=">, HelpText<"Sample profile file path">; -def lto_whole_program_visibility: FF<"lto-whole-program-visibility">, - HelpText<"Asserts that the LTO link has whole program visibility">; +defm lto_whole_program_visibility: BB<"lto-whole-program-visibility", + "Asserts that the LTO link has whole program visibility", + "Asserts that the LTO link does not have whole program visibility">; +def lto_pseudo_probe_for_profiling: F<"lto-pseudo-probe-for-profiling">, + HelpText<"Emit pseudo probes for sample profiling">; def disable_verify: F<"disable-verify">; defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">; def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">, HelpText<"YAML output file for optimization remarks">; +defm opt_remarks_hotness_threshold: EEq<"opt-remarks-hotness-threshold", + "Minimum profile count required for an optimization remark to be output." + " Use 'auto' to apply the threshold from profile summary.">, + MetaVarName<"<value>">; def opt_remarks_passes: Separate<["--"], "opt-remarks-passes">, HelpText<"Regex for the passes that need to be serialized to the output file">; def opt_remarks_with_hotness: FF<"opt-remarks-with-hotness">, HelpText<"Include hotness information in the optimization remarks file">; def opt_remarks_format: Separate<["--"], "opt-remarks-format">, HelpText<"The format used for serializing remarks (default: YAML)">; -def save_temps: F<"save-temps">; -def lto_basicblock_sections: JJ<"lto-basicblock-sections=">, +def save_temps: F<"save-temps">, HelpText<"Save intermediate LTO compilation results">; +def lto_basic_block_sections: JJ<"lto-basic-block-sections=">, HelpText<"Enable basic block sections for LTO">; -defm lto_unique_bb_section_names: BB<"lto-unique-bb-section-names", +defm lto_unique_basic_block_section_names: BB<"lto-unique-basic-block-section-names", "Give unique names to every basic block section for LTO", "Do not give unique names to every basic block section for LTO (default)">; -def shuffle_sections: JJ<"shuffle-sections=">, MetaVarName<"<seed>">, - HelpText<"Shuffle input sections using the given seed. If 0, use a random seed">; +defm shuffle_sections: EEq<"shuffle-sections", + "Shuffle matched sections using the given seed before mapping them to the output sections. " + "If -1, reverse the section order. If 0, use a random seed">, + MetaVarName<"<section-glob>=<seed>">; def thinlto_cache_dir: JJ<"thinlto-cache-dir=">, HelpText<"Path to ThinLTO cached object file directory">; defm thinlto_cache_policy: EEq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">; @@ -580,7 +621,9 @@ def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for --thinlto-j def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for --lto-partitions">; def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">; def: F<"plugin-opt=new-pass-manager">, - Alias<lto_new_pass_manager>, HelpText<"Alias for --lto-new-pass-manager">; + Alias<no_lto_legacy_pass_manager>, HelpText<"Alias for --no-lto-legacy-pass-manager">; +def: F<"plugin-opt=legacy-pass-manager">, + Alias<lto_legacy_pass_manager>, HelpText<"Alias for --no-legacy-pass-manager">; def: F<"plugin-opt=cs-profile-generate">, Alias<lto_cs_profile_generate>, HelpText<"Alias for --lto-cs-profile-generate">; def: J<"plugin-opt=cs-profile-path=">, @@ -588,6 +631,23 @@ def: J<"plugin-opt=cs-profile-path=">, def: J<"plugin-opt=obj-path=">, Alias<lto_obj_path_eq>, HelpText<"Alias for --lto-obj-path=">; +def: J<"plugin-opt=opt-remarks-filename=">, + Alias<opt_remarks_filename>, + HelpText<"Alias for --opt-remarks-filename">; +def: J<"plugin-opt=opt-remarks-passes=">, + Alias<opt_remarks_passes>, + HelpText<"Alias for --opt-remarks-passes">; +def: J<"plugin-opt=opt-remarks-format=">, + Alias<opt_remarks_format>, + HelpText<"Alias for --opt-remarks-format">; +def: F<"plugin-opt=opt-remarks-with-hotness">, + Alias<opt_remarks_with_hotness>, + HelpText<"Alias for --opt-remarks-with_hotness">; +def: J<"plugin-opt=opt-remarks-hotness-threshold=">, + Alias<opt_remarks_hotness_threshold>, + HelpText<"Alias for --opt-remarks-hotness-threshold">; +def: J<"plugin-opt=pseudo-probe-for-profiling">, + Alias<lto_pseudo_probe_for_profiling>, HelpText<"Alias for --lto-pseudo-probe-for-profiling">; def: J<"plugin-opt=sample-profile=">, Alias<lto_sample_profile>, HelpText<"Alias for --lto-sample-profile">; def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for --save-temps">; @@ -648,8 +708,6 @@ def: F<"stats">; def: F<"warn-execstack">; def: F<"warn-once">; def: F<"warn-shared-textrel">; -def: F<"EB">; -def: F<"EL">; def: JoinedOrSeparate<["-"], "G">; def: F<"Qy">; @@ -657,3 +715,9 @@ def: F<"Qy">; defm mips_got_size: Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">, Flags<[HelpHidden]>; + +// Hidden option used to opt-in to additional output checks. +defm check_dynamic_relocations: BB<"check-dynamic-relocations", + "Perform additional validation of the written dynamic relocations", + "Do not perform additional validation of the written dynamic relocations">, + Flags<[HelpHidden]>; diff --git a/gnu/llvm/lld/ELF/Relocations.cpp b/gnu/llvm/lld/ELF/Relocations.cpp index 751ded39776..bf576752c54 100644 --- a/gnu/llvm/lld/ELF/Relocations.cpp +++ b/gnu/llvm/lld/ELF/Relocations.cpp @@ -74,12 +74,12 @@ static Optional<std::string> getLinkerScriptLocation(const Symbol &sym) { } static std::string getDefinedLocation(const Symbol &sym) { - std::string msg = "\n>>> defined in "; + const char msg[] = "\n>>> defined in "; if (sym.file) - msg += toString(sym.file); - else if (Optional<std::string> loc = getLinkerScriptLocation(sym)) - msg += *loc; - return msg; + return msg + toString(sym.file); + if (Optional<std::string> loc = getLinkerScriptLocation(sym)) + return msg + *loc; + return ""; } // Construct a message in the following format. @@ -113,6 +113,17 @@ void elf::reportRangeError(uint8_t *loc, const Relocation &rel, const Twine &v, ", " + Twine(max).str() + "]" + hint); } +void elf::reportRangeError(uint8_t *loc, int64_t v, int n, const Symbol &sym, + const Twine &msg) { + ErrorPlace errPlace = getErrorPlace(loc); + std::string hint; + if (!sym.getName().empty()) + hint = "; references " + lld::toString(sym) + getDefinedLocation(sym); + errorOrWarn(errPlace.loc + msg + " is out of range: " + Twine(v) + + " is not in [" + Twine(llvm::minIntN(n)) + ", " + + Twine(llvm::maxIntN(n)) + "]" + hint); +} + namespace { // Build a bitmask with one bit set for each RelExpr. // @@ -189,17 +200,21 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c, config->shared) { if (in.got->addDynTlsEntry(sym)) { uint64_t off = in.got->getGlobalDynOffset(sym); - mainPart->relaDyn->addReloc( - {target->tlsDescRel, in.got, off, !sym.isPreemptible, &sym, 0}); + mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible( + target->tlsDescRel, in.got, off, sym, target->tlsDescRel); } if (expr != R_TLSDESC_CALL) c.relocations.push_back({expr, type, offset, addend, &sym}); return 1; } + // ARM, Hexagon and RISC-V do not support GD/LD to IE/LE relaxation. For + // PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable + // relaxation as well. bool toExecRelax = !config->shared && config->emachine != EM_ARM && config->emachine != EM_HEXAGON && - config->emachine != EM_RISCV; + config->emachine != EM_RISCV && + !c.file->ppc64DisableTLSRelax; // If we are producing an executable and the symbol is non-preemptable, it // must be defined and the code sequence can be relaxed to use Local-Exec. @@ -219,8 +234,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c, // Local-Dynamic relocs can be relaxed to Local-Exec. if (toExecRelax) { c.relocations.push_back( - {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_LD_TO_LE), type, - offset, addend, &sym}); + {target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE), type, offset, + addend, &sym}); return target->getTlsGdRelaxSkip(type); } if (expr == R_TLSLD_HINT) @@ -230,8 +245,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c, in.got->relocations.push_back( {R_ADDEND, target->symbolicRel, in.got->getTlsIndexOff(), 1, &sym}); else - mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, in.got, - in.got->getTlsIndexOff(), nullptr); + mainPart->relaDyn->addReloc( + {target->tlsModuleIndexRel, in.got, in.got->getTlsIndexOff()}); } c.relocations.push_back({expr, type, offset, addend, &sym}); return 1; @@ -239,9 +254,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c, // Local-Dynamic relocs can be relaxed to Local-Exec. if (expr == R_DTPREL && toExecRelax) { - c.relocations.push_back( - {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_LD_TO_LE), type, - offset, addend, &sym}); + c.relocations.push_back({target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE), + type, offset, addend, &sym}); return 1; } @@ -269,14 +283,15 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c, in.got->relocations.push_back( {R_ADDEND, target->symbolicRel, off, 1, &sym}); else - mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, in.got, off, &sym); + mainPart->relaDyn->addSymbolReloc(target->tlsModuleIndexRel, in.got, + off, sym); // If the symbol is preemptible we need the dynamic linker to write // the offset too. uint64_t offsetOff = off + config->wordsize; if (sym.isPreemptible) - mainPart->relaDyn->addReloc(target->tlsOffsetRel, in.got, offsetOff, - &sym); + mainPart->relaDyn->addSymbolReloc(target->tlsOffsetRel, in.got, + offsetOff, sym); else in.got->relocations.push_back( {R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym}); @@ -289,17 +304,17 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c, // depending on the symbol being locally defined or not. if (sym.isPreemptible) { c.relocations.push_back( - {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_GD_TO_IE), type, - offset, addend, &sym}); + {target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_IE), type, offset, + addend, &sym}); if (!sym.isInGot()) { in.got->addEntry(sym); - mainPart->relaDyn->addReloc(target->tlsGotRel, in.got, sym.getGotOffset(), - &sym); + mainPart->relaDyn->addSymbolReloc(target->tlsGotRel, in.got, + sym.getGotOffset(), sym); } } else { c.relocations.push_back( - {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_GD_TO_LE), type, - offset, addend, &sym}); + {target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_LE), type, offset, + addend, &sym}); } return target->getTlsGdRelaxSkip(type); } @@ -367,8 +382,8 @@ static bool needsPlt(RelExpr expr) { // TLS variables uses GOT differently than the regular variables. static bool needsGot(RelExpr expr) { return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF, - R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT>( - expr); + R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT, + R_AARCH64_GOT_PAGE>(expr); } // True if this expression is of the form Sym - X, where X is a position in the @@ -376,7 +391,7 @@ static bool needsGot(RelExpr expr) { static bool isRelExpr(RelExpr expr) { return oneof<R_PC, R_GOTREL, R_GOTPLTREL, R_MIPS_GOTREL, R_PPC64_CALL, R_PPC64_RELAX_TOC, R_AARCH64_PAGE_PC, R_RELAX_GOT_PC, - R_RISCV_PC_INDIRECT>(expr); + R_RISCV_PC_INDIRECT, R_PPC64_RELAX_GOT_PC>(expr); } // Returns true if a given relocation can be computed at link-time. @@ -397,7 +412,8 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, R_TLSDESC_CALL, - R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT, R_TLSIE_HINT>( + R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT, R_TLSIE_HINT, + R_AARCH64_GOT_PAGE>( e)) return true; @@ -511,6 +527,13 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &ss) { if (auto *alias = dyn_cast_or_null<SharedSymbol>(sym)) ret.insert(alias); } + + // The loop does not check SHT_GNU_verneed, so ret does not contain + // non-default version symbols. If ss has a non-default version, ret won't + // contain ss. Just add ss unconditionally. If a non-default version alias is + // separately copy relocated, it and ss will have different addresses. + // Fortunately this case is impractical and fails with GNU ld as well. + ret.insert(&ss); return ret; } @@ -603,7 +626,7 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) { for (SharedSymbol *sym : getSymbolsAt<ELFT>(ss)) replaceWithDefined(*sym, sec, 0, sym->size); - mainPart->relaDyn->addReloc(target->copyRel, sec, 0, &ss); + mainPart->relaDyn->addSymbolReloc(target->copyRel, sec, 0, ss); } // MIPS has an odd notion of "paired" relocations to calculate addends. @@ -681,7 +704,7 @@ static std::string maybeReportDiscarded(Undefined &sym) { if (sym.type == ELF::STT_SECTION) { msg = "relocation refers to a discarded section: "; msg += CHECK( - file->getObj().getSectionName(&objSections[sym.discardedSecIdx]), file); + file->getObj().getSectionName(objSections[sym.discardedSecIdx]), file); } else { msg = "relocation refers to a symbol in a discarded section: " + toString(sym); @@ -748,7 +771,7 @@ static const Symbol *getAlternativeSpelling(const Undefined &sym, // Build a map of local defined symbols. for (const Symbol *s : sym.file->getSymbols()) - if (s->isLocal() && s->isDefined()) + if (s->isLocal() && s->isDefined() && !s->getName().empty()) map.try_emplace(s->getName(), s); } @@ -805,10 +828,10 @@ static const Symbol *getAlternativeSpelling(const Undefined &sym, // Case mismatch, e.g. Foo vs FOO. for (auto &it : map) - if (name.equals_lower(it.first)) + if (name.equals_insensitive(it.first)) return it.second; for (Symbol *sym : symtab->symbols()) - if (!sym->isUndefined() && name.equals_lower(sym->getName())) + if (!sym->isUndefined() && name.equals_insensitive(sym->getName())) return sym; // The reference may be a mangled name while the definition is not. Suggest a @@ -908,7 +931,7 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef, if (undef.isWarning) warn(msg); else - error(msg); + error(msg, ErrorTag::SymbolNotFound, {sym.getName()}); } template <class ELFT> void elf::reportUndefinedSymbols() { @@ -935,7 +958,15 @@ template <class ELFT> void elf::reportUndefinedSymbols() { // Returns true if the undefined symbol will produce an error message. static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec, uint64_t offset) { - if (!sym.isUndefined() || sym.isWeak()) + if (!sym.isUndefined()) + return false; + // If versioned, issue an error (even if the symbol is weak) because we don't + // know the defining filename which is required to construct a Verneed entry. + if (*sym.getVersionSuffix() == '@') { + undefs.push_back({&sym, {{&sec, offset}}, false}); + return true; + } + if (sym.isWeak()) return false; bool canBeExternal = !sym.isLocal() && sym.visibility == STV_DEFAULT; @@ -1024,7 +1055,7 @@ private: } // namespace static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec, - Symbol *sym, int64_t addend, RelExpr expr, + Symbol &sym, int64_t addend, RelExpr expr, RelType type) { Partition &part = isec->getPartition(); @@ -1035,12 +1066,12 @@ static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec, // don't store the addend values, so we must write it to the relocated // address. if (part.relrDyn && isec->alignment >= 2 && offsetInSec % 2 == 0) { - isec->relocations.push_back({expr, type, offsetInSec, addend, sym}); + isec->relocations.push_back({expr, type, offsetInSec, addend, &sym}); part.relrDyn->relocs.push_back({isec, offsetInSec}); return; } - part.relaDyn->addReloc(target->relativeRel, isec, offsetInSec, sym, addend, - expr, type); + part.relaDyn->addRelativeReloc(target->relativeRel, isec, offsetInSec, sym, + addend, type, expr); } template <class PltSection, class GotPltSection> @@ -1048,14 +1079,16 @@ static void addPltEntry(PltSection *plt, GotPltSection *gotPlt, RelocationBaseSection *rel, RelType type, Symbol &sym) { plt->addEntry(sym); gotPlt->addEntry(sym); - rel->addReloc( - {type, gotPlt, sym.getGotPltOffset(), !sym.isPreemptible, &sym, 0}); + rel->addReloc({type, gotPlt, sym.getGotPltOffset(), + sym.isPreemptible ? DynamicReloc::AgainstSymbol + : DynamicReloc::AddendOnlyWithTargetVA, + sym, 0, R_ABS}); } static void addGotEntry(Symbol &sym) { in.got->addEntry(sym); - RelExpr expr = sym.isTls() ? R_TLS : R_ABS; + RelExpr expr = sym.isTls() ? R_TPREL : R_ABS; uint64_t off = sym.getGotOffset(); // If a GOT slot value can be calculated at link-time, which is now, @@ -1074,13 +1107,13 @@ static void addGotEntry(Symbol &sym) { // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that // the GOT slot will be fixed at load-time. - if (!sym.isTls() && !sym.isPreemptible && config->isPic && !isAbsolute(sym)) { - addRelativeReloc(in.got, off, &sym, 0, R_ABS, target->symbolicRel); + if (!sym.isTls() && !sym.isPreemptible && config->isPic) { + addRelativeReloc(in.got, off, sym, 0, R_ABS, target->symbolicRel); return; } - mainPart->relaDyn->addReloc( - sym.isTls() ? target->tlsGotRel : target->gotRel, in.got, off, &sym, 0, - sym.isPreemptible ? R_ADDEND : R_ABS, target->symbolicRel); + mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible( + sym.isTls() ? target->tlsGotRel : target->gotRel, in.got, off, sym, + target->symbolicRel); } // Return true if we can define a symbol in the executable that @@ -1124,11 +1157,18 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type, // relocation will be created, pass the control to relocateAlloc() or // relocateNonAlloc() to resolve it. // - // The behavior of an undefined weak reference is implementation defined. If - // the relocation is to a weak undef, and we are producing an executable, let - // relocate{,Non}Alloc() resolve it. + // The behavior of an undefined weak reference is implementation defined. For + // non-link-time constants, we resolve relocations statically (let + // relocate{,Non}Alloc() resolve them) for -no-pie and try producing dynamic + // relocations for -pie and -shared. + // + // The general expectation of -no-pie static linking is that there is no + // dynamic relocation (except IRELATIVE). Emitting dynamic relocations for + // -shared matches the spirit of its -z undefs default. -pie has freedom on + // choices, and we choose dynamic relocations to be consistent with the + // handling of GOT-generating relocations. if (isStaticLinkTimeConstant(expr, type, sym, sec, offset) || - (!config->shared && sym.isUndefWeak())) { + (!config->isPic && sym.isUndefWeak())) { sec.relocations.push_back({expr, type, offset, addend, &sym}); return; } @@ -1137,13 +1177,13 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type, if (canWrite) { RelType rel = target->getDynRel(type); if (expr == R_GOT || (rel == target->symbolicRel && !sym.isPreemptible)) { - addRelativeReloc(&sec, offset, &sym, addend, expr, type); + addRelativeReloc(&sec, offset, sym, addend, expr, type); return; } else if (rel != 0) { if (config->emachine == EM_MIPS && rel == target->symbolicRel) rel = target->relativeRel; - sec.getPartition().relaDyn->addReloc(rel, &sec, offset, &sym, addend, - R_ADDEND, type); + sec.getPartition().relaDyn->addSymbolReloc(rel, &sec, offset, sym, addend, + type); // MIPS ABI turns using of GOT and dynamic relocations inside out. // While regular ABI uses dynamic relocations to fill up GOT entries @@ -1263,7 +1303,7 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type, template <class ELFT, class RelTy> static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, - RelTy *end) { + RelTy *start, RelTy *end) { const RelTy &rel = *i; uint32_t symIndex = rel.getSymbol(config->isMips64EL); Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIndex); @@ -1294,16 +1334,6 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, if (expr == R_NONE) return; - if (sym.isGnuIFunc() && !config->zText && config->warnIfuncTextrel) { - warn("using ifunc symbols when text relocations are allowed may produce " - "a binary that will segfault, if the object file is linked with " - "old version of glibc (glibc 2.28 and earlier). If this applies to " - "you, consider recompiling the object files without -fPIC and " - "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to " - "turn off this warning." + - getLocation(sec, sym, offset)); - } - // Read an addend. int64_t addend = computeAddend<ELFT>(rel, end, sec, expr, sym.isLocal()); @@ -1324,6 +1354,21 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, if (type == R_PPC64_TOC16_LO && sym.isSection() && isa<Defined>(sym) && cast<Defined>(sym).section->name == ".toc") ppc64noTocRelax.insert({&sym, addend}); + + if ((type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) || + (type == R_PPC64_TLSLD && expr == R_TLSLD_HINT)) { + if (i == end) { + errorOrWarn("R_PPC64_TLSGD/R_PPC64_TLSLD may not be the last " + "relocation" + + getLocation(sec, sym, offset)); + return; + } + + // Offset the 4-byte aligned R_PPC64_TLSGD by one byte in the NOTOC case, + // so we can discern it later from the toc-case. + if (i->getType(/*isMips64EL=*/false) == R_PPC64_REL24_NOTOC) + ++offset; + } } // Relax relocations. @@ -1335,9 +1380,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, // runtime, because the main executable is always at the beginning of a search // list. We can leverage that fact. if (!sym.isPreemptible && (!sym.isGnuIFunc() || config->zIfuncNoplt)) { - if (expr == R_GOT_PC && !isAbsoluteValue(sym)) { - expr = target->adjustRelaxExpr(type, relocatedAddr, expr); - } else { + if (expr != R_GOT_PC) { // The 0x8000 bit of r_addend of R_PPC_PLTREL24 is used to choose call // stub type. It should be ignored if optimized to R_PC. if (config->emachine == EM_PPC && expr == R_PPC32_PLTREL) @@ -1349,6 +1392,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, type == R_HEX_GD_PLT_B22_PCREL_X || type == R_HEX_GD_PLT_B32_PCREL_X))) expr = fromPlt(expr); + } else if (!isAbsoluteValue(sym)) { + expr = target->adjustGotPcExpr(type, addend, relocatedAddr); } } @@ -1358,15 +1403,22 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, // The 4 types that relative GOTPLT are all x86 and x86-64 specific. if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_TLSGD_GOTPLT>(expr)) { in.gotPlt->hasGotPltOffRel = true; - } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC64_TOCBASE, R_PPC64_RELAX_TOC>( - expr)) { + } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC32_PLTREL, R_PPC64_TOCBASE, + R_PPC64_RELAX_TOC>(expr)) { in.got->hasGotOffRel = true; } - // Process some TLS relocations, including relaxing TLS relocations. - // Note that this function does not handle all TLS relocations. - if (unsigned processed = - handleTlsRelocation<ELFT>(type, sym, sec, offset, addend, expr)) { + // Process TLS relocations, including relaxing TLS relocations. Note that + // R_TPREL and R_TPREL_NEG relocations are resolved in processRelocAux. + if (expr == R_TPREL || expr == R_TPREL_NEG) { + if (config->shared) { + errorOrWarn("relocation " + toString(type) + " against " + toString(sym) + + " cannot be used with -shared" + + getLocation(sec, sym, offset)); + return; + } + } else if (unsigned processed = handleTlsRelocation<ELFT>( + type, sym, sec, offset, addend, expr)) { i += (processed - 1); return; } @@ -1375,7 +1427,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, // direct relocation on through. if (sym.isGnuIFunc() && config->zIfuncNoplt) { sym.exportDynamic = true; - mainPart->relaDyn->addReloc(type, &sec, offset, &sym, addend, R_ADDEND, type); + mainPart->relaDyn->addSymbolReloc(type, &sec, offset, sym, addend, type); return; } @@ -1494,6 +1546,43 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, processRelocAux<ELFT>(sec, expr, type, offset, sym, rel, addend); } +// R_PPC64_TLSGD/R_PPC64_TLSLD is required to mark `bl __tls_get_addr` for +// General Dynamic/Local Dynamic code sequences. If a GD/LD GOT relocation is +// found but no R_PPC64_TLSGD/R_PPC64_TLSLD is seen, we assume that the +// instructions are generated by very old IBM XL compilers. Work around the +// issue by disabling GD/LD to IE/LE relaxation. +template <class RelTy> +static void checkPPC64TLSRelax(InputSectionBase &sec, ArrayRef<RelTy> rels) { + // Skip if sec is synthetic (sec.file is null) or if sec has been marked. + if (!sec.file || sec.file->ppc64DisableTLSRelax) + return; + bool hasGDLD = false; + for (const RelTy &rel : rels) { + RelType type = rel.getType(false); + switch (type) { + case R_PPC64_TLSGD: + case R_PPC64_TLSLD: + return; // Found a marker + case R_PPC64_GOT_TLSGD16: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSGD16_HI: + case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TLSLD16: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSLD16_HI: + case R_PPC64_GOT_TLSLD16_LO: + hasGDLD = true; + break; + } + } + if (hasGDLD) { + sec.file->ppc64DisableTLSRelax = true; + warn(toString(sec.file) + + ": disable TLS relaxation due to R_PPC64_GOT_TLS* relocations without " + "R_PPC64_TLSGD/R_PPC64_TLSLD relocations"); + } +} + template <class ELFT, class RelTy> static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) { OffsetGetter getOffset(sec); @@ -1501,8 +1590,18 @@ static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) { // Not all relocations end up in Sec.Relocations, but a lot do. sec.relocations.reserve(rels.size()); + if (config->emachine == EM_PPC64) + checkPPC64TLSRelax<RelTy>(sec, rels); + + // For EhInputSection, OffsetGetter expects the relocations to be sorted by + // r_offset. In rare cases (.eh_frame pieces are reordered by a linker + // script), the relocations may be unordered. + SmallVector<RelTy, 0> storage; + if (isa<EhInputSection>(sec)) + rels = sortRels(rels, storage); + for (auto i = rels.begin(), end = rels.end(); i != end;) - scanReloc<ELFT>(sec, getOffset, i, end); + scanReloc<ELFT>(sec, getOffset, i, rels.begin(), end); // Sort relocations by offset for more efficient searching for // R_RISCV_PCREL_HI20 and R_PPC64_ADDR64. @@ -1688,14 +1787,17 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> outputSections) { // Find or create a ThunkSection within the InputSectionDescription (ISD) that // is in range of Src. An ISD maps to a range of InputSections described by a // linker script section pattern such as { .text .text.* }. -ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os, InputSection *isec, +ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os, + InputSection *isec, InputSectionDescription *isd, - uint32_t type, uint64_t src) { + const Relocation &rel, + uint64_t src) { for (std::pair<ThunkSection *, uint32_t> tp : isd->thunkSections) { ThunkSection *ts = tp.first; - uint64_t tsBase = os->addr + ts->outSecOff; - uint64_t tsLimit = tsBase + ts->getSize(); - if (target->inBranchRange(type, src, (src > tsLimit) ? tsBase : tsLimit)) + uint64_t tsBase = os->addr + ts->outSecOff + rel.addend; + uint64_t tsLimit = tsBase + ts->getSize() + rel.addend; + if (target->inBranchRange(rel.type, src, + (src > tsLimit) ? tsBase : tsLimit)) return ts; } @@ -1705,9 +1807,11 @@ ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os, InputSection *isec // possible. Error if InputSection is so large we cannot place ThunkSection // anywhere in Range. uint64_t thunkSecOff = isec->outSecOff; - if (!target->inBranchRange(type, src, os->addr + thunkSecOff)) { + if (!target->inBranchRange(rel.type, src, + os->addr + thunkSecOff + rel.addend)) { thunkSecOff = isec->outSecOff + isec->getSize(); - if (!target->inBranchRange(type, src, os->addr + thunkSecOff)) + if (!target->inBranchRange(rel.type, src, + os->addr + thunkSecOff + rel.addend)) fatal("InputSection too large for range extension thunk " + isec->getObjMsg(src - (os->addr + isec->outSecOff))); } @@ -1858,7 +1962,11 @@ static int64_t getPCBias(RelType type) { std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec, Relocation &rel, uint64_t src) { std::vector<Thunk *> *thunkVec = nullptr; - int64_t addend = rel.addend + getPCBias(rel.type); + // Arm and Thumb have a PC Bias of 8 and 4 respectively, this is cancelled + // out in the relocation addend. We compensate for the PC bias so that + // an Arm and Thumb relocation to the same destination get the same keyAddend, + // which is usually 0. + int64_t keyAddend = rel.addend + getPCBias(rel.type); // We use a ((section, offset), addend) pair to find the thunk position if // possible so that we create only one thunk for aliased symbols or ICFed @@ -1868,17 +1976,16 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec, if (auto *d = dyn_cast<Defined>(rel.sym)) if (!d->isInPlt() && d->section) thunkVec = &thunkedSymbolsBySectionAndAddend[{ - {d->section->repl, d->value}, addend}]; + {d->section->repl, d->value}, keyAddend}]; if (!thunkVec) - thunkVec = &thunkedSymbols[{rel.sym, addend}]; + thunkVec = &thunkedSymbols[{rel.sym, keyAddend}]; // Check existing Thunks for Sym to see if they can be reused for (Thunk *t : *thunkVec) if (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) && t->isCompatibleWith(*isec, rel) && target->inBranchRange(rel.type, src, - t->getThunkTargetSym()->getVA(rel.addend) + - getPCBias(rel.type))) + t->getThunkTargetSym()->getVA(rel.addend))) return std::make_pair(t, false); // No existing compatible Thunk in range, create a new one @@ -1893,8 +2000,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec, // relocation back to its original non-Thunk target. bool ThunkCreator::normalizeExistingThunk(Relocation &rel, uint64_t src) { if (Thunk *t = thunks.lookup(rel.sym)) { - if (target->inBranchRange(rel.type, src, - rel.sym->getVA(rel.addend) + getPCBias(rel.type))) + if (target->inBranchRange(rel.type, src, rel.sym->getVA(rel.addend))) return true; rel.sym = &t->destination; rel.addend = t->addend; @@ -1966,7 +2072,7 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) { if (auto *tis = t->getTargetInputSection()) ts = getISThunkSec(tis); else - ts = getISDThunkSec(os, isec, isd, rel.type, src); + ts = getISDThunkSec(os, isec, isd, rel, src); ts->addThunk(t); thunks[t->getThunkTargetSym()] = t; } diff --git a/gnu/llvm/lld/ELF/Symbols.cpp b/gnu/llvm/lld/ELF/Symbols.cpp index 8371b3a389d..81385011736 100644 --- a/gnu/llvm/lld/ELF/Symbols.cpp +++ b/gnu/llvm/lld/ELF/Symbols.cpp @@ -37,11 +37,9 @@ std::string lld::toString(const elf::Symbol &sym) { StringRef name = sym.getName(); std::string ret = demangle(name); - // If sym has a non-default version, its name may have been truncated at '@' - // by Symbol::parseSymbolVersion(). Add the trailing part. This check is safe - // because every symbol name ends with '\0'. - if (name.data()[name.size()] == '@') - ret += name.data() + name.size(); + const char *suffix = sym.getVersionSuffix(); + if (*suffix == '@') + ret += suffix; return ret; } @@ -65,7 +63,8 @@ Defined *ElfSym::relaIpltStart; Defined *ElfSym::relaIpltEnd; Defined *ElfSym::riscvGlobalPointer; Defined *ElfSym::tlsModuleBase; -DenseMap<const Symbol *, const InputFile *> elf::backwardReferences; +DenseMap<const Symbol *, std::pair<const InputFile *, const InputFile *>> + elf::backwardReferences; static uint64_t getSymVA(const Symbol &sym, int64_t &addend) { switch (sym.kind()) { @@ -162,7 +161,9 @@ uint64_t Symbol::getGotVA() const { return in.got->getVA() + getGotOffset(); } -uint64_t Symbol::getGotOffset() const { return gotIndex * config->wordsize; } +uint64_t Symbol::getGotOffset() const { + return gotIndex * target->gotEntrySize; +} uint64_t Symbol::getGotPltVA() const { if (isInIplt) @@ -172,8 +173,8 @@ uint64_t Symbol::getGotPltVA() const { uint64_t Symbol::getGotPltOffset() const { if (isInIplt) - return pltIndex * config->wordsize; - return (pltIndex + target->gotPltHeaderEntriesNum) * config->wordsize; + return pltIndex * target->gotEntrySize; + return (pltIndex + target->gotPltHeaderEntriesNum) * target->gotEntrySize; } uint64_t Symbol::getPltVA() const { @@ -208,6 +209,9 @@ OutputSection *Symbol::getOutputSection() const { // If a symbol name contains '@', the characters after that is // a symbol version name. This function parses that. void Symbol::parseSymbolVersion() { + // Return if localized by a local: pattern in a version script. + if (versionId == VER_NDX_LOCAL) + return; StringRef s = getName(); size_t pos = s.find('@'); if (pos == 0 || pos == StringRef::npos) @@ -279,7 +283,7 @@ uint8_t Symbol::computeBinding() const { if (config->relocatable) return binding; if ((visibility != STV_DEFAULT && visibility != STV_PROTECTED) || - (versionId == VER_NDX_LOCAL && isDefined())) + (versionId == VER_NDX_LOCAL && !isLazy())) return STB_LOCAL; if (!config->gnuUnique && binding == STB_GNU_UNIQUE) return STB_GLOBAL; @@ -368,8 +372,12 @@ bool elf::computeIsPreemptible(const Symbol &sym) { // If -Bsymbolic or --dynamic-list is specified, or -Bsymbolic-functions is // specified and the symbol is STT_FUNC, the symbol is preemptible iff it is - // in the dynamic list. - if (config->symbolic || (config->bsymbolicFunctions && sym.isFunc())) + // in the dynamic list. -Bsymbolic-non-weak-functions is a non-weak subset of + // -Bsymbolic-functions. + if (config->symbolic || + (config->bsymbolic == BsymbolicKind::Functions && sym.isFunc()) || + (config->bsymbolic == BsymbolicKind::NonWeakFunctions && sym.isFunc() && + sym.binding != STB_WEAK)) return sym.inDynamicList; return true; } @@ -377,8 +385,18 @@ bool elf::computeIsPreemptible(const Symbol &sym) { void elf::reportBackrefs() { for (auto &it : backwardReferences) { const Symbol &sym = *it.first; - warn("backward reference detected: " + sym.getName() + " in " + - toString(it.second) + " refers to " + toString(sym.file)); + std::string to = toString(it.second.second); + // Some libraries have known problems and can cause noise. Filter them out + // with --warn-backrefs-exclude=. to may look like *.o or *.a(*.o). + bool exclude = false; + for (const llvm::GlobPattern &pat : config->warnBackrefsExclude) + if (pat.match(to)) { + exclude = true; + break; + } + if (!exclude) + warn("backward reference detected: " + sym.getName() + " in " + + toString(it.second.first) + " refers to " + to); } } @@ -514,17 +532,6 @@ void Symbol::resolveUndefined(const Undefined &other) { // group assignment rule simulates the traditional linker's semantics. bool backref = config->warnBackrefs && other.file && file->groupId < other.file->groupId; - if (backref) { - // Some libraries have known problems and can cause noise. Filter them out - // with --warn-backrefs-exclude=. - StringRef name = - !file->archiveName.empty() ? file->archiveName : file->getName(); - for (const llvm::GlobPattern &pat : config->warnBackrefsExclude) - if (pat.match(name)) { - backref = false; - break; - } - } fetch(); // We don't report backward references to weak symbols as they can be @@ -533,9 +540,10 @@ void Symbol::resolveUndefined(const Undefined &other) { // A traditional linker does not error for -ldef1 -lref -ldef2 (linking // sandwich), where def2 may or may not be the same as def1. We don't want // to warn for this case, so dismiss the warning if we see a subsequent lazy - // definition. + // definition. this->file needs to be saved because in the case of LTO it + // may be reset to nullptr or be replaced with a file named lto.tmp. if (backref && !isWeak()) - backwardReferences.try_emplace(this, other.file); + backwardReferences.try_emplace(this, std::make_pair(other.file, file)); return; } @@ -691,7 +699,33 @@ void Symbol::resolveDefined(const Defined &other) { other.value); } +template <class LazyT> +static void replaceCommon(Symbol &oldSym, const LazyT &newSym) { + backwardReferences.erase(&oldSym); + oldSym.replace(newSym); + newSym.fetch(); +} + template <class LazyT> void Symbol::resolveLazy(const LazyT &other) { + // For common objects, we want to look for global or weak definitions that + // should be fetched as the canonical definition instead. + if (isCommon() && elf::config->fortranCommon) { + if (auto *laSym = dyn_cast<LazyArchive>(&other)) { + ArchiveFile *archive = cast<ArchiveFile>(laSym->file); + const Archive::Symbol &archiveSym = laSym->sym; + if (archive->shouldFetchForCommon(archiveSym)) { + replaceCommon(*this, other); + return; + } + } else if (auto *loSym = dyn_cast<LazyObject>(&other)) { + LazyObjFile *obj = cast<LazyObjFile>(loSym->file); + if (obj->shouldFetchForCommon(loSym->getName())) { + replaceCommon(*this, other); + return; + } + } + } + if (!isUndefined()) { // See the comment in resolveUndefined(). if (isDefined()) diff --git a/gnu/llvm/lld/ELF/Symbols.h b/gnu/llvm/lld/ELF/Symbols.h index 097b96a34f6..d4a589ee600 100644 --- a/gnu/llvm/lld/ELF/Symbols.h +++ b/gnu/llvm/lld/ELF/Symbols.h @@ -132,9 +132,11 @@ public: // doesn't know the final contents of the symbol. uint8_t canInline : 1; - // Used by Undefined and SharedSymbol to track if there has been at least one - // undefined reference to the symbol. The binding may change to STB_WEAK if - // the first undefined reference from a non-shared object is weak. + // Used to track if there has been at least one undefined reference to the + // symbol. For Undefined and SharedSymbol, the binding may change to STB_WEAK + // if the first undefined reference from a non-shared object is weak. + // + // This is also used to retain __wrap_foo when foo is referenced. uint8_t referenced : 1; // True if this symbol is specified by --trace-symbol option. @@ -178,6 +180,15 @@ public: void parseSymbolVersion(); + // Get the NUL-terminated version suffix ("", "@...", or "@@..."). + // + // For @@, the name has been truncated by insert(). For @, the name has been + // truncated by Symbol::parseSymbolVersion(). + const char *getVersionSuffix() const { + (void)getName(); + return nameData + nameSize; + } + bool isInGot() const { return gotIndex != -1U; } bool isInPlt() const { return pltIndex != -1U; } @@ -212,13 +223,13 @@ public: // non-lazy object causes a runtime error. void fetch() const; -private: static bool isExportDynamic(Kind k, uint8_t visibility) { if (k == SharedKind) return visibility == llvm::ELF::STV_DEFAULT; return config->shared || config->exportDynamic; } +private: void resolveUndefined(const Undefined &other); void resolveCommon(const CommonSymbol &other); void resolveDefined(const Defined &other); @@ -570,7 +581,9 @@ void reportBackrefs(); // A mapping from a symbol to an InputFile referencing it backward. Used by // --warn-backrefs. -extern llvm::DenseMap<const Symbol *, const InputFile *> backwardReferences; +extern llvm::DenseMap<const Symbol *, + std::pair<const InputFile *, const InputFile *>> + backwardReferences; } // namespace elf } // namespace lld diff --git a/gnu/llvm/lld/ELF/SyntheticSections.cpp b/gnu/llvm/lld/ELF/SyntheticSections.cpp index 7f8bc16fbb8..187b2ac90c2 100644 --- a/gnu/llvm/lld/ELF/SyntheticSections.cpp +++ b/gnu/llvm/lld/ELF/SyntheticSections.cpp @@ -28,7 +28,6 @@ #include "lld/Common/Strings.h" #include "lld/Common/Version.h" #include "llvm/ADT/SetOperations.h" -#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" @@ -371,10 +370,10 @@ CieRecord *EhFrameSection::addCie(EhSectionPiece &cie, ArrayRef<RelTy> rels) { return rec; } -// There is one FDE per function. Returns true if a given FDE -// points to a live function. +// There is one FDE per function. Returns a non-null pointer to the function +// symbol if the given FDE points to a live function. template <class ELFT, class RelTy> -bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) { +Defined *EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) { auto *sec = cast<EhInputSection>(fde.sec); unsigned firstRelI = fde.firstRelocation; @@ -384,7 +383,7 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) { // corresponding FDEs, which results in creating bad .eh_frame sections. // To deal with that, we ignore such FDEs. if (firstRelI == (unsigned)-1) - return false; + return nullptr; const RelTy &rel = rels[firstRelI]; Symbol &b = sec->template getFile<ELFT>()->getRelocTargetSym(rel); @@ -392,9 +391,9 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) { // FDEs for garbage-collected or merged-by-ICF sections, or sections in // another partition, are dead. if (auto *d = dyn_cast<Defined>(&b)) - if (SectionBase *sec = d->section) - return sec->partition == partition; - return false; + if (d->section && d->section->partition == partition) + return d; + return nullptr; } // .eh_frame is a sequence of CIE or FDE records. In general, there @@ -448,6 +447,51 @@ void EhFrameSection::addSection(EhInputSection *sec) { dependentSections.push_back(ds); } +// Used by ICF<ELFT>::handleLSDA(). This function is very similar to +// EhFrameSection::addRecords(). +template <class ELFT, class RelTy> +void EhFrameSection::iterateFDEWithLSDAAux( + EhInputSection &sec, ArrayRef<RelTy> rels, DenseSet<size_t> &ciesWithLSDA, + llvm::function_ref<void(InputSection &)> fn) { + for (EhSectionPiece &piece : sec.pieces) { + // Skip ZERO terminator. + if (piece.size == 4) + continue; + + size_t offset = piece.inputOff; + uint32_t id = + endian::read32<ELFT::TargetEndianness>(piece.data().data() + 4); + if (id == 0) { + if (hasLSDA(piece)) + ciesWithLSDA.insert(offset); + continue; + } + uint32_t cieOffset = offset + 4 - id; + if (ciesWithLSDA.count(cieOffset) == 0) + continue; + + // The CIE has a LSDA argument. Call fn with d's section. + if (Defined *d = isFdeLive<ELFT>(piece, rels)) + if (auto *s = dyn_cast_or_null<InputSection>(d->section)) + fn(*s); + } +} + +template <class ELFT> +void EhFrameSection::iterateFDEWithLSDA( + llvm::function_ref<void(InputSection &)> fn) { + DenseSet<size_t> ciesWithLSDA; + for (EhInputSection *sec : sections) { + ciesWithLSDA.clear(); + if (sec->areRelocsRela) + iterateFDEWithLSDAAux<ELFT>(*sec, sec->template relas<ELFT>(), + ciesWithLSDA, fn); + else + iterateFDEWithLSDAAux<ELFT>(*sec, sec->template rels<ELFT>(), + ciesWithLSDA, fn); + } +} + static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) { memcpy(buf, d.data(), d.size()); @@ -600,15 +644,9 @@ void EhFrameSection::writeTo(uint8_t *buf) { } GotSection::GotSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, - ".got") { - // If ElfSym::globalOffsetTable is relative to .got and is referenced, - // increase numEntries by the number of entries used to emit - // ElfSym::globalOffsetTable. - if (ElfSym::globalOffsetTable && !target->gotBaseSymInGotPlt) - numEntries += target->gotHeaderEntriesNum; - else if (config->emachine == EM_PPC && !config->relocatable) - numEntries += target->gotHeaderEntriesNum; + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, + target->gotEntrySize, ".got") { + numEntries = target->gotHeaderEntriesNum; } void GotSection::addEntry(Symbol &sym) { @@ -644,21 +682,22 @@ uint64_t GotSection::getGlobalDynOffset(const Symbol &b) const { } void GotSection::finalizeContents() { - size = numEntries * config->wordsize; + if (config->emachine == EM_PPC64 && + numEntries <= target->gotHeaderEntriesNum && !ElfSym::globalOffsetTable) + size = 0; + else + size = numEntries * config->wordsize; } bool GotSection::isNeeded() const { - // We need to emit a GOT even if it's empty if there's a relocation that is - // relative to GOT(such as GOTOFFREL). - return numEntries || hasGotOffRel; + // Needed if the GOT symbol is used or the number of entries is more than just + // the header. A GOT with just the header may not be needed. + return hasGotOffRel || numEntries > target->gotHeaderEntriesNum; } void GotSection::writeTo(uint8_t *buf) { - // Buf points to the start of this section's buffer, - // whereas InputSectionBase::relocateAlloc() expects its argument - // to point to the start of the output section. target->writeGotHeader(buf); - relocateAlloc(buf - outSecOff, buf - outSecOff + size); + relocateAlloc(buf, buf + size); } static uint64_t getMipsPageAddr(uint64_t addr) { @@ -946,30 +985,37 @@ void MipsGotSection::build() { for (std::pair<Symbol *, size_t> &p : got.tls) { Symbol *s = p.first; uint64_t offset = p.second * config->wordsize; - if (s->isPreemptible) - mainPart->relaDyn->addReloc(target->tlsGotRel, this, offset, s); + // When building a shared library we still need a dynamic relocation + // for the TP-relative offset as we don't know how much other data will + // be allocated before us in the static TLS block. + if (s->isPreemptible || config->shared) + mainPart->relaDyn->addReloc({target->tlsGotRel, this, offset, + DynamicReloc::AgainstSymbolWithTargetVA, + *s, 0, R_ABS}); } for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) { Symbol *s = p.first; uint64_t offset = p.second * config->wordsize; if (s == nullptr) { - if (!config->isPic) + if (!config->shared) continue; - mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s); + mainPart->relaDyn->addReloc({target->tlsModuleIndexRel, this, offset}); } else { // When building a shared library we still need a dynamic relocation // for the module index. Therefore only checking for // S->isPreemptible is not sufficient (this happens e.g. for // thread-locals that have been marked as local through a linker script) - if (!s->isPreemptible && !config->isPic) + if (!s->isPreemptible && !config->shared) continue; - mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s); + mainPart->relaDyn->addSymbolReloc(target->tlsModuleIndexRel, this, + offset, *s); // However, we can skip writing the TLS offset reloc for non-preemptible // symbols since it is known even in shared libraries if (!s->isPreemptible) continue; offset += config->wordsize; - mainPart->relaDyn->addReloc(target->tlsOffsetRel, this, offset, s); + mainPart->relaDyn->addSymbolReloc(target->tlsOffsetRel, this, offset, + *s); } } @@ -981,7 +1027,8 @@ void MipsGotSection::build() { // Dynamic relocations for "global" entries. for (const std::pair<Symbol *, size_t> &p : got.global) { uint64_t offset = p.second * config->wordsize; - mainPart->relaDyn->addReloc(target->relativeRel, this, offset, p.first); + mainPart->relaDyn->addSymbolReloc(target->relativeRel, this, offset, + *p.first); } if (!config->isPic) continue; @@ -992,13 +1039,14 @@ void MipsGotSection::build() { for (size_t pi = 0; pi < pageCount; ++pi) { uint64_t offset = (l.second.firstIndex + pi) * config->wordsize; mainPart->relaDyn->addReloc({target->relativeRel, this, offset, l.first, - int64_t(pi * 0x10000)}); + int64_t(pi * 0x10000)}); } } for (const std::pair<GotEntry, size_t> &p : got.local16) { uint64_t offset = p.second * config->wordsize; - mainPart->relaDyn->addReloc({target->relativeRel, this, offset, true, - p.first.first, p.first.second}); + mainPart->relaDyn->addReloc({target->relativeRel, this, offset, + DynamicReloc::AddendOnlyWithTargetVA, + *p.first.first, p.first.second, R_ABS}); } } } @@ -1054,7 +1102,7 @@ void MipsGotSection::writeTo(uint8_t *buf) { // If TLS entry has a corresponding dynamic relocations, leave it // initialized by zero. Write down adjusted TLS symbol's values otherwise. // To calculate the adjustments use offsets for thread-local storage. - // https://www.linux-mips.org/wiki/NPTL + // http://web.archive.org/web/20190324223224/https://www.linux-mips.org/wiki/NPTL for (const std::pair<GotEntry, size_t> &p : g.local16) write(p.second, p.first.first, p.first.second); // Write VA to the primary GOT only. For secondary GOTs that @@ -1065,15 +1113,16 @@ void MipsGotSection::writeTo(uint8_t *buf) { for (const std::pair<Symbol *, size_t> &p : g.relocs) write(p.second, p.first, 0); for (const std::pair<Symbol *, size_t> &p : g.tls) - write(p.second, p.first, p.first->isPreemptible ? 0 : -0x7000); + write(p.second, p.first, + p.first->isPreemptible || config->shared ? 0 : -0x7000); for (const std::pair<Symbol *, size_t> &p : g.dynTlsSymbols) { - if (p.first == nullptr && !config->isPic) + if (p.first == nullptr && !config->shared) write(p.second, nullptr, 1); else if (p.first && !p.first->isPreemptible) { - // If we are emitting PIC code with relocations we mustn't write + // If we are emitting a shared libary with relocations we mustn't write // anything to the GOT here. When using Elf_Rel relocations the value // one will be treated as an addend and will cause crashes at runtime - if (!config->isPic) + if (!config->shared) write(p.second, nullptr, 1); write(p.second + 1, p.first, -0x8000); } @@ -1102,15 +1151,16 @@ void GotPltSection::addEntry(Symbol &sym) { } size_t GotPltSection::getSize() const { - return (target->gotPltHeaderEntriesNum + entries.size()) * config->wordsize; + return (target->gotPltHeaderEntriesNum + entries.size()) * + target->gotEntrySize; } void GotPltSection::writeTo(uint8_t *buf) { target->writeGotPltHeader(buf); - buf += target->gotPltHeaderEntriesNum * config->wordsize; + buf += target->gotPltHeaderEntriesNum * target->gotEntrySize; for (const Symbol *b : entries) { target->writeGotPlt(buf, *b); - buf += config->wordsize; + buf += target->gotEntrySize; } } @@ -1138,7 +1188,7 @@ static StringRef getIgotPltName() { IgotPltSection::IgotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, config->emachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, - config->wordsize, getIgotPltName()) {} + target->gotEntrySize, getIgotPltName()) {} void IgotPltSection::addEntry(Symbol &sym) { assert(sym.pltIndex == entries.size()); @@ -1146,13 +1196,13 @@ void IgotPltSection::addEntry(Symbol &sym) { } size_t IgotPltSection::getSize() const { - return entries.size() * config->wordsize; + return entries.size() * target->gotEntrySize; } void IgotPltSection::writeTo(uint8_t *buf) { for (const Symbol *b : entries) { target->writeIgotPlt(buf, *b); - buf += config->wordsize; + buf += target->gotEntrySize; } } @@ -1306,7 +1356,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { // Set DT_FLAGS and DT_FLAGS_1. uint32_t dtFlags = 0; uint32_t dtFlags1 = 0; - if (config->bsymbolic) + if (config->bsymbolic == BsymbolicKind::All) dtFlags |= DF_SYMBOLIC; if (config->zGlobal) dtFlags1 |= DF_1_GLOBAL; @@ -1397,6 +1447,13 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { case EM_SPARCV9: addInSec(DT_PLTGOT, in.plt); break; + case EM_AARCH64: + if (llvm::find_if(in.relaPlt->relocs, [](const DynamicReloc &r) { + return r.type == target->pltRel && + r.sym->stOther & STO_AARCH64_VARIANT_PCS; + }) != in.relaPlt->relocs.end()) + addInt(DT_AARCH64_VARIANT_PCS, 0); + LLVM_FALLTHROUGH; default: addInSec(DT_PLTGOT, in.gotPlt); break; @@ -1517,16 +1574,26 @@ uint64_t DynamicReloc::getOffset() const { } int64_t DynamicReloc::computeAddend() const { - if (useSymVA) - return sym->getVA(addend); - if (!outputSec) + switch (kind) { + case AddendOnly: + assert(sym == nullptr); + return addend; + case AgainstSymbol: + assert(sym != nullptr); return addend; - // See the comment in the DynamicReloc ctor. - return getMipsPageAddr(outputSec->addr) + addend; + case AddendOnlyWithTargetVA: + case AgainstSymbolWithTargetVA: + return InputSection::getRelocTargetVA(inputSec->file, type, addend, + getOffset(), *sym, expr); + case MipsMultiGotPage: + assert(sym == nullptr); + return getMipsPageAddr(outputSec->addr) + addend; + } + llvm_unreachable("Unknown DynamicReloc::Kind enum"); } uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const { - if (sym && !useSymVA) + if (needsDynSymIndex()) return symTab->getSymbolIndex(sym); return 0; } @@ -1537,21 +1604,51 @@ RelocationBaseSection::RelocationBaseSection(StringRef name, uint32_t type, : SyntheticSection(SHF_ALLOC, type, config->wordsize, name), dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag) {} -void RelocationBaseSection::addReloc(RelType dynType, InputSectionBase *isec, - uint64_t offsetInSec, Symbol *sym) { - addReloc({dynType, isec, offsetInSec, false, sym, 0}); +void RelocationBaseSection::addSymbolReloc(RelType dynType, + InputSectionBase *isec, + uint64_t offsetInSec, Symbol &sym, + int64_t addend, + Optional<RelType> addendRelType) { + addReloc(DynamicReloc::AgainstSymbol, dynType, isec, offsetInSec, sym, addend, + R_ADDEND, addendRelType ? *addendRelType : target->noneRel); +} + +void RelocationBaseSection::addRelativeReloc( + RelType dynType, InputSectionBase *inputSec, uint64_t offsetInSec, + Symbol &sym, int64_t addend, RelType addendRelType, RelExpr expr) { + // This function should only be called for non-preemptible symbols or + // RelExpr values that refer to an address inside the output file (e.g. the + // address of the GOT entry for a potentially preemptible symbol). + assert((!sym.isPreemptible || expr == R_GOT) && + "cannot add relative relocation against preemptible symbol"); + assert(expr != R_ADDEND && "expected non-addend relocation expression"); + addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, inputSec, offsetInSec, + sym, addend, expr, addendRelType); +} + +void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible( + RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, Symbol &sym, + RelType addendRelType) { + // No need to write an addend to the section for preemptible symbols. + if (sym.isPreemptible) + addReloc({dynType, isec, offsetInSec, DynamicReloc::AgainstSymbol, sym, 0, + R_ABS}); + else + addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec, offsetInSec, + sym, 0, R_ABS, addendRelType); } -void RelocationBaseSection::addReloc(RelType dynType, +void RelocationBaseSection::addReloc(DynamicReloc::Kind kind, RelType dynType, InputSectionBase *inputSec, - uint64_t offsetInSec, Symbol *sym, + uint64_t offsetInSec, Symbol &sym, int64_t addend, RelExpr expr, - RelType type) { + RelType addendRelType) { // Write the addends to the relocated address if required. We skip // it if the written value would be zero. if (config->writeAddends && (expr != R_ADDEND || addend != 0)) - inputSec->relocations.push_back({expr, type, offsetInSec, addend, sym}); - addReloc({dynType, inputSec, offsetInSec, expr != R_ADDEND, sym, addend}); + inputSec->relocations.push_back( + {expr, addendRelType, offsetInSec, addend, &sym}); + addReloc({dynType, inputSec, offsetInSec, kind, sym, addend, expr}); } void RelocationBaseSection::addReloc(const DynamicReloc &reloc) { @@ -1571,10 +1668,14 @@ void RelocationBaseSection::finalizeContents() { else getParent()->link = 0; - if (in.relaPlt == this) + if (in.relaPlt == this) { + getParent()->flags |= ELF::SHF_INFO_LINK; getParent()->info = in.gotPlt->getParent()->sectionIndex; - if (in.relaIplt == this) + } + if (in.relaIplt == this) { + getParent()->flags |= ELF::SHF_INFO_LINK; getParent()->info = in.igotPlt->getParent()->sectionIndex; + } } RelrBaseSection::RelrBaseSection() @@ -2138,6 +2239,10 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *buf) { // See getPPC64GlobalEntryToLocalEntryOffset() for more details. if (config->emachine == EM_PPC64) eSym->st_other |= sym->stOther & 0xe0; + // The most significant bit of st_other is used by AArch64 ABI for the + // variant PCS. + else if (config->emachine == EM_AARCH64) + eSym->st_other |= sym->stOther & STO_AARCH64_VARIANT_PCS; eSym->st_name = ent.strTabOffset; if (isDefinedHere) @@ -2155,9 +2260,8 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *buf) { else eSym->st_size = sym->getSize(); - // st_value is usually an address of a symbol, but that has a - // special meaning for uninstantiated common symbols (this can - // occur if -r is given). + // st_value is usually an address of a symbol, but that has a special + // meaning for uninstantiated common symbols (--no-define-common). if (BssSection *commonSec = getCommonSec(ent.sym)) eSym->st_value = commonSec->alignment; else if (isDefinedHere) @@ -2826,6 +2930,13 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() { else if (isec->name == ".debug_info") files.insert(isec->file); } + // Drop .rel[a].debug_gnu_pub{names,types} for --emit-relocs. + llvm::erase_if(inputSections, [](InputSectionBase *s) { + if (auto *isec = dyn_cast<InputSection>(s)) + if (InputSectionBase *rel = isec->getRelocatedSection()) + return !rel->isLive(); + return !s->isLive(); + }); std::vector<GdbChunk> chunks(files.size()); std::vector<std::vector<NameAttrEntry>> nameAttrs(files.size()); @@ -2875,7 +2986,8 @@ void GdbIndexSection::writeTo(uint8_t *buf) { uint32_t cuOff = 0; for (GdbChunk &chunk : chunks) { for (AddressEntry &e : chunk.addressAreas) { - uint64_t baseAddr = e.section->getVA(0); + // In the case of ICF there may be duplicate address range entries. + const uint64_t baseAddr = e.section->repl->getVA(0); write64le(buf, baseAddr + e.lowAddress); write64le(buf + 8, baseAddr + e.highAddress); write32le(buf + 16, e.cuIndex + cuOff); @@ -3049,7 +3161,10 @@ size_t VersionTableSection::getSize() const { void VersionTableSection::writeTo(uint8_t *buf) { buf += 2; for (const SymbolTableEntry &s : getPartition().dynSymTab->getSymbols()) { - write16(buf, s.sym->versionId); + // Use the original versionId for an unfetched lazy symbol (undefined weak), + // which must be VER_NDX_GLOBAL (an undefined versioned symbol is an error). + write16(buf, s.sym->isLazy() ? static_cast<uint16_t>(VER_NDX_GLOBAL) + : s.sym->versionId); buf += 2; } } @@ -3456,7 +3571,7 @@ void ARMExidxSyntheticSection::writeTo(uint8_t *buf) { assert(isec->getParent() != nullptr); if (InputSection *d = findExidxSection(isec)) { memcpy(buf + offset, d->data().data(), d->data().size()); - d->relocateAlloc(buf, buf + d->getSize()); + d->relocateAlloc(buf + d->outSecOff, buf + d->outSecOff + d->getSize()); offset += d->getSize(); } else { // A Linker generated CANTUNWIND section. @@ -3486,8 +3601,8 @@ bool ARMExidxSyntheticSection::classof(const SectionBase *d) { } ThunkSection::ThunkSection(OutputSection *os, uint64_t off) - : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4, - ".text.thunk") { + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, + config->emachine == EM_PPC64 ? 16 : 4, ".text.thunk") { this->parent = os; this->outSecOff = off; } @@ -3763,6 +3878,15 @@ template class elf::MipsOptionsSection<ELF32BE>; template class elf::MipsOptionsSection<ELF64LE>; template class elf::MipsOptionsSection<ELF64BE>; +template void EhFrameSection::iterateFDEWithLSDA<ELF32LE>( + function_ref<void(InputSection &)>); +template void EhFrameSection::iterateFDEWithLSDA<ELF32BE>( + function_ref<void(InputSection &)>); +template void EhFrameSection::iterateFDEWithLSDA<ELF64LE>( + function_ref<void(InputSection &)>); +template void EhFrameSection::iterateFDEWithLSDA<ELF64BE>( + function_ref<void(InputSection &)>); + template class elf::MipsReginfoSection<ELF32LE>; template class elf::MipsReginfoSection<ELF32BE>; template class elf::MipsReginfoSection<ELF64LE>; diff --git a/gnu/llvm/lld/ELF/Writer.cpp b/gnu/llvm/lld/ELF/Writer.cpp index c271294208e..9e6692b3709 100644 --- a/gnu/llvm/lld/ELF/Writer.cpp +++ b/gnu/llvm/lld/ELF/Writer.cpp @@ -19,6 +19,7 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/Arrays.h" #include "lld/Common/Filesystem.h" #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" @@ -45,10 +46,9 @@ namespace { // The writer writes a SymbolTable result to a file. template <class ELFT> class Writer { public: + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Writer() : buffer(errorHandler().outputBuffer) {} - using Elf_Shdr = typename ELFT::Shdr; - using Elf_Ehdr = typename ELFT::Ehdr; - using Elf_Phdr = typename ELFT::Phdr; void run(); @@ -131,9 +131,14 @@ StringRef elf::getOutputSectionName(const InputSectionBase *s) { // SampleFDO is used, if a function doesn't have sample, it could be very // cold or it could be a new function never being sampled. Those functions // will be kept in the ".text.unknown" section. + // ".text.split." holds symbols which are split out from functions in other + // input sections. For example, with -fsplit-machine-functions, placing the + // cold parts in .text.split instead of .text.unlikely mitigates against poor + // profile inaccuracy. Techniques such as hugepage remapping can make + // conservative decisions at the section granularity. if (config->zKeepTextSectionPrefix) for (StringRef v : {".text.hot.", ".text.unknown.", ".text.unlikely.", - ".text.startup.", ".text.exit."}) + ".text.startup.", ".text.exit.", ".text.split."}) if (isSectionPrefix(v, s->name)) return v.drop_back(); @@ -154,7 +159,6 @@ static bool needsInterpSection() { } template <class ELFT> void elf::writeResult() { - llvm::TimeTraceScope timeScope("Write output file"); Writer<ELFT>().run(); } @@ -201,6 +205,7 @@ void elf::copySectionsIntoPartitions() { } void elf::combineEhSections() { + llvm::TimeTraceScope timeScope("Combine EH sections"); for (InputSectionBase *&s : inputSections) { // Ignore dead sections and the partition end marker (.part.end), // whose partition number is out of bounds. @@ -633,28 +638,32 @@ template <class ELFT> void Writer<ELFT>::run() { // It does not make sense try to open the file if we have error already. if (errorCount()) return; - // Write the result down to a file. - openFile(); - if (errorCount()) - return; - if (!config->oFormatBinary) { - if (config->zSeparate != SeparateSegmentKind::None) - writeTrapInstr(); - writeHeader(); - writeSections(); - } else { - writeSectionsBinary(); - } + { + llvm::TimeTraceScope timeScope("Write output file"); + // Write the result down to a file. + openFile(); + if (errorCount()) + return; - // Backfill .note.gnu.build-id section content. This is done at last - // because the content is usually a hash value of the entire output file. - writeBuildId(); - if (errorCount()) - return; + if (!config->oFormatBinary) { + if (config->zSeparate != SeparateSegmentKind::None) + writeTrapInstr(); + writeHeader(); + writeSections(); + } else { + writeSectionsBinary(); + } - if (auto e = buffer->commit()) - error("failed to write to the output file: " + toString(std::move(e))); + // Backfill .note.gnu.build-id section content. This is done at last + // because the content is usually a hash value of the entire output file. + writeBuildId(); + if (errorCount()) + return; + + if (auto e = buffer->commit()) + error("failed to write to the output file: " + toString(std::move(e))); + } } template <class ELFT, class RelTy> @@ -760,6 +769,7 @@ static bool includeInSymtab(const Symbol &b) { template <class ELFT> void Writer<ELFT>::copyLocalSymbols() { if (!in.symTab) return; + llvm::TimeTraceScope timeScope("Add local symbols"); if (config->copyRelocs && config->discard != DiscardPolicy::None) markUsedLocalSymbols<ELFT>(); for (InputFile *file : objectFiles) { @@ -808,9 +818,12 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() { if (isa<SyntheticSection>(isec) && !(isec->flags & SHF_MERGE)) continue; + // Set the symbol to be relative to the output section so that its st_value + // equals the output section address. Note, there may be a gap between the + // start of the output section and isec. auto *sym = make<Defined>(isec->file, "", STB_LOCAL, /*stOther=*/0, STT_SECTION, - /*value=*/0, /*size=*/0, isec); + /*value=*/0, /*size=*/0, isec->getOutputSection()); in.symTab->addSymbol(sym); } } @@ -1081,7 +1094,7 @@ void PhdrEntry::add(OutputSection *sec) { // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { - if (config->relocatable || needsInterpSection()) + if (config->relocatable || config->isPic) return; // By default, __rela_iplt_{start,end} belong to a dummy section 0 @@ -1288,22 +1301,39 @@ findOrphanPos(std::vector<BaseCommand *>::iterator b, // Adds random priorities to sections not already in the map. static void maybeShuffle(DenseMap<const InputSectionBase *, int> &order) { - if (!config->shuffleSectionSeed) + if (config->shuffleSections.empty()) return; - std::vector<int> priorities(inputSections.size() - order.size()); + std::vector<InputSectionBase *> matched, sections = inputSections; + matched.reserve(sections.size()); + for (const auto &patAndSeed : config->shuffleSections) { + matched.clear(); + for (InputSectionBase *sec : sections) + if (patAndSeed.first.match(sec->name)) + matched.push_back(sec); + const uint32_t seed = patAndSeed.second; + if (seed == UINT32_MAX) { + // If --shuffle-sections <section-glob>=-1, reverse the section order. The + // section order is stable even if the number of sections changes. This is + // useful to catch issues like static initialization order fiasco + // reliably. + std::reverse(matched.begin(), matched.end()); + } else { + std::mt19937 g(seed ? seed : std::random_device()()); + llvm::shuffle(matched.begin(), matched.end(), g); + } + size_t i = 0; + for (InputSectionBase *&sec : sections) + if (patAndSeed.first.match(sec->name)) + sec = matched[i++]; + } + // Existing priorities are < 0, so use priorities >= 0 for the missing // sections. - int curPrio = 0; - for (int &prio : priorities) - prio = curPrio++; - uint32_t seed = *config->shuffleSectionSeed; - std::mt19937 g(seed ? seed : std::random_device()()); - llvm::shuffle(priorities.begin(), priorities.end(), g); - int prioIndex = 0; - for (InputSectionBase *sec : inputSections) { - if (order.try_emplace(sec, priorities[prioIndex]).second) - ++prioIndex; + int prio = 0; + for (InputSectionBase *sec : sections) { + if (order.try_emplace(sec, prio).second) + ++prio; } } @@ -1355,9 +1385,11 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() { addSym(*sym); for (InputFile *file : objectFiles) - for (Symbol *sym : file->getSymbols()) - if (sym->isLocal()) - addSym(*sym); + for (Symbol *sym : file->getSymbols()) { + if (!sym->isLocal()) + break; + addSym(*sym); + } if (config->warnSymbolOrdering) for (auto orderEntry : symbolOrder) @@ -1440,6 +1472,14 @@ static void sortSection(OutputSection *sec, if (name == ".init" || name == ".fini") return; + // IRelative relocations that usually live in the .rel[a].dyn section should + // be processed last by the dynamic loader. To achieve that we add synthetic + // sections in the required order from the beginning so that the in.relaIplt + // section is placed last in an output section. Here we just do not apply + // sorting for an output section which holds the in.relaIplt section. + if (in.relaIplt->getParent() == sec) + return; + // Sort input sections by priority using the list provided by // --symbol-ordering-file or --shuffle-sections=. This is a least significant // digit radix sort. The sections may be sorted stably again by a more @@ -1495,6 +1535,7 @@ template <class ELFT> void Writer<ELFT>::sortInputSections() { } template <class ELFT> void Writer<ELFT>::sortSections() { + llvm::TimeTraceScope timeScope("Sort sections"); script->adjustSectionsBeforeSorting(); // Don't sort if using -r. It is not necessary and we want to preserve the @@ -1613,8 +1654,12 @@ template <class ELFT> void Writer<ELFT>::sortSections() { } static bool compareByFilePosition(InputSection *a, InputSection *b) { - InputSection *la = a->getLinkOrderDep(); - InputSection *lb = b->getLinkOrderDep(); + InputSection *la = a->flags & SHF_LINK_ORDER ? a->getLinkOrderDep() : nullptr; + InputSection *lb = b->flags & SHF_LINK_ORDER ? b->getLinkOrderDep() : nullptr; + // SHF_LINK_ORDER sections with non-zero sh_link are ordered before + // non-SHF_LINK_ORDER sections and SHF_LINK_ORDER sections with zero sh_link. + if (!la || !lb) + return la && !lb; OutputSection *aOut = la->getParent(); OutputSection *bOut = lb->getParent(); @@ -1624,6 +1669,7 @@ static bool compareByFilePosition(InputSection *a, InputSection *b) { } template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { + llvm::TimeTraceScope timeScope("Resolve SHF_LINK_ORDER"); for (OutputSection *sec : outputSections) { if (!(sec->flags & SHF_LINK_ORDER)) continue; @@ -1634,50 +1680,42 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { sec->type == SHT_ARM_EXIDX) continue; - // Link order may be distributed across several InputSectionDescriptions - // but sort must consider them all at once. + // Link order may be distributed across several InputSectionDescriptions. + // Sorting is performed separately. std::vector<InputSection **> scriptSections; std::vector<InputSection *> sections; - bool started = false, stopped = false; for (BaseCommand *base : sec->sectionCommands) { - if (auto *isd = dyn_cast<InputSectionDescription>(base)) { - for (InputSection *&isec : isd->sections) { - if (!(isec->flags & SHF_LINK_ORDER)) { - if (started) - stopped = true; - } else if (stopped) { - error(toString(isec) + ": SHF_LINK_ORDER sections in " + sec->name + - " are not contiguous"); - } else { - started = true; - - scriptSections.push_back(&isec); - sections.push_back(isec); - - InputSection *link = isec->getLinkOrderDep(); - if (!link->getParent()) - error(toString(isec) + ": sh_link points to discarded section " + - toString(link)); - } + auto *isd = dyn_cast<InputSectionDescription>(base); + if (!isd) + continue; + bool hasLinkOrder = false; + scriptSections.clear(); + sections.clear(); + for (InputSection *&isec : isd->sections) { + if (isec->flags & SHF_LINK_ORDER) { + InputSection *link = isec->getLinkOrderDep(); + if (link && !link->getParent()) + error(toString(isec) + ": sh_link points to discarded section " + + toString(link)); + hasLinkOrder = true; } - } else if (started) { - stopped = true; + scriptSections.push_back(&isec); + sections.push_back(isec); + } + if (hasLinkOrder && errorCount() == 0) { + llvm::stable_sort(sections, compareByFilePosition); + for (int i = 0, n = sections.size(); i != n; ++i) + *scriptSections[i] = sections[i]; } } - - if (errorCount()) - continue; - - llvm::stable_sort(sections, compareByFilePosition); - - for (int i = 0, n = sections.size(); i < n; ++i) - *scriptSections[i] = sections[i]; } } static void finalizeSynthetic(SyntheticSection *sec) { - if (sec && sec->isNeeded() && sec->getParent()) + if (sec && sec->isNeeded() && sec->getParent()) { + llvm::TimeTraceScope timeScope("Finalize synthetic sections", sec->name); sec->finalizeContents(); + } } // We need to generate and finalize the content that depends on the address of @@ -1685,6 +1723,7 @@ static void finalizeSynthetic(SyntheticSection *sec) { // addresses we must converge to a fixed point. We do that here. See the comment // in Writer<ELFT>::finalizeSections(). template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { + llvm::TimeTraceScope timeScope("Finalize address dependent content"); ThunkCreator tc; AArch64Err843419Patcher a64p; ARMErr657417Patcher a32p; @@ -1706,8 +1745,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { bool changed = target->needsThunks && tc.createThunks(outputSections); // With Thunk Size much smaller than branch range we expect to - // converge quickly; if we get to 10 something has gone wrong. - if (changed && tc.pass >= 10) { + // converge quickly; if we get to 15 something has gone wrong. + if (changed && tc.pass >= 15) { error("thunk creation not converged"); break; } @@ -1757,7 +1796,7 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { Twine(os->alignment) + ")"); } -// If Input Sections have been shrinked (basic block sections) then +// If Input Sections have been shrunk (basic block sections) then // update symbol values and sizes associated with these sections. With basic // block sections, input sections can shrink when the jump instructions at // the end of the section are relaxed. @@ -1859,26 +1898,44 @@ template <class ELFT> void Writer<ELFT>::optimizeBasicBlockJumps() { // out to be empty. static void removeUnusedSyntheticSections() { // All input synthetic sections that can be empty are placed after - // all regular ones. We iterate over them all and exit at first - // non-synthetic. - for (InputSectionBase *s : llvm::reverse(inputSections)) { - SyntheticSection *ss = dyn_cast<SyntheticSection>(s); - if (!ss) - return; - OutputSection *os = ss->getParent(); - if (!os || ss->isNeeded()) - continue; + // all regular ones. Reverse iterate to find the first synthetic section + // after a non-synthetic one which will be our starting point. + auto start = std::find_if(inputSections.rbegin(), inputSections.rend(), + [](InputSectionBase *s) { + return !isa<SyntheticSection>(s); + }) + .base(); + + DenseSet<InputSectionDescription *> isdSet; + // Mark unused synthetic sections for deletion + auto end = std::stable_partition( + start, inputSections.end(), [&](InputSectionBase *s) { + SyntheticSection *ss = dyn_cast<SyntheticSection>(s); + OutputSection *os = ss->getParent(); + if (!os || ss->isNeeded()) + return true; - // If we reach here, then ss is an unused synthetic section and we want to - // remove it from the corresponding input section description, and - // orphanSections. - for (BaseCommand *b : os->sectionCommands) - if (auto *isd = dyn_cast<InputSectionDescription>(b)) - llvm::erase_if(isd->sections, - [=](InputSection *isec) { return isec == ss; }); - llvm::erase_if(script->orphanSections, - [=](const InputSectionBase *isec) { return isec == ss; }); - } + // If we reach here, then ss is an unused synthetic section and we want + // to remove it from the corresponding input section description, and + // orphanSections. + for (BaseCommand *b : os->sectionCommands) + if (auto *isd = dyn_cast<InputSectionDescription>(b)) + isdSet.insert(isd); + + llvm::erase_if( + script->orphanSections, + [=](const InputSectionBase *isec) { return isec == ss; }); + + return false; + }); + + DenseSet<InputSectionBase *> unused(end, inputSections.end()); + for (auto *isd : isdSet) + llvm::erase_if(isd->sections, + [=](InputSection *isec) { return unused.count(isec); }); + + // Erase unused synthetic sections. + inputSections.erase(end, inputSections.end()); } // Create output section objects and add them to OutputSections. @@ -1941,11 +1998,14 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { } } - // This responsible for splitting up .eh_frame section into - // pieces. The relocation scan uses those pieces, so this has to be - // earlier. - for (Partition &part : partitions) - finalizeSynthetic(part.ehFrame); + { + llvm::TimeTraceScope timeScope("Finalize .eh_frame"); + // This responsible for splitting up .eh_frame section into + // pieces. The relocation scan uses those pieces, so this has to be + // earlier. + for (Partition &part : partitions) + finalizeSynthetic(part.ehFrame); + } for (Symbol *sym : symtab->symbols()) sym->isPreemptible = computeIsPreemptible(*sym); @@ -1954,14 +2014,17 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // by declareSymbols) to actual definitions. script->processSymbolAssignments(); - // Scan relocations. This must be done after every symbol is declared so that - // we can correctly decide if a dynamic relocation is needed. This is called - // after processSymbolAssignments() because it needs to know whether a - // linker-script-defined symbol is absolute. - ppc64noTocRelax.clear(); - if (!config->relocatable) { - forEachRelSec(scanRelocations<ELFT>); - reportUndefinedSymbols<ELFT>(); + { + llvm::TimeTraceScope timeScope("Scan relocations"); + // Scan relocations. This must be done after every symbol is declared so + // that we can correctly decide if a dynamic relocation is needed. This is + // called after processSymbolAssignments() because it needs to know whether + // a linker-script-defined symbol is absolute. + ppc64noTocRelax.clear(); + if (!config->relocatable) { + forEachRelSec(scanRelocations<ELFT>); + reportUndefinedSymbols<ELFT>(); + } } if (in.plt && in.plt->isNeeded()) @@ -1969,7 +2032,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (in.iplt && in.iplt->isNeeded()) in.iplt->addSymbols(); - if (!config->allowShlibUndefined) { + if (config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) { + auto diagnose = + config->unresolvedSymbolsInShlib == UnresolvedPolicy::ReportError + ? errorOrWarn + : warn; // Error on undefined symbols in a shared object, if all of its DT_NEEDED // entries are seen. These cases would otherwise lead to runtime errors // reported by the dynamic linker. @@ -1977,45 +2044,49 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // ld.bfd traces all DT_NEEDED to emulate the logic of the dynamic linker to // catch more cases. That is too much for us. Our approach resembles the one // used in ld.gold, achieves a good balance to be useful but not too smart. - for (SharedFile *file : sharedFiles) - file->allNeededIsKnown = + for (SharedFile *file : sharedFiles) { + bool allNeededIsKnown = llvm::all_of(file->dtNeeded, [&](StringRef needed) { return symtab->soNames.count(needed); }); - - for (Symbol *sym : symtab->symbols()) - if (sym->isUndefined() && !sym->isWeak()) - if (auto *f = dyn_cast_or_null<SharedFile>(sym->file)) - if (f->allNeededIsKnown) - errorOrWarn(toString(f) + ": undefined reference to " + - toString(*sym) + " [--no-allow-shlib-undefined]"); + if (!allNeededIsKnown) + continue; + for (Symbol *sym : file->requiredSymbols) + if (sym->isUndefined() && !sym->isWeak()) + diagnose(toString(file) + ": undefined reference to " + + toString(*sym) + " [--no-allow-shlib-undefined]"); + } } - // Now that we have defined all possible global symbols including linker- - // synthesized ones. Visit all symbols to give the finishing touches. - for (Symbol *sym : symtab->symbols()) { - if (!includeInSymtab(*sym)) - continue; - if (in.symTab) - in.symTab->addSymbol(sym); - - if (sym->includeInDynsym()) { - partitions[sym->partition - 1].dynSymTab->addSymbol(sym); - if (auto *file = dyn_cast_or_null<SharedFile>(sym->file)) - if (file->isNeeded && !sym->isUndefined()) - addVerneed(sym); + { + llvm::TimeTraceScope timeScope("Add symbols to symtabs"); + // Now that we have defined all possible global symbols including linker- + // synthesized ones. Visit all symbols to give the finishing touches. + for (Symbol *sym : symtab->symbols()) { + if (!includeInSymtab(*sym)) + continue; + if (in.symTab) + in.symTab->addSymbol(sym); + + if (sym->includeInDynsym()) { + partitions[sym->partition - 1].dynSymTab->addSymbol(sym); + if (auto *file = dyn_cast_or_null<SharedFile>(sym->file)) + if (file->isNeeded && !sym->isUndefined()) + addVerneed(sym); + } } - } - // We also need to scan the dynamic relocation tables of the other partitions - // and add any referenced symbols to the partition's dynsym. - for (Partition &part : MutableArrayRef<Partition>(partitions).slice(1)) { - DenseSet<Symbol *> syms; - for (const SymbolTableEntry &e : part.dynSymTab->getSymbols()) - syms.insert(e.sym); - for (DynamicReloc &reloc : part.relaDyn->relocs) - if (reloc.sym && !reloc.useSymVA && syms.insert(reloc.sym).second) - part.dynSymTab->addSymbol(reloc.sym); + // We also need to scan the dynamic relocation tables of the other + // partitions and add any referenced symbols to the partition's dynsym. + for (Partition &part : MutableArrayRef<Partition>(partitions).slice(1)) { + DenseSet<Symbol *> syms; + for (const SymbolTableEntry &e : part.dynSymTab->getSymbols()) + syms.insert(e.sym); + for (DynamicReloc &reloc : part.relaDyn->relocs) + if (reloc.sym && reloc.needsDynSymIndex() && + syms.insert(reloc.sym).second) + part.dynSymTab->addSymbol(reloc.sym); + } } // Do not proceed if there was an undefined symbol. @@ -2096,35 +2167,39 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // have the headers, we can find out which sections they point to. setReservedSymbolSections(); - finalizeSynthetic(in.bss); - finalizeSynthetic(in.bssRelRo); - finalizeSynthetic(in.symTabShndx); - finalizeSynthetic(in.shStrTab); - finalizeSynthetic(in.strTab); - finalizeSynthetic(in.got); - finalizeSynthetic(in.mipsGot); - finalizeSynthetic(in.igotPlt); - finalizeSynthetic(in.gotPlt); - finalizeSynthetic(in.relaIplt); - finalizeSynthetic(in.relaPlt); - finalizeSynthetic(in.plt); - finalizeSynthetic(in.iplt); - finalizeSynthetic(in.ppc32Got2); - finalizeSynthetic(in.partIndex); - - // Dynamic section must be the last one in this list and dynamic - // symbol table section (dynSymTab) must be the first one. - for (Partition &part : partitions) { - finalizeSynthetic(part.dynSymTab); - finalizeSynthetic(part.gnuHashTab); - finalizeSynthetic(part.hashTab); - finalizeSynthetic(part.verDef); - finalizeSynthetic(part.relaDyn); - finalizeSynthetic(part.relrDyn); - finalizeSynthetic(part.ehFrameHdr); - finalizeSynthetic(part.verSym); - finalizeSynthetic(part.verNeed); - finalizeSynthetic(part.dynamic); + { + llvm::TimeTraceScope timeScope("Finalize synthetic sections"); + + finalizeSynthetic(in.bss); + finalizeSynthetic(in.bssRelRo); + finalizeSynthetic(in.symTabShndx); + finalizeSynthetic(in.shStrTab); + finalizeSynthetic(in.strTab); + finalizeSynthetic(in.got); + finalizeSynthetic(in.mipsGot); + finalizeSynthetic(in.igotPlt); + finalizeSynthetic(in.gotPlt); + finalizeSynthetic(in.relaIplt); + finalizeSynthetic(in.relaPlt); + finalizeSynthetic(in.plt); + finalizeSynthetic(in.iplt); + finalizeSynthetic(in.ppc32Got2); + finalizeSynthetic(in.partIndex); + + // Dynamic section must be the last one in this list and dynamic + // symbol table section (dynSymTab) must be the first one. + for (Partition &part : partitions) { + finalizeSynthetic(part.dynSymTab); + finalizeSynthetic(part.gnuHashTab); + finalizeSynthetic(part.hashTab); + finalizeSynthetic(part.verDef); + finalizeSynthetic(part.relaDyn); + finalizeSynthetic(part.relrDyn); + finalizeSynthetic(part.ehFrameHdr); + finalizeSynthetic(part.verSym); + finalizeSynthetic(part.verNeed); + finalizeSynthetic(part.dynamic); + } } if (!script->hasSectionsCommand && !config->relocatable) @@ -2155,9 +2230,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (errorCount()) return; - // finalizeAddressDependentContent may have added local symbols to the static symbol table. - finalizeSynthetic(in.symTab); - finalizeSynthetic(in.ppc64LongBranchTarget); + { + llvm::TimeTraceScope timeScope("Finalize synthetic sections"); + // finalizeAddressDependentContent may have added local symbols to the + // static symbol table. + finalizeSynthetic(in.symTab); + finalizeSynthetic(in.ppc64LongBranchTarget); + } // Relaxation to delete inter-basic block jumps created by basic block // sections. Run after in.symTab is finalized as optimizeBasicBlockJumps @@ -2245,7 +2324,7 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *sec) { } static bool needsPtLoad(OutputSection *sec) { - if (!(sec->flags & SHF_ALLOC) || sec->noload) + if (!(sec->flags & SHF_ALLOC)) return false; // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is @@ -2335,8 +2414,6 @@ std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Partition &part) { } for (OutputSection *sec : outputSections) { - if (!(sec->flags & SHF_ALLOC)) - break; if (!needsPtLoad(sec)) continue; @@ -2581,11 +2658,24 @@ static uint64_t setFileOffset(OutputSection *os, uint64_t off) { } template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() { - uint64_t off = 0; + // Compute the minimum LMA of all non-empty non-NOBITS sections as minAddr. + auto needsOffset = [](OutputSection &sec) { + return sec.type != SHT_NOBITS && (sec.flags & SHF_ALLOC) && sec.size > 0; + }; + uint64_t minAddr = UINT64_MAX; for (OutputSection *sec : outputSections) - if (sec->flags & SHF_ALLOC) - off = setFileOffset(sec, off); - fileSize = alignTo(off, config->wordsize); + if (needsOffset(*sec)) { + sec->offset = sec->getLMA(); + minAddr = std::min(minAddr, sec->offset); + } + + // Sections are laid out at LMA minus minAddr. + fileSize = 0; + for (OutputSection *sec : outputSections) + if (needsOffset(*sec)) { + sec->offset -= minAddr; + fileSize = std::max(fileSize, sec->offset + sec->size); + } } static std::string rangeToString(uint64_t addr, uint64_t len) { @@ -2604,7 +2694,11 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() { if (p->p_type == PT_LOAD && (p->p_flags & PF_X)) lastRX = p; + // Layout SHF_ALLOC sections before non-SHF_ALLOC sections. A non-SHF_ALLOC + // will not occupy file offsets contained by a PT_LOAD. for (OutputSection *sec : outputSections) { + if (!(sec->flags & SHF_ALLOC)) + continue; off = setFileOffset(sec, off); // If this is a last section of the last executable segment and that @@ -2614,6 +2708,9 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() { lastRX->lastSec == sec) off = alignTo(off, config->commonPageSize); } + for (OutputSection *sec : outputSections) + if (!(sec->flags & SHF_ALLOC)) + off = setFileOffset(sec, off); sectionHeaderOff = alignTo(off, config->wordsize); fileSize = sectionHeaderOff + (outputSections.size() + 1) * sizeof(Elf_Shdr); @@ -2845,7 +2942,13 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { template <class ELFT> void Writer<ELFT>::openFile() { uint64_t maxSize = config->is64 ? INT64_MAX : UINT32_MAX; if (fileSize != size_t(fileSize) || maxSize < fileSize) { - error("output file too large: " + Twine(fileSize) + " bytes"); + std::string msg; + raw_string_ostream s(msg); + s << "output file too large: " << Twine(fileSize) << " bytes\n" + << "section sizes:\n"; + for (OutputSection *os : outputSections) + s << os->name << ' ' << os->size << "\n"; + error(s.str()); return; } @@ -2920,19 +3023,13 @@ template <class ELFT> void Writer<ELFT>::writeSections() { for (OutputSection *sec : outputSections) if (sec->type != SHT_REL && sec->type != SHT_RELA) sec->writeTo<ELFT>(Out::bufferStart + sec->offset); -} -// Split one uint8 array into small pieces of uint8 arrays. -static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> arr, - size_t chunkSize) { - std::vector<ArrayRef<uint8_t>> ret; - while (arr.size() > chunkSize) { - ret.push_back(arr.take_front(chunkSize)); - arr = arr.drop_front(chunkSize); + // Finally, check that all dynamic relocation addends were written correctly. + if (config->checkDynamicRelocs && config->writeAddends) { + for (OutputSection *sec : outputSections) + if (sec->type == SHT_REL || sec->type == SHT_RELA) + sec->checkDynRelAddends(Out::bufferStart); } - if (!arr.empty()) - ret.push_back(arr); - return ret; } // Computes a hash value of Data using a given hash function. diff --git a/gnu/llvm/lld/MachO/MergedOutputSection.cpp b/gnu/llvm/lld/MachO/MergedOutputSection.cpp deleted file mode 100644 index 2d0be253834..00000000000 --- a/gnu/llvm/lld/MachO/MergedOutputSection.cpp +++ /dev/null @@ -1,74 +0,0 @@ -//===- OutputSection.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 -// -//===----------------------------------------------------------------------===// - -#include "MergedOutputSection.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" -#include "llvm/BinaryFormat/MachO.h" - -using namespace llvm; -using namespace llvm::MachO; -using namespace lld; -using namespace lld::macho; - -void MergedOutputSection::mergeInput(InputSection *input) { - if (inputs.empty()) { - align = input->align; - flags = input->flags; - } else { - mergeFlags(input->flags); - align = std::max(align, input->align); - } - - inputs.push_back(input); - input->parent = this; -} - -void MergedOutputSection::finalize() { - uint64_t isecAddr = addr; - uint64_t isecFileOff = fileOff; - for (InputSection *isec : inputs) { - isecAddr = alignTo(isecAddr, isec->align); - isecFileOff = alignTo(isecFileOff, isec->align); - isec->outSecOff = isecAddr - addr; - isec->outSecFileOff = isecFileOff - fileOff; - isecAddr += isec->getSize(); - isecFileOff += isec->getFileSize(); - } - size = isecAddr - addr; - fileSize = isecFileOff - fileOff; -} - -void MergedOutputSection::writeTo(uint8_t *buf) const { - for (InputSection *isec : inputs) { - isec->writeTo(buf + isec->outSecFileOff); - } -} - -// TODO: this is most likely wrong; reconsider how section flags -// are actually merged. The logic presented here was written without -// any form of informed research. -void MergedOutputSection::mergeFlags(uint32_t inputFlags) { - uint8_t sectionFlag = MachO::SECTION_TYPE & inputFlags; - if (sectionFlag != (MachO::SECTION_TYPE & flags)) - error("Cannot add merge section; inconsistent type flags " + - Twine(sectionFlag)); - - uint32_t inconsistentFlags = - MachO::S_ATTR_DEBUG | MachO::S_ATTR_STRIP_STATIC_SYMS | - MachO::S_ATTR_NO_DEAD_STRIP | MachO::S_ATTR_LIVE_SUPPORT; - if ((inputFlags ^ flags) & inconsistentFlags) - error("Cannot add merge section; cannot merge inconsistent flags"); - - // Negate pure instruction presence if any section isn't pure. - uint32_t pureMask = ~MachO::S_ATTR_PURE_INSTRUCTIONS | (inputFlags & flags); - - // Merge the rest - flags |= inputFlags; - flags &= pureMask; -} diff --git a/gnu/llvm/lld/MachO/MergedOutputSection.h b/gnu/llvm/lld/MachO/MergedOutputSection.h deleted file mode 100644 index 279a7e0f75c..00000000000 --- a/gnu/llvm/lld/MachO/MergedOutputSection.h +++ /dev/null @@ -1,56 +0,0 @@ -//===- OutputSection.h ------------------------------------------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_MACHO_MERGED_OUTPUT_SECTION_H -#define LLD_MACHO_MERGED_OUTPUT_SECTION_H - -#include "InputSection.h" -#include "OutputSection.h" -#include "lld/Common/LLVM.h" -#include "llvm/ADT/MapVector.h" - -namespace lld { -namespace macho { - -// Linking multiple files will inevitably mean resolving sections in different -// files that are labeled with the same segment and section name. This class -// contains all such sections and writes the data from each section sequentially -// in the final binary. -class MergedOutputSection : public OutputSection { -public: - MergedOutputSection(StringRef name) : OutputSection(MergedKind, name) {} - - const InputSection *firstSection() const { return inputs.front(); } - const InputSection *lastSection() const { return inputs.back(); } - - // These accessors will only be valid after finalizing the section - uint64_t getSize() const override { return size; } - uint64_t getFileSize() const override { return fileSize; } - - void mergeInput(InputSection *input); - void finalize() override; - - void writeTo(uint8_t *buf) const override; - - std::vector<InputSection *> inputs; - - static bool classof(const OutputSection *sec) { - return sec->kind() == MergedKind; - } - -private: - void mergeFlags(uint32_t inputFlags); - - size_t size = 0; - uint64_t fileSize = 0; -}; - -} // namespace macho -} // namespace lld - -#endif diff --git a/gnu/llvm/lld/docs/ld.lld.1 b/gnu/llvm/lld/docs/ld.lld.1 index 92d67b17e24..86d47f24378 100644 --- a/gnu/llvm/lld/docs/ld.lld.1 +++ b/gnu/llvm/lld/docs/ld.lld.1 @@ -57,7 +57,7 @@ Do not error if a symbol is defined multiple times. The first definition will be used. .It Fl -allow-shlib-undefined Allow unresolved references in shared libraries. -This option is enabled by default when linking a shared library. +This option is enabled by default. .It Fl -apply-dynamic-relocs Apply link-time values for dynamic relocations. .It Fl -as-needed @@ -72,10 +72,22 @@ field to the specified name. Link against shared libraries. .It Fl -Bstatic , Fl -static , Fl -dn Do not link against shared libraries. -.It Fl -Bsymbolic -Bind defined symbols locally. -.It Fl -Bsymbolic-functions -Bind defined function symbols locally. +.It Fl Bno-symbolic +Don't bind default visibility defined symbols locally for +.Fl shared +(default). +.It Fl Bsymbolic +Bind default visibility defined symbols locally for +.Fl shared. +Also set the +.Dv DF_SYMBOLIC +flag. +.It Fl Bsymbolic-functions +Bind default visibility defined function symbols locally for +.Fl shared. +.It Fl Bsymbolic-non-weak-functions +Bind default visibility defined STB_GLOBAL function symbols locally for +.Fl shared. .It Fl -build-id Ns = Ns Ar value Generate a build ID note. .Ar value @@ -157,6 +169,14 @@ This is recorded in an ELF segment of type .It Fl -dynamic-list Ns = Ns Ar file Read a list of dynamic symbols from .Ar file . +(executable) Put matched non-local defined symbols to the dynamic symbol table. +(shared object) References to matched non-local STV_DEFAULT symbols shouldn't be bound to definitions within the shared object. Implies +.Cm -Bsymbolic +but does not set DF_SYMBOLIC +.It Fl -EB +Select the big-endian format in the OUTPUT_FORMAT command. +.It Fl -EL +Select the little-endian format in the OUTPUT_FORMAT command. .It Fl -eh-frame-hdr Request creation of .Li .eh_frame_hdr @@ -177,6 +197,19 @@ Maximum number of errors to emit before stopping. A value of zero indicates that there is no limit. .It Fl -error-unresolved-symbols Report unresolved symbols as errors. +.It Fl -error-handing-script Ns = Ns Ar script_path +Call script +.Ar script_path +upon some error, with +.Ar tag +as first argument, and an extra parameter as second argument. The script is +expected to return 0 on success. Any other value is considered a generic error. +.Ar tag +may be +.Cm missing-lib +followed by the name of the missing library. +.Cm undefined-symbol +followed by the name of the undefined symbol. .It Fl -execute-only Mark executable sections unreadable. This option is currently only supported on AArch64. @@ -184,10 +217,14 @@ This option is currently only supported on AArch64. Exclude static libraries from automatic export. .It Fl -export-dynamic , Fl E Put symbols in the dynamic symbol table. -.It Fl -export-dynamic-symbol Ns = Ns Ar symbol -Include -.Ar symbol -in the dynamic symbol table. +.It Fl -export-dynamic-symbol Ns = Ns Ar glob +(executable) Put matched non-local defined symbols to the dynamic symbol table. +(shared object) References to matched non-local STV_DEFAULT symbols shouldn't be bound to definitions within the shared object even if they would otherwise be due to +.Cm -Bsymbolic +, +.Cm -Bsymbolic-functions +or +.Cm --dynamic-list .It Fl -fatal-warnings Treat warnings as errors. .It Fl -filter Ns = Ns Ar value , Fl F Ar value @@ -275,7 +312,7 @@ Print a link map to Do not page align sections, link against static libraries. .It Fl -no-allow-shlib-undefined Do not allow unresolved references in shared libraries. -This option is enabled by default when linking an executable. +This option is disabled by default. .It Fl -no-as-needed Always set .Dv DT_NEEDED @@ -290,6 +327,8 @@ Do not demangle symbol names. Inhibit output of an .Li .interp section. +.It Fl -no-fortran-common +Do not search archive members for definitions to override COMMON symbols. .It Fl -no-gc-sections Disable garbage collection of unused sections. .It Fl -no-gnu-unique @@ -300,10 +339,10 @@ Disable merging .ARM.exidx entries. Page align sections. .It Fl -no-omagic Do not set the text data sections to be writable, page align sections. +.It Fl -no-relax +Disable target-specific relaxations. This is currently a no-op. .It Fl -no-rosegment Do not put read-only non-executable sections in their own segment. -.It Fl -no-threads -Do not run the linker multi-threaded. .It Fl -no-undefined-version Report version scripts that refer undefined symbols. .It Fl -no-undefined @@ -416,6 +455,9 @@ List removed unused sections. List identical folded sections. .It Fl -print-map Print a link map to the standard output. +.It Fl -print-archive-stats Ns = Ns Ar file +Write archive usage statistics to the specified file. +Print the numbers of members and fetched members for each archive. .It Fl -push-state Save the current state of .Fl -as-needed , @@ -456,6 +498,9 @@ were concatenated in the order they appeared on the command line. Set address of section. .It Fl -shared , Fl -Bsharable Build a shared object. +.It Fl -shuffle-sections Ns = Ns Ar seed +Shuffle matched sections using the given seed before mapping them to the output sections. +If -1, reverse the section order. If 0, use a random seed. .It Fl -soname Ns = Ns Ar value , Fl h Ar value Set .Dv DT_SONAME @@ -470,6 +515,8 @@ Start a grouping of objects that should be treated as if they were together in an archive. .It Fl -strip-all , Fl s Strip all symbols. +Implies +.Fl -strip-debug . .It Fl -strip-debug , Fl S Strip debugging information. .It Fl -symbol-ordering-file Ns = Ns Ar file @@ -523,9 +570,19 @@ Path to ThinLTO cached object file directory. Pruning policy for the ThinLTO cache. .It Fl -thinlto-jobs Ns = Ns Ar value Number of ThinLTO jobs. -.It Fl -threads -Run the linker multi-threaded. -This option is enabled by default. +.It Fl -threads Ns = Ns Ar N +Number of threads. +.Cm all +(default) means all of concurrent threads supported. +.Cm 1 +disables multi-threading. +.It Fl -time-trace +Record time trace. +.It Fl -time-trace-file Ns = Ns Ar file +Write time trace output to +.Ar file . +.It Fl -time-trace-granularity Ns = Ns Ar value +Minimum time granularity (in microseconds) traced by time profiler. .It Fl -trace Print the names of the input files. .It Fl -trace-symbol Ns = Ns Ar symbol , Fl y Ar symbol @@ -551,6 +608,8 @@ matches the characters within brackets. All symbols that match a given pattern are handled as if they were given as arguments of .Fl -undefined . +.It Fl -unique +Creates a separate output section for every orphan input section. .It Fl -unresolved-symbols Ns = Ns Ar value Determine how to handle unresolved symbols. .It Fl -use-android-relr-tags @@ -569,6 +628,10 @@ Read version script from Warn about reverse or cyclic dependencies to or between static archives. This can be used to ensure linker invocation remains compatible with traditional Unix-like linkers. +.It Fl -warn-backrefs-exclude Ns = Ns Ar glob +Glob describing an archive (or an object file within --start-lib) +which should be ignored for +.Fl -warn-backrefs .It Fl -warn-common Warn about duplicate common symbols. .It Fl -warn-ifunc-textrel @@ -591,11 +654,25 @@ Report unresolved symbols as warnings. .It Fl -whole-archive Force load of all members in a static library. .It Fl -wrap Ns = Ns Ar symbol -Use wrapper functions for symbol. +Redirect +.Ar symbol +references to +.Ar __wrap_symbol +and +.Ar __real_symbol +references to +.Ar symbol. .It Fl z Ar option Linker option extensions. .Bl -tag -width indent -compact .Pp +.It Cm dead-reloc-in-nonalloc Ns = Ns Ar section_glob=value +Resolve a relocation in a matched non-SHF_ALLOC section referencing a discarded symbol to +.Ar value +Accepts globs, in the event of a section matching more than one option, the last +option takes precedence. An order of least specific to most specific match is +recommended. +.Pp .It Cm execstack Make the main stack executable. Stack permissions are recorded in the @@ -701,6 +778,12 @@ processing. .It Cm pac-plt AArch64 only, use pointer authentication in PLT. .Pp +.It Cm rel +Use REL format for dynamic relocations. +.Pp +.It Cm rela +Use RELA format for dynamic relocations. +.Pp .It Cm retpolineplt Emit retpoline format PLT entries as a mitigation for CVE-2017-5715. .Pp @@ -734,6 +817,12 @@ The stack size is recorded as the size of the .Dv PT_GNU_STACK program segment. .Pp +.It Cm start-stop-gc +Don't let __start_/__stop_ references retain the associated C identifier name sections (default). +.Pp +.It Cm nostart-stop-gc +Let __start_/__stop_ references retain the associated C identifier name sections. +.Pp .It Cm text Do not allow relocations against read-only segments. This is the default. diff --git a/gnu/llvm/lld/tools/lld/lld.cpp b/gnu/llvm/lld/tools/lld/lld.cpp index 4b3d54d1be4..8d76f25b372 100644 --- a/gnu/llvm/lld/tools/lld/lld.cpp +++ b/gnu/llvm/lld/tools/lld/lld.cpp @@ -26,6 +26,7 @@ //===----------------------------------------------------------------------===// #include "lld/Common/Driver.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" @@ -33,6 +34,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" @@ -48,11 +50,11 @@ enum Flavor { Gnu, // -flavor gnu WinLink, // -flavor link Darwin, // -flavor darwin - DarwinNew, // -flavor darwinnew + DarwinOld, // -flavor darwinold Wasm, // -flavor wasm }; -LLVM_ATTRIBUTE_NORETURN static void die(const Twine &s) { +[[noreturn]] static void die(const Twine &s) { llvm::errs() << s << "\n"; exit(1); } @@ -62,8 +64,9 @@ static Flavor getFlavor(StringRef s) { .CasesLower("ld", "ld.lld", "gnu", Gnu) .CasesLower("wasm", "ld-wasm", Wasm) .CaseLower("link", WinLink) - .CasesLower("ld64", "ld64.lld", "darwin", Darwin) - .CaseLower("darwinnew", DarwinNew) + .CasesLower("ld64", "ld64.lld", "darwin", "darwinnew", + "ld64.lld.darwinnew", Darwin) + .CasesLower("darwinold", "ld64.lld.darwinold", DarwinOld) .Default(Invalid); } @@ -93,7 +96,12 @@ static bool isPETarget(std::vector<const char *> &v) { continue; return isPETargetName(*(it + 1)); } + +#ifdef LLD_DEFAULT_LD_LLD_IS_MINGW + return true; +#else return false; +#endif } #endif @@ -125,41 +133,32 @@ static Flavor parseFlavor(std::vector<const char *> &v) { // Deduct the flavor from argv[0]. StringRef arg0 = path::filename(v[0]); - if (arg0.endswith_lower(".exe")) + if (arg0.endswith_insensitive(".exe")) arg0 = arg0.drop_back(4); return parseProgname(arg0); } -// If this function returns true, lld calls _exit() so that it quickly -// exits without invoking destructors of globally allocated objects. -// -// We don't want to do that if we are running tests though, because -// doing that breaks leak sanitizer. So, lit sets this environment variable, -// and we use it to detect whether we are running tests or not. -static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; } - /// Universal linker main(). This linker emulates the gnu, darwin, or /// windows linker based on the argv[0] or -flavor option. -int main(int argc, const char **argv) { - InitLLVM x(argc, argv); - +static int lldMain(int argc, const char **argv, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, bool exitEarly = true) { std::vector<const char *> args(argv, argv + argc); switch (parseFlavor(args)) { case Gnu: #ifndef __OpenBSD__ if (isPETarget(args)) - return !mingw::link(args, canExitEarly(), llvm::outs(), llvm::errs()); + return !mingw::link(args, exitEarly, stdoutOS, stderrOS); #endif - return !elf::link(args, canExitEarly(), llvm::outs(), llvm::errs()); + return !elf::link(args, exitEarly, stdoutOS, stderrOS); #ifndef __OpenBSD__ case WinLink: - return !coff::link(args, canExitEarly(), llvm::outs(), llvm::errs()); + return !coff::link(args, exitEarly, stdoutOS, stderrOS); case Darwin: - return !mach_o::link(args, canExitEarly(), llvm::outs(), llvm::errs()); - case DarwinNew: - return !macho::link(args, canExitEarly(), llvm::outs(), llvm::errs()); + return !macho::link(args, exitEarly, stdoutOS, stderrOS); + case DarwinOld: + return !mach_o::link(args, exitEarly, stdoutOS, stderrOS); case Wasm: - return !wasm::link(args, canExitEarly(), llvm::outs(), llvm::errs()); + return !lld::wasm::link(args, exitEarly, stdoutOS, stderrOS); #endif default: die("lld is a generic driver.\n" @@ -167,3 +166,70 @@ int main(int argc, const char **argv) { " (WebAssembly) instead"); } } + +// Similar to lldMain except that exceptions are caught. +SafeReturn lld::safeLldMain(int argc, const char **argv, + llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS) { + int r = 0; + { + // The crash recovery is here only to be able to recover from arbitrary + // control flow when fatal() is called (through setjmp/longjmp or + // __try/__except). + llvm::CrashRecoveryContext crc; + if (!crc.RunSafely([&]() { + r = lldMain(argc, argv, stdoutOS, stderrOS, /*exitEarly=*/false); + })) + return {crc.RetCode, /*canRunAgain=*/false}; + } + + // Cleanup memory and reset everything back in pristine condition. This path + // is only taken when LLD is in test, or when it is used as a library. + llvm::CrashRecoveryContext crc; + if (!crc.RunSafely([&]() { errorHandler().reset(); })) { + // The memory is corrupted beyond any possible recovery. + return {r, /*canRunAgain=*/false}; + } + return {r, /*canRunAgain=*/true}; +} + +// When in lit tests, tells how many times the LLD tool should re-execute the +// main loop with the same inputs. When not in test, returns a value of 0 which +// signifies that LLD shall not release any memory after execution, to speed up +// process destruction. +static unsigned inTestVerbosity() { + unsigned v = 0; + StringRef(getenv("LLD_IN_TEST")).getAsInteger(10, v); + return v; +} + +int main(int argc, const char **argv) { + InitLLVM x(argc, argv); + + // Not running in lit tests, just take the shortest codepath with global + // exception handling and no memory cleanup on exit. + if (!inTestVerbosity()) + return lldMain(argc, argv, llvm::outs(), llvm::errs()); + + Optional<int> mainRet; + CrashRecoveryContext::Enable(); + + for (unsigned i = inTestVerbosity(); i > 0; --i) { + // Disable stdout/stderr for all iterations but the last one. + if (i != 1) + errorHandler().disableOutput = true; + + // Execute one iteration. + auto r = safeLldMain(argc, argv, llvm::outs(), llvm::errs()); + if (!r.canRunAgain) + exitLld(r.ret); // Exit now, can't re-execute again. + + if (!mainRet) { + mainRet = r.ret; + } else if (r.ret != *mainRet) { + // Exit now, to fail the tests if the result is different between runs. + return r.ret; + } + } + return *mainRet; +} diff --git a/gnu/llvm/lld/wasm/InputEvent.h b/gnu/llvm/lld/wasm/InputEvent.h deleted file mode 100644 index 98cfdf7bfc7..00000000000 --- a/gnu/llvm/lld/wasm/InputEvent.h +++ /dev/null @@ -1,62 +0,0 @@ -//===- InputEvent.h ---------------------------------------------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Wasm events are features that suspend the current execution and transfer the -// control flow to a corresponding handler. Currently the only supported event -// kind is exceptions. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_WASM_INPUT_EVENT_H -#define LLD_WASM_INPUT_EVENT_H - -#include "Config.h" -#include "InputFiles.h" -#include "WriterUtils.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/Wasm.h" - -namespace lld { -namespace wasm { - -// Represents a single Wasm Event within an input file. These are combined to -// form the final EVENTS section. -class InputEvent { -public: - InputEvent(const WasmSignature &s, const WasmEvent &e, ObjFile *f) - : file(f), event(e), signature(s), live(!config->gcSections) {} - - StringRef getName() const { return event.SymbolName; } - const WasmEventType &getType() const { return event.Type; } - - uint32_t getEventIndex() const { return eventIndex.getValue(); } - bool hasEventIndex() const { return eventIndex.hasValue(); } - void setEventIndex(uint32_t index) { - assert(!hasEventIndex()); - eventIndex = index; - } - - ObjFile *file; - WasmEvent event; - const WasmSignature &signature; - - bool live = false; - -protected: - llvm::Optional<uint32_t> eventIndex; -}; - -} // namespace wasm - -inline std::string toString(const wasm::InputEvent *e) { - return (toString(e->file) + ":(" + e->getName() + ")").str(); -} - -} // namespace lld - -#endif // LLD_WASM_INPUT_EVENT_H diff --git a/gnu/llvm/lld/wasm/InputGlobal.h b/gnu/llvm/lld/wasm/InputGlobal.h deleted file mode 100644 index 89cde8423c8..00000000000 --- a/gnu/llvm/lld/wasm/InputGlobal.h +++ /dev/null @@ -1,55 +0,0 @@ -//===- InputGlobal.h --------------------------------------------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_WASM_INPUT_GLOBAL_H -#define LLD_WASM_INPUT_GLOBAL_H - -#include "Config.h" -#include "InputFiles.h" -#include "WriterUtils.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/Wasm.h" - -namespace lld { -namespace wasm { - -// Represents a single Wasm Global Variable within an input file. These are -// combined to form the final GLOBALS section. -class InputGlobal { -public: - InputGlobal(const WasmGlobal &g, ObjFile *f) - : file(f), global(g), live(!config->gcSections) {} - - StringRef getName() const { return global.SymbolName; } - const WasmGlobalType &getType() const { return global.Type; } - - uint32_t getGlobalIndex() const { return globalIndex.getValue(); } - bool hasGlobalIndex() const { return globalIndex.hasValue(); } - void setGlobalIndex(uint32_t index) { - assert(!hasGlobalIndex()); - globalIndex = index; - } - - ObjFile *file; - WasmGlobal global; - - bool live = false; - -protected: - llvm::Optional<uint32_t> globalIndex; -}; - -} // namespace wasm - -inline std::string toString(const wasm::InputGlobal *g) { - return (toString(g->file) + ":(" + g->getName() + ")").str(); -} - -} // namespace lld - -#endif // LLD_WASM_INPUT_GLOBAL_H |