diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2363,6 +2363,7 @@ // No more lazy bitcode can be extracted at this point. Do post parse work // like checking duplicate symbols. + parallelForEach(objectFiles, initializeLocalSymbols); parallelForEach(objectFiles, postParseObjectFile); parallelForEach(bitcodeFiles, [](BitcodeFile *file) { file->postParse(); }); @@ -2433,8 +2434,9 @@ // compileBitcodeFiles may have produced lto.tmp object files. No more file is // added at this point. - parallelForEach(makeArrayRef(objectFiles).slice(numObjsBeforeLTO), - postParseObjectFile); + auto newObjectFiles = makeArrayRef(objectFiles).slice(numObjsBeforeLTO); + parallelForEach(newObjectFiles, initializeLocalSymbols); + parallelForEach(newObjectFiles, postParseObjectFile); // Handle --exclude-libs again because lto.tmp may reference additional // libcalls symbols defined in an excluded archive. This may override diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -273,6 +273,7 @@ // Get cached DWARF information. DWARFCache *getDwarf(); + void initializeLocalSymbols(); void postParse(); private: @@ -302,6 +303,9 @@ // If the section does not exist (which is common), the array is empty. ArrayRef shndxTable; + // Storage for local symbols. + std::unique_ptr localSymStorage; + // Debugging information to retrieve source file and line for error // reporting. Linker may find reasonable number of errors in a // single object file, so we cache debugging information in order to @@ -377,6 +381,8 @@ std::string replaceThinLTOSuffix(StringRef path); +void initializeLocalSymbols(ELFFileBase *file); + extern SmallVector> memoryBuffers; extern SmallVector binaryFiles; extern SmallVector bitcodeFiles; diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1021,40 +1021,6 @@ ArrayRef eSyms = this->getELFSyms(); symbols.resize(eSyms.size()); - SymbolUnion *locals = - firstGlobal == 0 - ? nullptr - : getSpecificAllocSingleton().Allocate(firstGlobal); - - for (size_t i = 0, end = firstGlobal; i != end; ++i) { - const Elf_Sym &eSym = eSyms[i]; - uint32_t secIdx = eSym.st_shndx; - if (LLVM_UNLIKELY(secIdx == SHN_XINDEX)) - secIdx = check(getExtendedSymbolTableIndex(eSym, i, shndxTable)); - else if (secIdx >= SHN_LORESERVE) - secIdx = 0; - if (LLVM_UNLIKELY(secIdx >= sections.size())) - fatal(toString(this) + ": invalid section index: " + Twine(secIdx)); - if (LLVM_UNLIKELY(eSym.getBinding() != STB_LOCAL)) - error(toString(this) + ": non-local symbol (" + Twine(i) + - ") found at index < .symtab's sh_info (" + Twine(end) + ")"); - - InputSectionBase *sec = sections[secIdx]; - uint8_t type = eSym.getType(); - if (type == STT_FILE) - sourceFile = CHECK(eSym.getName(stringTable), this); - if (LLVM_UNLIKELY(stringTable.size() <= eSym.st_name)) - fatal(toString(this) + ": invalid symbol name offset"); - StringRef name(stringTable.data() + eSym.st_name); - - symbols[i] = reinterpret_cast(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 - new (symbols[i]) Defined(this, name, STB_LOCAL, eSym.st_other, type, - eSym.st_value, eSym.st_size, sec); - } // Some entries have been filled by LazyObjFile. for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) @@ -1149,6 +1115,67 @@ } } +template void ObjFile::initializeLocalSymbols() { + if (!firstGlobal) + return; + localSymStorage = std::make_unique( + sizeof(SymbolUnion) * firstGlobal + alignof(SymbolUnion) - 1); + SymbolUnion *locals = reinterpret_cast( + reinterpret_cast(localSymStorage.get() + alignof(SymbolUnion) - + 1) & + -alignof(SymbolUnion)); + + ArrayRef eSyms = this->getELFSyms(); + for (size_t i = 0, end = firstGlobal; i != end; ++i) { + const Elf_Sym &eSym = eSyms[i]; + uint32_t secIdx = eSym.st_shndx; + if (LLVM_UNLIKELY(secIdx == SHN_XINDEX)) + secIdx = check(getExtendedSymbolTableIndex(eSym, i, shndxTable)); + else if (secIdx >= SHN_LORESERVE) + secIdx = 0; + if (LLVM_UNLIKELY(secIdx >= sections.size())) + fatal(toString(this) + ": invalid section index: " + Twine(secIdx)); + if (LLVM_UNLIKELY(eSym.getBinding() != STB_LOCAL)) + error(toString(this) + ": non-local symbol (" + Twine(i) + + ") found at index < .symtab's sh_info (" + Twine(end) + ")"); + + InputSectionBase *sec = sections[secIdx]; + uint8_t type = eSym.getType(); + if (type == STT_FILE) + sourceFile = CHECK(eSym.getName(stringTable), this); + if (LLVM_UNLIKELY(stringTable.size() <= eSym.st_name)) + fatal(toString(this) + ": invalid symbol name offset"); + StringRef name(stringTable.data() + eSym.st_name); + + symbols[i] = reinterpret_cast(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 + new (symbols[i]) Defined(this, name, STB_LOCAL, eSym.st_other, type, + eSym.st_value, eSym.st_size, sec); + } +} + +void elf::initializeLocalSymbols(ELFFileBase *file) { + switch (config->ekind) { + case ELF32LEKind: + cast>(file)->initializeLocalSymbols(); + break; + case ELF32BEKind: + cast>(file)->initializeLocalSymbols(); + break; + case ELF64LEKind: + cast>(file)->initializeLocalSymbols(); + break; + case ELF64BEKind: + cast>(file)->initializeLocalSymbols(); + break; + default: + llvm_unreachable(""); + } +} + // Called after all ObjFile::parse is called for all ObjFiles. This checks // duplicate symbols and may do symbol property merge in the future. template void ObjFile::postParse() { diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -297,9 +297,10 @@ if (!file->archiveName.empty()) archive = (" in archive " + file->archiveName).str(); - // Find a symbol that encloses a given location. + // Find a symbol that encloses a given location. getObjMsg may be called + // before ObjFile::initializeLocalSymbols where local symbols are initialized. for (Symbol *b : file->getSymbols()) - if (auto *d = dyn_cast(b)) + if (auto *d = dyn_cast_or_null(b)) if (d->section == this && d->value <= off && off < d->value + d->size) return filename + ":(" + toString(*d) + ")" + archive;