aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/Driver.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-12-09 13:28:42 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-12-09 13:28:42 +0000
commitb1c73532ee8997fe5dfbeb7d223027bdf99758a0 (patch)
tree7d6e51c294ab6719475d660217aa0c0ad0526292 /lld/ELF/Driver.cpp
parent7fa27ce4a07f19b07799a767fc29416f3b625afb (diff)
downloadsrc-b1c73532ee8997fe5dfbeb7d223027bdf99758a0.tar.gz
src-b1c73532ee8997fe5dfbeb7d223027bdf99758a0.zip
Diffstat (limited to 'lld/ELF/Driver.cpp')
-rw-r--r--lld/ELF/Driver.cpp181
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);