diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-12-09 13:28:42 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-12-09 13:28:42 +0000 |
commit | b1c73532ee8997fe5dfbeb7d223027bdf99758a0 (patch) | |
tree | 7d6e51c294ab6719475d660217aa0c0ad0526292 /lld/ELF/Driver.cpp | |
parent | 7fa27ce4a07f19b07799a767fc29416f3b625afb (diff) | |
download | src-b1c73532ee8997fe5dfbeb7d223027bdf99758a0.tar.gz src-b1c73532ee8997fe5dfbeb7d223027bdf99758a0.zip |
Diffstat (limited to 'lld/ELF/Driver.cpp')
-rw-r--r-- | lld/ELF/Driver.cpp | 181 |
1 files changed, 128 insertions, 53 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index c2059c70e15a..6bef09eeca01 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -52,6 +52,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Remarks/HotnessThresholdParser.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" @@ -103,8 +104,13 @@ void Ctx::reset() { nonPrevailingSyms.clear(); whyExtractRecords.clear(); backwardReferences.clear(); + auxiliaryFiles.clear(); hasSympart.store(false, std::memory_order_relaxed); + hasTlsIe.store(false, std::memory_order_relaxed); needsTlsLd.store(false, std::memory_order_relaxed); + scriptSymOrderCounter = 1; + scriptSymOrder.clear(); + ltoAllVtablesHaveTypeInfos = false; } llvm::raw_fd_ostream Ctx::openAuxiliaryFile(llvm::StringRef filename, @@ -239,6 +245,19 @@ static bool isBitcode(MemoryBufferRef mb) { return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode; } +bool LinkerDriver::tryAddFatLTOFile(MemoryBufferRef mb, StringRef archiveName, + uint64_t offsetInArchive, bool lazy) { + if (!config->fatLTOObjects) + return false; + Expected<MemoryBufferRef> fatLTOData = + IRObjectFile::findBitcodeInMemBuffer(mb); + if (errorToBool(fatLTOData.takeError())) + return false; + files.push_back( + make<BitcodeFile>(*fatLTOData, archiveName, offsetInArchive, lazy)); + return true; +} + // Opens a file and create a file object. Path has to be resolved already. void LinkerDriver::addFile(StringRef path, bool withLOption) { using namespace sys::fs; @@ -263,7 +282,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) { for (const std::pair<MemoryBufferRef, uint64_t> &p : members) { if (isBitcode(p.first)) files.push_back(make<BitcodeFile>(p.first, path, p.second, false)); - else + else if (!tryAddFatLTOFile(p.first, path, p.second, false)) files.push_back(createObjFile(p.first, path)); } return; @@ -287,9 +306,10 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) { InputFile::isInGroup = true; for (const std::pair<MemoryBufferRef, uint64_t> &p : members) { auto magic = identify_magic(p.first.getBuffer()); - if (magic == file_magic::elf_relocatable) - files.push_back(createObjFile(p.first, path, true)); - else if (magic == file_magic::bitcode) + if (magic == file_magic::elf_relocatable) { + if (!tryAddFatLTOFile(p.first, path, p.second, true)) + files.push_back(createObjFile(p.first, path, true)); + } else if (magic == file_magic::bitcode) files.push_back(make<BitcodeFile>(p.first, path, p.second, true)); else warn(path + ": archive member '" + p.first.getBufferIdentifier() + @@ -321,7 +341,8 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) { files.push_back(make<BitcodeFile>(mbref, "", 0, inLib)); break; case file_magic::elf_relocatable: - files.push_back(createObjFile(mbref, "", inLib)); + if (!tryAddFatLTOFile(mbref, "", 0, inLib)) + files.push_back(createObjFile(mbref, "", inLib)); break; default: error(path + ": unknown file type"); @@ -786,13 +807,6 @@ static int getMemtagMode(opt::InputArgList &args) { return ELF::NT_MEMTAG_LEVEL_NONE; } - if (!config->androidMemtagHeap && !config->androidMemtagStack) { - error("when using --android-memtag-mode, at least one of " - "--android-memtag-heap or " - "--android-memtag-stack is required"); - return ELF::NT_MEMTAG_LEVEL_NONE; - } - if (memtagModeArg == "sync") return ELF::NT_MEMTAG_LEVEL_SYNC; if (memtagModeArg == "async") @@ -1023,6 +1037,74 @@ template <class ELFT> static void readCallGraphsFromObjectFiles() { } } +template <class ELFT> +static void ltoValidateAllVtablesHaveTypeInfos(opt::InputArgList &args) { + DenseSet<StringRef> typeInfoSymbols; + SmallSetVector<StringRef, 0> vtableSymbols; + auto processVtableAndTypeInfoSymbols = [&](StringRef name) { + if (name.consume_front("_ZTI")) + typeInfoSymbols.insert(name); + else if (name.consume_front("_ZTV")) + vtableSymbols.insert(name); + }; + + // Examine all native symbol tables. + for (ELFFileBase *f : ctx.objectFiles) { + using Elf_Sym = typename ELFT::Sym; + for (const Elf_Sym &s : f->template getGlobalELFSyms<ELFT>()) { + if (s.st_shndx != SHN_UNDEF) { + StringRef name = check(s.getName(f->getStringTable())); + processVtableAndTypeInfoSymbols(name); + } + } + } + + for (SharedFile *f : ctx.sharedFiles) { + using Elf_Sym = typename ELFT::Sym; + for (const Elf_Sym &s : f->template getELFSyms<ELFT>()) { + if (s.st_shndx != SHN_UNDEF) { + StringRef name = check(s.getName(f->getStringTable())); + processVtableAndTypeInfoSymbols(name); + } + } + } + + SmallSetVector<StringRef, 0> vtableSymbolsWithNoRTTI; + for (StringRef s : vtableSymbols) + if (!typeInfoSymbols.count(s)) + vtableSymbolsWithNoRTTI.insert(s); + + // Remove known safe symbols. + for (auto *arg : args.filtered(OPT_lto_known_safe_vtables)) { + StringRef knownSafeName = arg->getValue(); + if (!knownSafeName.consume_front("_ZTV")) + error("--lto-known-safe-vtables=: expected symbol to start with _ZTV, " + "but got " + + knownSafeName); + vtableSymbolsWithNoRTTI.remove(knownSafeName); + } + + ctx.ltoAllVtablesHaveTypeInfos = vtableSymbolsWithNoRTTI.empty(); + // Check for unmatched RTTI symbols + for (StringRef s : vtableSymbolsWithNoRTTI) { + message( + "--lto-validate-all-vtables-have-type-infos: RTTI missing for vtable " + "_ZTV" + + s + ", --lto-whole-program-visibility disabled"); + } +} + +static CGProfileSortKind getCGProfileSortKind(opt::InputArgList &args) { + StringRef s = args.getLastArgValue(OPT_call_graph_profile_sort, "cdsort"); + if (s == "hfsort") + return CGProfileSortKind::Hfsort; + if (s == "cdsort") + return CGProfileSortKind::Cdsort; + if (s != "none") + error("unknown --call-graph-profile-sort= value: " + s); + return CGProfileSortKind::None; +} + static DebugCompressionType getCompressionType(StringRef s, StringRef option) { DebugCompressionType type = StringSwitch<DebugCompressionType>(s) .Case("zlib", DebugCompressionType::Zlib) @@ -1121,7 +1203,7 @@ static bool remapInputs(StringRef line, const Twine &location) { else if (Expected<GlobPattern> pat = GlobPattern::create(fields[0])) config->remapInputsWildcards.emplace_back(std::move(*pat), fields[1]); else { - error(location + ": " + toString(pat.takeError())); + error(location + ": " + toString(pat.takeError()) + ": " + fields[0]); return true; } return false; @@ -1141,19 +1223,24 @@ static void readConfigs(opt::InputArgList &args) { args.hasFlag(OPT_android_memtag_heap, OPT_no_android_memtag_heap, false); config->androidMemtagStack = args.hasFlag(OPT_android_memtag_stack, OPT_no_android_memtag_stack, false); + config->fatLTOObjects = + args.hasFlag(OPT_fat_lto_objects, OPT_no_fat_lto_objects, false); config->androidMemtagMode = getMemtagMode(args); config->auxiliaryList = args::getStrings(args, OPT_auxiliary); config->armBe8 = args.hasArg(OPT_be8); - if (opt::Arg *arg = - args.getLastArg(OPT_Bno_symbolic, OPT_Bsymbolic_non_weak_functions, - OPT_Bsymbolic_functions, OPT_Bsymbolic)) { + if (opt::Arg *arg = args.getLastArg( + OPT_Bno_symbolic, OPT_Bsymbolic_non_weak_functions, + OPT_Bsymbolic_functions, OPT_Bsymbolic_non_weak, 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_non_weak)) + config->bsymbolic = BsymbolicKind::NonWeak; else if (arg->getOption().matches(OPT_Bsymbolic)) config->bsymbolic = BsymbolicKind::All; } + config->callGraphProfileSort = getCGProfileSortKind(args); config->checkSections = args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); config->chroot = args.getLastArgValue(OPT_chroot); @@ -1174,8 +1261,6 @@ static void readConfigs(opt::InputArgList &args) { args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false); config->emitLLVM = args.hasArg(OPT_plugin_opt_emit_llvm, false); config->emitRelocs = args.hasArg(OPT_emit_relocs); - config->callGraphProfileSort = args.hasFlag( - OPT_call_graph_profile_sort, OPT_no_call_graph_profile_sort, true); config->enableNewDtags = args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true); config->entry = args.getLastArgValue(OPT_entry); @@ -1219,6 +1304,9 @@ static void readConfigs(opt::InputArgList &args) { config->ltoWholeProgramVisibility = args.hasFlag(OPT_lto_whole_program_visibility, OPT_no_lto_whole_program_visibility, false); + config->ltoValidateAllVtablesHaveTypeInfos = + args.hasFlag(OPT_lto_validate_all_vtables_have_type_infos, + OPT_no_lto_validate_all_vtables_have_type_infos, false); config->ltoo = args::getInteger(args, OPT_lto_O, 2); if (config->ltoo > 3) error("invalid optimization level for LTO: " + Twine(config->ltoo)); @@ -1422,7 +1510,7 @@ static void readConfigs(opt::InputArgList &args) { 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())); + error(errPrefix + toString(pat.takeError()) + ": " + kv.first); } auto reports = {std::make_pair("bti-report", &config->zBtiReport), @@ -1460,7 +1548,7 @@ static void readConfigs(opt::InputArgList &args) { else if (Expected<GlobPattern> pat = GlobPattern::create(kv.first)) config->deadRelocInNonAlloc.emplace_back(std::move(*pat), v); else - error(errPrefix + toString(pat.takeError())); + error(errPrefix + toString(pat.takeError()) + ": " + kv.first); } cl::ResetAllOptionOccurrences(); @@ -1569,8 +1657,8 @@ static void readConfigs(opt::InputArgList &args) { // Page alignment can be disabled by the -n (--nmagic) and -N (--omagic). // As PT_GNU_RELRO relies on Paging, do not create it when we have disabled - // it. - if (config->nmagic || config->omagic) + // it. Also disable RELRO for -r. + if (config->nmagic || config->omagic || config->relocatable) config->zRelro = false; std::tie(config->buildId, config->buildIdVector) = getBuildId(args); @@ -1591,7 +1679,7 @@ static void readConfigs(opt::InputArgList &args) { config->symbolOrderingFile = getSymbolOrderingFile(*buffer); // Also need to disable CallGraphProfileSort to prevent // LLD order symbols with CGProfile - config->callGraphProfileSort = false; + config->callGraphProfileSort = CGProfileSortKind::None; } } @@ -1617,7 +1705,8 @@ static void readConfigs(opt::InputArgList &args) { if (Expected<GlobPattern> pat = GlobPattern::create(pattern)) config->warnBackrefsExclude.push_back(std::move(*pat)); else - error(arg->getSpelling() + ": " + toString(pat.takeError())); + error(arg->getSpelling() + ": " + toString(pat.takeError()) + ": " + + pattern); } // For -no-pie and -pie, --export-dynamic-symbol specifies defined symbols @@ -1691,14 +1780,10 @@ static void setConfigs(opt::InputArgList &args) { 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. + // builds and disabled otherwise. This check is enabled when writeAddends is + // true. #ifndef NDEBUG - bool checkDynamicRelocsDefault = m == EM_AARCH64 || m == EM_ARM || - m == EM_386 || m == EM_LOONGARCH || - m == EM_MIPS || m == EM_RISCV || - m == EM_X86_64; + bool checkDynamicRelocsDefault = true; #else bool checkDynamicRelocsDefault = false; #endif @@ -1975,7 +2060,7 @@ static void handleUndefined(Symbol *sym, const char *option) { static void handleUndefinedGlob(StringRef arg) { Expected<GlobPattern> pat = GlobPattern::create(arg); if (!pat) { - error("--undefined-glob: " + toString(pat.takeError())); + error("--undefined-glob: " + toString(pat.takeError()) + ": " + arg); return; } @@ -2163,24 +2248,6 @@ static void replaceCommonSymbols() { } } -// If all references to a DSO happen to be weak, the DSO is not added to -// DT_NEEDED. If that happens, replace ShardSymbol with Undefined to avoid -// dangling references to an unneeded DSO. Use a weak binding to avoid -// --no-allow-shlib-undefined diagnostics. Similarly, demote lazy symbols. -static void demoteSharedAndLazySymbols() { - llvm::TimeTraceScope timeScope("Demote shared and lazy symbols"); - for (Symbol *sym : symtab.getSymbols()) { - auto *s = dyn_cast<SharedSymbol>(sym); - if (!(s && !cast<SharedFile>(s->file)->isNeeded) && !sym->isLazy()) - continue; - - uint8_t binding = sym->isLazy() ? sym->binding : uint8_t(STB_WEAK); - Undefined(nullptr, sym->getName(), binding, sym->stOther, sym->type) - .overwrite(*sym); - sym->versionId = VER_NDX_GLOBAL; - } -} - // The section referred to by `s` is considered address-significant. Set the // keepUnique flag on the section if appropriate. static void markAddrsig(Symbol *s) { @@ -2229,7 +2296,7 @@ static void findKeepUniqueSections(opt::InputArgList &args) { const uint8_t *cur = contents.begin(); while (cur != contents.end()) { unsigned size; - const char *err; + const char *err = nullptr; uint64_t symIndex = decodeULEB128(cur, &size, contents.end(), &err); if (err) fatal(toString(f) + ": could not decode addrsig section: " + err); @@ -2801,6 +2868,10 @@ void LinkerDriver::link(opt::InputArgList &args) { config->ltoEmitAsm || !config->thinLTOModulesToCompile.empty(); + // Handle --lto-validate-all-vtables-have-type-infos. + if (config->ltoValidateAllVtablesHaveTypeInfos) + invokeELFT(ltoValidateAllVtablesHaveTypeInfos, args); + // Do link-time optimization if given files are LLVM bitcode files. // This compiles bitcode files into real object files. // @@ -2934,12 +3005,16 @@ void LinkerDriver::link(opt::InputArgList &args) { // Garbage collection and removal of shared symbols from unused shared objects. invokeELFT(markLive,); - demoteSharedAndLazySymbols(); // Make copies of any input sections that need to be copied into each // partition. copySectionsIntoPartitions(); + if (canHaveMemtagGlobals()) { + llvm::TimeTraceScope timeScope("Process memory tagged symbols"); + createTaggedSymbols(ctx.objectFiles); + } + // Create synthesized sections such as .got and .plt. This is called before // processSectionCommands() so that they can be placed by SECTIONS commands. invokeELFT(createSyntheticSections,); @@ -2987,7 +3062,7 @@ void LinkerDriver::link(opt::InputArgList &args) { } // Read the callgraph now that we know what was gced or icfed - if (config->callGraphProfileSort) { + if (config->callGraphProfileSort != CGProfileSortKind::None) { if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) if (std::optional<MemoryBufferRef> buffer = readFile(arg->getValue())) readCallGraph(*buffer); |