diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2219,6 +2219,25 @@ return ret; } +static void 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(""); + } +} + static void postParseObjectFile(ELFFileBase *file) { switch (config->ekind) { case ELF32LEKind: @@ -2357,6 +2376,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(); }); @@ -2428,6 +2448,7 @@ // compileBitcodeFiles may have produced lto.tmp object files. After this, no // more file will be added. auto newObjectFiles = makeArrayRef(objectFiles).slice(numObjsBeforeLTO); + parallelForEach(newObjectFiles, initializeLocalSymbols); parallelForEach(newObjectFiles, postParseObjectFile); // Handle --exclude-libs again because lto.tmp may reference additional diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -10,6 +10,7 @@ #define LLD_ELF_INPUT_FILES_H #include "Config.h" +#include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" #include "lld/Common/Reproduce.h" @@ -273,6 +274,7 @@ // Get cached DWARF information. DWARFCache *getDwarf(); + void initializeLocalSymbols(); void postParse(); private: @@ -302,6 +304,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 diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1021,41 +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); - symbols[i]->isUsedInRegularObj = true; - } // Some entries have been filled by LazyObjFile. for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) @@ -1149,6 +1114,45 @@ } } +template void ObjFile::initializeLocalSymbols() { + if (!firstGlobal) + return; + localSymStorage = std::make_unique(firstGlobal); + SymbolUnion *locals = localSymStorage.get(); + + 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); + symbols[i]->isUsedInRegularObj = true; + } +} + // 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;