diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2385,19 +2385,20 @@ return ret; } -static void initializeLocalSymbols(ELFFileBase *file) { +static void initSectionsAndLocalSyms(ELFFileBase *file, + bool ignoreComdats = false) { switch (config->ekind) { case ELF32LEKind: - cast>(file)->initializeLocalSymbols(); + cast>(file)->initSectionsAndLocalSyms(ignoreComdats); break; case ELF32BEKind: - cast>(file)->initializeLocalSymbols(); + cast>(file)->initSectionsAndLocalSyms(ignoreComdats); break; case ELF64LEKind: - cast>(file)->initializeLocalSymbols(); + cast>(file)->initSectionsAndLocalSyms(ignoreComdats); break; case ELF64BEKind: - cast>(file)->initializeLocalSymbols(); + cast>(file)->initSectionsAndLocalSyms(ignoreComdats); break; default: llvm_unreachable(""); @@ -2548,7 +2549,9 @@ // No more lazy bitcode can be extracted at this point. Do post parse work // like checking duplicate symbols. - parallelForEach(ctx->objectFiles, initializeLocalSymbols); + parallelForEach(ctx->objectFiles, [](ELFFileBase *file) { + initSectionsAndLocalSyms(file, /*ignoreComdats=*/false); + }); parallelForEach(ctx->objectFiles, postParseObjectFile); parallelForEach(ctx->bitcodeFiles, [](BitcodeFile *file) { file->postParse(); }); @@ -2632,7 +2635,9 @@ // compileBitcodeFiles may have produced lto.tmp object files. After this, no // more file will be added. auto newObjectFiles = makeArrayRef(ctx->objectFiles).slice(numObjsBeforeLTO); - parallelForEach(newObjectFiles, initializeLocalSymbols); + parallelForEach(newObjectFiles, [](ELFFileBase *file) { + initSectionsAndLocalSyms(file, /*ignoreComdats=*/true); + }); parallelForEach(newObjectFiles, postParseObjectFile); for (const DuplicateSymbol &d : ctx->duplicates) reportDuplicate(*d.sym, d.file, d.section, d.value); diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -274,7 +274,7 @@ // Get cached DWARF information. DWARFCache *getDwarf(); - void initializeLocalSymbols(); + void initSectionsAndLocalSyms(bool ignoreComdats); void postParse(); private: diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -430,10 +430,70 @@ template void ObjFile::parse(bool ignoreComdats) { object::ELFFile obj = this->getObj(); // Read a section table. justSymbols is usually false. - if (this->justSymbols) + if (this->justSymbols) { initializeJustSymbols(); - else - initializeSections(ignoreComdats, obj); + initializeSymbols(obj); + return; + } + + ArrayRef objSections = getELFShdrs(); + StringRef shstrtab = CHECK(obj.getSectionStringTable(objSections), this); + uint64_t size = objSections.size(); + sections.resize(size); + for (size_t i = 0; i != size; ++i) { + const Elf_Shdr &sec = objSections[i]; + if (sec.sh_type == SHT_LLVM_DEPENDENT_LIBRARIES && !config->relocatable) { + StringRef name = check(obj.getSectionName(sec, shstrtab)); + ArrayRef data = CHECK( + this->getObj().template getSectionContentsAsArray(sec), this); + if (!data.empty() && data.back() != '\0') { + error( + toString(this) + + ": corrupted dependent libraries section (unterminated string): " + + name); + } else { + for (const char *d = data.begin(), *e = data.end(); d < e;) { + StringRef s(d); + addDependentLibrary(s, this); + d += s.size() + 1; + } + } + this->sections[i] = &InputSection::discarded; + continue; + } + + if (sec.sh_type != SHT_GROUP) + continue; + StringRef signature = getShtGroupSignature(objSections, sec); + ArrayRef entries = + CHECK(obj.template getSectionContentsAsArray(sec), this); + if (entries.empty()) + fatal(toString(this) + ": empty SHT_GROUP"); + + Elf_Word flag = entries[0]; + if (flag && flag != GRP_COMDAT) + fatal(toString(this) + ": unsupported SHT_GROUP format"); + + // sections[i] = &InputSection::discarded; + bool keepGroup = + (flag & GRP_COMDAT) == 0 || ignoreComdats || + symtab->comdatGroups.try_emplace(CachedHashStringRef(signature), this) + .second; + if (keepGroup) { + if (config->relocatable) + this->sections[i] = createInputSection( + i, sec, check(obj.getSectionName(sec, shstrtab))); + continue; + } + + // Otherwise, discard group members. + for (uint32_t secIndex : entries.slice(1)) { + if (secIndex >= size) + fatal(toString(this) + + ": invalid section index in group: " + Twine(secIndex)); + this->sections[secIndex] = &InputSection::discarded; + } + } // Read a symbol table. initializeSymbols(obj); @@ -515,10 +575,7 @@ ArrayRef objSections = getELFShdrs(); StringRef shstrtab = CHECK(obj.getSectionStringTable(objSections), this); uint64_t size = objSections.size(); - this->sections.resize(size); - - std::vector> selectedGroups; - + SmallVector, 0> selectedGroups; for (size_t i = 0; i != size; ++i) { if (this->sections[i] == &InputSection::discarded) continue; @@ -550,44 +607,22 @@ } switch (sec.sh_type) { + case SHT_SYMTAB_SHNDX: + shndxTable = CHECK(obj.getSHNDXTable(sec, objSections), this); + break; case SHT_GROUP: { - // De-duplicate section groups by their signatures. - StringRef signature = getShtGroupSignature(objSections, sec); - this->sections[i] = &InputSection::discarded; - + if (!config->relocatable) + sections[i] = &InputSection::discarded; + StringRef signature = + cantFail(this->getELFSyms()[sec.sh_info].getName(stringTable)); ArrayRef entries = - CHECK(obj.template getSectionContentsAsArray(sec), this); - if (entries.empty()) - fatal(toString(this) + ": empty SHT_GROUP"); - - Elf_Word flag = entries[0]; - if (flag && flag != GRP_COMDAT) - fatal(toString(this) + ": unsupported SHT_GROUP format"); - - bool keepGroup = - (flag & GRP_COMDAT) == 0 || ignoreComdats || - symtab->comdatGroups.try_emplace(CachedHashStringRef(signature), this) - .second; - if (keepGroup) { - if (config->relocatable) - this->sections[i] = createInputSection( - i, sec, check(obj.getSectionName(sec, shstrtab))); + cantFail(obj.template getSectionContentsAsArray(sec)); + if ((entries[0] & GRP_COMDAT) == 0 || ignoreComdats || + symtab->comdatGroups.find(CachedHashStringRef(signature))->second == + this) selectedGroups.push_back(entries); - continue; - } - - // Otherwise, discard group members. - for (uint32_t secIndex : entries.slice(1)) { - if (secIndex >= size) - fatal(toString(this) + - ": invalid section index in group: " + Twine(secIndex)); - this->sections[secIndex] = &InputSection::discarded; - } break; } - case SHT_SYMTAB_SHNDX: - shndxTable = CHECK(obj.getSHNDXTable(sec, objSections), this); - break; case SHT_SYMTAB: case SHT_STRTAB: case SHT_REL: @@ -603,6 +638,9 @@ } } + for (ArrayRef entries : selectedGroups) + handleSectionGroup(this->sections, entries); + // We have a second loop. It is used to: // 1) handle SHF_LINK_ORDER sections. // 2) create SHT_REL[A] sections. In some cases the section header index of a @@ -632,8 +670,8 @@ // simply handle such sections as non-mergeable ones. Degrading like this // is acceptable because section merging is optional. if (auto *ms = dyn_cast(s)) { - s = make(ms->file, ms->flags, ms->type, ms->alignment, - ms->data(), ms->name); + s = makeTL(ms->file, ms->flags, ms->type, ms->alignment, + ms->data(), ms->name); sections[info] = s; } @@ -648,7 +686,7 @@ // specified, we need to copy them to the output. (Some post link analysis // tools specify --emit-relocs to obtain the information.) if (config->copyRelocs) { - auto *isec = make( + auto *isec = makeTL( *this, sec, check(obj.getSectionName(sec, shstrtab))); // If the relocated section is discarded (due to /DISCARD/ or // --gc-sections), the relocation section should be discarded as well. @@ -678,9 +716,6 @@ " with SHF_LINK_ORDER should not refer a non-regular section: " + toString(linkSec)); } - - for (ArrayRef entries : selectedGroups) - handleSectionGroup(this->sections, entries); } // For ARM only, to set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD @@ -911,23 +946,6 @@ } } - if (sec.sh_type == SHT_LLVM_DEPENDENT_LIBRARIES && !config->relocatable) { - ArrayRef data = - CHECK(this->getObj().template getSectionContentsAsArray(sec), this); - if (!data.empty() && data.back() != '\0') { - error(toString(this) + - ": corrupted dependent libraries section (unterminated string): " + - name); - return &InputSection::discarded; - } - for (const char *d = data.begin(), *e = data.end(); d < e;) { - StringRef s(d); - addDependentLibrary(s, this); - d += s.size() + 1; - } - 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 @@ -993,11 +1011,11 @@ // .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(*this, sec, name); + return makeTL(*this, sec, name); if ((sec.sh_flags & SHF_MERGE) && shouldMerge(sec, name)) - return make(*this, sec, name); - return make(*this, sec, name); + return makeTL(*this, sec, name); + return makeTL(*this, sec, name); } // Initialize this->Symbols. this->Symbols is a parallel array as @@ -1063,7 +1081,12 @@ } } -template void ObjFile::initializeLocalSymbols() { +template +void ObjFile::initSectionsAndLocalSyms(bool ignoreComdats) { + object::ELFFile obj = this->getObj(); + if (!justSymbols) + initializeSections(ignoreComdats, obj); + if (!firstGlobal) return; localSymStorage = std::make_unique(firstGlobal); diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -282,7 +282,8 @@ archive = (" in archive " + file->archiveName).str(); // Find a symbol that encloses a given location. getObjMsg may be called - // before ObjFile::initializeLocalSymbols where local symbols are initialized. + // before ObjFile::initSectionsAndLocalSyms where local symbols are + // initialized. for (Symbol *b : file->getSymbols()) if (auto *d = dyn_cast_or_null(b)) if (d->section == this && d->value <= off && off < d->value + d->size) diff --git a/lld/include/lld/Common/Memory.h b/lld/include/lld/Common/Memory.h --- a/lld/include/lld/Common/Memory.h +++ b/lld/include/lld/Common/Memory.h @@ -62,6 +62,25 @@ T(std::forward(args)...); } +template +inline llvm::SpecificBumpPtrAllocator & +getSpecificAllocSingletonThreadLocal() { + thread_local SpecificAlloc instance; + return instance.alloc; +} + +// Create a new instance of T off a thread-local SpecificAlloc, used by code +// like parallel input section initialization. +// +// Note: Some ports (e.g. ELF) have lots of global states which are currently +// infeasible to remove, and context() just adds overhead with no benefit. The +// allocation performance is of higher importance, so we simply use thread_local +// allocators instead of doing context indirection and pthread_getspecific. +template T *makeTL(U &&...args) { + return new (getSpecificAllocSingletonThreadLocal().Allocate()) + T(std::forward(args)...); +} + } // namespace lld #endif