diff options
Diffstat (limited to 'lld/ELF')
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 §ion) { - auto *s = make<Defined>(section.file, name, STB_LOCAL, STV_DEFAULT, type, - value, size, §ion); + Defined *s = makeDefined(section.file, name, STB_LOCAL, STV_DEFAULT, type, + value, size, §ion); 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. |