aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF')
-rw-r--r--lld/ELF/AArch64ErrataFix.cpp5
-rw-r--r--lld/ELF/ARMErrataFix.cpp5
-rw-r--r--lld/ELF/Arch/AArch64.cpp4
-rw-r--r--lld/ELF/Arch/PPC.cpp5
-rw-r--r--lld/ELF/CallGraphSort.cpp4
-rw-r--r--lld/ELF/Config.h7
-rw-r--r--lld/ELF/DWARF.cpp3
-rw-r--r--lld/ELF/Driver.cpp129
-rw-r--r--lld/ELF/Driver.h2
-rw-r--r--lld/ELF/ICF.cpp16
-rw-r--r--lld/ELF/InputFiles.cpp423
-rw-r--r--lld/ELF/InputFiles.h173
-rw-r--r--lld/ELF/InputSection.cpp119
-rw-r--r--lld/ELF/InputSection.h23
-rw-r--r--lld/ELF/LTO.cpp6
-rw-r--r--lld/ELF/LinkerScript.cpp49
-rw-r--r--lld/ELF/LinkerScript.h4
-rw-r--r--lld/ELF/MapFile.cpp15
-rw-r--r--lld/ELF/MarkLive.cpp85
-rw-r--r--lld/ELF/Options.td15
-rw-r--r--lld/ELF/OutputSections.cpp14
-rw-r--r--lld/ELF/OutputSections.h2
-rw-r--r--lld/ELF/Relocations.cpp465
-rw-r--r--lld/ELF/Relocations.h1
-rw-r--r--lld/ELF/SymbolTable.cpp44
-rw-r--r--lld/ELF/SymbolTable.h19
-rw-r--r--lld/ELF/Symbols.cpp63
-rw-r--r--lld/ELF/Symbols.h53
-rw-r--r--lld/ELF/SyntheticSections.cpp163
-rw-r--r--lld/ELF/SyntheticSections.h84
-rw-r--r--lld/ELF/Thunks.cpp7
-rw-r--r--lld/ELF/Writer.cpp137
32 files changed, 1124 insertions, 1020 deletions
diff --git a/lld/ELF/AArch64ErrataFix.cpp b/lld/ELF/AArch64ErrataFix.cpp
index 741ff26a7e6c..50d4c237778b 100644
--- a/lld/ELF/AArch64ErrataFix.cpp
+++ b/lld/ELF/AArch64ErrataFix.cpp
@@ -440,9 +440,8 @@ void AArch64Err843419Patcher::init() {
};
// Collect mapping symbols for every executable InputSection.
- for (InputFile *file : objectFiles) {
- auto *f = cast<ObjFile<ELF64LE>>(file);
- for (Symbol *b : f->getLocalSymbols()) {
+ for (ELFFileBase *file : objectFiles) {
+ for (Symbol *b : file->getLocalSymbols()) {
auto *def = dyn_cast<Defined>(b);
if (!def)
continue;
diff --git a/lld/ELF/ARMErrataFix.cpp b/lld/ELF/ARMErrataFix.cpp
index fe6ec09bd979..5ad55f1326b3 100644
--- a/lld/ELF/ARMErrataFix.cpp
+++ b/lld/ELF/ARMErrataFix.cpp
@@ -329,9 +329,8 @@ void ARMErr657417Patcher::init() {
};
// Collect mapping symbols for every executable InputSection.
- for (InputFile *file : objectFiles) {
- auto *f = cast<ObjFile<ELF32LE>>(file);
- for (Symbol *s : f->getLocalSymbols()) {
+ for (ELFFileBase *file : objectFiles) {
+ for (Symbol *s : file->getLocalSymbols()) {
auto *def = dyn_cast<Defined>(s);
if (!def)
continue;
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index b57fd61b65cc..ca3a6aa58dc5 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -690,11 +690,11 @@ void AArch64BtiPac::writePlt(uint8_t *buf, const Symbol &sym,
};
const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
- // needsPltAddr indicates a non-ifunc canonical PLT entry whose address may
+ // needsCopy indicates a non-ifunc canonical PLT entry whose address may
// escape to shared objects. isInIplt indicates a non-preemptible ifunc. Its
// address may escape if referenced by a direct relocation. The condition is
// conservative.
- bool hasBti = btiHeader && (sym.needsPltAddr || sym.isInIplt);
+ bool hasBti = btiHeader && (sym.needsCopy || sym.isInIplt);
if (hasBti) {
memcpy(buf, btiData, sizeof(btiData));
buf += sizeof(btiData);
diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp
index 0dda9a40eef7..e28b62329494 100644
--- a/lld/ELF/Arch/PPC.cpp
+++ b/lld/ELF/Arch/PPC.cpp
@@ -20,6 +20,9 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
+// Undefine the macro predefined by GCC powerpc32.
+#undef PPC
+
namespace {
class PPC final : public TargetInfo {
public:
@@ -74,7 +77,7 @@ void elf::writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
// non-GOT-non-PLT relocations referencing external functions for -fpie/-fPIE.
uint32_t glink = in.plt->getVA(); // VA of .glink
if (!config->isPic) {
- for (const Symbol *sym : cast<PPC32GlinkSection>(in.plt)->canonical_plts) {
+ for (const Symbol *sym : cast<PPC32GlinkSection>(*in.plt).canonical_plts) {
writePPC32PltCallStub(buf, sym->getGotPltVA(), nullptr, 0);
buf += 16;
glink += 16;
diff --git a/lld/ELF/CallGraphSort.cpp b/lld/ELF/CallGraphSort.cpp
index aa00d6eadbf9..5b07f0e18c8a 100644
--- a/lld/ELF/CallGraphSort.cpp
+++ b/lld/ELF/CallGraphSort.cpp
@@ -114,8 +114,8 @@ CallGraphSort::CallGraphSort() {
// Create the graph.
for (std::pair<SectionPair, uint64_t> &c : profile) {
- const auto *fromSB = cast<InputSectionBase>(c.first.first->repl);
- const auto *toSB = cast<InputSectionBase>(c.first.second->repl);
+ const auto *fromSB = cast<InputSectionBase>(c.first.first);
+ const auto *toSB = cast<InputSectionBase>(c.first.second);
uint64_t weight = c.second;
// Ignore edges between input sections belonging to different output
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index c660a8e67c21..b3d5219ff57b 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -22,6 +22,7 @@
#include "llvm/Support/GlobPattern.h"
#include "llvm/Support/PrettyStackTrace.h"
#include <atomic>
+#include <memory>
#include <vector>
namespace lld {
@@ -30,7 +31,7 @@ namespace elf {
class InputFile;
class InputSectionBase;
-enum ELFKind {
+enum ELFKind : uint8_t {
ELFNoneKind,
ELF32LEKind,
ELF32BEKind,
@@ -128,6 +129,8 @@ struct Configuration {
llvm::StringRef thinLTOCacheDir;
llvm::StringRef thinLTOIndexOnlyArg;
llvm::StringRef whyExtract;
+ StringRef zBtiReport = "none";
+ StringRef zCetReport = "none";
llvm::StringRef ltoBasicBlockSections;
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
std::pair<llvm::StringRef, llvm::StringRef> thinLTOPrefixReplace;
@@ -341,7 +344,7 @@ struct Configuration {
};
// The only instance of Configuration struct.
-extern Configuration *config;
+extern std::unique_ptr<Configuration> config;
// The first two elements of versionDefinitions represent VER_NDX_LOCAL and
// VER_NDX_GLOBAL. This helper returns other elements.
diff --git a/lld/ELF/DWARF.cpp b/lld/ELF/DWARF.cpp
index 4d84c09a0185..789820ba7a8e 100644
--- a/lld/ELF/DWARF.cpp
+++ b/lld/ELF/DWARF.cpp
@@ -27,8 +27,7 @@ using namespace lld::elf;
template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) {
// Get the ELF sections to retrieve sh_flags. See the SHF_GROUP comment below.
- ArrayRef<typename ELFT::Shdr> objSections =
- CHECK(obj->getObj().sections(), obj);
+ ArrayRef<typename ELFT::Shdr> objSections = obj->template getELFShdrs<ELFT>();
assert(objSections.size() == obj->getSections().size());
for (auto it : llvm::enumerate(obj->getSections())) {
InputSectionBase *sec = it.value();
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 1376e6c2c253..6b689f50cce7 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -71,8 +71,8 @@ using namespace llvm::support;
using namespace lld;
using namespace lld::elf;
-Configuration *elf::config;
-LinkerDriver *elf::driver;
+std::unique_ptr<Configuration> elf::config;
+std::unique_ptr<LinkerDriver> elf::driver;
static void setConfigs(opt::InputArgList &args);
static void readConfigs(opt::InputArgList &args);
@@ -90,7 +90,7 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
archiveFiles.clear();
binaryFiles.clear();
bitcodeFiles.clear();
- lazyObjFiles.clear();
+ lazyBitcodeFiles.clear();
objectFiles.clear();
sharedFiles.clear();
backwardReferences.clear();
@@ -111,10 +111,10 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
errorHandler().exitEarly = canExitEarly;
stderrOS.enable_colors(stderrOS.has_colors());
- config = make<Configuration>();
- driver = make<LinkerDriver>();
- script = make<LinkerScript>();
- symtab = make<SymbolTable>();
+ config = std::make_unique<Configuration>();
+ driver = std::make_unique<LinkerDriver>();
+ script = std::make_unique<LinkerScript>();
+ symtab = std::make_unique<SymbolTable>();
partitions = {Partition()};
@@ -248,7 +248,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) {
for (const std::pair<MemoryBufferRef, uint64_t> &p :
getArchiveMembers(mbref))
- files.push_back(make<LazyObjFile>(p.first, path, p.second));
+ files.push_back(createLazyFile(p.first, path, p.second));
return;
}
@@ -273,7 +273,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) {
case file_magic::bitcode:
case file_magic::elf_relocatable:
if (inLib)
- files.push_back(make<LazyObjFile>(mbref, "", 0));
+ files.push_back(createLazyFile(mbref, "", 0));
else
files.push_back(createObjectFile(mbref));
break;
@@ -368,7 +368,13 @@ static void checkOptions() {
error("-z pac-plt only supported on AArch64");
if (config->zForceBti)
error("-z force-bti only supported on AArch64");
+ if (config->zBtiReport != "none")
+ error("-z bti-report only supported on AArch64");
}
+
+ if (config->emachine != EM_386 && config->emachine != EM_X86_64 &&
+ config->zCetReport != "none")
+ error("-z cet-report only supported on X86 and X86_64");
}
static const char *getReproduceOption(opt::InputArgList &args) {
@@ -455,6 +461,7 @@ static bool isKnownZFlag(StringRef s) {
s == "rela" || s == "relro" || s == "retpolineplt" ||
s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" ||
s == "wxneeded" || s.startswith("common-page-size=") ||
+ s.startswith("bti-report=") || s.startswith("cet-report=") ||
s.startswith("dead-reloc-in-nonalloc=") ||
s.startswith("max-page-size=") || s.startswith("stack-size=") ||
s.startswith("start-stop-visibility=");
@@ -798,7 +805,7 @@ static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &args) {
static void readCallGraph(MemoryBufferRef mb) {
// Build a map from symbol name to section
DenseMap<StringRef, Symbol *> map;
- for (InputFile *file : objectFiles)
+ for (ELFFileBase *file : objectFiles)
for (Symbol *sym : file->getSymbols())
map[sym->getName()] = sym;
@@ -839,14 +846,13 @@ 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;
+ ArrayRef<Elf_Shdr_Impl<ELFT>> objSections =
+ inputObj->template getELFShdrs<ELFT>();
+ symbolIndices.clear();
+ const ELFFile<ELFT> &obj = inputObj->getObj();
cgProfile =
check(obj.template getSectionContentsAsArray<typename ELFT::CGProfile>(
objSections[inputObj->cgProfileSectionIndex]));
@@ -970,6 +976,11 @@ static void parseClangOption(StringRef opt, const Twine &msg) {
error(msg + ": " + StringRef(err).trim());
}
+// Checks the parameter of the bti-report and cet-report options.
+static bool isValidReportString(StringRef arg) {
+ return arg == "none" || arg == "warning" || arg == "error";
+}
+
// Initializes Config members by the command line options.
static void readConfigs(opt::InputArgList &args) {
errorHandler().verbose = args.hasArg(OPT_verbose);
@@ -1203,6 +1214,23 @@ static void readConfigs(opt::InputArgList &args) {
error(errPrefix + toString(pat.takeError()));
}
+ auto reports = {std::make_pair("bti-report", &config->zBtiReport),
+ std::make_pair("cet-report", &config->zCetReport)};
+ for (opt::Arg *arg : args.filtered(OPT_z)) {
+ std::pair<StringRef, StringRef> option =
+ StringRef(arg->getValue()).split('=');
+ for (auto reportArg : reports) {
+ if (option.first != reportArg.first)
+ continue;
+ if (!isValidReportString(option.second)) {
+ error(Twine("-z ") + reportArg.first + "= parameter " + option.second +
+ " is not recognized");
+ continue;
+ }
+ *reportArg.second = option.second;
+ }
+ }
+
for (opt::Arg *arg : args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> option =
StringRef(arg->getValue()).split('=');
@@ -1662,7 +1690,7 @@ static void excludeLibs(opt::InputArgList &args) {
sym->versionId = VER_NDX_LOCAL;
};
- for (InputFile *file : objectFiles)
+ for (ELFFileBase *file : objectFiles)
visit(file);
for (BitcodeFile *file : bitcodeFiles)
@@ -1793,17 +1821,21 @@ static void writeDependencyFile() {
// 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)
+ for (ELFFileBase *file : objectFiles) {
+ if (!file->hasCommonSyms)
continue;
+ for (Symbol *sym : file->getGlobalSymbols()) {
+ auto *s = dyn_cast<CommonSymbol>(sym);
+ if (!s)
+ continue;
- auto *bss = make<BssSection>("COMMON", s->size, s->alignment);
- bss->file = s->file;
- bss->markDead();
- inputSections.push_back(bss);
- s->replace(Defined{s->file, s->getName(), s->binding, s->stOther, s->type,
- /*value=*/0, s->size, bss});
+ auto *bss = make<BssSection>("COMMON", s->size, s->alignment);
+ bss->file = s->file;
+ bss->markDead();
+ inputSections.push_back(bss);
+ s->replace(Defined{s->file, s->getName(), s->binding, s->stOther, s->type,
+ /*value=*/0, s->size, bss});
+ }
}
}
@@ -1975,7 +2007,7 @@ template <class ELFT> void LinkerDriver::compileBitcodeFiles() {
if (!config->relocatable)
for (Symbol *sym : obj->getGlobalSymbols())
sym->parseSymbolVersion();
- objectFiles.push_back(file);
+ objectFiles.push_back(obj);
}
}
@@ -2091,11 +2123,10 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
return;
// Update pointers in input files.
- parallelForEach(objectFiles, [&](InputFile *file) {
- MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
- for (size_t i = 0, e = syms.size(); i != e; ++i)
- if (Symbol *s = map.lookup(syms[i]))
- syms[i] = s;
+ parallelForEach(objectFiles, [&](ELFFileBase *file) {
+ for (Symbol *&sym : file->getMutableGlobalSymbols())
+ if (Symbol *s = map.lookup(sym))
+ sym = s;
});
// Update pointers in the symbol table.
@@ -2103,6 +2134,16 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
symtab->wrap(w.sym, w.real, w.wrap);
}
+static void checkAndReportMissingFeature(StringRef config, uint32_t features,
+ uint32_t mask, const Twine &report) {
+ if (!(features & mask)) {
+ if (config == "error")
+ error(report);
+ else if (config == "warning")
+ warn(report);
+ }
+}
+
// To enable CET (x86's hardware-assited control flow enforcement), each
// source file must be compiled with -fcf-protection. Object files compiled
// with the flag contain feature flags indicating that they are compatible
@@ -2119,14 +2160,32 @@ template <class ELFT> static uint32_t getAndFeatures() {
uint32_t ret = -1;
for (InputFile *f : objectFiles) {
uint32_t features = cast<ObjFile<ELFT>>(f)->andFeatures;
+
+ checkAndReportMissingFeature(
+ config->zBtiReport, features, GNU_PROPERTY_AARCH64_FEATURE_1_BTI,
+ toString(f) + ": -z bti-report: file does not have "
+ "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");
+
+ checkAndReportMissingFeature(
+ config->zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_IBT,
+ toString(f) + ": -z cet-report: file does not have "
+ "GNU_PROPERTY_X86_FEATURE_1_IBT property");
+
+ checkAndReportMissingFeature(
+ config->zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_SHSTK,
+ toString(f) + ": -z cet-report: file does not have "
+ "GNU_PROPERTY_X86_FEATURE_1_SHSTK property");
+
if (config->zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) {
- warn(toString(f) + ": -z force-bti: file does not have "
- "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");
features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+ if (config->zBtiReport == "none")
+ warn(toString(f) + ": -z force-bti: file does not have "
+ "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");
} else if (config->zForceIbt &&
!(features & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
- warn(toString(f) + ": -z force-ibt: file does not have "
- "GNU_PROPERTY_X86_FEATURE_1_IBT property");
+ if (config->zCetReport == "none")
+ warn(toString(f) + ": -z force-ibt: file does not have "
+ "GNU_PROPERTY_X86_FEATURE_1_IBT property");
features |= GNU_PROPERTY_X86_FEATURE_1_IBT;
}
if (config->zPacPlt && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) {
diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h
index 96d040041c5a..5961e1f69472 100644
--- a/lld/ELF/Driver.h
+++ b/lld/ELF/Driver.h
@@ -22,7 +22,7 @@
namespace lld {
namespace elf {
-extern class LinkerDriver *driver;
+extern std::unique_ptr<class LinkerDriver> driver;
class LinkerDriver {
public:
diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp
index 0ec748e8f990..ec63d2ef4d6f 100644
--- a/lld/ELF/ICF.cpp
+++ b/lld/ELF/ICF.cpp
@@ -550,6 +550,22 @@ template <class ELFT> void ICF<ELFT>::run() {
}
});
+ // Change Defined symbol's section field to the canonical one.
+ auto fold = [](Symbol *sym) {
+ if (auto *d = dyn_cast<Defined>(sym))
+ if (auto *sec = dyn_cast_or_null<InputSection>(d->section))
+ if (sec->repl != d->section) {
+ d->section = sec->repl;
+ d->folded = true;
+ }
+ };
+ for (Symbol *sym : symtab->symbols())
+ fold(sym);
+ parallelForEach(objectFiles, [&](ELFFileBase *file) {
+ for (Symbol *sym : file->getLocalSymbols())
+ fold(sym);
+ });
+
// InputSectionDescription::sections is populated by processSectionCommands().
// ICF may fold some input sections assigned to output sections. Remove them.
for (SectionCommand *cmd : script->sectionCommands)
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 031a8679db41..e321b0d82920 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -43,12 +43,12 @@ using namespace lld::elf;
bool InputFile::isInGroup;
uint32_t InputFile::nextGroupId;
-std::vector<ArchiveFile *> elf::archiveFiles;
-std::vector<BinaryFile *> elf::binaryFiles;
-std::vector<BitcodeFile *> elf::bitcodeFiles;
-std::vector<LazyObjFile *> elf::lazyObjFiles;
-std::vector<InputFile *> elf::objectFiles;
-std::vector<SharedFile *> elf::sharedFiles;
+SmallVector<ArchiveFile *, 0> elf::archiveFiles;
+SmallVector<BinaryFile *, 0> elf::binaryFiles;
+SmallVector<BitcodeFile *, 0> elf::bitcodeFiles;
+SmallVector<BitcodeFile *, 0> elf::lazyBitcodeFiles;
+SmallVector<ELFFileBase *, 0> elf::objectFiles;
+SmallVector<SharedFile *, 0> elf::sharedFiles;
std::unique_ptr<TarWriter> elf::tar;
@@ -59,11 +59,11 @@ std::string lld::toString(const InputFile *f) {
if (f->toStringCache.empty()) {
if (f->archiveName.empty())
- f->toStringCache = std::string(f->getName());
+ f->toStringCache = f->getName();
else
- f->toStringCache = (f->archiveName + "(" + f->getName() + ")").str();
+ (f->archiveName + "(" + f->getName() + ")").toVector(f->toStringCache);
}
- return f->toStringCache;
+ return std::string(f->toStringCache);
}
static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) {
@@ -186,9 +186,13 @@ template <class ELFT> static void doParseFile(InputFile *file) {
}
// Lazy object file
- if (auto *f = dyn_cast<LazyObjFile>(file)) {
- lazyObjFiles.push_back(f);
- f->parse<ELFT>();
+ if (file->lazy) {
+ if (auto *f = dyn_cast<BitcodeFile>(file)) {
+ lazyBitcodeFiles.push_back(f);
+ f->parseLazy();
+ } else {
+ cast<ObjFile<ELFT>>(file)->parseLazy();
+ }
return;
}
@@ -209,7 +213,7 @@ template <class ELFT> static void doParseFile(InputFile *file) {
}
// Regular object file
- objectFiles.push_back(file);
+ objectFiles.push_back(cast<ELFFileBase>(file));
cast<ObjFile<ELFT>>(file)->parse();
}
@@ -366,6 +370,8 @@ template <class ELFT> void ELFFileBase::init() {
abiVersion = obj.getHeader().e_ident[llvm::ELF::EI_ABIVERSION];
ArrayRef<Elf_Shdr> sections = CHECK(obj.sections(), this);
+ elfShdrs = sections.data();
+ numELFShdrs = sections.size();
// Find a symbol table.
bool isDSO =
@@ -384,7 +390,7 @@ template <class ELFT> void ELFFileBase::init() {
fatal(toString(this) + ": invalid sh_info in symbol table");
elfSyms = reinterpret_cast<const void *>(eSyms.data());
- numELFSyms = eSyms.size();
+ numELFSyms = uint32_t(eSyms.size());
stringTable = CHECK(obj.getStringTableForSymtab(*symtabSec, sections), this);
}
@@ -421,9 +427,6 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> sections,
template <class ELFT>
bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &sec, StringRef name) {
- if (!(sec.sh_flags & SHF_MERGE))
- return false;
-
// On a regular link we don't merge sections if -O0 (default is -O1). This
// sometimes makes the linker significantly faster, although the output will
// be bigger.
@@ -476,8 +479,7 @@ bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &sec, StringRef name) {
// When the option is given, we link "just symbols". The section table is
// initialized with null pointers.
template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() {
- ArrayRef<Elf_Shdr> sections = CHECK(this->getObj().sections(), this);
- this->sections.resize(sections.size());
+ sections.resize(numELFShdrs);
}
// An ELF object file may contain a `.deplibs` section. If it exists, the
@@ -543,7 +545,7 @@ template <class ELFT>
void ObjFile<ELFT>::initializeSections(bool ignoreComdats) {
const ELFFile<ELFT> &obj = this->getObj();
- ArrayRef<Elf_Shdr> objSections = CHECK(obj.sections(), this);
+ ArrayRef<Elf_Shdr> objSections = getELFShdrs<ELFT>();
StringRef shstrtab = CHECK(obj.getSectionStringTable(objSections), this);
uint64_t size = objSections.size();
this->sections.resize(size);
@@ -555,13 +557,12 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats) {
continue;
const Elf_Shdr &sec = objSections[i];
- if (sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE)
- cgProfileSectionIndex = i;
-
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
if ((sec.sh_flags & SHF_EXCLUDE) && !config->relocatable) {
+ if (sec.sh_type == SHT_LLVM_CALL_GRAPH_PROFILE)
+ cgProfileSectionIndex = i;
if (sec.sh_type == SHT_LLVM_ADDRSIG) {
// We ignore the address-significance table if we know that the object
// file was created by objcopy or ld -r. This is because these tools
@@ -966,54 +967,65 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
}
}
- // The GNU linker uses .note.GNU-stack section as a marker indicating
- // that the code in the object file does not expect that the stack is
- // executable (in terms of NX bit). If all input files have the marker,
- // the GNU linker adds a PT_GNU_STACK segment to tells the loader to
- // make the stack non-executable. Most object files have this section as
- // of 2017.
- //
- // But making the stack non-executable is a norm today for security
- // reasons. Failure to do so may result in a serious security issue.
- // Therefore, we make LLD always add PT_GNU_STACK unless it is
- // explicitly told to do otherwise (by -z execstack). Because the stack
- // executable-ness is controlled solely by command line options,
- // .note.GNU-stack sections are simply ignored.
- if (name == ".note.GNU-stack")
- return &InputSection::discarded;
+ if (name.startswith(".n")) {
+ // The GNU linker uses .note.GNU-stack section as a marker indicating
+ // that the code in the object file does not expect that the stack is
+ // executable (in terms of NX bit). If all input files have the marker,
+ // the GNU linker adds a PT_GNU_STACK segment to tells the loader to
+ // make the stack non-executable. Most object files have this section as
+ // of 2017.
+ //
+ // But making the stack non-executable is a norm today for security
+ // reasons. Failure to do so may result in a serious security issue.
+ // Therefore, we make LLD always add PT_GNU_STACK unless it is
+ // explicitly told to do otherwise (by -z execstack). Because the stack
+ // executable-ness is controlled solely by command line options,
+ // .note.GNU-stack sections are simply ignored.
+ if (name == ".note.GNU-stack")
+ return &InputSection::discarded;
- // Object files that use processor features such as Intel Control-Flow
- // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
- // .note.gnu.property section containing a bitfield of feature bits like the
- // GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
- //
- // Since we merge bitmaps from multiple object files to create a new
- // .note.gnu.property containing a single AND'ed bitmap, we discard an input
- // file's .note.gnu.property section.
- if (name == ".note.gnu.property") {
- this->andFeatures = readAndFeatures<ELFT>(InputSection(*this, sec, name));
- return &InputSection::discarded;
- }
+ // Object files that use processor features such as Intel Control-Flow
+ // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
+ // .note.gnu.property section containing a bitfield of feature bits like the
+ // GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
+ //
+ // Since we merge bitmaps from multiple object files to create a new
+ // .note.gnu.property containing a single AND'ed bitmap, we discard an input
+ // file's .note.gnu.property section.
+ if (name == ".note.gnu.property") {
+ this->andFeatures = readAndFeatures<ELFT>(InputSection(*this, sec, name));
+ return &InputSection::discarded;
+ }
- // Split stacks is a feature to support a discontiguous stack,
- // commonly used in the programming language Go. For the details,
- // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled
- // for split stack will include a .note.GNU-split-stack section.
- if (name == ".note.GNU-split-stack") {
- if (config->relocatable) {
- error("cannot mix split-stack and non-split-stack in a relocatable link");
+ // Split stacks is a feature to support a discontiguous stack,
+ // commonly used in the programming language Go. For the details,
+ // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled
+ // for split stack will include a .note.GNU-split-stack section.
+ if (name == ".note.GNU-split-stack") {
+ if (config->relocatable) {
+ error(
+ "cannot mix split-stack and non-split-stack in a relocatable link");
+ return &InputSection::discarded;
+ }
+ this->splitStack = true;
return &InputSection::discarded;
}
- this->splitStack = true;
- return &InputSection::discarded;
- }
- // An object file cmpiled for split stack, but where some of the
- // functions were compiled with the no_split_stack_attribute will
- // include a .note.GNU-no-split-stack section.
- if (name == ".note.GNU-no-split-stack") {
- this->someNoSplitStack = true;
- return &InputSection::discarded;
+ // An object file cmpiled for split stack, but where some of the
+ // functions were compiled with the no_split_stack_attribute will
+ // include a .note.GNU-no-split-stack section.
+ if (name == ".note.GNU-no-split-stack") {
+ this->someNoSplitStack = true;
+ return &InputSection::discarded;
+ }
+
+ // Strip existing .note.gnu.build-id sections so that the output won't have
+ // more than one build-id. This is not usually a problem because input
+ // object files normally don't have .build-id sections, but you can create
+ // such files by "ld.{bfd,gold,lld} -r --build-id", and we want to guard
+ // against it.
+ if (name == ".note.gnu.build-id")
+ return &InputSection::discarded;
}
// The linkonce feature is a sort of proto-comdat. Some glibc i386 object
@@ -1025,20 +1037,13 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx")
return &InputSection::discarded;
- // Strip existing .note.gnu.build-id sections so that the output won't have
- // more than one build-id. This is not usually a problem because input object
- // files normally don't have .build-id sections, but you can create such files
- // by "ld.{bfd,gold,lld} -r --build-id", and we want to guard against it.
- if (name == ".note.gnu.build-id")
- return &InputSection::discarded;
-
// The linker merges EH (exception handling) frames and creates a
// .eh_frame_hdr section for runtime. So we handle them with a special
// class. For relocatable outputs, they are just passed through.
if (name == ".eh_frame" && !config->relocatable)
return make<EhInputSection>(*this, sec, name);
- if (shouldMerge(sec, name))
+ if ((sec.sh_flags & SHF_MERGE) && shouldMerge(sec, name))
return make<MergeInputSection>(*this, sec, name);
return make<InputSection>(*this, sec, name);
}
@@ -1046,84 +1051,80 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
// Initialize this->Symbols. this->Symbols is a parallel array as
// its corresponding ELF symbol table.
template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
+ ArrayRef<InputSectionBase *> sections(this->sections);
+ SymbolTable &symtab = *elf::symtab;
+
ArrayRef<Elf_Sym> eSyms = this->getELFSyms<ELFT>();
- this->symbols.resize(eSyms.size());
+ symbols.resize(eSyms.size());
+ SymbolUnion *locals =
+ firstGlobal == 0
+ ? nullptr
+ : getSpecificAllocSingleton<SymbolUnion>().Allocate(firstGlobal);
- // Fill in InputFile::symbols. Some entries have been initialized
- // because of LazyObjFile.
- for (size_t i = 0, end = eSyms.size(); i != end; ++i) {
- if (this->symbols[i])
- continue;
+ for (size_t i = 0, end = firstGlobal; i != end; ++i) {
const Elf_Sym &eSym = eSyms[i];
uint32_t secIdx = getSectionIndex(eSym);
- if (secIdx >= this->sections.size())
+ if (LLVM_UNLIKELY(secIdx >= sections.size()))
fatal(toString(this) + ": invalid section index: " + Twine(secIdx));
- if (eSym.getBinding() != STB_LOCAL) {
- if (i < firstGlobal)
- error(toString(this) + ": non-local symbol (" + Twine(i) +
- ") found at index < .symtab's sh_info (" + Twine(firstGlobal) +
- ")");
- this->symbols[i] =
- symtab->insert(CHECK(eSyms[i].getName(this->stringTable), this));
- continue;
- }
+ if (LLVM_UNLIKELY(eSym.getBinding() != STB_LOCAL))
+ error(toString(this) + ": non-local symbol (" + Twine(i) +
+ ") found at index < .symtab's sh_info (" + Twine(end) + ")");
- // Handle local symbols. Local symbols are not added to the symbol
- // table because they are not visible from other object files. We
- // allocate symbol instances and add their pointers to symbols.
- if (i >= firstGlobal)
- errorOrWarn(toString(this) + ": STB_LOCAL symbol (" + Twine(i) +
- ") found at index >= .symtab's sh_info (" +
- Twine(firstGlobal) + ")");
-
- InputSectionBase *sec = this->sections[secIdx];
+ InputSectionBase *sec = sections[secIdx];
uint8_t type = eSym.getType();
if (type == STT_FILE)
- sourceFile = CHECK(eSym.getName(this->stringTable), this);
- if (this->stringTable.size() <= eSym.st_name)
+ sourceFile = CHECK(eSym.getName(stringTable), this);
+ if (LLVM_UNLIKELY(stringTable.size() <= eSym.st_name))
fatal(toString(this) + ": invalid symbol name offset");
- StringRefZ name = this->stringTable.data() + eSym.st_name;
-
- if (eSym.st_shndx == SHN_UNDEF)
- this->symbols[i] =
- make<Undefined>(this, name, STB_LOCAL, eSym.st_other, type);
- else if (sec == &InputSection::discarded)
- this->symbols[i] =
- make<Undefined>(this, name, STB_LOCAL, eSym.st_other, type,
- /*discardedSecIdx=*/secIdx);
+ StringRefZ name = stringTable.data() + eSym.st_name;
+
+ symbols[i] = reinterpret_cast<Symbol *>(locals + i);
+ if (eSym.st_shndx == SHN_UNDEF || sec == &InputSection::discarded)
+ new (symbols[i]) Undefined(this, name, STB_LOCAL, eSym.st_other, type,
+ /*discardedSecIdx=*/secIdx);
else
- this->symbols[i] = make<Defined>(this, name, STB_LOCAL, eSym.st_other,
- type, eSym.st_value, eSym.st_size, sec);
+ new (symbols[i]) Defined(this, name, STB_LOCAL, eSym.st_other, type,
+ eSym.st_value, eSym.st_size, sec);
}
- // Symbol resolution of non-local symbols.
+ // Some entries have been filled by LazyObjFile.
+ for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i)
+ if (!symbols[i])
+ symbols[i] = symtab.insert(CHECK(eSyms[i].getName(stringTable), this));
+
+ // Perform symbol resolution on non-local symbols.
SmallVector<unsigned, 32> undefineds;
for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) {
const Elf_Sym &eSym = eSyms[i];
uint8_t binding = eSym.getBinding();
- if (binding == STB_LOCAL)
- continue; // Errored above.
-
+ if (LLVM_UNLIKELY(binding == STB_LOCAL)) {
+ errorOrWarn(toString(this) + ": STB_LOCAL symbol (" + Twine(i) +
+ ") found at index >= .symtab's sh_info (" +
+ Twine(firstGlobal) + ")");
+ continue;
+ }
uint32_t secIdx = getSectionIndex(eSym);
- InputSectionBase *sec = this->sections[secIdx];
+ if (LLVM_UNLIKELY(secIdx >= sections.size()))
+ fatal(toString(this) + ": invalid section index: " + Twine(secIdx));
+ InputSectionBase *sec = sections[secIdx];
uint8_t stOther = eSym.st_other;
uint8_t type = eSym.getType();
uint64_t value = eSym.st_value;
uint64_t size = eSym.st_size;
- StringRefZ name = this->stringTable.data() + eSym.st_name;
- // Handle global undefined symbols.
if (eSym.st_shndx == SHN_UNDEF) {
undefineds.push_back(i);
continue;
}
- // Handle global common symbols.
- if (eSym.st_shndx == SHN_COMMON) {
+ Symbol *sym = symbols[i];
+ const StringRef name = sym->getName();
+ if (LLVM_UNLIKELY(eSym.st_shndx == SHN_COMMON)) {
if (value == 0 || value >= UINT32_MAX)
- fatal(toString(this) + ": common symbol '" + StringRef(name.data) +
+ fatal(toString(this) + ": common symbol '" + name +
"' has invalid alignment: " + Twine(value));
- this->symbols[i]->resolve(
+ hasCommonSyms = true;
+ sym->resolve(
CommonSymbol{this, name, binding, stOther, type, value, size});
continue;
}
@@ -1135,16 +1136,14 @@ template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
// defined symbol in a .eh_frame becomes dangling symbols.
if (sec == &InputSection::discarded) {
Undefined und{this, name, binding, stOther, type, secIdx};
- Symbol *sym = this->symbols[i];
- // !ArchiveFile::parsed or LazyObjFile::extracted means that the file
+ // !ArchiveFile::parsed or !LazyObjFile::lazy means that the file
// containing this object has not finished processing, i.e. this symbol is
// a result of a lazy symbol extract. We should demote the lazy symbol to
// an Undefined so that any relocations outside of the group to it will
// trigger a discarded section error.
if ((sym->symbolKind == Symbol::LazyArchiveKind &&
!cast<ArchiveFile>(sym->file)->parsed) ||
- (sym->symbolKind == Symbol::LazyObjectKind &&
- cast<LazyObjFile>(sym->file)->extracted)) {
+ (sym->symbolKind == Symbol::LazyObjectKind && !sym->file->lazy)) {
sym->replace(und);
// Prevent LTO from internalizing the symbol in case there is a
// reference to this symbol from this file.
@@ -1157,7 +1156,7 @@ template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
// Handle global defined symbols.
if (binding == STB_GLOBAL || binding == STB_WEAK ||
binding == STB_GNU_UNIQUE) {
- this->symbols[i]->resolve(
+ sym->resolve(
Defined{this, name, binding, stOther, type, value, size, sec});
continue;
}
@@ -1173,10 +1172,10 @@ template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
// being resolved to different files.
for (unsigned i : undefineds) {
const Elf_Sym &eSym = eSyms[i];
- StringRefZ name = this->stringTable.data() + eSym.st_name;
- this->symbols[i]->resolve(Undefined{this, name, eSym.getBinding(),
- eSym.st_other, eSym.getType()});
- this->symbols[i]->referenced = true;
+ Symbol *sym = symbols[i];
+ sym->resolve(Undefined{this, sym->getName(), eSym.getBinding(),
+ eSym.st_other, eSym.getType()});
+ sym->referenced = true;
}
}
@@ -1185,8 +1184,9 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&file)
file(std::move(file)) {}
void ArchiveFile::parse() {
+ SymbolTable &symtab = *elf::symtab;
for (const Archive::Symbol &sym : file->symbols())
- symtab->addSymbol(LazyArchive{*this, sym});
+ symtab.addSymbol(LazyArchive{*this, sym});
// Inform a future invocation of ObjFile<ELFT>::initializeSymbols() that this
// archive has been processed.
@@ -1319,26 +1319,21 @@ unsigned SharedFile::vernauxNum;
// vector whose nth element contains a pointer to the Elf_Verdef for version
// identifier n. Version identifiers that are not definitions map to nullptr.
template <typename ELFT>
-static std::vector<const void *> parseVerdefs(const uint8_t *base,
- const typename ELFT::Shdr *sec) {
+static SmallVector<const void *, 0>
+parseVerdefs(const uint8_t *base, const typename ELFT::Shdr *sec) {
if (!sec)
return {};
- // We cannot determine the largest verdef identifier without inspecting
- // every Elf_Verdef, but both bfd and gold assign verdef identifiers
- // sequentially starting from 1, so we predict that the largest identifier
- // will be verdefCount.
- unsigned verdefCount = sec->sh_info;
- std::vector<const void *> verdefs(verdefCount + 1);
-
// Build the Verdefs array by following the chain of Elf_Verdef objects
// from the start of the .gnu.version_d section.
+ SmallVector<const void *, 0> verdefs;
const uint8_t *verdef = base + sec->sh_offset;
- for (unsigned i = 0; i != verdefCount; ++i) {
+ for (unsigned i = 0, e = sec->sh_info; i != e; ++i) {
auto *curVerdef = reinterpret_cast<const typename ELFT::Verdef *>(verdef);
verdef += curVerdef->vd_next;
unsigned verdefIndex = curVerdef->vd_ndx;
- verdefs.resize(verdefIndex + 1);
+ if (verdefIndex >= verdefs.size())
+ verdefs.resize(verdefIndex + 1);
verdefs[verdefIndex] = curVerdef;
}
return verdefs;
@@ -1417,7 +1412,7 @@ template <class ELFT> void SharedFile::parse() {
ArrayRef<Elf_Dyn> dynamicTags;
const ELFFile<ELFT> obj = this->getObj<ELFT>();
- ArrayRef<Elf_Shdr> sections = CHECK(obj.sections(), this);
+ ArrayRef<Elf_Shdr> sections = getELFShdrs<ELFT>();
const Elf_Shdr *versymSec = nullptr;
const Elf_Shdr *verdefSec = nullptr;
@@ -1502,15 +1497,16 @@ template <class ELFT> void SharedFile::parse() {
SmallString<0> versionedNameBuffer;
// Add symbols to the symbol table.
+ SymbolTable &symtab = *elf::symtab;
ArrayRef<Elf_Sym> syms = this->getGlobalELFSyms<ELFT>();
- for (size_t i = 0; i < syms.size(); ++i) {
+ for (size_t i = 0, e = syms.size(); i != e; ++i) {
const Elf_Sym &sym = syms[i];
// ELF spec requires that all local symbols precede weak or global
// symbols in each symbol table, and the index of first non-local symbol
// is stored to sh_info. If a local symbol appears after some non-local
// symbol, that's a violation of the spec.
- StringRef name = CHECK(sym.getName(this->stringTable), this);
+ StringRef name = CHECK(sym.getName(stringTable), this);
if (sym.getBinding() == STB_LOCAL) {
warn("found local symbol '" + name +
"' in global part of symbol table in file " + toString(this));
@@ -1528,15 +1524,15 @@ template <class ELFT> void SharedFile::parse() {
toString(this));
continue;
}
- StringRef verName = this->stringTable.data() + verneeds[idx];
+ StringRef verName = stringTable.data() + verneeds[idx];
versionedNameBuffer.clear();
name =
saver.save((name + "@" + verName).toStringRef(versionedNameBuffer));
}
- Symbol *s = symtab->addSymbol(
+ Symbol *s = symtab.addSymbol(
Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()});
s->exportDynamic = true;
- if (s->isUndefined() && !s->isWeak() &&
+ if (s->isUndefined() && sym.getBinding() != STB_WEAK &&
config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore)
requiredSymbols.push_back(s);
continue;
@@ -1551,9 +1547,9 @@ template <class ELFT> void SharedFile::parse() {
uint32_t alignment = getAlignment<ELFT>(sections, sym);
if (!(versyms[i] & VERSYM_HIDDEN)) {
- symtab->addSymbol(SharedSymbol{*this, name, sym.getBinding(),
- sym.st_other, sym.getType(), sym.st_value,
- sym.st_size, alignment, idx});
+ symtab.addSymbol(SharedSymbol{*this, name, sym.getBinding(), sym.st_other,
+ sym.getType(), sym.st_value, sym.st_size,
+ alignment, idx});
}
// Also add the symbol with the versioned name to handle undefined symbols
@@ -1569,13 +1565,13 @@ template <class ELFT> void SharedFile::parse() {
}
StringRef verName =
- this->stringTable.data() +
+ stringTable.data() +
reinterpret_cast<const Elf_Verdef *>(verdefs[idx])->getAux()->vda_name;
versionedNameBuffer.clear();
name = (name + "@" + verName).toStringRef(versionedNameBuffer);
- symtab->addSymbol(SharedSymbol{*this, saver.save(name), sym.getBinding(),
- sym.st_other, sym.getType(), sym.st_value,
- sym.st_size, alignment, idx});
+ symtab.addSymbol(SharedSymbol{*this, saver.save(name), sym.getBinding(),
+ sym.st_other, sym.getType(), sym.st_value,
+ sym.st_size, alignment, idx});
}
}
@@ -1641,9 +1637,10 @@ static uint8_t getOsAbi(const Triple &t) {
}
BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive)
+ uint64_t offsetInArchive, bool lazy)
: InputFile(BitcodeKind, mb) {
- this->archiveName = std::string(archiveName);
+ this->archiveName = archiveName;
+ this->lazy = lazy;
std::string path = mb.getBufferIdentifier().str();
if (config->thinLTOIndexOnly)
@@ -1722,13 +1719,22 @@ template <class ELFT> void BitcodeFile::parse() {
.second);
}
- for (const lto::InputFile::Symbol &objSym : obj->symbols())
- symbols.push_back(createBitcodeSymbol<ELFT>(keptComdats, objSym, *this));
+ symbols.assign(obj->symbols().size(), nullptr);
+ for (auto it : llvm::enumerate(obj->symbols()))
+ symbols[it.index()] =
+ createBitcodeSymbol<ELFT>(keptComdats, it.value(), *this);
for (auto l : obj->getDependentLibraries())
addDependentLibrary(l, this);
}
+void BitcodeFile::parseLazy() {
+ SymbolTable &symtab = *elf::symtab;
+ for (const lto::InputFile::Symbol &sym : obj->symbols())
+ if (!sym.isUndefined())
+ symtab.addSymbol(LazyObject{*this, saver.save(sym.getName())});
+}
+
void BinaryFile::parse() {
ArrayRef<uint8_t> data = arrayRefFromStringRef(mb.getBuffer());
auto *section = make<InputSection>(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
@@ -1755,7 +1761,7 @@ void BinaryFile::parse() {
InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive) {
if (isBitcode(mb))
- return make<BitcodeFile>(mb, archiveName, offsetInArchive);
+ return make<BitcodeFile>(mb, archiveName, offsetInArchive, /*lazy=*/false);
switch (getELFKind(mb, archiveName)) {
case ELF32LEKind:
@@ -1771,80 +1777,40 @@ InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName,
}
}
-void LazyObjFile::extract() {
- if (extracted)
- return;
- extracted = true;
-
- InputFile *file = createObjectFile(mb, archiveName, offsetInArchive);
- file->groupId = groupId;
-
- // Copy symbol vector so that the new InputFile doesn't have to
- // insert the same defined symbols to the symbol table again.
- file->symbols = std::move(symbols);
+InputFile *elf::createLazyFile(MemoryBufferRef mb, StringRef archiveName,
+ uint64_t offsetInArchive) {
+ if (isBitcode(mb))
+ return make<BitcodeFile>(mb, archiveName, offsetInArchive, /*lazy=*/true);
- parseFile(file);
+ auto *file =
+ cast<ELFFileBase>(createObjectFile(mb, archiveName, offsetInArchive));
+ file->lazy = true;
+ return file;
}
-template <class ELFT> void LazyObjFile::parse() {
- using Elf_Sym = typename ELFT::Sym;
+template <class ELFT> void ObjFile<ELFT>::parseLazy() {
+ const ArrayRef<typename ELFT::Sym> eSyms = this->getELFSyms<ELFT>();
+ SymbolTable &symtab = *elf::symtab;
- // A lazy object file wraps either a bitcode file or an ELF file.
- if (isBitcode(this->mb)) {
- std::unique_ptr<lto::InputFile> obj =
- CHECK(lto::InputFile::create(this->mb), this);
- for (const lto::InputFile::Symbol &sym : obj->symbols()) {
- if (sym.isUndefined())
- continue;
- symtab->addSymbol(LazyObject{*this, saver.save(sym.getName())});
- }
- return;
- }
-
- if (getELFKind(this->mb, archiveName) != config->ekind) {
- error("incompatible file: " + this->mb.getBufferIdentifier());
- return;
- }
-
- // Find a symbol table.
- ELFFile<ELFT> obj = check(ELFFile<ELFT>::create(mb.getBuffer()));
- ArrayRef<typename ELFT::Shdr> sections = CHECK(obj.sections(), this);
-
- for (const typename ELFT::Shdr &sec : sections) {
- if (sec.sh_type != SHT_SYMTAB)
- continue;
+ symbols.resize(eSyms.size());
+ for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i)
+ if (eSyms[i].st_shndx != SHN_UNDEF)
+ symbols[i] = symtab.insert(CHECK(eSyms[i].getName(stringTable), this));
- // A symbol table is found.
- ArrayRef<Elf_Sym> eSyms = CHECK(obj.symbols(&sec), this);
- uint32_t firstGlobal = sec.sh_info;
- StringRef strtab = CHECK(obj.getStringTableForSymtab(sec, sections), this);
- this->symbols.resize(eSyms.size());
-
- // Get existing symbols or insert placeholder symbols.
- for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i)
- if (eSyms[i].st_shndx != SHN_UNDEF)
- this->symbols[i] = symtab->insert(CHECK(eSyms[i].getName(strtab), this));
-
- // Replace existing symbols with LazyObject symbols.
- //
- // resolve() may trigger this->extract() if an existing symbol is an
- // undefined symbol. If that happens, this LazyObjFile has served
- // its purpose, and we can exit from the loop early.
- for (Symbol *sym : this->symbols) {
- if (!sym)
- continue;
+ // Replace existing symbols with LazyObject symbols.
+ //
+ // resolve() may trigger this->extract() if an existing symbol is an undefined
+ // symbol. If that happens, this function has served its purpose, and we can
+ // exit from the loop early.
+ for (Symbol *sym : makeArrayRef(symbols).slice(firstGlobal))
+ if (sym) {
sym->resolve(LazyObject{*this, sym->getName()});
-
- // If extracted, stop iterating because this->symbols has been transferred
- // to the instantiated ObjFile.
- if (extracted)
+ if (!lazy)
return;
}
- return;
- }
}
-bool LazyObjFile::shouldExtractForCommon(const StringRef &name) {
+bool InputFile::shouldExtractForCommon(StringRef name) {
if (isBitcode(mb))
return isBitcodeNonCommonDef(mb, name, archiveName);
@@ -1865,11 +1831,6 @@ template void BitcodeFile::parse<ELF32BE>();
template void BitcodeFile::parse<ELF64LE>();
template void BitcodeFile::parse<ELF64BE>();
-template void LazyObjFile::parse<ELF32LE>();
-template void LazyObjFile::parse<ELF32BE>();
-template void LazyObjFile::parse<ELF64LE>();
-template void LazyObjFile::parse<ELF64BE>();
-
template class elf::ObjFile<ELF32LE>;
template class elf::ObjFile<ELF32BE>;
template class elf::ObjFile<ELF64LE>;
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index 5bbfb7656e47..d622390fcade 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -41,6 +41,7 @@ namespace elf {
using llvm::object::Archive;
+class InputSection;
class Symbol;
// If --reproduce is specified, all input files are written to this tar archive.
@@ -54,8 +55,15 @@ void parseFile(InputFile *file);
// The root class of input files.
class InputFile {
+private:
+ // Cache for getNameForScript().
+ mutable SmallString<0> nameForScriptCache;
+
+protected:
+ SmallVector<InputSectionBase *, 0> sections;
+
public:
- enum Kind {
+ enum Kind : uint8_t {
ObjKind,
SharedKind,
LazyObjKind,
@@ -83,9 +91,7 @@ public:
// Returns object file symbols. It is a runtime error to call this
// function on files of other types.
- ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); }
-
- MutableArrayRef<Symbol *> getMutableSymbols() {
+ ArrayRef<Symbol *> getSymbols() const {
assert(fileKind == BinaryKind || fileKind == ObjKind ||
fileKind == BitcodeKind);
return symbols;
@@ -94,29 +100,51 @@ public:
// Get filename to use for linker script processing.
StringRef getNameForScript() const;
+ // Check if a non-common symbol should be extracted to override a common
+ // definition.
+ bool shouldExtractForCommon(StringRef name);
+
// If not empty, this stores the name of the archive containing this file.
// We use this string for creating error messages.
- std::string archiveName;
+ SmallString<0> archiveName;
+
+ // Cache for toString(). Only toString() should use this member.
+ mutable SmallString<0> toStringCache;
+
+ SmallVector<Symbol *, 0> symbols;
+
+ // .got2 in the current file. This is used by PPC32 -fPIC/-fPIE to compute
+ // offsets in PLT call stubs.
+ InputSection *ppc32Got2 = nullptr;
+
+ // Index of MIPS GOT built for this file.
+ uint32_t mipsGotIndex = -1;
+
+ // groupId is used for --warn-backrefs which is an optional error
+ // checking feature. All files within the same --{start,end}-group or
+ // --{start,end}-lib get the same group ID. Otherwise, each file gets a new
+ // group ID. For more info, see checkDependency() in SymbolTable.cpp.
+ uint32_t groupId;
+ static bool isInGroup;
+ static uint32_t nextGroupId;
// If this is an architecture-specific file, the following members
// have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
- ELFKind ekind = ELFNoneKind;
uint16_t emachine = llvm::ELF::EM_NONE;
+ const Kind fileKind;
+ ELFKind ekind = ELFNoneKind;
uint8_t osabi = 0;
uint8_t abiVersion = 0;
- // Cache for toString(). Only toString() should use this member.
- mutable std::string toStringCache;
-
- std::string getSrcMsg(const Symbol &sym, InputSectionBase &sec,
- uint64_t offset);
+ // True if this is a relocatable object file/bitcode file between --start-lib
+ // and --end-lib.
+ bool lazy = false;
// True if this is an argument for --just-symbols. Usually false.
bool justSymbols = false;
- // outSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE
- // to compute offsets in PLT call stubs.
- uint32_t ppc32Got2OutSecOff = 0;
+ std::string getSrcMsg(const Symbol &sym, InputSectionBase &sec,
+ uint64_t offset);
// On PPC64 we need to keep track of which files contain small code model
// relocations that access the .toc section. To minimize the chance of a
@@ -133,28 +161,8 @@ public:
// R_PPC64_TLSLD. Disable TLS relaxation to avoid bad code generation.
bool ppc64DisableTLSRelax = false;
- // groupId is used for --warn-backrefs which is an optional error
- // checking feature. All files within the same --{start,end}-group or
- // --{start,end}-lib get the same group ID. Otherwise, each file gets a new
- // group ID. For more info, see checkDependency() in SymbolTable.cpp.
- uint32_t groupId;
- static bool isInGroup;
- static uint32_t nextGroupId;
-
- // Index of MIPS GOT built for this file.
- llvm::Optional<size_t> mipsGotIndex;
-
- std::vector<Symbol *> symbols;
-
protected:
InputFile(Kind k, MemoryBufferRef m);
- std::vector<InputSectionBase *> sections;
-
-private:
- const Kind fileKind;
-
- // Cache for getNameForScript().
- mutable std::string nameForScriptCache;
};
class ELFFileBase : public InputFile {
@@ -176,7 +184,15 @@ public:
ArrayRef<Symbol *> getGlobalSymbols() {
return llvm::makeArrayRef(symbols).slice(firstGlobal);
}
+ MutableArrayRef<Symbol *> getMutableGlobalSymbols() {
+ return llvm::makeMutableArrayRef(symbols.data(), symbols.size())
+ .slice(firstGlobal);
+ }
+ template <typename ELFT> typename ELFT::ShdrRange getELFShdrs() const {
+ return typename ELFT::ShdrRange(
+ reinterpret_cast<const typename ELFT::Shdr *>(elfShdrs), numELFShdrs);
+ }
template <typename ELFT> typename ELFT::SymRange getELFSyms() const {
return typename ELFT::SymRange(
reinterpret_cast<const typename ELFT::Sym *>(elfSyms), numELFSyms);
@@ -189,10 +205,15 @@ protected:
// Initializes this class's member variables.
template <typename ELFT> void init();
+ StringRef stringTable;
+ const void *elfShdrs = nullptr;
const void *elfSyms = nullptr;
- size_t numELFSyms = 0;
+ uint32_t numELFShdrs = 0;
+ uint32_t numELFSyms = 0;
uint32_t firstGlobal = 0;
- StringRef stringTable;
+
+public:
+ bool hasCommonSyms = false;
};
// .o file.
@@ -207,10 +228,11 @@ public:
}
ObjFile(MemoryBufferRef m, StringRef archiveName) : ELFFileBase(ObjKind, m) {
- this->archiveName = std::string(archiveName);
+ this->archiveName = archiveName;
}
void parse(bool ignoreComdats = false);
+ void parseLazy();
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> sections,
const Elf_Shdr &sec);
@@ -231,6 +253,17 @@ public:
llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef name);
+ // Name of source file obtained from STT_FILE symbol value,
+ // or empty string if there is no such symbol in object file
+ // symbol table.
+ StringRef sourceFile;
+
+ // Pointer to this input file's .llvm_addrsig section, if it has one.
+ const Elf_Shdr *addrsigSec = nullptr;
+
+ // SHT_LLVM_CALL_GRAPH_PROFILE section index.
+ uint32_t cgProfileSectionIndex = 0;
+
// MIPS GP0 value defined by this file. This value represents the gp value
// used to create the relocatable object and required to support
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
@@ -238,11 +271,6 @@ public:
uint32_t andFeatures = 0;
- // Name of source file obtained from STT_FILE symbol value,
- // or empty string if there is no such symbol in object file
- // symbol table.
- StringRef sourceFile;
-
// True if the file defines functions compiled with
// -fsplit-stack. Usually false.
bool splitStack = false;
@@ -251,12 +279,6 @@ public:
// but had one or more functions with the no_split_stack attribute.
bool someNoSplitStack = false;
- // Pointer to this input file's .llvm_addrsig section, if it has one.
- const Elf_Shdr *addrsigSec = nullptr;
-
- // SHT_LLVM_CALL_GRAPH_PROFILE section index.
- uint32_t cgProfileSectionIndex = 0;
-
// Get cached DWARF information.
DWARFCache *getDwarf();
@@ -294,36 +316,6 @@ private:
llvm::once_flag initDwarf;
};
-// LazyObjFile is analogous to ArchiveFile in the sense that
-// the file contains lazy symbols. The difference is that
-// LazyObjFile wraps a single file instead of multiple files.
-//
-// This class is used for --start-lib and --end-lib options which
-// instruct the linker to link object files between them with the
-// archive file semantics.
-class LazyObjFile : public InputFile {
-public:
- LazyObjFile(MemoryBufferRef m, StringRef archiveName,
- uint64_t offsetInArchive)
- : InputFile(LazyObjKind, m), offsetInArchive(offsetInArchive) {
- this->archiveName = std::string(archiveName);
- }
-
- static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; }
-
- template <class ELFT> void parse();
- void extract();
-
- // Check if a non-common symbol should be extracted to override a common
- // definition.
- bool shouldExtractForCommon(const StringRef &name);
-
- bool extracted = false;
-
-private:
- uint64_t offsetInArchive;
-};
-
// An ArchiveFile object represents a .a file.
class ArchiveFile : public InputFile {
public:
@@ -354,9 +346,10 @@ private:
class BitcodeFile : public InputFile {
public:
BitcodeFile(MemoryBufferRef m, StringRef archiveName,
- uint64_t offsetInArchive);
+ uint64_t offsetInArchive, bool lazy);
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
template <class ELFT> void parse();
+ void parseLazy();
std::unique_ptr<llvm::lto::InputFile> obj;
};
@@ -368,16 +361,16 @@ public:
isNeeded(!config->asNeeded) {}
// This is actually a vector of Elf_Verdef pointers.
- std::vector<const void *> verdefs;
+ SmallVector<const void *, 0> verdefs;
// If the output file needs Elf_Verneed data structures for this file, this is
// a vector of Elf_Vernaux version identifiers that map onto the entries in
// Verdefs, otherwise it is empty.
- std::vector<unsigned> vernauxs;
+ SmallVector<uint32_t, 0> vernauxs;
static unsigned vernauxNum;
- std::vector<StringRef> dtNeeded;
+ SmallVector<StringRef, 0> dtNeeded;
StringRef soName;
static bool classof(const InputFile *f) { return f->kind() == SharedKind; }
@@ -389,7 +382,7 @@ public:
// Non-weak undefined symbols which are not yet resolved when the SO is
// parsed. Only filled for `--no-allow-shlib-undefined`.
- std::vector<Symbol *> requiredSymbols;
+ SmallVector<Symbol *, 0> requiredSymbols;
private:
template <typename ELFT>
@@ -406,6 +399,8 @@ public:
InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "",
uint64_t offsetInArchive = 0);
+InputFile *createLazyFile(MemoryBufferRef mb, StringRef archiveName,
+ uint64_t offsetInArchive);
inline bool isBitcode(MemoryBufferRef mb) {
return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
@@ -413,12 +408,12 @@ inline bool isBitcode(MemoryBufferRef mb) {
std::string replaceThinLTOSuffix(StringRef path);
-extern std::vector<ArchiveFile *> archiveFiles;
-extern std::vector<BinaryFile *> binaryFiles;
-extern std::vector<BitcodeFile *> bitcodeFiles;
-extern std::vector<LazyObjFile *> lazyObjFiles;
-extern std::vector<InputFile *> objectFiles;
-extern std::vector<SharedFile *> sharedFiles;
+extern SmallVector<ArchiveFile *, 0> archiveFiles;
+extern SmallVector<BinaryFile *, 0> binaryFiles;
+extern SmallVector<BitcodeFile *, 0> bitcodeFiles;
+extern SmallVector<BitcodeFile *, 0> lazyBitcodeFiles;
+extern SmallVector<ELFFileBase *, 0> objectFiles;
+extern SmallVector<SharedFile *, 0> sharedFiles;
} // namespace elf
} // namespace lld
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 4d5bd1f1e5f2..e1ee3def89f3 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -40,7 +40,7 @@ using namespace llvm::sys;
using namespace lld;
using namespace lld::elf;
-std::vector<InputSectionBase *> elf::inputSections;
+SmallVector<InputSectionBase *, 0> elf::inputSections;
DenseSet<std::pair<const Symbol *, uint64_t>> elf::ppc64noTocRelax;
// Returns a string to construct an error message.
@@ -163,16 +163,16 @@ template <class ELFT> RelsOrRelas<ELFT> InputSectionBase::relsOrRelas() const {
if (relSecIdx == 0)
return {};
RelsOrRelas<ELFT> ret;
- const ELFFile<ELFT> obj = cast<ELFFileBase>(file)->getObj<ELFT>();
- typename ELFT::Shdr shdr = cantFail(obj.sections())[relSecIdx];
+ typename ELFT::Shdr shdr =
+ cast<ELFFileBase>(file)->getELFShdrs<ELFT>()[relSecIdx];
if (shdr.sh_type == SHT_REL) {
ret.rels = makeArrayRef(reinterpret_cast<const typename ELFT::Rel *>(
- obj.base() + shdr.sh_offset),
+ file->mb.getBufferStart() + shdr.sh_offset),
shdr.sh_size / sizeof(typename ELFT::Rel));
} else {
assert(shdr.sh_type == SHT_RELA);
ret.relas = makeArrayRef(reinterpret_cast<const typename ELFT::Rela *>(
- obj.base() + shdr.sh_offset),
+ file->mb.getBufferStart() + shdr.sh_offset),
shdr.sh_size / sizeof(typename ELFT::Rela));
}
return ret;
@@ -325,7 +325,7 @@ std::string InputSectionBase::getObjMsg(uint64_t off) {
std::string archive;
if (!file->archiveName.empty())
- archive = " in archive " + file->archiveName;
+ archive = (" in archive " + file->archiveName).str();
// Find a symbol that encloses a given location.
for (Symbol *b : file->getSymbols())
@@ -395,6 +395,7 @@ InputSectionBase *InputSection::getRelocatedSection() const {
// for each relocation. So we copy relocations one by one.
template <class ELFT, class RelTy>
void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
+ const TargetInfo &target = *elf::target;
InputSectionBase *sec = getRelocatedSection();
for (const RelTy &rel : rels) {
@@ -433,8 +434,7 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
sec->name != ".gcc_except_table" && sec->name != ".got2" &&
sec->name != ".toc") {
uint32_t secIdx = cast<Undefined>(sym).discardedSecIdx;
- Elf_Shdr_Impl<ELFT> sec =
- CHECK(file->getObj().sections(), file)[secIdx];
+ Elf_Shdr_Impl<ELFT> sec = file->template getELFShdrs<ELFT>()[secIdx];
warn("relocation refers to a discarded section: " +
CHECK(file->getObj().getSectionName(sec), file) +
"\n>>> referenced by " + getObjMsg(p->r_offset));
@@ -442,7 +442,7 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
p->setSymbolAndType(0, 0, false);
continue;
}
- SectionBase *section = d->section->repl;
+ SectionBase *section = d->section;
if (!section->isLive()) {
p->setSymbolAndType(0, 0, false);
continue;
@@ -451,10 +451,10 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
int64_t addend = getAddend<ELFT>(rel);
const uint8_t *bufLoc = sec->data().begin() + rel.r_offset;
if (!RelTy::IsRela)
- addend = target->getImplicitAddend(bufLoc, type);
+ addend = target.getImplicitAddend(bufLoc, type);
if (config->emachine == EM_MIPS &&
- target->getRelExpr(type, sym, bufLoc) == R_MIPS_GOTREL) {
+ target.getRelExpr(type, sym, bufLoc) == R_MIPS_GOTREL) {
// Some MIPS relocations depend on "gp" value. By default,
// this value has 0x7ff0 offset from a .got section. But
// relocatable files produced by a compiler or a linker
@@ -471,16 +471,16 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
if (RelTy::IsRela)
p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr;
- else if (config->relocatable && type != target->noneRel)
+ else if (config->relocatable && type != target.noneRel)
sec->relocations.push_back({R_ABS, type, rel.r_offset, addend, &sym});
} else if (config->emachine == EM_PPC && type == R_PPC_PLTREL24 &&
- p->r_addend >= 0x8000) {
+ p->r_addend >= 0x8000 && sec->file->ppc32Got2) {
// Similar to R_MIPS_GPREL{16,32}. If the addend of R_PPC_PLTREL24
// indicates that r30 is relative to the input section .got2
// (r_addend>=0x8000), after linking, r30 should be relative to the output
// section .got2 . To compensate for the shift, adjust r_addend by
- // ppc32Got2OutSecOff.
- p->r_addend += sec->file->ppc32Got2OutSecOff;
+ // ppc32Got->outSecOff.
+ p->r_addend += sec->file->ppc32Got2->outSecOff;
}
}
}
@@ -865,6 +865,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
template <class ELFT, class RelTy>
void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
const unsigned bits = sizeof(typename ELFT::uint) * 8;
+ const TargetInfo &target = *elf::target;
const bool isDebug = isDebugSection(*this);
const bool isDebugLocOrRanges =
isDebug && (name == ".debug_loc" || name == ".debug_ranges");
@@ -890,16 +891,16 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
uint8_t *bufLoc = buf + offset;
int64_t addend = getAddend<ELFT>(rel);
if (!RelTy::IsRela)
- addend += target->getImplicitAddend(bufLoc, type);
+ addend += target.getImplicitAddend(bufLoc, type);
Symbol &sym = getFile<ELFT>()->getRelocTargetSym(rel);
- RelExpr expr = target->getRelExpr(type, sym, bufLoc);
+ RelExpr expr = target.getRelExpr(type, sym, bufLoc);
if (expr == R_NONE)
continue;
if (expr == R_SIZE) {
- target->relocateNoSym(bufLoc, type,
- SignExtend64<bits>(sym.getSize() + addend));
+ target.relocateNoSym(bufLoc, type,
+ SignExtend64<bits>(sym.getSize() + addend));
continue;
}
@@ -923,14 +924,14 @@ 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(
+ target.relocateNoSym(
bufLoc, type,
SignExtend64<bits>(sym.getVA(addend - offset - outSecOff)));
continue;
}
if (tombstone ||
- (isDebug && (type == target->symbolicRel || expr == R_DTPREL))) {
+ (isDebug && (type == target.symbolicRel || expr == R_DTPREL))) {
// Resolve relocations in .debug_* referencing (discarded symbols or ICF
// folded section symbols) to a tombstone value. Resolving to addend is
// unsatisfactory because the result address range may collide with a
@@ -948,10 +949,10 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
//
// If the referenced symbol is discarded (made Undefined), or the
// section defining the referenced symbol is garbage collected,
- // sym.getOutputSection() is nullptr. `ds->section->repl != ds->section`
- // catches the ICF folded case. However, resolving a relocation in
- // .debug_line to -1 would stop debugger users from setting breakpoints on
- // the folded-in function, so exclude .debug_line.
+ // sym.getOutputSection() is nullptr. `ds->folded` catches the ICF folded
+ // case. However, resolving a relocation in .debug_line to -1 would stop
+ // debugger users from setting breakpoints on the folded-in function, so
+ // exclude .debug_line.
//
// For pre-DWARF-v5 .debug_loc and .debug_ranges, -1 is a reserved value
// (base address selection entry), use 1 (which is used by GNU ld for
@@ -960,16 +961,15 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
// TODO To reduce disruption, we use 0 instead of -1 as the tombstone
// value. Enable -1 in a future release.
auto *ds = dyn_cast<Defined>(&sym);
- if (!sym.getOutputSection() ||
- (ds && ds->section->repl != ds->section && !isDebugLine)) {
+ if (!sym.getOutputSection() || (ds && ds->folded && !isDebugLine)) {
// If -z dead-reloc-in-nonalloc= is specified, respect it.
const uint64_t value = tombstone ? SignExtend64<bits>(*tombstone)
: (isDebugLocOrRanges ? 1 : 0);
- target->relocateNoSym(bufLoc, type, value);
+ target.relocateNoSym(bufLoc, type, value);
continue;
}
}
- target->relocateNoSym(bufLoc, type, SignExtend64<bits>(sym.getVA(addend)));
+ target.relocateNoSym(bufLoc, type, SignExtend64<bits>(sym.getVA(addend)));
}
}
@@ -992,7 +992,7 @@ static void relocateNonAllocForRelocatable(InputSection *sec, uint8_t *buf) {
template <class ELFT>
void InputSectionBase::relocate(uint8_t *buf, uint8_t *bufEnd) {
- if (flags & SHF_EXECINSTR)
+ if ((flags & SHF_EXECINSTR) && LLVM_UNLIKELY(getFile<ELFT>()->splitStack))
adjustSplitStackFunctionPrologues<ELFT>(buf, bufEnd);
if (flags & SHF_ALLOC) {
@@ -1015,6 +1015,7 @@ 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;
+ const TargetInfo &target = *elf::target;
uint64_t lastPPCRelaxedRelocOff = UINT64_C(-1);
for (const Relocation &rel : relocations) {
@@ -1022,20 +1023,18 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
continue;
uint64_t offset = rel.offset;
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),
- bits);
+ const uint64_t targetVA =
+ SignExtend64(getRelocTargetVA(file, rel.type, rel.addend, addrLoc,
+ *rel.sym, rel.expr), bits);
- switch (expr) {
+ switch (rel.expr) {
case R_RELAX_GOT_PC:
case R_RELAX_GOT_PC_NOPIC:
- target->relaxGot(bufLoc, rel, targetVA);
+ target.relaxGot(bufLoc, rel, targetVA);
break;
case R_PPC64_RELAX_GOT_PC: {
// The R_PPC64_PCREL_OPT relocation must appear immediately after
@@ -1044,11 +1043,11 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
// 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)
+ if (rel.type == R_PPC64_GOT_PCREL34)
lastPPCRelaxedRelocOff = offset;
- if (type == R_PPC64_PCREL_OPT && offset != lastPPCRelaxedRelocOff)
+ if (rel.type == R_PPC64_PCREL_OPT && offset != lastPPCRelaxedRelocOff)
break;
- target->relaxGot(bufLoc, rel, targetVA);
+ target.relaxGot(bufLoc, rel, targetVA);
break;
}
case R_PPC64_RELAX_TOC:
@@ -1059,25 +1058,25 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
// opportunities but is safe.
if (ppc64noTocRelax.count({rel.sym, rel.addend}) ||
!tryRelaxPPC64TocIndirection(rel, bufLoc))
- target->relocate(bufLoc, rel, targetVA);
+ target.relocate(bufLoc, rel, targetVA);
break;
case R_RELAX_TLS_IE_TO_LE:
- target->relaxTlsIeToLe(bufLoc, rel, targetVA);
+ target.relaxTlsIeToLe(bufLoc, rel, targetVA);
break;
case R_RELAX_TLS_LD_TO_LE:
case R_RELAX_TLS_LD_TO_LE_ABS:
- target->relaxTlsLdToLe(bufLoc, rel, targetVA);
+ target.relaxTlsLdToLe(bufLoc, rel, targetVA);
break;
case R_RELAX_TLS_GD_TO_LE:
case R_RELAX_TLS_GD_TO_LE_NEG:
- target->relaxTlsGdToLe(bufLoc, rel, targetVA);
+ target.relaxTlsGdToLe(bufLoc, rel, targetVA);
break;
case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE:
case R_RELAX_TLS_GD_TO_IE_ABS:
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
case R_RELAX_TLS_GD_TO_IE_GOTPLT:
- target->relaxTlsGdToIe(bufLoc, rel, targetVA);
+ target.relaxTlsGdToIe(bufLoc, rel, targetVA);
break;
case R_PPC64_CALL:
// If this is a call to __tls_get_addr, it may be part of a TLS
@@ -1102,10 +1101,10 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
}
write32(bufLoc + 4, 0xe8410018); // ld %r2, 24(%r1)
}
- target->relocate(bufLoc, rel, targetVA);
+ target.relocate(bufLoc, rel, targetVA);
break;
default:
- target->relocate(bufLoc, rel, targetVA);
+ target.relocate(bufLoc, rel, targetVA);
break;
}
}
@@ -1118,7 +1117,7 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
for (const JumpInstrMod &jumpMod : jumpInstrMods) {
uint64_t offset = jumpMod.offset;
uint8_t *bufLoc = buf + offset;
- target->applyJumpInstrMod(bufLoc, jumpMod.original, jumpMod.size);
+ target.applyJumpInstrMod(bufLoc, jumpMod.original, jumpMod.size);
}
}
}
@@ -1175,8 +1174,6 @@ static bool enclosingPrologueAttempted(uint64_t offset,
template <class ELFT>
void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *buf,
uint8_t *end) {
- if (!getFile<ELFT>()->splitStack)
- return;
DenseSet<Defined *> prologues;
std::vector<Relocation *> morestackCalls;
@@ -1229,27 +1226,26 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *buf,
}
template <class ELFT> void InputSection::writeTo(uint8_t *buf) {
- if (type == SHT_NOBITS)
- return;
-
if (auto *s = dyn_cast<SyntheticSection>(this)) {
s->writeTo(buf + outSecOff);
return;
}
+ if (LLVM_UNLIKELY(type == SHT_NOBITS))
+ return;
// If -r or --emit-relocs is given, then an InputSection
// may be a relocation section.
- if (type == SHT_RELA) {
+ if (LLVM_UNLIKELY(type == SHT_RELA)) {
copyRelocations<ELFT>(buf + outSecOff, getDataAs<typename ELFT::Rela>());
return;
}
- if (type == SHT_REL) {
+ if (LLVM_UNLIKELY(type == SHT_REL)) {
copyRelocations<ELFT>(buf + outSecOff, getDataAs<typename ELFT::Rel>());
return;
}
// If -r is given, we may have a SHT_GROUP section.
- if (type == SHT_GROUP) {
+ if (LLVM_UNLIKELY(type == SHT_GROUP)) {
copyShtGroup<ELFT>(buf + outSecOff);
return;
}
@@ -1369,7 +1365,7 @@ SyntheticSection *MergeInputSection::getParent() const {
// null-terminated strings.
void MergeInputSection::splitStrings(ArrayRef<uint8_t> data, size_t entSize) {
size_t off = 0;
- bool isAlloc = flags & SHF_ALLOC;
+ const bool live = !(flags & SHF_ALLOC) || !config->gcSections;
StringRef s = toStringRef(data);
while (!s.empty()) {
@@ -1378,7 +1374,7 @@ void MergeInputSection::splitStrings(ArrayRef<uint8_t> data, size_t entSize) {
fatal(toString(this) + ": string is not null terminated");
size_t size = end + entSize;
- pieces.emplace_back(off, xxHash64(s.substr(0, size)), !isAlloc);
+ pieces.emplace_back(off, xxHash64(s.substr(0, size)), live);
s = s.substr(size);
off += size;
}
@@ -1390,10 +1386,11 @@ void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> data,
size_t entSize) {
size_t size = data.size();
assert((size % entSize) == 0);
- bool isAlloc = flags & SHF_ALLOC;
+ const bool live = !(flags & SHF_ALLOC) || !config->gcSections;
- for (size_t i = 0; i != size; i += entSize)
- pieces.emplace_back(i, xxHash64(data.slice(i, entSize)), !isAlloc);
+ pieces.assign(size / entSize, SectionPiece(0, 0, false));
+ for (size_t i = 0, j = 0; i != size; i += entSize, j++)
+ pieces[j] = {i, (uint32_t)xxHash64(data.slice(i, entSize)), live};
}
template <class ELFT>
diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
index 7ddc43916a0f..5319830b5d80 100644
--- a/lld/ELF/InputSection.h
+++ b/lld/ELF/InputSection.h
@@ -52,13 +52,6 @@ public:
StringRef name;
- // This pointer points to the "real" instance of this instance.
- // Usually Repl == this. However, if ICF merges two sections,
- // Repl pointer of one section points to another section. So,
- // if you need to get a pointer to this instance, do not use
- // this but instead this->Repl.
- SectionBase *repl;
-
uint8_t sectionKind : 3;
// The next two bit fields are only used by InputSectionBase, but we
@@ -102,9 +95,9 @@ protected:
constexpr SectionBase(Kind sectionKind, StringRef name, uint64_t flags,
uint32_t entsize, uint32_t alignment, uint32_t type,
uint32_t info, uint32_t link)
- : name(name), repl(this), sectionKind(sectionKind), bss(false),
- keepUnique(false), partition(0), alignment(alignment), flags(flags),
- entsize(entsize), type(type), link(link), info(info) {}
+ : name(name), sectionKind(sectionKind), bss(false), keepUnique(false),
+ partition(0), alignment(alignment), flags(flags), entsize(entsize),
+ type(type), link(link), info(info) {}
};
// This corresponds to a section of an input file.
@@ -250,7 +243,7 @@ protected:
// be found by looking at the next one).
struct SectionPiece {
SectionPiece(size_t off, uint32_t hash, bool live)
- : inputOff(off), live(live || !config->gcSections), hash(hash >> 1) {}
+ : inputOff(off), live(live), hash(hash >> 1) {}
uint32_t inputOff;
uint32_t live : 1;
@@ -278,7 +271,7 @@ public:
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
- std::vector<SectionPiece> pieces;
+ SmallVector<SectionPiece, 0> pieces;
// Returns I'th piece's data. This function is very hot when
// string merging is enabled, so we want to inline.
@@ -367,6 +360,10 @@ public:
template <class ELFT, class RelTy>
void relocateNonAlloc(uint8_t *buf, llvm::ArrayRef<RelTy> rels);
+ // Points to the canonical section. If ICF folds two sections, repl pointer of
+ // one section points to the other.
+ InputSection *repl = this;
+
// Used by ICF.
uint32_t eqClass[2] = {0, 0};
@@ -394,7 +391,7 @@ inline bool isDebugSection(const InputSectionBase &sec) {
}
// The list of all input sections.
-extern std::vector<InputSectionBase *> inputSections;
+extern SmallVector<InputSectionBase *, 0> inputSections;
// The set of TOC entries (.toc + addend) for which we should not apply
// toc-indirect to toc-relative relaxation. const Symbol * refers to the
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index 46dc77a6789c..65b943c4a54c 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -204,6 +204,8 @@ BitcodeCompiler::BitcodeCompiler() {
config->ltoPartitions);
// Initialize usedStartStop.
+ if (bitcodeFiles.empty())
+ return;
for (Symbol *sym : symtab->symbols()) {
StringRef s = sym->getName();
for (StringRef prefix : {"__start_", "__stop_"})
@@ -278,8 +280,8 @@ void BitcodeCompiler::add(BitcodeFile &f) {
// This is needed because this is what GNU gold plugin does and we have a
// distributed build system that depends on that behavior.
static void thinLTOCreateEmptyIndexFiles() {
- for (LazyObjFile *f : lazyObjFiles) {
- if (f->extracted || !isBitcode(f->mb))
+ for (BitcodeFile *f : lazyBitcodeFiles) {
+ if (!f->lazy)
continue;
std::string path = replaceThinLTOSuffix(getThinLTOOutputFile(f->getName()));
std::unique_ptr<raw_fd_ostream> os = openFile(path + ".thinlto.bc");
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index cf4da7ab54c9..e8f2ce4fdf1f 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -47,10 +47,10 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
-LinkerScript *elf::script;
+std::unique_ptr<LinkerScript> elf::script;
static bool isSectionPrefix(StringRef prefix, StringRef name) {
- return name.startswith(prefix) || name == prefix.drop_back();
+ return name.consume_front(prefix) && (name.empty() || name[0] == '.');
}
static StringRef getOutputSectionName(const InputSectionBase *s) {
@@ -94,18 +94,21 @@ static StringRef getOutputSectionName(const InputSectionBase *s) {
// 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.split."})
- if (isSectionPrefix(v, s->name))
- return v.drop_back();
+ if (isSectionPrefix(".text", s->name)) {
+ if (config->zKeepTextSectionPrefix)
+ for (StringRef v : {".text.hot", ".text.unknown", ".text.unlikely",
+ ".text.startup", ".text.exit", ".text.split"})
+ if (isSectionPrefix(v.substr(5), s->name.substr(5)))
+ return v;
+ return ".text";
+ }
for (StringRef v :
- {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
- ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
- ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."})
+ {".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
+ ".gcc_except_table", ".init_array", ".fini_array", ".tbss", ".tdata",
+ ".ARM.exidx", ".ARM.extab", ".ctors", ".dtors"})
if (isSectionPrefix(v, s->name))
- return v.drop_back();
+ return v;
return s->name;
}
@@ -557,22 +560,22 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd,
return ret;
}
-void LinkerScript::discard(InputSectionBase *s) {
- if (s == in.shStrTab || s == mainPart->relrDyn)
- error("discarding " + s->name + " section is not allowed");
+void LinkerScript::discard(InputSectionBase &s) {
+ if (&s == in.shStrTab || &s == mainPart->relrDyn)
+ error("discarding " + s.name + " section is not allowed");
// You can discard .hash and .gnu.hash sections by linker scripts. Since
// they are synthesized sections, we need to handle them differently than
// other regular sections.
- if (s == mainPart->gnuHashTab)
+ if (&s == mainPart->gnuHashTab)
mainPart->gnuHashTab = nullptr;
- if (s == mainPart->hashTab)
+ if (&s == mainPart->hashTab)
mainPart->hashTab = nullptr;
- s->markDead();
- s->parent = nullptr;
- for (InputSection *ds : s->dependentSections)
- discard(ds);
+ s.markDead();
+ s.parent = nullptr;
+ for (InputSection *sec : s.dependentSections)
+ discard(*sec);
}
void LinkerScript::discardSynthetic(OutputSection &outCmd) {
@@ -586,7 +589,7 @@ void LinkerScript::discardSynthetic(OutputSection &outCmd) {
std::vector<InputSectionBase *> matches =
computeInputSections(isd, secs);
for (InputSectionBase *s : matches)
- discard(s);
+ discard(*s);
}
}
}
@@ -615,7 +618,7 @@ void LinkerScript::processSectionCommands() {
// Any input section assigned to it is discarded.
if (osec->name == "/DISCARD/") {
for (InputSectionBase *s : v)
- discard(s);
+ discard(*s);
discardSynthetic(*osec);
osec->commands.clear();
return false;
@@ -1335,7 +1338,7 @@ std::vector<PhdrEntry *> LinkerScript::createPhdrs() {
// Process PHDRS and FILEHDR keywords because they are not
// real output sections and cannot be added in the following loop.
for (const PhdrsCommand &cmd : phdrsCommands) {
- PhdrEntry *phdr = make<PhdrEntry>(cmd.type, cmd.flags ? *cmd.flags : PF_R);
+ PhdrEntry *phdr = make<PhdrEntry>(cmd.type, cmd.flags.getValueOr(PF_R));
if (cmd.hasFilehdr)
phdr->add(Out::elfHeader);
diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h
index badc4d126be8..f385c8320978 100644
--- a/lld/ELF/LinkerScript.h
+++ b/lld/ELF/LinkerScript.h
@@ -312,7 +312,7 @@ public:
bool hasPhdrsCommands() { return !phdrsCommands.empty(); }
uint64_t getDot() { return dot; }
- void discard(InputSectionBase *s);
+ void discard(InputSectionBase &s);
ExprValue getSymbolValue(StringRef name, const Twine &loc);
@@ -366,7 +366,7 @@ public:
std::vector<const InputSectionBase *> orphanSections;
};
-extern LinkerScript *script;
+extern std::unique_ptr<LinkerScript> script;
} // end namespace elf
} // end namespace lld
diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp
index 06735802f7f1..1998192bfba6 100644
--- a/lld/ELF/MapFile.cpp
+++ b/lld/ELF/MapFile.cpp
@@ -54,11 +54,11 @@ static void writeHeader(raw_ostream &os, uint64_t vma, uint64_t lma,
// Returns a list of all symbols that we want to print out.
static std::vector<Defined *> getSymbols() {
std::vector<Defined *> v;
- for (InputFile *file : objectFiles)
+ for (ELFFileBase *file : objectFiles)
for (Symbol *b : file->getSymbols())
if (auto *dr = dyn_cast<Defined>(b))
if (!dr->isSection() && dr->section && dr->section->isLive() &&
- (dr->file == file || dr->needsPltAddr || dr->section->bss))
+ (dr->file == file || dr->needsCopy || dr->section->bss))
v.push_back(dr);
return v;
}
@@ -72,10 +72,17 @@ static SymbolMapTy getSectionSyms(ArrayRef<Defined *> syms) {
// Sort symbols by address. We want to print out symbols in the
// order in the output file rather than the order they appeared
// in the input files.
- for (auto &it : ret)
+ SmallPtrSet<Defined *, 4> set;
+ for (auto &it : ret) {
+ // Deduplicate symbols which need a canonical PLT entry/copy relocation.
+ set.clear();
+ llvm::erase_if(it.second,
+ [&](Defined *sym) { return !set.insert(sym).second; });
+
llvm::stable_sort(it.second, [](Defined *a, Defined *b) {
return a->getVA() < b->getVA();
});
+ }
return ret;
}
@@ -236,7 +243,7 @@ void elf::writeWhyExtract() {
static void writeCref(raw_fd_ostream &os) {
// Collect symbols and files.
MapVector<Symbol *, SetVector<InputFile *>> map;
- for (InputFile *file : objectFiles) {
+ for (ELFFileBase *file : objectFiles) {
for (Symbol *sym : file->getSymbols()) {
if (isa<SharedSymbol>(sym))
map[sym].insert(file);
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 11e0466b1157..b63f2beb9dcb 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -177,10 +177,11 @@ static bool isReserved(InputSectionBase *sec) {
// SHT_NOTE sections in a group are subject to garbage collection.
return !sec->nextInSectionGroup;
default:
+ // Support SHT_PROGBITS .init_array for a while
+ // (https://golang.org/issue/50295).
StringRef s = sec->name;
- return s.startswith(".ctors") || s.startswith(".dtors") ||
- s.startswith(".init") || s.startswith(".fini") ||
- s.startswith(".jcr");
+ return s == ".init" || s == ".fini" || s == ".init_array" || s == ".jcr" ||
+ s.startswith(".ctors") || s.startswith(".dtors");
}
}
@@ -243,8 +244,6 @@ template <class ELFT> void MarkLive<ELFT>::run() {
for (StringRef s : script->referencedSymbols)
markSymbol(symtab->find(s));
- // Preserve special sections and those which are specified in linker
- // script KEEP command.
for (InputSectionBase *sec : inputSections) {
// Mark .eh_frame sections as live because there are usually no relocations
// that point to .eh_frames. Otherwise, the garbage collector would drop
@@ -258,6 +257,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
scanEhFrameSection(*eh, rels.rels);
else if (rels.relas.size())
scanEhFrameSection(*eh, rels.relas);
+ continue;
}
if (sec->flags & SHF_GNU_RETAIN) {
@@ -267,6 +267,39 @@ template <class ELFT> void MarkLive<ELFT>::run() {
if (sec->flags & SHF_LINK_ORDER)
continue;
+ // Usually, non-SHF_ALLOC sections are not removed even if they are
+ // unreachable through relocations because reachability is not a good signal
+ // whether they are garbage or not (e.g. there is usually no section
+ // referring to a .comment section, but we want to keep it.) When a
+ // non-SHF_ALLOC section is retained, we also retain sections dependent on
+ // it.
+ //
+ // Note on SHF_LINK_ORDER: Such sections contain metadata and they
+ // have a reverse dependency on the InputSection they are linked with.
+ // We are able to garbage collect them.
+ //
+ // Note on SHF_REL{,A}: Such sections reach here only when -r
+ // or --emit-reloc were given. And they are subject of garbage
+ // collection because, if we remove a text section, we also
+ // remove its relocation section.
+ //
+ // Note on nextInSectionGroup: The ELF spec says that group sections are
+ // included or omitted as a unit. We take the interpretation that:
+ //
+ // - Group members (nextInSectionGroup != nullptr) are subject to garbage
+ // collection.
+ // - Groups members are retained or discarded as a unit.
+ if (!(sec->flags & SHF_ALLOC)) {
+ bool isRel = sec->type == SHT_REL || sec->type == SHT_RELA;
+ if (!isRel && !sec->nextInSectionGroup) {
+ sec->markLive();
+ for (InputSection *isec : sec->dependentSections)
+ isec->markLive();
+ }
+ }
+
+ // Preserve special sections and those which are specified in linker
+ // script KEEP command.
if (isReserved(sec) || script->shouldKeep(sec)) {
enqueue(sec, 0);
} else if ((!config->zStartStopGC || sec->name.startswith("__libc_")) &&
@@ -312,7 +345,7 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
// to from __start_/__stop_ symbols because there will only be one set of
// symbols for the whole program.
template <class ELFT> void MarkLive<ELFT>::moveToMain() {
- for (InputFile *file : objectFiles)
+ for (ELFFileBase *file : objectFiles)
for (Symbol *s : file->getSymbols())
if (auto *d = dyn_cast<Defined>(s))
if ((d->type == STT_GNU_IFUNC || d->type == STT_TLS) && d->section &&
@@ -348,46 +381,6 @@ template <class ELFT> void elf::markLive() {
return;
}
- // Otherwise, do mark-sweep GC.
- //
- // The --gc-sections option works only for SHF_ALLOC sections (sections that
- // are memory-mapped at runtime). So we can unconditionally make non-SHF_ALLOC
- // sections alive except SHF_LINK_ORDER, SHT_REL/SHT_RELA sections, and
- // sections in a group.
- //
- // Usually, non-SHF_ALLOC sections are not removed even if they are
- // unreachable through relocations because reachability is not a good signal
- // whether they are garbage or not (e.g. there is usually no section referring
- // to a .comment section, but we want to keep it.) When a non-SHF_ALLOC
- // section is retained, we also retain sections dependent on it.
- //
- // Note on SHF_LINK_ORDER: Such sections contain metadata and they
- // have a reverse dependency on the InputSection they are linked with.
- // We are able to garbage collect them.
- //
- // Note on SHF_REL{,A}: Such sections reach here only when -r
- // or --emit-reloc were given. And they are subject of garbage
- // collection because, if we remove a text section, we also
- // remove its relocation section.
- //
- // Note on nextInSectionGroup: The ELF spec says that group sections are
- // included or omitted as a unit. We take the interpretation that:
- //
- // - Group members (nextInSectionGroup != nullptr) are subject to garbage
- // collection.
- // - Groups members are retained or discarded as a unit.
- for (InputSectionBase *sec : inputSections) {
- bool isAlloc = (sec->flags & SHF_ALLOC);
- bool isLinkOrder = (sec->flags & SHF_LINK_ORDER);
- bool isRel = (sec->type == SHT_REL || sec->type == SHT_RELA);
-
- if (!isAlloc && !isLinkOrder && !isRel && !sec->nextInSectionGroup) {
- sec->markLive();
- for (InputSection *isec : sec->dependentSections)
- isec->markLive();
- }
- }
-
// Follow the graph to mark all live sections.
for (unsigned curPart = 1; curPart <= partitions.size(); ++curPart)
MarkLive<ELFT>(curPart).run();
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index f9f9f54a80d8..bddf13a3cb42 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -79,9 +79,6 @@ defm split_stack_adjust_size
"non-split-stack function">,
MetaVarName<"<value>">;
-defm library_path:
- Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">;
-
def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
defm Tbss: Eq<"Tbss", "Same as --section-start with .bss as the sectionname">;
@@ -266,8 +263,10 @@ defm just_symbols: Eq<"just-symbols", "Just link symbols">;
defm keep_unique: Eq<"keep-unique", "Do not fold this symbol during ICF">;
-defm library: Eq<"library", "Root name of library to use">,
- MetaVarName<"<libName>">;
+def library: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libname>">,
+ HelpText<"Search for library <libname>">;
+def library_path: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
+ HelpText<"Add <dir> to the library search path">;
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
@@ -524,8 +523,10 @@ def: JoinedOrSeparate<["-"], "e">, Alias<entry>, HelpText<"Alias for --entry">;
def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">;
def: Separate<["-"], "F">, Alias<filter>, HelpText<"Alias for --filter">;
def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">;
-def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">;
-def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">;
+def: Separate<["--", "-"], "library">, Alias<library>;
+def: Joined<["--", "-"], "library=">, Alias<library>;
+def: Separate<["--", "-"], "library-path">, Alias<library_path>;
+def: Joined<["--", "-"], "library-path=">, Alias<library_path>;
def: Flag<["-"], "n">, Alias<nmagic>, HelpText<"Alias for --nmagic">;
def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">;
def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">;
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index a17f713b742a..4a03ac387814 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -40,7 +40,7 @@ OutputSection *Out::preinitArray;
OutputSection *Out::initArray;
OutputSection *Out::finiArray;
-std::vector<OutputSection *> elf::outputSections;
+SmallVector<OutputSection *, 0> elf::outputSections;
uint32_t OutputSection::getPhdrFlags() const {
uint32_t ret = 0;
@@ -155,6 +155,15 @@ void OutputSection::commitSection(InputSection *isec) {
entsize = 0;
}
+static MergeSyntheticSection *createMergeSynthetic(StringRef name,
+ uint32_t type,
+ uint64_t flags,
+ uint32_t alignment) {
+ if ((flags & SHF_STRINGS) && config->optimize >= 2)
+ return make<MergeTailSection>(name, type, flags, alignment);
+ return make<MergeNoTailSection>(name, type, flags, alignment);
+}
+
// This function scans over the InputSectionBase list sectionBases to create
// InputSectionDescription::sections.
//
@@ -323,6 +332,7 @@ static void writeInt(uint8_t *buf, uint64_t data, uint64_t size) {
}
template <class ELFT> void OutputSection::writeTo(uint8_t *buf) {
+ llvm::TimeTraceScope timeScope("Write sections", name);
if (type == SHT_NOBITS)
return;
@@ -550,7 +560,7 @@ void OutputSection::checkDynRelAddends(const uint8_t *bufStart) {
if (!sec)
return;
for (const DynamicReloc &rel : sec->relocs) {
- int64_t addend = rel.computeAddend();
+ int64_t addend = rel.addend;
const OutputSection *relOsec = rel.inputSec->getOutputSection();
assert(relOsec != nullptr && "missing output section for relocation");
const uint8_t *relocTarget =
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index a5b05cf28aa8..fb3eb0059909 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -138,7 +138,7 @@ struct Out {
uint64_t getHeaderSize();
-extern std::vector<OutputSection *> outputSections;
+extern llvm::SmallVector<OutputSection *, 0> outputSections;
} // namespace elf
} // namespace lld
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 5136ba2151a3..cfe49007b814 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -295,18 +295,20 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &ss) {
// in .bss and in the case of a canonical plt entry it is in .plt. This function
// replaces the existing symbol with a Defined pointing to the appropriate
// location.
-static void replaceWithDefined(Symbol &sym, SectionBase *sec, uint64_t value,
+static void replaceWithDefined(Symbol &sym, SectionBase &sec, uint64_t value,
uint64_t size) {
Symbol old = sym;
sym.replace(Defined{sym.file, sym.getName(), sym.binding, sym.stOther,
- sym.type, value, size, sec});
+ sym.type, value, size, &sec});
sym.pltIndex = old.pltIndex;
sym.gotIndex = old.gotIndex;
sym.verdefIndex = old.verdefIndex;
sym.exportDynamic = true;
sym.isUsedInRegularObj = true;
+ // A copy relocated alias may need a GOT entry.
+ sym.needsGot = old.needsGot;
}
// Reserve space in .bss or .bss.rel.ro for copy relocation.
@@ -351,7 +353,7 @@ static void replaceWithDefined(Symbol &sym, SectionBase *sec, uint64_t value,
// to the variable in .bss. This kind of issue is sometimes very hard to
// debug. What's a solution? Instead of exporting a variable V from a DSO,
// define an accessor getV().
-template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) {
+template <class ELFT> static void addCopyRelSymbolImpl(SharedSymbol &ss) {
// Copy relocation against zero-sized symbol doesn't make sense.
uint64_t symSize = ss.getSize();
if (symSize == 0 || ss.alignment == 0)
@@ -377,9 +379,29 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) {
// dynamic symbol for each one. This causes the copy relocation to correctly
// interpose any aliases.
for (SharedSymbol *sym : getSymbolsAt<ELFT>(ss))
- replaceWithDefined(*sym, sec, 0, sym->size);
+ replaceWithDefined(*sym, *sec, 0, sym->size);
- mainPart->relaDyn->addSymbolReloc(target->copyRel, sec, 0, ss);
+ mainPart->relaDyn->addSymbolReloc(target->copyRel, *sec, 0, ss);
+}
+
+static void addCopyRelSymbol(SharedSymbol &ss) {
+ const SharedFile &file = ss.getFile();
+ switch (file.ekind) {
+ case ELF32LEKind:
+ addCopyRelSymbolImpl<ELF32LE>(ss);
+ break;
+ case ELF32BEKind:
+ addCopyRelSymbolImpl<ELF32BE>(ss);
+ break;
+ case ELF64LEKind:
+ addCopyRelSymbolImpl<ELF64LE>(ss);
+ break;
+ case ELF64BEKind:
+ addCopyRelSymbolImpl<ELF64BE>(ss);
+ break;
+ default:
+ llvm_unreachable("");
+ }
}
// MIPS has an odd notion of "paired" relocations to calculate addends.
@@ -450,8 +472,8 @@ static std::string maybeReportDiscarded(Undefined &sym) {
if (!file || !sym.discardedSecIdx ||
file->getSections()[sym.discardedSecIdx] != &InputSection::discarded)
return "";
- ArrayRef<Elf_Shdr_Impl<ELFT>> objSections =
- CHECK(file->getObj().sections(), file);
+ ArrayRef<typename ELFT::Shdr> objSections =
+ file->template getELFShdrs<ELFT>();
std::string msg;
if (sym.type == ELF::STT_SECTION) {
@@ -680,6 +702,12 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef,
msg +=
"\n>>> the vtable symbol may be undefined because the class is missing "
"its key function (see https://lld.llvm.org/missingkeyfunction)";
+ if (config->gcSections && config->zStartStopGC &&
+ sym.getName().startswith("__start_")) {
+ msg += "\n>>> the encapsulation symbol needs to be retained under "
+ "--gc-sections properly; consider -z nostart-stop-gc "
+ "(see https://lld.llvm.org/ELF/start-stop-gc)";
+ }
if (undef.isWarning)
warn(msg);
@@ -711,8 +739,6 @@ 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())
- 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() == '@') {
@@ -807,10 +833,10 @@ private:
};
} // namespace
-static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
+static void addRelativeReloc(InputSectionBase &isec, uint64_t offsetInSec,
Symbol &sym, int64_t addend, RelExpr expr,
RelType type) {
- Partition &part = isec->getPartition();
+ Partition &part = isec.getPartition();
// Add a relative relocation. If relrDyn section is enabled, and the
// relocation offset is guaranteed to be even, add the relocation to
@@ -818,9 +844,9 @@ static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
// relrDyn sections don't support odd offsets. Also, relrDyn sections
// 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});
- part.relrDyn->relocs.push_back({isec, offsetInSec});
+ if (part.relrDyn && isec.alignment >= 2 && offsetInSec % 2 == 0) {
+ isec.relocations.push_back({expr, type, offsetInSec, addend, &sym});
+ part.relrDyn->relocs.push_back({&isec, offsetInSec});
return;
}
part.relaDyn->addRelativeReloc(target->relativeRel, isec, offsetInSec, sym,
@@ -828,14 +854,14 @@ static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
}
template <class PltSection, class GotPltSection>
-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 ? DynamicReloc::AgainstSymbol
- : DynamicReloc::AddendOnlyWithTargetVA,
- sym, 0, R_ABS});
+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 ? DynamicReloc::AgainstSymbol
+ : DynamicReloc::AddendOnlyWithTargetVA,
+ sym, 0, R_ABS});
}
static void addGotEntry(Symbol &sym) {
@@ -854,7 +880,7 @@ static void addGotEntry(Symbol &sym) {
if (!config->isPic || isAbsolute(sym))
in.got->relocations.push_back({R_ABS, target->symbolicRel, off, 0, &sym});
else
- addRelativeReloc(in.got, off, sym, 0, R_ABS, target->symbolicRel);
+ addRelativeReloc(*in.got, off, sym, 0, R_ABS, target->symbolicRel);
}
static void addTpOffsetGotEntry(Symbol &sym) {
@@ -865,7 +891,7 @@ static void addTpOffsetGotEntry(Symbol &sym) {
return;
}
mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
- target->tlsGotRel, in.got, off, sym, target->symbolicRel);
+ target->tlsGotRel, *in.got, off, sym, target->symbolicRel);
}
// Return true if we can define a symbol in the executable that
@@ -993,12 +1019,12 @@ 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->addSymbolReloc(rel, &sec, offset, sym, addend,
+ sec.getPartition().relaDyn->addSymbolReloc(rel, sec, offset, sym, addend,
type);
// MIPS ABI turns using of GOT and dynamic relocations inside out.
@@ -1039,7 +1065,7 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
" against symbol '" + toString(*ss) +
"'; recompile with -fPIC or remove '-z nocopyreloc'" +
getLocation(sec, sym, offset));
- addCopyRelSymbol<ELFT>(*ss);
+ sym.needsCopy = true;
}
sec.relocations.push_back({expr, type, offset, addend, &sym});
return;
@@ -1077,20 +1103,8 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
errorOrWarn("symbol '" + toString(sym) +
"' cannot be preempted; recompile with -fPIE" +
getLocation(sec, sym, offset));
- if (!sym.isInPlt())
- addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
- if (!sym.isDefined()) {
- replaceWithDefined(
- sym, in.plt,
- target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
- if (config->emachine == EM_PPC) {
- // PPC32 canonical PLT entries are at the beginning of .glink
- cast<Defined>(sym).value = in.plt->headerSize;
- in.plt->headerSize += 16;
- cast<PPC32GlinkSection>(in.plt)->canonical_plts.push_back(&sym);
- }
- }
- sym.needsPltAddr = true;
+ sym.needsCopy = true;
+ sym.needsPlt = true;
sec.relocations.push_back({expr, type, offset, addend, &sym});
return;
}
@@ -1144,13 +1158,10 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSDESC_GOTPLT>(expr) &&
config->shared) {
- if (in.got->addDynTlsEntry(sym)) {
- uint64_t off = in.got->getGlobalDynOffset(sym);
- mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
- target->tlsDescRel, in.got, off, sym, target->tlsDescRel);
- }
- if (expr != R_TLSDESC_CALL)
+ if (expr != R_TLSDESC_CALL) {
+ sym.needsTlsDesc = true;
c.relocations.push_back({expr, type, offset, addend, &sym});
+ }
return 1;
}
@@ -1186,14 +1197,7 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
}
if (expr == R_TLSLD_HINT)
return 1;
- if (in.got->addTlsIndex()) {
- if (isLocalInExecutable)
- 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()});
- }
+ sym.needsTlsLd = true;
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
}
@@ -1209,12 +1213,7 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
// Local-Dynamic sequence where offset of tls variable relative to dynamic
// thread pointer is stored in the got. This cannot be relaxed to Local-Exec.
if (expr == R_TLSLD_GOT_OFF) {
- if (!sym.isInGot()) {
- in.got->addEntry(sym);
- uint64_t off = sym.getGotOffset();
- in.got->relocations.push_back(
- {R_ABS, target->tlsOffsetRel, off, 0, &sym});
- }
+ sym.needsGotDtprel = true;
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
}
@@ -1222,27 +1221,7 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSDESC_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(expr)) {
if (!toExecRelax) {
- if (in.got->addDynTlsEntry(sym)) {
- uint64_t off = in.got->getGlobalDynOffset(sym);
-
- if (isLocalInExecutable)
- // Write one to the GOT slot.
- in.got->relocations.push_back(
- {R_ADDEND, target->symbolicRel, off, 1, &sym});
- else
- 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->addSymbolReloc(target->tlsOffsetRel, in.got,
- offsetOff, sym);
- else
- in.got->relocations.push_back(
- {R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym});
- }
+ sym.needsTlsGd = true;
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
}
@@ -1250,14 +1229,10 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
// Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
// depending on the symbol being locally defined or not.
if (sym.isPreemptible) {
+ sym.needsTlsGdToIe = true;
c.relocations.push_back(
{target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_IE), type, offset,
addend, &sym});
- if (!sym.isInGot()) {
- in.got->addEntry(sym);
- mainPart->relaDyn->addSymbolReloc(target->tlsGotRel, in.got,
- sym.getGotOffset(), sym);
- }
} else {
c.relocations.push_back(
{target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_LE), type, offset,
@@ -1274,11 +1249,10 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
c.relocations.push_back(
{R_RELAX_TLS_IE_TO_LE, type, offset, addend, &sym});
} else if (expr != R_TLSIE_HINT) {
- if (!sym.isInGot())
- addTpOffsetGotEntry(sym);
+ sym.needsTlsIe = true;
// R_GOT needs a relative relocation for PIC on i386 and Hexagon.
if (expr == R_GOT && config->isPic && !target->usesOnlyLowPageBits(type))
- addRelativeReloc(&c, offset, sym, addend, expr, type);
+ addRelativeReloc(c, offset, sym, addend, expr, type);
else
c.relocations.push_back({expr, type, offset, addend, &sym});
}
@@ -1311,7 +1285,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// Error if the target symbol is undefined. Symbol index 0 may be used by
// marker relocations, e.g. R_*_NONE and R_ARM_V4BX. Don't error on them.
- if (symIndex != 0 && maybeReportUndefined(sym, sec, rel.r_offset))
+ if (sym.isUndefined() && symIndex != 0 &&
+ maybeReportUndefined(sym, sec, rel.r_offset))
return;
const uint8_t *relocatedAddr = sec.data().begin() + rel.r_offset;
@@ -1365,8 +1340,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_PLT_GOTPLT,
R_TLSDESC_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;
}
@@ -1415,120 +1390,27 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// direct relocation on through.
if (sym.isGnuIFunc() && config->zIfuncNoplt) {
sym.exportDynamic = true;
- mainPart->relaDyn->addSymbolReloc(type, &sec, offset, sym, addend, type);
+ mainPart->relaDyn->addSymbolReloc(type, sec, offset, sym, addend, type);
return;
}
- // Non-preemptible ifuncs require special handling. First, handle the usual
- // case where the symbol isn't one of these.
- if (!sym.isGnuIFunc() || sym.isPreemptible) {
- // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
- if (needsPlt(expr) && !sym.isInPlt())
- addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
-
- // Create a GOT slot if a relocation needs GOT.
- if (needsGot(expr)) {
- if (config->emachine == EM_MIPS) {
- // MIPS ABI has special rules to process GOT entries and doesn't
- // require relocation entries for them. A special case is TLS
- // relocations. In that case dynamic loader applies dynamic
- // relocations to initialize TLS GOT entries.
- // See "Global Offset Table" in Chapter 5 in the following document
- // for detailed description:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- in.mipsGot->addEntry(*sec.file, sym, addend, expr);
- } else if (!sym.isInGot()) {
- addGotEntry(sym);
- }
+ if (needsGot(expr)) {
+ if (config->emachine == EM_MIPS) {
+ // MIPS ABI has special rules to process GOT entries and doesn't
+ // require relocation entries for them. A special case is TLS
+ // relocations. In that case dynamic loader applies dynamic
+ // relocations to initialize TLS GOT entries.
+ // See "Global Offset Table" in Chapter 5 in the following document
+ // for detailed description:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ in.mipsGot->addEntry(*sec.file, sym, addend, expr);
+ } else {
+ sym.needsGot = true;
}
+ } else if (needsPlt(expr)) {
+ sym.needsPlt = true;
} else {
- // Handle a reference to a non-preemptible ifunc. These are special in a
- // few ways:
- //
- // - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have
- // a fixed value. But assuming that all references to the ifunc are
- // GOT-generating or PLT-generating, the handling of an ifunc is
- // relatively straightforward. We create a PLT entry in Iplt, which is
- // usually at the end of .plt, which makes an indirect call using a
- // matching GOT entry in igotPlt, which is usually at the end of .got.plt.
- // The GOT entry is relocated using an IRELATIVE relocation in relaIplt,
- // which is usually at the end of .rela.plt. Unlike most relocations in
- // .rela.plt, which may be evaluated lazily without -z now, dynamic
- // loaders evaluate IRELATIVE relocs eagerly, which means that for
- // IRELATIVE relocs only, GOT-generating relocations can point directly to
- // .got.plt without requiring a separate GOT entry.
- //
- // - Despite the fact that an ifunc does not have a fixed value, compilers
- // that are not passed -fPIC will assume that they do, and will emit
- // direct (non-GOT-generating, non-PLT-generating) relocations to the
- // symbol. This means that if a direct relocation to the symbol is
- // seen, the linker must set a value for the symbol, and this value must
- // be consistent no matter what type of reference is made to the symbol.
- // This can be done by creating a PLT entry for the symbol in the way
- // described above and making it canonical, that is, making all references
- // point to the PLT entry instead of the resolver. In lld we also store
- // the address of the PLT entry in the dynamic symbol table, which means
- // that the symbol will also have the same value in other modules.
- // Because the value loaded from the GOT needs to be consistent with
- // the value computed using a direct relocation, a non-preemptible ifunc
- // may end up with two GOT entries, one in .got.plt that points to the
- // address returned by the resolver and is used only by the PLT entry,
- // and another in .got that points to the PLT entry and is used by
- // GOT-generating relocations.
- //
- // - The fact that these symbols do not have a fixed value makes them an
- // exception to the general rule that a statically linked executable does
- // not require any form of dynamic relocation. To handle these relocations
- // correctly, the IRELATIVE relocations are stored in an array which a
- // statically linked executable's startup code must enumerate using the
- // linker-defined symbols __rela?_iplt_{start,end}.
- if (!sym.isInPlt()) {
- // Create PLT and GOTPLT slots for the symbol.
- sym.isInIplt = true;
-
- // Create a copy of the symbol to use as the target of the IRELATIVE
- // relocation in the igotPlt. This is in case we make the PLT canonical
- // later, which would overwrite the original symbol.
- //
- // FIXME: Creating a copy of the symbol here is a bit of a hack. All
- // that's really needed to create the IRELATIVE is the section and value,
- // so ideally we should just need to copy those.
- auto *directSym = make<Defined>(cast<Defined>(sym));
- addPltEntry(in.iplt, in.igotPlt, in.relaIplt, target->iRelativeRel,
- *directSym);
- sym.pltIndex = directSym->pltIndex;
- }
- if (needsGot(expr)) {
- // Redirect GOT accesses to point to the Igot.
- //
- // This field is also used to keep track of whether we ever needed a GOT
- // entry. If we did and we make the PLT canonical later, we'll need to
- // create a GOT entry pointing to the PLT entry for Sym.
- sym.gotInIgot = true;
- } else if (!needsPlt(expr)) {
- // Make the ifunc's PLT entry canonical by changing the value of its
- // symbol to redirect all references to point to it.
- auto &d = cast<Defined>(sym);
- d.section = in.iplt;
- d.value = sym.pltIndex * target->ipltEntrySize;
- d.size = 0;
- // It's important to set the symbol type here so that dynamic loaders
- // don't try to call the PLT as if it were an ifunc resolver.
- d.type = STT_FUNC;
-
- if (sym.gotInIgot) {
- // We previously encountered a GOT generating reference that we
- // redirected to the Igot. Now that the PLT entry is canonical we must
- // clear the redirection to the Igot and add a GOT entry. As we've
- // changed the symbol type to STT_FUNC future GOT generating references
- // will naturally use this GOT entry.
- //
- // We don't need to worry about creating a MIPS GOT here because ifuncs
- // aren't a thing on MIPS.
- sym.gotInIgot = false;
- addGotEntry(sym);
- }
- }
+ sym.hasDirectReloc = true;
}
processRelocAux<ELFT>(sec, expr, type, offset, sym, addend);
@@ -1609,6 +1491,179 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &s) {
scanRelocs<ELFT>(s, rels.relas);
}
+static bool handleNonPreemptibleIfunc(Symbol &sym) {
+ // Handle a reference to a non-preemptible ifunc. These are special in a
+ // few ways:
+ //
+ // - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have
+ // a fixed value. But assuming that all references to the ifunc are
+ // GOT-generating or PLT-generating, the handling of an ifunc is
+ // relatively straightforward. We create a PLT entry in Iplt, which is
+ // usually at the end of .plt, which makes an indirect call using a
+ // matching GOT entry in igotPlt, which is usually at the end of .got.plt.
+ // The GOT entry is relocated using an IRELATIVE relocation in relaIplt,
+ // which is usually at the end of .rela.plt. Unlike most relocations in
+ // .rela.plt, which may be evaluated lazily without -z now, dynamic
+ // loaders evaluate IRELATIVE relocs eagerly, which means that for
+ // IRELATIVE relocs only, GOT-generating relocations can point directly to
+ // .got.plt without requiring a separate GOT entry.
+ //
+ // - Despite the fact that an ifunc does not have a fixed value, compilers
+ // that are not passed -fPIC will assume that they do, and will emit
+ // direct (non-GOT-generating, non-PLT-generating) relocations to the
+ // symbol. This means that if a direct relocation to the symbol is
+ // seen, the linker must set a value for the symbol, and this value must
+ // be consistent no matter what type of reference is made to the symbol.
+ // This can be done by creating a PLT entry for the symbol in the way
+ // described above and making it canonical, that is, making all references
+ // point to the PLT entry instead of the resolver. In lld we also store
+ // the address of the PLT entry in the dynamic symbol table, which means
+ // that the symbol will also have the same value in other modules.
+ // Because the value loaded from the GOT needs to be consistent with
+ // the value computed using a direct relocation, a non-preemptible ifunc
+ // may end up with two GOT entries, one in .got.plt that points to the
+ // address returned by the resolver and is used only by the PLT entry,
+ // and another in .got that points to the PLT entry and is used by
+ // GOT-generating relocations.
+ //
+ // - The fact that these symbols do not have a fixed value makes them an
+ // exception to the general rule that a statically linked executable does
+ // not require any form of dynamic relocation. To handle these relocations
+ // correctly, the IRELATIVE relocations are stored in an array which a
+ // statically linked executable's startup code must enumerate using the
+ // linker-defined symbols __rela?_iplt_{start,end}.
+ if (!sym.isGnuIFunc() || sym.isPreemptible || config->zIfuncNoplt)
+ return false;
+ // Skip unreferenced non-preemptible ifunc.
+ if (!(sym.needsGot || sym.needsPlt || sym.hasDirectReloc))
+ return true;
+
+ sym.isInIplt = true;
+
+ // Create an Iplt and the associated IRELATIVE relocation pointing to the
+ // original section/value pairs. For non-GOT non-PLT relocation case below, we
+ // may alter section/value, so create a copy of the symbol to make
+ // section/value fixed.
+ auto *directSym = makeDefined(cast<Defined>(sym));
+ addPltEntry(*in.iplt, *in.igotPlt, *in.relaIplt, target->iRelativeRel,
+ *directSym);
+ sym.pltIndex = directSym->pltIndex;
+
+ if (sym.hasDirectReloc) {
+ // Change the value to the IPLT and redirect all references to it.
+ auto &d = cast<Defined>(sym);
+ d.section = in.iplt;
+ d.value = sym.pltIndex * target->ipltEntrySize;
+ d.size = 0;
+ // It's important to set the symbol type here so that dynamic loaders
+ // don't try to call the PLT as if it were an ifunc resolver.
+ d.type = STT_FUNC;
+
+ if (sym.needsGot)
+ addGotEntry(sym);
+ } else if (sym.needsGot) {
+ // Redirect GOT accesses to point to the Igot.
+ sym.gotInIgot = true;
+ }
+ return true;
+}
+
+void elf::postScanRelocations() {
+ auto fn = [](Symbol &sym) {
+ if (handleNonPreemptibleIfunc(sym))
+ return;
+ if (sym.needsGot)
+ addGotEntry(sym);
+ if (sym.needsPlt)
+ addPltEntry(*in.plt, *in.gotPlt, *in.relaPlt, target->pltRel, sym);
+ if (sym.needsCopy) {
+ if (sym.isObject()) {
+ addCopyRelSymbol(cast<SharedSymbol>(sym));
+ // needsCopy is cleared for sym and its aliases so that in later
+ // iterations aliases won't cause redundant copies.
+ assert(!sym.needsCopy);
+ } else {
+ assert(sym.isFunc() && sym.needsPlt);
+ if (!sym.isDefined()) {
+ replaceWithDefined(
+ sym, *in.plt,
+ target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
+ sym.needsCopy = true;
+ if (config->emachine == EM_PPC) {
+ // PPC32 canonical PLT entries are at the beginning of .glink
+ cast<Defined>(sym).value = in.plt->headerSize;
+ in.plt->headerSize += 16;
+ cast<PPC32GlinkSection>(*in.plt).canonical_plts.push_back(&sym);
+ }
+ }
+ }
+ }
+
+ if (!sym.isTls())
+ return;
+ bool isLocalInExecutable = !sym.isPreemptible && !config->shared;
+
+ if (sym.needsTlsDesc) {
+ in.got->addDynTlsEntry(sym);
+ mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
+ target->tlsDescRel, *in.got, in.got->getGlobalDynOffset(sym), sym,
+ target->tlsDescRel);
+ }
+ if (sym.needsTlsGd && !sym.needsTlsDesc) {
+ // TODO Support mixed TLSDESC and TLS GD.
+ in.got->addDynTlsEntry(sym);
+ uint64_t off = in.got->getGlobalDynOffset(sym);
+ if (isLocalInExecutable)
+ // Write one to the GOT slot.
+ in.got->relocations.push_back(
+ {R_ADDEND, target->symbolicRel, off, 1, &sym});
+ else
+ 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->addSymbolReloc(target->tlsOffsetRel, *in.got,
+ offsetOff, sym);
+ else
+ in.got->relocations.push_back(
+ {R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym});
+ }
+ if (sym.needsTlsGdToIe) {
+ in.got->addEntry(sym);
+ mainPart->relaDyn->addSymbolReloc(target->tlsGotRel, *in.got,
+ sym.getGotOffset(), sym);
+ }
+
+ if (sym.needsTlsLd && in.got->addTlsIndex()) {
+ if (isLocalInExecutable)
+ 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()});
+ }
+ if (sym.needsGotDtprel) {
+ in.got->addEntry(sym);
+ in.got->relocations.push_back(
+ {R_ABS, target->tlsOffsetRel, sym.getGotOffset(), 0, &sym});
+ }
+
+ if (sym.needsTlsIe && !sym.needsTlsGdToIe)
+ addTpOffsetGotEntry(sym);
+ };
+ for (Symbol *sym : symtab->symbols())
+ fn(*sym);
+
+ // Local symbols may need the aforementioned non-preemptible ifunc and GOT
+ // handling. They don't need regular PLT.
+ for (ELFFileBase *file : objectFiles)
+ for (Symbol *sym : cast<ELFFileBase>(file)->getLocalSymbols())
+ fn(*sym);
+}
+
static bool mergeCmp(const InputSection *a, const InputSection *b) {
// std::merge requires a strict weak ordering.
if (a->outSecOff < b->outSecOff)
@@ -1964,8 +2019,8 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
// non-Thunk target, so we cannot fold offset + addend.
if (auto *d = dyn_cast<Defined>(rel.sym))
if (!d->isInPlt() && d->section)
- thunkVec = &thunkedSymbolsBySectionAndAddend[{
- {d->section->repl, d->value}, keyAddend}];
+ thunkVec = &thunkedSymbolsBySectionAndAddend[{{d->section, d->value},
+ keyAddend}];
if (!thunkVec)
thunkVec = &thunkedSymbols[{rel.sym, keyAddend}];
@@ -2119,7 +2174,7 @@ void elf::hexagonTLSSymbolUpdate(ArrayRef<OutputSection *> outputSections) {
for (Relocation &rel : isec->relocations)
if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC) {
if (needEntry) {
- addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel,
+ addPltEntry(*in.plt, *in.gotPlt, *in.relaPlt, target->pltRel,
*sym);
needEntry = false;
}
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 86e6cf4bc1f5..c652c0a5f70f 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -126,6 +126,7 @@ struct JumpInstrMod {
// Call reportUndefinedSymbols() after calling scanRelocations() to emit
// the diagnostics.
template <class ELFT> void scanRelocations(InputSectionBase &);
+void postScanRelocations();
template <class ELFT> void reportUndefinedSymbols();
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index e615fb70a40f..a12c5f22c4fe 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -29,7 +29,7 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-SymbolTable *elf::symtab;
+std::unique_ptr<SymbolTable> elf::symtab;
void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {
// Redirect __real_foo to the original foo and foo to the original __wrap_foo.
@@ -64,16 +64,18 @@ Symbol *SymbolTable::insert(StringRef name) {
// Since this is a hot path, the following string search code is
// optimized for speed. StringRef::find(char) is much faster than
// StringRef::find(StringRef).
+ StringRef stem = name;
size_t pos = name.find('@');
if (pos != StringRef::npos && pos + 1 < name.size() && name[pos + 1] == '@')
- name = name.take_front(pos);
-
- auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
- int &symIndex = p.first->second;
- bool isNew = p.second;
-
- if (!isNew)
- return symVector[symIndex];
+ stem = name.take_front(pos);
+
+ auto p = symMap.insert({CachedHashStringRef(stem), (int)symVector.size()});
+ if (!p.second) {
+ Symbol *sym = symVector[p.first->second];
+ if (stem.size() != name.size())
+ sym->setName(name);
+ return sym;
+ }
Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
symVector.push_back(sym);
@@ -105,10 +107,7 @@ Symbol *SymbolTable::find(StringRef name) {
auto it = symMap.find(CachedHashStringRef(name));
if (it == symMap.end())
return nullptr;
- Symbol *sym = symVector[it->second];
- if (sym->isPlaceholder())
- return nullptr;
- return sym;
+ return symVector[it->second];
}
// A version script/dynamic list is only meaningful for a Defined symbol.
@@ -131,7 +130,7 @@ static bool canBeVersioned(const Symbol &sym) {
// other than trying to match a pattern against all demangled symbols.
// So, if "extern C++" feature is used, we need to demangle all known
// symbols.
-StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() {
+StringMap<SmallVector<Symbol *, 0>> &SymbolTable::getDemangledSyms() {
if (!demangledSyms) {
demangledSyms.emplace();
std::string demangled;
@@ -152,7 +151,7 @@ StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() {
return *demangledSyms;
}
-std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion ver) {
+SmallVector<Symbol *, 0> SymbolTable::findByVersion(SymbolVersion ver) {
if (ver.isExternCpp)
return getDemangledSyms().lookup(ver.name);
if (Symbol *sym = find(ver.name))
@@ -161,9 +160,9 @@ std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion ver) {
return {};
}
-std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion ver,
- bool includeNonDefault) {
- std::vector<Symbol *> res;
+SmallVector<Symbol *, 0> SymbolTable::findAllByVersion(SymbolVersion ver,
+ bool includeNonDefault) {
+ SmallVector<Symbol *, 0> res;
SingleStringMatcher m(ver.name);
auto check = [&](StringRef name) {
size_t pos = name.find('@');
@@ -189,8 +188,8 @@ std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion ver,
}
void SymbolTable::handleDynamicList() {
+ SmallVector<Symbol *, 0> syms;
for (SymbolVersion &ver : config->dynamicList) {
- std::vector<Symbol *> syms;
if (ver.hasWildcard)
syms = findAllByVersion(ver, /*includeNonDefault=*/true);
else
@@ -207,7 +206,7 @@ bool SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
StringRef versionName,
bool includeNonDefault) {
// Get a list of symbols which we need to assign the version to.
- std::vector<Symbol *> syms = findByVersion(ver);
+ SmallVector<Symbol *, 0> syms = findByVersion(ver);
auto getName = [](uint16_t ver) -> std::string {
if (ver == VER_NDX_LOCAL)
@@ -228,7 +227,7 @@ bool SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
// If the version has not been assigned, verdefIndex is -1. Use an arbitrary
// number (0) to indicate the version has been assigned.
- if (sym->verdefIndex == UINT32_C(-1)) {
+ if (sym->verdefIndex == uint16_t(-1)) {
sym->verdefIndex = 0;
sym->versionId = versionId;
}
@@ -247,7 +246,7 @@ void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId,
// so we set a version to a symbol only if no version has been assigned
// to the symbol. This behavior is compatible with GNU.
for (Symbol *sym : findAllByVersion(ver, includeNonDefault))
- if (sym->verdefIndex == UINT32_C(-1)) {
+ if (sym->verdefIndex == uint16_t(-1)) {
sym->verdefIndex = 0;
sym->versionId = versionId;
}
@@ -262,7 +261,6 @@ void SymbolTable::scanVersionScript() {
SmallString<128> buf;
// First, we assign versions to exact matching symbols,
// i.e. version definitions not containing any glob meta-characters.
- std::vector<Symbol *> syms;
for (VersionDefinition &v : config->versionDefinitions) {
auto assignExact = [&](SymbolVersion pat, uint16_t id, StringRef ver) {
bool found =
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index 54c4b1169ed1..84d93a3dc786 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -35,8 +35,9 @@ class SymbolTable {
struct FilterOutPlaceholder {
bool operator()(Symbol *S) const { return !S->isPlaceholder(); }
};
- using iterator = llvm::filter_iterator<std::vector<Symbol *>::const_iterator,
- FilterOutPlaceholder>;
+ using iterator =
+ llvm::filter_iterator<SmallVector<Symbol *, 0>::const_iterator,
+ FilterOutPlaceholder>;
public:
llvm::iterator_range<iterator> symbols() const {
@@ -64,11 +65,11 @@ public:
llvm::DenseMap<llvm::CachedHashStringRef, const InputFile *> comdatGroups;
private:
- std::vector<Symbol *> findByVersion(SymbolVersion ver);
- std::vector<Symbol *> findAllByVersion(SymbolVersion ver,
- bool includeNonDefault);
+ SmallVector<Symbol *, 0> findByVersion(SymbolVersion ver);
+ SmallVector<Symbol *, 0> findAllByVersion(SymbolVersion ver,
+ bool includeNonDefault);
- llvm::StringMap<std::vector<Symbol *>> &getDemangledSyms();
+ llvm::StringMap<SmallVector<Symbol *, 0>> &getDemangledSyms();
bool assignExactVersion(SymbolVersion ver, uint16_t versionId,
StringRef versionName, bool includeNonDefault);
void assignWildcardVersion(SymbolVersion ver, uint16_t versionId,
@@ -82,16 +83,16 @@ private:
// FIXME: Experiment with passing in a custom hashing or sorting the symbols
// once symbol resolution is finished.
llvm::DenseMap<llvm::CachedHashStringRef, int> symMap;
- std::vector<Symbol *> symVector;
+ SmallVector<Symbol *, 0> symVector;
// A map from demangled symbol names to their symbol objects.
// This mapping is 1:N because two symbols with different versions
// can have the same name. We use this map to handle "extern C++ {}"
// directive in version scripts.
- llvm::Optional<llvm::StringMap<std::vector<Symbol *>>> demangledSyms;
+ llvm::Optional<llvm::StringMap<SmallVector<Symbol *, 0>>> demangledSyms;
};
-extern SymbolTable *symtab;
+extern std::unique_ptr<SymbolTable> symtab;
} // namespace elf
} // namespace lld
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 8c410b4d5bfb..20301497a059 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -67,7 +67,7 @@ DenseMap<const Symbol *, std::pair<const InputFile *, const InputFile *>>
SmallVector<std::tuple<std::string, const InputFile *, const Symbol &>, 0>
elf::whyExtract;
-static uint64_t getSymVA(const Symbol &sym, int64_t &addend) {
+static uint64_t getSymVA(const Symbol &sym, int64_t addend) {
switch (sym.kind()) {
case Symbol::DefinedKind: {
auto &d = cast<Defined>(sym);
@@ -78,7 +78,6 @@ static uint64_t getSymVA(const Symbol &sym, int64_t &addend) {
return d.value;
assert(isec != &InputSection::discarded);
- isec = isec->repl;
uint64_t offset = d.value;
@@ -93,10 +92,8 @@ static uint64_t getSymVA(const Symbol &sym, int64_t &addend) {
// To make this work, we incorporate the addend into the section
// offset (and zero out the addend for later processing) so that
// we find the right object in the section.
- if (d.isSection()) {
+ if (d.isSection())
offset += addend;
- addend = 0;
- }
// In the typical case, this is actually very simple and boils
// down to adding together 3 numbers:
@@ -109,6 +106,8 @@ static uint64_t getSymVA(const Symbol &sym, int64_t &addend) {
// line (and how they get built), then you have a pretty good
// understanding of the linker.
uint64_t va = isec->getVA(offset);
+ if (d.isSection())
+ va -= addend;
// MIPS relocatable files can mix regular and microMIPS code.
// Linker needs to distinguish such code. To do so microMIPS
@@ -120,7 +119,7 @@ static uint64_t getSymVA(const Symbol &sym, int64_t &addend) {
// field etc) do the same trick as compiler uses to mark microMIPS
// for CPU - set the less-significant bit.
if (config->emachine == EM_MIPS && isMicroMips() &&
- ((sym.stOther & STO_MIPS_MICROMIPS) || sym.needsPltAddr))
+ ((sym.stOther & STO_MIPS_MICROMIPS) || sym.needsCopy))
va |= 1;
if (d.isTls() && !config->relocatable) {
@@ -152,8 +151,7 @@ static uint64_t getSymVA(const Symbol &sym, int64_t &addend) {
}
uint64_t Symbol::getVA(int64_t addend) const {
- uint64_t outVA = getSymVA(*this, addend);
- return outVA + addend;
+ return getSymVA(*this, addend) + addend;
}
uint64_t Symbol::getGotVA() const {
@@ -201,7 +199,7 @@ uint64_t Symbol::getSize() const {
OutputSection *Symbol::getOutputSection() const {
if (auto *s = dyn_cast<Defined>(this)) {
if (auto *sec = s->section)
- return sec->repl->getOutputSection();
+ return sec->getOutputSection();
return nullptr;
}
return nullptr;
@@ -215,7 +213,7 @@ void Symbol::parseSymbolVersion() {
return;
StringRef s = getName();
size_t pos = s.find('@');
- if (pos == 0 || pos == StringRef::npos)
+ if (pos == StringRef::npos)
return;
StringRef verstr = s.substr(pos + 1);
if (verstr.empty())
@@ -257,10 +255,12 @@ void Symbol::parseSymbolVersion() {
}
void Symbol::extract() const {
- if (auto *sym = dyn_cast<LazyArchive>(this))
+ if (auto *sym = dyn_cast<LazyArchive>(this)) {
cast<ArchiveFile>(sym->file)->extract(sym->sym);
- else
- cast<LazyObjFile>(this->file)->extract();
+ } else if (file->lazy) {
+ file->lazy = false;
+ parseFile(file);
+ }
}
MemoryBufferRef LazyArchive::getMemberBuffer() {
@@ -347,7 +347,7 @@ void elf::maybeWarnUnorderableSymbol(const Symbol *sym) {
report(": unable to order absolute symbol: ");
else if (d && isa<OutputSection>(d->section))
report(": unable to order synthetic symbol: ");
- else if (d && !d->section->repl->isLive())
+ else if (d && !d->section->isLive())
report(": unable to order discarded symbol: ");
}
@@ -550,7 +550,7 @@ void Symbol::resolveUndefined(const Undefined &other) {
}
// Undefined symbols in a SharedFile do not change the binding.
- if (dyn_cast_or_null<SharedFile>(other.file))
+ if (isa_and_nonnull<SharedFile>(other.file))
return;
if (isUndefined() || isShared()) {
@@ -562,22 +562,6 @@ void Symbol::resolveUndefined(const Undefined &other) {
}
}
-// Using .symver foo,foo@@VER unfortunately creates two symbols: foo and
-// foo@@VER. We want to effectively ignore foo, so give precedence to
-// foo@@VER.
-// FIXME: If users can transition to using
-// .symver foo,foo@@@VER
-// we can delete this hack.
-static int compareVersion(StringRef a, StringRef b) {
- bool x = a.contains("@@");
- bool y = b.contains("@@");
- if (!x && y)
- return 1;
- if (x && !y)
- return -1;
- return 0;
-}
-
// Compare two symbols. Return 1 if the new symbol should win, -1 if
// the new symbol should lose, or 0 if there is a conflict.
int Symbol::compare(const Symbol *other) const {
@@ -586,8 +570,16 @@ int Symbol::compare(const Symbol *other) const {
if (!isDefined() && !isCommon())
return 1;
- if (int cmp = compareVersion(getName(), other->getName()))
- return cmp;
+ // .symver foo,foo@@VER unfortunately creates two defined symbols: foo and
+ // foo@@VER. In GNU ld, if foo and foo@@VER are in the same file, foo is
+ // ignored. In our implementation, when this is foo, this->getName() may still
+ // contain @@, return 1 in this case as well.
+ if (file == other->file) {
+ if (other->getName().contains("@@"))
+ return 1;
+ if (getName().contains("@@"))
+ return -1;
+ }
if (other->isWeak())
return -1;
@@ -616,7 +608,7 @@ int Symbol::compare(const Symbol *other) const {
auto *oldSym = cast<Defined>(this);
auto *newSym = cast<Defined>(other);
- if (dyn_cast_or_null<BitcodeFile>(other->file))
+ if (isa_and_nonnull<BitcodeFile>(other->file))
return 0;
if (!oldSym->section && !newSym->section && oldSym->value == newSym->value &&
@@ -720,8 +712,7 @@ template <class LazyT> void Symbol::resolveLazy(const LazyT &other) {
return;
}
} else if (auto *loSym = dyn_cast<LazyObject>(&other)) {
- LazyObjFile *obj = cast<LazyObjFile>(loSym->file);
- if (obj->shouldExtractForCommon(loSym->getName())) {
+ if (loSym->file->shouldExtractForCommon(loSym->getName())) {
replaceCommon(*this, other);
return;
}
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index cc48ef0ab3b7..27c36eedce80 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -16,6 +16,7 @@
#include "InputFiles.h"
#include "InputSection.h"
#include "lld/Common/LLVM.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Object/Archive.h"
@@ -85,7 +86,7 @@ public:
uint32_t globalDynIndex = -1;
// This field is a index to the symbol's version definition.
- uint32_t verdefIndex = -1;
+ uint16_t verdefIndex = -1;
// Version definition index.
uint16_t versionId;
@@ -245,16 +246,14 @@ protected:
type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3),
isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind),
exportDynamic(isExportDynamic(k, visibility)), inDynamicList(false),
- canInline(false), referenced(false), traced(false), needsPltAddr(false),
- isInIplt(false), gotInIgot(false), isPreemptible(false),
- used(!config->gcSections), needsTocRestore(false),
- scriptDefined(false) {}
+ canInline(false), referenced(false), traced(false), isInIplt(false),
+ gotInIgot(false), isPreemptible(false), used(!config->gcSections),
+ folded(false), needsTocRestore(false), scriptDefined(false),
+ needsCopy(false), needsGot(false), needsPlt(false), needsTlsDesc(false),
+ needsTlsGd(false), needsTlsGdToIe(false), needsTlsLd(false),
+ needsGotDtprel(false), needsTlsIe(false), hasDirectReloc(false) {}
public:
- // True the symbol should point to its PLT entry.
- // For SharedSymbol only.
- uint8_t needsPltAddr : 1;
-
// True if this symbol is in the Iplt sub-section of the Plt and the Igot
// sub-section of the .got.plt or .got.
uint8_t isInIplt : 1;
@@ -272,6 +271,9 @@ public:
// which are referenced by relocations when -r or --emit-relocs is given.
uint8_t used : 1;
+ // True if defined relative to a section discarded by ICF.
+ uint8_t folded : 1;
+
// True if a call to this symbol needs to be followed by a restore of the
// PPC64 toc pointer.
uint8_t needsTocRestore : 1;
@@ -279,6 +281,22 @@ public:
// True if this symbol is defined by a linker script.
uint8_t scriptDefined : 1;
+ // True if this symbol needs a canonical PLT entry, or (during
+ // postScanRelocations) a copy relocation.
+ uint8_t needsCopy : 1;
+
+ // Temporary flags used to communicate which symbol entries need PLT and GOT
+ // entries during postScanRelocations();
+ uint8_t needsGot : 1;
+ uint8_t needsPlt : 1;
+ uint8_t needsTlsDesc : 1;
+ uint8_t needsTlsGd : 1;
+ uint8_t needsTlsGdToIe : 1;
+ uint8_t needsTlsLd : 1;
+ uint8_t needsGotDtprel : 1;
+ uint8_t needsTlsIe : 1;
+ uint8_t hasDirectReloc : 1;
+
// The partition whose dynamic symbol table contains this symbol's definition.
uint8_t partition = 1;
@@ -358,7 +376,7 @@ public:
SharedSymbol(InputFile &file, StringRef name, uint8_t binding,
uint8_t stOther, uint8_t type, uint64_t value, uint64_t size,
- uint32_t alignment, uint32_t verdefIndex)
+ uint32_t alignment, uint16_t verdefIndex)
: Symbol(SharedKind, &file, name, binding, stOther, type), value(value),
size(size), alignment(alignment) {
this->verdefIndex = verdefIndex;
@@ -423,7 +441,9 @@ class LazyObject : public Symbol {
public:
LazyObject(InputFile &file, StringRef name)
: Symbol(LazyObjectKind, &file, name, llvm::ELF::STB_GLOBAL,
- llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE) {}
+ llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE) {
+ isUsedInRegularObj = false;
+ }
static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; }
};
@@ -559,17 +579,18 @@ void Symbol::replace(const Symbol &newSym) {
scriptDefined = old.scriptDefined;
partition = old.partition;
- // Symbol length is computed lazily. If we already know a symbol length,
- // propagate it.
- if (nameData == old.nameData && nameSize == 0 && old.nameSize != 0)
- nameSize = old.nameSize;
-
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
if (traced)
printTraceSymbol(this);
}
+template <typename... T> Defined *makeDefined(T &&...args) {
+ return new (reinterpret_cast<Defined *>(
+ getSpecificAllocSingleton<SymbolUnion>().Allocate()))
+ Defined(std::forward<T>(args)...);
+}
+
void maybeWarnUnorderableSymbol(const Symbol *sym);
bool computeIsPreemptible(const Symbol &sym);
void reportBackrefs();
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 4078f7e01674..e480118f5ae9 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -264,8 +264,8 @@ InputSection *elf::createInterpSection() {
Defined *elf::addSyntheticLocal(StringRef name, uint8_t type, uint64_t value,
uint64_t size, InputSectionBase &section) {
- auto *s = make<Defined>(section.file, name, STB_LOCAL, STV_DEFAULT, type,
- value, size, &section);
+ Defined *s = makeDefined(section.file, name, STB_LOCAL, STV_DEFAULT, type,
+ value, size, &section);
if (in.symTab)
in.symTab->addSymbol(s);
return s;
@@ -391,7 +391,7 @@ Defined *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 (d->section && d->section->partition == partition)
+ if (!d->folded && d->section && d->section->partition == partition)
return d;
return nullptr;
}
@@ -763,18 +763,18 @@ size_t MipsGotSection::FileGot::getIndexedEntriesNum() const {
}
MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &f) {
- if (!f.mipsGotIndex.hasValue()) {
+ if (f.mipsGotIndex == uint32_t(-1)) {
gots.emplace_back();
gots.back().file = &f;
f.mipsGotIndex = gots.size() - 1;
}
- return gots[*f.mipsGotIndex];
+ return gots[f.mipsGotIndex];
}
uint64_t MipsGotSection::getPageEntryOffset(const InputFile *f,
const Symbol &sym,
int64_t addend) const {
- const FileGot &g = gots[*f->mipsGotIndex];
+ const FileGot &g = gots[f->mipsGotIndex];
uint64_t index = 0;
if (const OutputSection *outSec = sym.getOutputSection()) {
uint64_t secAddr = getMipsPageAddr(outSec->addr);
@@ -788,7 +788,7 @@ uint64_t MipsGotSection::getPageEntryOffset(const InputFile *f,
uint64_t MipsGotSection::getSymEntryOffset(const InputFile *f, const Symbol &s,
int64_t addend) const {
- const FileGot &g = gots[*f->mipsGotIndex];
+ const FileGot &g = gots[f->mipsGotIndex];
Symbol *sym = const_cast<Symbol *>(&s);
if (sym->isTls())
return g.tls.lookup(sym) * config->wordsize;
@@ -798,13 +798,13 @@ uint64_t MipsGotSection::getSymEntryOffset(const InputFile *f, const Symbol &s,
}
uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *f) const {
- const FileGot &g = gots[*f->mipsGotIndex];
+ const FileGot &g = gots[f->mipsGotIndex];
return g.dynTlsSymbols.lookup(nullptr) * config->wordsize;
}
uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *f,
const Symbol &s) const {
- const FileGot &g = gots[*f->mipsGotIndex];
+ const FileGot &g = gots[f->mipsGotIndex];
Symbol *sym = const_cast<Symbol *>(&s);
return g.dynTlsSymbols.lookup(sym) * config->wordsize;
}
@@ -1007,14 +1007,14 @@ void MipsGotSection::build() {
// thread-locals that have been marked as local through a linker script)
if (!s->isPreemptible && !config->shared)
continue;
- mainPart->relaDyn->addSymbolReloc(target->tlsModuleIndexRel, this,
+ 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->addSymbolReloc(target->tlsOffsetRel, this, offset,
+ mainPart->relaDyn->addSymbolReloc(target->tlsOffsetRel, *this, offset,
*s);
}
}
@@ -1027,7 +1027,7 @@ 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->addSymbolReloc(target->relativeRel, this, offset,
+ mainPart->relaDyn->addSymbolReloc(target->relativeRel, *this, offset,
*p.first);
}
if (!config->isPic)
@@ -1061,10 +1061,9 @@ uint64_t MipsGotSection::getGp(const InputFile *f) const {
// For files without related GOT or files refer a primary GOT
// returns "common" _gp value. For secondary GOTs calculate
// individual _gp values.
- if (!f || !f->mipsGotIndex.hasValue() || *f->mipsGotIndex == 0)
+ if (!f || f->mipsGotIndex == uint32_t(-1) || f->mipsGotIndex == 0)
return ElfSym::mipsGp->getVA(0);
- return getVA() + gots[*f->mipsGotIndex].startIndex * config->wordsize +
- 0x7ff0;
+ return getVA() + gots[f->mipsGotIndex].startIndex * config->wordsize + 0x7ff0;
}
void MipsGotSection::writeTo(uint8_t *buf) {
@@ -1298,8 +1297,8 @@ DynamicSection<ELFT>::computeContents() {
auto addInt = [&](int32_t tag, uint64_t val) {
entries.emplace_back(tag, val);
};
- auto addInSec = [&](int32_t tag, const InputSection *sec) {
- entries.emplace_back(tag, sec->getVA());
+ auto addInSec = [&](int32_t tag, const InputSection &sec) {
+ entries.emplace_back(tag, sec.getVA());
};
for (StringRef s : config->filterList)
@@ -1375,7 +1374,7 @@ DynamicSection<ELFT>::computeContents() {
if (part.relaDyn->isNeeded() ||
(in.relaIplt->isNeeded() &&
part.relaDyn->getParent() == in.relaIplt->getParent())) {
- addInSec(part.relaDyn->dynamicTag, part.relaDyn);
+ addInSec(part.relaDyn->dynamicTag, *part.relaDyn);
entries.emplace_back(part.relaDyn->sizeDynamicTag, addRelaSz(part.relaDyn));
bool isRela = config->isRela;
@@ -1393,7 +1392,7 @@ DynamicSection<ELFT>::computeContents() {
}
if (part.relrDyn && !part.relrDyn->relocs.empty()) {
addInSec(config->useAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
- part.relrDyn);
+ *part.relrDyn);
addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
part.relrDyn->getParent()->size);
addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
@@ -1406,14 +1405,14 @@ DynamicSection<ELFT>::computeContents() {
// case, so here we always use relaPlt as marker for the beginning of
// .rel[a].plt section.
if (isMain && (in.relaPlt->isNeeded() || in.relaIplt->isNeeded())) {
- addInSec(DT_JMPREL, in.relaPlt);
+ addInSec(DT_JMPREL, *in.relaPlt);
entries.emplace_back(DT_PLTRELSZ, addPltRelSz());
switch (config->emachine) {
case EM_MIPS:
- addInSec(DT_MIPS_PLTGOT, in.gotPlt);
+ addInSec(DT_MIPS_PLTGOT, *in.gotPlt);
break;
case EM_SPARCV9:
- addInSec(DT_PLTGOT, in.plt);
+ addInSec(DT_PLTGOT, *in.plt);
break;
case EM_AARCH64:
if (llvm::find_if(in.relaPlt->relocs, [](const DynamicReloc &r) {
@@ -1423,7 +1422,7 @@ DynamicSection<ELFT>::computeContents() {
addInt(DT_AARCH64_VARIANT_PCS, 0);
LLVM_FALLTHROUGH;
default:
- addInSec(DT_PLTGOT, in.gotPlt);
+ addInSec(DT_PLTGOT, *in.gotPlt);
break;
}
addInt(DT_PLTREL, config->isRela ? DT_RELA : DT_REL);
@@ -1436,16 +1435,16 @@ DynamicSection<ELFT>::computeContents() {
addInt(DT_AARCH64_PAC_PLT, 0);
}
- addInSec(DT_SYMTAB, part.dynSymTab);
+ addInSec(DT_SYMTAB, *part.dynSymTab);
addInt(DT_SYMENT, sizeof(Elf_Sym));
- addInSec(DT_STRTAB, part.dynStrTab);
+ addInSec(DT_STRTAB, *part.dynStrTab);
addInt(DT_STRSZ, part.dynStrTab->getSize());
if (!config->zText)
addInt(DT_TEXTREL, 0);
if (part.gnuHashTab)
- addInSec(DT_GNU_HASH, part.gnuHashTab);
+ addInSec(DT_GNU_HASH, *part.gnuHashTab);
if (part.hashTab)
- addInSec(DT_HASH, part.hashTab);
+ addInSec(DT_HASH, *part.hashTab);
if (isMain) {
if (Out::preinitArray) {
@@ -1470,13 +1469,13 @@ DynamicSection<ELFT>::computeContents() {
}
if (part.verSym && part.verSym->isNeeded())
- addInSec(DT_VERSYM, part.verSym);
+ addInSec(DT_VERSYM, *part.verSym);
if (part.verDef && part.verDef->isLive()) {
- addInSec(DT_VERDEF, part.verDef);
+ addInSec(DT_VERDEF, *part.verDef);
addInt(DT_VERDEFNUM, getVerDefNum());
}
if (part.verNeed && part.verNeed->isNeeded()) {
- addInSec(DT_VERNEED, part.verNeed);
+ addInSec(DT_VERNEED, *part.verNeed);
unsigned needNum = 0;
for (SharedFile *f : sharedFiles)
if (!f->vernauxs.empty())
@@ -1495,10 +1494,10 @@ DynamicSection<ELFT>::computeContents() {
addInt(DT_MIPS_GOTSYM, b->dynsymIndex);
else
addInt(DT_MIPS_GOTSYM, part.dynSymTab->getNumSymbols());
- addInSec(DT_PLTGOT, in.mipsGot);
+ addInSec(DT_PLTGOT, *in.mipsGot);
if (in.mipsRldMap) {
if (!config->pie)
- addInSec(DT_MIPS_RLD_MAP, in.mipsRldMap);
+ addInSec(DT_MIPS_RLD_MAP, *in.mipsRldMap);
// Store the offset to the .rld_map section
// relative to the address of the tag.
addInt(DT_MIPS_RLD_MAP_REL,
@@ -1509,7 +1508,7 @@ DynamicSection<ELFT>::computeContents() {
// DT_PPC_GOT indicates to glibc Secure PLT is used. If DT_PPC_GOT is absent,
// glibc assumes the old-style BSS PLT layout which we don't support.
if (config->emachine == EM_PPC)
- addInSec(DT_PPC_GOT, in.got);
+ addInSec(DT_PPC_GOT, *in.got);
// Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
if (config->emachine == EM_PPC64 && in.plt->isNeeded()) {
@@ -1574,7 +1573,7 @@ RelocationBaseSection::RelocationBaseSection(StringRef name, uint32_t type,
dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag) {}
void RelocationBaseSection::addSymbolReloc(RelType dynType,
- InputSectionBase *isec,
+ InputSectionBase &isec,
uint64_t offsetInSec, Symbol &sym,
int64_t addend,
Optional<RelType> addendRelType) {
@@ -1583,7 +1582,7 @@ void RelocationBaseSection::addSymbolReloc(RelType dynType,
}
void RelocationBaseSection::addRelativeReloc(
- RelType dynType, InputSectionBase *inputSec, uint64_t offsetInSec,
+ 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
@@ -1596,11 +1595,11 @@ void RelocationBaseSection::addRelativeReloc(
}
void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible(
- RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, Symbol &sym,
+ 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,
+ addReloc({dynType, &isec, offsetInSec, DynamicReloc::AgainstSymbol, sym, 0,
R_ABS});
else
addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec, offsetInSec,
@@ -1608,16 +1607,16 @@ void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible(
}
void RelocationBaseSection::addReloc(DynamicReloc::Kind kind, RelType dynType,
- InputSectionBase *inputSec,
+ InputSectionBase &inputSec,
uint64_t offsetInSec, Symbol &sym,
int64_t addend, RelExpr expr,
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(
+ inputSec.relocations.push_back(
{expr, addendRelType, offsetInSec, addend, &sym});
- addReloc({dynType, inputSec, offsetInSec, kind, sym, addend, expr});
+ addReloc({dynType, &inputSec, offsetInSec, kind, sym, addend, expr});
}
void RelocationBaseSection::addReloc(const DynamicReloc &reloc) {
@@ -1653,13 +1652,19 @@ RelrBaseSection::RelrBaseSection()
config->wordsize, ".relr.dyn") {}
template <class ELFT>
-static void encodeDynamicReloc(SymbolTableBaseSection *symTab,
- typename ELFT::Rela *p,
+static void encodeDynamicReloc(typename ELFT::Rela *p,
const DynamicReloc &rel) {
+ p->r_offset = rel.r_offset;
+ p->setSymbolAndType(rel.r_sym, rel.type, config->isMips64EL);
if (config->isRela)
- p->r_addend = rel.computeAddend();
- p->r_offset = rel.getOffset();
- p->setSymbolAndType(rel.getSymIndex(symTab), rel.type, config->isMips64EL);
+ p->r_addend = rel.addend;
+}
+
+void DynamicReloc::computeRaw(SymbolTableBaseSection *symtab) {
+ r_offset = getOffset();
+ r_sym = getSymIndex(symtab);
+ addend = computeAddend();
+ kind = AddendOnly; // Catch errors
}
template <class ELFT>
@@ -1674,20 +1679,21 @@ RelocationSection<ELFT>::RelocationSection(StringRef name, bool sort)
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *buf) {
SymbolTableBaseSection *symTab = getPartition().dynSymTab;
+ parallelForEach(relocs,
+ [symTab](DynamicReloc &rel) { rel.computeRaw(symTab); });
// Sort by (!IsRelative,SymIndex,r_offset). DT_REL[A]COUNT requires us to
// place R_*_RELATIVE first. SymIndex is to improve locality, while r_offset
// is to make results easier to read.
- if (sort)
- llvm::stable_sort(
- relocs, [&](const DynamicReloc &a, const DynamicReloc &b) {
- return std::make_tuple(a.type != target->relativeRel,
- a.getSymIndex(symTab), a.getOffset()) <
- std::make_tuple(b.type != target->relativeRel,
- b.getSymIndex(symTab), b.getOffset());
- });
+ if (sort) {
+ const RelType relativeRel = target->relativeRel;
+ parallelSort(relocs, [&](const DynamicReloc &a, const DynamicReloc &b) {
+ return std::make_tuple(a.type != relativeRel, a.r_sym, a.r_offset) <
+ std::make_tuple(b.type != relativeRel, b.r_sym, b.r_offset);
+ });
+ }
for (const DynamicReloc &rel : relocs) {
- encodeDynamicReloc<ELFT>(symTab, reinterpret_cast<Elf_Rela *>(buf), rel);
+ encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(buf), rel);
buf += config->isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
}
@@ -1765,7 +1771,11 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
for (const DynamicReloc &rel : relocs) {
Elf_Rela r;
- encodeDynamicReloc<ELFT>(getPartition().dynSymTab, &r, rel);
+ r.r_offset = rel.getOffset();
+ r.setSymbolAndType(rel.getSymIndex(getPartition().dynSymTab), rel.type,
+ false);
+ if (config->isRela)
+ r.r_addend = rel.computeAddend();
if (r.getType(config->isMips64EL) == target->relativeRel)
relatives.push_back(r);
@@ -2175,7 +2185,8 @@ static BssSection *getCommonSec(Symbol *sym) {
static uint32_t getSymSectionIndex(Symbol *sym) {
if (getCommonSec(sym))
return SHN_COMMON;
- if (!isa<Defined>(sym) || sym->needsPltAddr)
+ assert(!(sym->needsCopy && sym->isObject()));
+ if (!isa<Defined>(sym) || sym->needsCopy)
return SHN_UNDEF;
if (const OutputSection *os = sym->getOutputSection())
return os->sectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX
@@ -2250,7 +2261,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *buf) {
for (SymbolTableEntry &ent : symbols) {
Symbol *sym = ent.sym;
- if (sym->isInPlt() && sym->needsPltAddr)
+ if (sym->isInPlt() && sym->needsCopy)
eSym->st_other |= STO_MIPS_PLT;
if (isMicroMips()) {
// We already set the less-significant bit for symbols
@@ -2261,7 +2272,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *buf) {
// like `objdump` will be able to deal with a correct
// symbol position.
if (sym->isDefined() &&
- ((sym->stOther & STO_MIPS_MICROMIPS) || sym->needsPltAddr)) {
+ ((sym->stOther & STO_MIPS_MICROMIPS) || sym->needsCopy)) {
if (!strTabSec.isDynamic())
eSym->st_value &= ~1;
eSym->st_other |= STO_MIPS_MICROMIPS;
@@ -2426,10 +2437,10 @@ static uint32_t hashGnu(StringRef name) {
// Add symbols to this symbol hash table. Note that this function
// destructively sort a given vector -- which is needed because
// GNU-style hash table places some sorting requirements.
-void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &v) {
+void GnuHashTableSection::addSymbols(SmallVectorImpl<SymbolTableEntry> &v) {
// We cannot use 'auto' for Mid because GCC 6.1 cannot deduce
// its type correctly.
- std::vector<SymbolTableEntry>::iterator mid =
+ auto mid =
std::stable_partition(v.begin(), v.end(), [&](const SymbolTableEntry &s) {
return !s.sym->isDefined() || s.sym->partition != partition;
});
@@ -2715,16 +2726,17 @@ void GdbIndexSection::initOutputSize() {
}
}
-static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &dwarf) {
- std::vector<GdbIndexSection::CuEntry> ret;
+static SmallVector<GdbIndexSection::CuEntry, 0>
+readCuList(DWARFContext &dwarf) {
+ SmallVector<GdbIndexSection::CuEntry, 0> ret;
for (std::unique_ptr<DWARFUnit> &cu : dwarf.compile_units())
ret.push_back({cu->getOffset(), cu->getLength() + 4});
return ret;
}
-static std::vector<GdbIndexSection::AddressEntry>
+static SmallVector<GdbIndexSection::AddressEntry, 0>
readAddressAreas(DWARFContext &dwarf, InputSection *sec) {
- std::vector<GdbIndexSection::AddressEntry> ret;
+ SmallVector<GdbIndexSection::AddressEntry, 0> ret;
uint32_t cuIdx = 0;
for (std::unique_ptr<DWARFUnit> &cu : dwarf.compile_units()) {
@@ -2757,7 +2769,7 @@ readAddressAreas(DWARFContext &dwarf, InputSection *sec) {
template <class ELFT>
static std::vector<GdbIndexSection::NameAttrEntry>
readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj,
- const std::vector<GdbIndexSection::CuEntry> &cus) {
+ const SmallVectorImpl<GdbIndexSection::CuEntry> &cus) {
const LLDDWARFSection &pubNames = obj.getGnuPubnamesSection();
const LLDDWARFSection &pubTypes = obj.getGnuPubtypesSection();
@@ -3254,8 +3266,8 @@ void MergeTailSection::finalizeContents() {
}
void MergeNoTailSection::writeTo(uint8_t *buf) {
- for (size_t i = 0; i < numShards; ++i)
- shards[i].write(buf + shardOffsets[i]);
+ parallelForEachN(0, numShards,
+ [&](size_t i) { shards[i].write(buf + shardOffsets[i]); });
}
// This function is very hot (i.e. it can take several seconds to finish)
@@ -3312,15 +3324,6 @@ void MergeNoTailSection::finalizeContents() {
});
}
-MergeSyntheticSection *elf::createMergeSynthetic(StringRef name, uint32_t type,
- uint64_t flags,
- uint32_t alignment) {
- bool shouldTailMerge = (flags & SHF_STRINGS) && config->optimize >= 2;
- if (shouldTailMerge)
- return make<MergeTailSection>(name, type, flags, alignment);
- return make<MergeNoTailSection>(name, type, flags, alignment);
-}
-
template <class ELFT> void elf::splitSections() {
llvm::TimeTraceScope timeScope("Split sections");
// splitIntoPieces needs to be called on each MergeInputSection
@@ -3617,14 +3620,12 @@ void PPC32Got2Section::finalizeContents() {
// .got2 . This function computes outSecOff of each .got2 to be used in
// PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is
// to collect input sections named ".got2".
- uint32_t offset = 0;
for (SectionCommand *cmd : getParent()->commands)
if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
for (InputSection *isec : isd->sections) {
- if (isec == this)
- continue;
- isec->file->ppc32Got2OutSecOff = offset;
- offset += (uint32_t)isec->getSize();
+ // isec->file may be nullptr for MergeSyntheticSection.
+ if (isec != this && isec->file)
+ isec->file->ppc32Got2 = isec;
}
}
}
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 3d2e73071d09..c35e19cf2fb4 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -61,7 +61,7 @@ public:
struct CieRecord {
EhSectionPiece *cie = nullptr;
- std::vector<EhSectionPiece *> fdes;
+ SmallVector<EhSectionPiece *, 0> fdes;
};
// Section for .eh_frame.
@@ -79,7 +79,7 @@ public:
void addSection(EhInputSection *sec);
- std::vector<EhInputSection *> sections;
+ SmallVector<EhInputSection *, 0> sections;
size_t numFdes = 0;
struct FdeData {
@@ -115,7 +115,7 @@ private:
uint64_t getFdePc(uint8_t *buf, size_t off, uint8_t enc) const;
- std::vector<CieRecord *> cieRecords;
+ SmallVector<CieRecord *, 0> cieRecords;
// CIE records are uniquified by their contents and personality functions.
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, Symbol *>, CieRecord *> cieMap;
@@ -387,7 +387,7 @@ public:
bool hasGotPltOffRel = false;
private:
- std::vector<const Symbol *> entries;
+ SmallVector<const Symbol *, 0> entries;
};
// The IgotPltSection is a Got associated with the PltSection for GNU Ifunc
@@ -403,7 +403,7 @@ public:
bool isNeeded() const override { return !entries.empty(); }
private:
- std::vector<const Symbol *> entries;
+ SmallVector<const Symbol *, 0> entries;
};
class StringTableSection final : public SyntheticSection {
@@ -420,7 +420,7 @@ private:
uint64_t size = 0;
llvm::DenseMap<StringRef, unsigned> stringMap;
- std::vector<StringRef> strings;
+ SmallVector<StringRef, 0> strings;
};
class DynamicReloc {
@@ -449,21 +449,21 @@ public:
DynamicReloc(RelType type, const InputSectionBase *inputSec,
uint64_t offsetInSec, Kind kind, Symbol &sym, int64_t addend,
RelExpr expr)
- : type(type), sym(&sym), inputSec(inputSec), offsetInSec(offsetInSec),
- kind(kind), expr(expr), addend(addend) {}
+ : sym(&sym), inputSec(inputSec), offsetInSec(offsetInSec), type(type),
+ addend(addend), kind(kind), expr(expr) {}
/// This constructor records a relative relocation with no symbol.
DynamicReloc(RelType type, const InputSectionBase *inputSec,
uint64_t offsetInSec, int64_t addend = 0)
- : type(type), sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec),
- kind(AddendOnly), expr(R_ADDEND), addend(addend) {}
+ : sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec), type(type),
+ addend(addend), kind(AddendOnly), expr(R_ADDEND) {}
/// This constructor records dynamic relocation settings used by the MIPS
/// multi-GOT implementation.
DynamicReloc(RelType type, const InputSectionBase *inputSec,
uint64_t offsetInSec, const OutputSection *outputSec,
int64_t addend)
- : type(type), sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec),
- kind(MipsMultiGotPage), expr(R_ADDEND), addend(addend),
- outputSec(outputSec) {}
+ : sym(nullptr), outputSec(outputSec), inputSec(inputSec),
+ offsetInSec(offsetInSec), type(type), addend(addend),
+ kind(MipsMultiGotPage), expr(R_ADDEND) {}
uint64_t getOffset() const;
uint32_t getSymIndex(SymbolTableBaseSection *symTab) const;
@@ -476,18 +476,24 @@ public:
/// address/the address of the corresponding GOT entry/etc.
int64_t computeAddend() const;
- RelType type;
+ void computeRaw(SymbolTableBaseSection *symtab);
+
Symbol *sym;
+ const OutputSection *outputSec = nullptr;
const InputSectionBase *inputSec;
uint64_t offsetInSec;
+ uint64_t r_offset;
+ RelType type;
+ uint32_t r_sym;
+ // Initially input addend, then the output addend after
+ // RelocationSection<ELFT>::writeTo.
+ int64_t addend;
private:
Kind kind;
// The kind of expression used to calculate the added (required e.g. for
// relative GOT relocations).
RelExpr expr;
- int64_t addend;
- const OutputSection *outputSec = nullptr;
};
template <class ELFT> class DynamicSection final : public SyntheticSection {
@@ -513,22 +519,22 @@ public:
/// using relocations on the input section (e.g. MipsGotSection::writeTo()).
void addReloc(const DynamicReloc &reloc);
/// Add a dynamic relocation against \p sym with an optional addend.
- void addSymbolReloc(RelType dynType, InputSectionBase *isec,
+ void addSymbolReloc(RelType dynType, InputSectionBase &isec,
uint64_t offsetInSec, Symbol &sym, int64_t addend = 0,
llvm::Optional<RelType> addendRelType = llvm::None);
/// Add a relative dynamic relocation that uses the target address of \p sym
/// (i.e. InputSection::getRelocTargetVA()) + \p addend as the addend.
- void addRelativeReloc(RelType dynType, InputSectionBase *isec,
+ void addRelativeReloc(RelType dynType, InputSectionBase &isec,
uint64_t offsetInSec, Symbol &sym, int64_t addend,
RelType addendRelType, RelExpr expr);
/// Add a dynamic relocation using the target address of \p sym as the addend
/// if \p sym is non-preemptible. Otherwise add a relocation against \p sym.
void addAddendOnlyRelocIfNonPreemptible(RelType dynType,
- InputSectionBase *isec,
+ InputSectionBase &isec,
uint64_t offsetInSec, Symbol &sym,
RelType addendRelType);
void addReloc(DynamicReloc::Kind kind, RelType dynType,
- InputSectionBase *inputSec, uint64_t offsetInSec, Symbol &sym,
+ InputSectionBase &inputSec, uint64_t offsetInSec, Symbol &sym,
int64_t addend, RelExpr expr, RelType addendRelType);
bool isNeeded() const override { return !relocs.empty(); }
size_t getSize() const override { return relocs.size() * this->entsize; }
@@ -540,7 +546,7 @@ public:
d->type == llvm::ELF::SHT_RELR);
}
int32_t dynamicTag, sizeDynamicTag;
- std::vector<DynamicReloc> relocs;
+ SmallVector<DynamicReloc, 0> relocs;
protected:
size_t numRelativeRelocs = 0;
@@ -588,7 +594,7 @@ class RelrBaseSection : public SyntheticSection {
public:
RelrBaseSection();
bool isNeeded() const override { return !relocs.empty(); }
- std::vector<RelativeReloc> relocs;
+ SmallVector<RelativeReloc, 0> relocs;
};
// RelrSection is used to encode offsets for relative relocations.
@@ -608,7 +614,7 @@ public:
}
private:
- std::vector<Elf_Relr> relrRelocs;
+ SmallVector<Elf_Relr, 0> relrRelocs;
};
struct SymbolTableEntry {
@@ -630,7 +636,7 @@ protected:
void sortSymTabSymbols();
// A vector of symbols and their string table offsets.
- std::vector<SymbolTableEntry> symbols;
+ SmallVector<SymbolTableEntry, 0> symbols;
StringTableSection &strTabSec;
@@ -669,7 +675,7 @@ public:
// Adds symbols to the hash table.
// Sorts the input to satisfy GNU hash section requirements.
- void addSymbols(std::vector<SymbolTableEntry> &symbols);
+ void addSymbols(llvm::SmallVectorImpl<SymbolTableEntry> &symbols);
private:
// See the comment in writeBloomFilter.
@@ -682,7 +688,7 @@ private:
uint32_t bucketIdx;
};
- std::vector<Entry> symbols;
+ SmallVector<Entry, 0> symbols;
size_t maskWords;
size_t nBuckets = 0;
size_t size = 0;
@@ -722,7 +728,7 @@ public:
size_t headerSize;
- std::vector<const Symbol *> entries;
+ SmallVector<const Symbol *, 0> entries;
};
// Used for non-preemptible ifuncs. It does not have a header. Each entry is
@@ -730,7 +736,7 @@ public:
// runtime. PltSection can only contain entries associated with JUMP_SLOT
// relocations, so IPLT entries are in a separate section.
class IpltSection final : public SyntheticSection {
- std::vector<const Symbol *> entries;
+ SmallVector<const Symbol *, 0> entries;
public:
IpltSection();
@@ -747,7 +753,7 @@ public:
void writeTo(uint8_t *buf) override;
size_t getSize() const override;
- std::vector<const Symbol *> canonical_plts;
+ SmallVector<const Symbol *, 0> canonical_plts;
static constexpr size_t footerSize = 64;
};
@@ -780,13 +786,13 @@ public:
struct GdbChunk {
InputSection *sec;
- std::vector<AddressEntry> addressAreas;
- std::vector<CuEntry> compilationUnits;
+ SmallVector<AddressEntry, 0> addressAreas;
+ SmallVector<CuEntry, 0> compilationUnits;
};
struct GdbSymbol {
llvm::CachedHashStringRef name;
- std::vector<uint32_t> cuVector;
+ SmallVector<uint32_t, 0> cuVector;
uint32_t nameOff;
uint32_t cuVectorOff;
};
@@ -859,7 +865,7 @@ private:
StringRef getFileDefName();
unsigned fileDefNameOff;
- std::vector<unsigned> verDefNameOffs;
+ SmallVector<unsigned, 0> verDefNameOffs;
};
// The .gnu.version section specifies the required version of each symbol in the
@@ -898,7 +904,7 @@ class VersionNeedSection final : public SyntheticSection {
std::vector<Vernaux> vernauxs;
};
- std::vector<Verneed> verneeds;
+ SmallVector<Verneed, 0> verneeds;
public:
VersionNeedSection();
@@ -915,7 +921,7 @@ public:
class MergeSyntheticSection : public SyntheticSection {
public:
void addSection(MergeInputSection *ms);
- std::vector<MergeInputSection *> sections;
+ SmallVector<MergeInputSection *, 0> sections;
protected:
MergeSyntheticSection(StringRef name, uint32_t type, uint64_t flags,
@@ -962,7 +968,7 @@ private:
// String table contents
constexpr static size_t numShards = 32;
- std::vector<llvm::StringTableBuilder> shards;
+ SmallVector<llvm::StringTableBuilder, 0> shards;
size_t shardOffsets[numShards];
};
@@ -1120,7 +1126,7 @@ public:
bool roundUpSizeForErrata = false;
private:
- std::vector<Thunk *> thunks;
+ SmallVector<Thunk *, 0> thunks;
size_t size = 0;
};
@@ -1151,7 +1157,7 @@ public:
void finalizeContents() override { finalized = true; }
private:
- std::vector<std::pair<const Symbol *, int64_t>> entries;
+ SmallVector<std::pair<const Symbol *, int64_t>, 0> entries;
llvm::DenseMap<std::pair<const Symbol *, int64_t>, uint32_t> entry_index;
bool finalized = false;
};
@@ -1182,8 +1188,6 @@ public:
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
-MergeSyntheticSection *createMergeSynthetic(StringRef name, uint32_t type,
- uint64_t flags, uint32_t alignment);
template <class ELFT> void splitSections();
template <typename ELFT> void writeEhdr(uint8_t *buf, Partition &part);
diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index ffbc8d94a800..38de4db191f4 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -384,7 +384,7 @@ public:
if (Optional<uint32_t> index =
in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
mainPart->relaDyn->addRelativeReloc(
- target->relativeRel, in.ppc64LongBranchTarget, *index * UINT64_C(8),
+ target->relativeRel, *in.ppc64LongBranchTarget, *index * UINT64_C(8),
dest, addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther),
target->symbolicRel, R_ABS);
}
@@ -806,8 +806,9 @@ void elf::writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
// The stub loads an address relative to r30 (.got2+Addend). Addend is
// almost always 0x8000. The address of .got2 is different in another object
// file, so a stub cannot be shared.
- offset = gotPltVA - (in.ppc32Got2->getParent()->getVA() +
- file->ppc32Got2OutSecOff + addend);
+ offset = gotPltVA -
+ (in.ppc32Got2->getParent()->getVA() +
+ (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + addend);
} else {
// The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
// currently the address of .got).
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 07c5e2303374..497e56886b72 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -297,7 +297,7 @@ template <class ELFT> void elf::createSyntheticSections() {
}
}
- auto add = [](SyntheticSection *sec) { inputSections.push_back(sec); };
+ auto add = [](SyntheticSection &sec) { inputSections.push_back(&sec); };
in.shStrTab = make<StringTableSection>(".shstrtab", false);
@@ -311,7 +311,7 @@ template <class ELFT> void elf::createSyntheticSections() {
}
in.bss = make<BssSection>(".bss", 0, 1);
- add(in.bss);
+ add(*in.bss);
// If there is a SECTIONS command and a .data.rel.ro section name use name
// .data.rel.ro.bss so that we match in the .data.rel.ro output section.
@@ -320,42 +320,42 @@ template <class ELFT> void elf::createSyntheticSections() {
script->hasSectionsCommand && findSection(".data.rel.ro", 0);
in.bssRelRo =
make<BssSection>(hasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
- add(in.bssRelRo);
+ add(*in.bssRelRo);
// Add MIPS-specific sections.
if (config->emachine == EM_MIPS) {
if (!config->shared && config->hasDynSymTab) {
in.mipsRldMap = make<MipsRldMapSection>();
- add(in.mipsRldMap);
+ add(*in.mipsRldMap);
}
if (auto *sec = MipsAbiFlagsSection<ELFT>::create())
- add(sec);
+ add(*sec);
if (auto *sec = MipsOptionsSection<ELFT>::create())
- add(sec);
+ add(*sec);
if (auto *sec = MipsReginfoSection<ELFT>::create())
- add(sec);
+ add(*sec);
}
StringRef relaDynName = config->isRela ? ".rela.dyn" : ".rel.dyn";
for (Partition &part : partitions) {
- auto add = [&](SyntheticSection *sec) {
- sec->partition = part.getNumber();
- inputSections.push_back(sec);
+ auto add = [&](SyntheticSection &sec) {
+ sec.partition = part.getNumber();
+ inputSections.push_back(&sec);
};
if (!part.name.empty()) {
part.elfHeader = make<PartitionElfHeaderSection<ELFT>>();
part.elfHeader->name = part.name;
- add(part.elfHeader);
+ add(*part.elfHeader);
part.programHeaders = make<PartitionProgramHeadersSection<ELFT>>();
- add(part.programHeaders);
+ add(*part.programHeaders);
}
if (config->buildId != BuildIdKind::None) {
part.buildId = make<BuildIdSection>();
- add(part.buildId);
+ add(*part.buildId);
}
part.dynStrTab = make<StringTableSection>(".dynstr", true);
@@ -368,53 +368,53 @@ template <class ELFT> void elf::createSyntheticSections() {
make<RelocationSection<ELFT>>(relaDynName, config->zCombreloc);
if (config->hasDynSymTab) {
- add(part.dynSymTab);
+ add(*part.dynSymTab);
part.verSym = make<VersionTableSection>();
- add(part.verSym);
+ add(*part.verSym);
if (!namedVersionDefs().empty()) {
part.verDef = make<VersionDefinitionSection>();
- add(part.verDef);
+ add(*part.verDef);
}
part.verNeed = make<VersionNeedSection<ELFT>>();
- add(part.verNeed);
+ add(*part.verNeed);
if (config->gnuHash) {
part.gnuHashTab = make<GnuHashTableSection>();
- add(part.gnuHashTab);
+ add(*part.gnuHashTab);
}
if (config->sysvHash) {
part.hashTab = make<HashTableSection>();
- add(part.hashTab);
+ add(*part.hashTab);
}
- add(part.dynamic);
- add(part.dynStrTab);
- add(part.relaDyn);
+ add(*part.dynamic);
+ add(*part.dynStrTab);
+ add(*part.relaDyn);
}
if (config->relrPackDynRelocs) {
part.relrDyn = make<RelrSection<ELFT>>();
- add(part.relrDyn);
+ add(*part.relrDyn);
}
if (!config->relocatable) {
if (config->ehFrameHdr) {
part.ehFrameHdr = make<EhFrameHeader>();
- add(part.ehFrameHdr);
+ add(*part.ehFrameHdr);
}
part.ehFrame = make<EhFrameSection>();
- add(part.ehFrame);
+ add(*part.ehFrame);
}
if (config->emachine == EM_ARM && !config->relocatable) {
// The ARMExidxsyntheticsection replaces all the individual .ARM.exidx
// InputSections.
part.armExidx = make<ARMExidxSyntheticSection>();
- add(part.armExidx);
+ add(*part.armExidx);
}
}
@@ -424,39 +424,39 @@ template <class ELFT> void elf::createSyntheticSections() {
// special handling (see createPhdrs() and combineEhSections()).
in.partEnd = make<BssSection>(".part.end", config->maxPageSize, 1);
in.partEnd->partition = 255;
- add(in.partEnd);
+ add(*in.partEnd);
in.partIndex = make<PartitionIndexSection>();
addOptionalRegular("__part_index_begin", in.partIndex, 0);
addOptionalRegular("__part_index_end", in.partIndex,
in.partIndex->getSize());
- add(in.partIndex);
+ add(*in.partIndex);
}
// Add .got. MIPS' .got is so different from the other archs,
// it has its own class.
if (config->emachine == EM_MIPS) {
in.mipsGot = make<MipsGotSection>();
- add(in.mipsGot);
+ add(*in.mipsGot);
} else {
in.got = make<GotSection>();
- add(in.got);
+ add(*in.got);
}
if (config->emachine == EM_PPC) {
in.ppc32Got2 = make<PPC32Got2Section>();
- add(in.ppc32Got2);
+ add(*in.ppc32Got2);
}
if (config->emachine == EM_PPC64) {
in.ppc64LongBranchTarget = make<PPC64LongBranchTargetSection>();
- add(in.ppc64LongBranchTarget);
+ add(*in.ppc64LongBranchTarget);
}
in.gotPlt = make<GotPltSection>();
- add(in.gotPlt);
+ add(*in.gotPlt);
in.igotPlt = make<IgotPltSection>();
- add(in.igotPlt);
+ add(*in.igotPlt);
// _GLOBAL_OFFSET_TABLE_ is defined relative to either .got.plt or .got. Treat
// it as a relocation and ensure the referenced section is created.
@@ -468,13 +468,13 @@ template <class ELFT> void elf::createSyntheticSections() {
}
if (config->gdbIndex)
- add(GdbIndexSection::create<ELFT>());
+ add(*GdbIndexSection::create<ELFT>());
// We always need to add rel[a].plt to output if it has entries.
// Even for static linking it can contain R_[*]_IRELATIVE relocations.
in.relaPlt = make<RelocationSection<ELFT>>(
config->isRela ? ".rela.plt" : ".rel.plt", /*sort=*/false);
- add(in.relaPlt);
+ add(*in.relaPlt);
// The relaIplt immediately follows .rel[a].dyn to ensure that the IRelative
// relocations are processed last by the dynamic loader. We cannot place the
@@ -485,22 +485,22 @@ template <class ELFT> void elf::createSyntheticSections() {
in.relaIplt = make<RelocationSection<ELFT>>(
config->androidPackDynRelocs ? in.relaPlt->name : relaDynName,
/*sort=*/false);
- add(in.relaIplt);
+ add(*in.relaIplt);
if ((config->emachine == EM_386 || config->emachine == EM_X86_64) &&
(config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
in.ibtPlt = make<IBTPltSection>();
- add(in.ibtPlt);
+ add(*in.ibtPlt);
}
in.plt = config->emachine == EM_PPC ? make<PPC32GlinkSection>()
: make<PltSection>();
- add(in.plt);
+ add(*in.plt);
in.iplt = make<IpltSection>();
- add(in.iplt);
+ add(*in.iplt);
if (config->andFeatures)
- add(make<GnuPropertySection>());
+ add(*make<GnuPropertySection>());
// .note.GNU-stack is always added when we are creating a re-linkable
// object file. Other linkers are using the presence of this marker
@@ -508,15 +508,15 @@ template <class ELFT> void elf::createSyntheticSections() {
// is irrelevant these days. Stack area should always be non-executable
// by default. So we emit this section unconditionally.
if (config->relocatable)
- add(make<GnuStackSection>());
+ add(*make<GnuStackSection>());
if (in.symTab)
- add(in.symTab);
+ add(*in.symTab);
if (in.symTabShndx)
- add(in.symTabShndx);
- add(in.shStrTab);
+ add(*in.symTabShndx);
+ add(*in.shStrTab);
if (in.strTab)
- add(in.strTab);
+ add(*in.strTab);
}
// The main function of the writer.
@@ -622,7 +622,7 @@ template <class ELFT> static void markUsedLocalSymbols() {
return;
// Without --gc-sections, the field is initialized with "true".
// Drop the flag first and then rise for symbols referenced in relocations.
- for (InputFile *file : objectFiles) {
+ for (ELFFileBase *file : objectFiles) {
ObjFile<ELFT> *f = cast<ObjFile<ELFT>>(file);
for (Symbol *b : f->getLocalSymbols())
b->used = false;
@@ -674,15 +674,11 @@ static bool shouldKeepInSymtab(const Defined &sym) {
}
static bool includeInSymtab(const Symbol &b) {
- if (!b.isLocal() && !b.isUsedInRegularObj)
- return false;
-
if (auto *d = dyn_cast<Defined>(&b)) {
// Always include absolute symbols.
SectionBase *sec = d->section;
if (!sec)
return true;
- sec = sec->repl;
// Exclude symbols pointing to garbage-collected sections.
if (isa<InputSectionBase>(sec) && !sec->isLive())
@@ -704,20 +700,16 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
llvm::TimeTraceScope timeScope("Add local symbols");
if (config->copyRelocs && config->discard != DiscardPolicy::None)
markUsedLocalSymbols<ELFT>();
- for (InputFile *file : objectFiles) {
- ObjFile<ELFT> *f = cast<ObjFile<ELFT>>(file);
- for (Symbol *b : f->getLocalSymbols()) {
+ for (ELFFileBase *file : objectFiles) {
+ for (Symbol *b : file->getLocalSymbols()) {
assert(b->isLocal() && "should have been caught in initializeSymbols()");
auto *dr = dyn_cast<Defined>(b);
// No reason to keep local undefined symbol in symtab.
if (!dr)
continue;
- if (!includeInSymtab(*b))
- continue;
- if (!shouldKeepInSymtab(*dr))
- continue;
- in.symTab->addSymbol(b);
+ if (includeInSymtab(*b) && shouldKeepInSymtab(*dr))
+ in.symTab->addSymbol(b);
}
}
}
@@ -753,10 +745,9 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
// 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->getOutputSection());
- in.symTab->addSymbol(sym);
+ in.symTab->addSymbol(
+ makeDefined(isec->file, "", STB_LOCAL, /*stOther=*/0, STT_SECTION,
+ /*value=*/0, /*size=*/0, isec->getOutputSection()));
}
}
@@ -1242,7 +1233,7 @@ static void maybeShuffle(DenseMap<const InputSectionBase *, int> &order) {
if (config->shuffleSections.empty())
return;
- std::vector<InputSectionBase *> matched, sections = inputSections;
+ SmallVector<InputSectionBase *, 0> matched, sections = inputSections;
matched.reserve(sections.size());
for (const auto &patAndSeed : config->shuffleSections) {
matched.clear();
@@ -1310,7 +1301,7 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
if (auto *d = dyn_cast<Defined>(&sym)) {
if (auto *sec = dyn_cast_or_null<InputSectionBase>(d->section)) {
- int &priority = sectionOrder[cast<InputSectionBase>(sec->repl)];
+ int &priority = sectionOrder[cast<InputSectionBase>(sec)];
priority = std::min(priority, ent.priority);
}
}
@@ -1322,7 +1313,7 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
if (!sym->isLazy())
addSym(*sym);
- for (InputFile *file : objectFiles)
+ for (ELFFileBase *file : objectFiles)
for (Symbol *sym : file->getSymbols()) {
if (!sym->isLocal())
break;
@@ -1477,13 +1468,6 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
if (!os)
continue;
os->sortRank = getSectionRank(os);
-
- // We want to assign rude approximation values to outSecOff fields
- // to know the relative order of the input sections. We use it for
- // sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder().
- uint64_t i = 0;
- for (InputSection *sec : getInputSections(os))
- sec->outSecOff = i++;
}
if (!script->hasSectionsCommand) {
@@ -1740,7 +1724,7 @@ static void fixSymbolsAfterShrinking() {
if (!sec)
return;
- const InputSectionBase *inputSec = dyn_cast<InputSectionBase>(sec->repl);
+ const InputSectionBase *inputSec = dyn_cast<InputSectionBase>(sec);
if (!inputSec || !inputSec->bytesDropped)
return;
@@ -1947,6 +1931,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (!config->relocatable) {
forEachRelSec(scanRelocations<ELFT>);
reportUndefinedSymbols<ELFT>();
+ postScanRelocations();
}
}
@@ -1986,7 +1971,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// 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))
+ if (!sym->isUsedInRegularObj || !includeInSymtab(*sym))
continue;
if (in.symTab)
in.symTab->addSymbol(sym);
@@ -2894,6 +2879,8 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
// Write section contents to a mmap'ed file.
template <class ELFT> void Writer<ELFT>::writeSections() {
+ llvm::TimeTraceScope timeScope("Write sections");
+
// In -r or --emit-relocs mode, write the relocation sections first as in
// ELf_Rel targets we might find out that we need to modify the relocated
// section while doing it.