Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -119,6 +119,12 @@ this->Header.sh_size = Relocs.size() * this->Header.sh_entsize; } void writeTo(uint8_t *Buf) override { + DynSymSec.prepareGlobalSymbols(); + for (const SymbolTableEntryInfo &Entry : DynSymSec.getGlobalSymbols()) { + assert(!Entry.Body->getDynamicSymbolTableIndex()); + assert(Entry.SymbolTableIndex > 0); + Entry.Body->setDynamicSymbolTableIndex(Entry.SymbolTableIndex); + } auto *P = reinterpret_cast(Buf); bool IsMips64EL = Relocs[0].C.getFile()->getObj()->isMips64EL(); for (const DynamicReloc &Rel : Relocs) { @@ -223,6 +229,14 @@ template class Writer; +struct SymbolTableEntryInfo { + explicit SymbolTableEntryInfo(SymbolBody *Body) : Body(Body) {} + + SymbolBody *Body; + unsigned StringTableNameOffset = 0; + unsigned SymbolTableIndex = 0; +}; + template class SymbolTableSection final : public OutputSectionBase { public: @@ -253,21 +267,37 @@ const SymbolTable &getSymTable() const { return Table; } - void addSymbol(StringRef Name, bool isLocal = false) { - StrTabSec.add(Name); - ++NumVisible; - if (isLocal) - ++NumLocals; + const std::vector &getGlobalSymbols() const { + return GlobalSymbols; } + void addLocalSymbol(StringRef Name) { + assert(!GlobalSymbolsPrepared); + StrTabSec.add(Name); + ++NumLocals; + } + + void addGlobalSymbol(SymbolBody *Body) { + assert(!GlobalSymbolsPrepared); + StrTabSec.add(Body->getName()); + GlobalSymbols.emplace_back(Body); + } + + // Ensure that StringTableNameOffset and SymbolTableIndex fields + // for all global symbols are filled + void prepareGlobalSymbols(); + StringTableSection &getStrTabSec() { return StrTabSec; } - unsigned getNumSymbols() const { return NumVisible + 1; } + unsigned getNumSymbols() const { + return GlobalSymbols.size() + NumLocals + 1; + } private: SymbolTable &Table; StringTableSection &StrTabSec; - unsigned NumVisible = 0; + std::vector GlobalSymbols; unsigned NumLocals = 0; + bool GlobalSymbolsPrepared = false; const Writer &W; }; @@ -283,17 +313,13 @@ this->Header.sh_addralign = sizeof(Elf_Word); } - void addSymbol(SymbolBody *S) { - StringRef Name = S->getName(); - DynSymSec.addSymbol(Name); - Hashes.push_back(hash(Name)); - S->setDynamicSymbolTableIndex(Hashes.size()); - } + void addSymbol(SymbolBody *S) { DynSymSec.addGlobalSymbol(S); } void finalize() override { this->Header.sh_link = DynSymSec.getSectionIndex(); - assert(DynSymSec.getNumSymbols() == Hashes.size() + 1); + assert(DynSymSec.getNumSymbols() == + DynSymSec.getGlobalSymbols().size() + 1); unsigned NumEntries = 2; // nbucket and nchain. NumEntries += DynSymSec.getNumSymbols(); // The chain entries. @@ -305,6 +331,7 @@ } void writeTo(uint8_t *Buf) override { + DynSymSec.prepareGlobalSymbols(); unsigned NumSymbols = DynSymSec.getNumSymbols(); auto *P = reinterpret_cast(Buf); *P++ = NumSymbols; // nbucket @@ -313,11 +340,15 @@ Elf_Word *Buckets = P; Elf_Word *Chains = P + NumSymbols; - for (unsigned I = 1; I < NumSymbols; ++I) { - uint32_t Hash = Hashes[I - 1] % NumSymbols; + unsigned I = 1; + for (const auto &Entry : DynSymSec.getGlobalSymbols()) { + assert(Entry.SymbolTableIndex == I); + uint32_t Hash = hash(Entry.Body->getName()) % NumSymbols; Chains[I] = Buckets[Hash]; Buckets[Hash] = I; + ++I; } + assert(I == NumSymbols); } SymbolTableSection &getDynSymSec() { return DynSymSec; } @@ -335,7 +366,6 @@ return H; } SymbolTableSection &DynSymSec; - std::vector Hashes; }; template @@ -658,11 +688,10 @@ memcpy(Buf, Data.data(), Data.size()); } -template -static int compareSym(const typename ELFFile::Elf_Sym *A, - const typename ELFFile::Elf_Sym *B) { - uint32_t AN = A->st_name; - uint32_t BN = B->st_name; +static int compareSym(const SymbolTableEntryInfo *A, + const SymbolTableEntryInfo *B) { + uint32_t AN = A->StringTableNameOffset; + uint32_t BN = B->StringTableNameOffset; assert(AN != BN); return AN - BN; } @@ -678,6 +707,23 @@ return true; } +// The order the global symbols are in is not defined. We can use an arbitrary +// order, but it has to be reproducible. That is true even when cross linking. +// The default hashing of StringRef produces different results on 32 and 64 +// bit systems so we sort by st_name. That is arbitrary but deterministic. +// FIXME: Experiment with passing in a custom hashing instead. +template void SymbolTableSection::prepareGlobalSymbols() { + if (GlobalSymbolsPrepared) + return; + for (SymbolTableEntryInfo &Entry : GlobalSymbols) + Entry.StringTableNameOffset = StrTabSec.getFileOff(Entry.Body->getName()); + array_pod_sort(GlobalSymbols.begin(), GlobalSymbols.end(), compareSym); + unsigned I = NumLocals; + for (SymbolTableEntryInfo &Entry : GlobalSymbols) + Entry.SymbolTableIndex = ++I; + GlobalSymbolsPrepared = true; +} + template void SymbolTableSection::writeTo(uint8_t *Buf) { Buf += sizeof(Elf_Sym); @@ -699,18 +745,13 @@ } } - uint8_t *GlobalStart = Buf; - - for (auto &P : Table.getSymbols()) { - StringRef Name = P.first; - Symbol *Sym = P.second; - SymbolBody *Body = Sym->Body; - if (!includeInSymtab(*Body)) - continue; + prepareGlobalSymbols(); + for (const SymbolTableEntryInfo &Entry : GlobalSymbols) { + SymbolBody *Body = Entry.Body; const Elf_Sym &InputSym = cast>(Body)->Sym; auto *ESym = reinterpret_cast(Buf); - ESym->st_name = StrTabSec.getFileOff(Name); + ESym->st_name = Entry.StringTableNameOffset; const SectionChunk *Section = nullptr; const OutputSection *Out = nullptr; @@ -755,14 +796,6 @@ Buf += sizeof(Elf_Sym); } - - // The order the global symbols are in is not defined. We can use an arbitrary - // order, but it has to be reproducible. That is true even when cross linking. - // The default hashing of StringRef produces different results on 32 and 64 - // bit systems so we sort by st_name. That is arbitrary but deterministic. - // FIXME: Experiment with passing in a custom hashing instead. - auto *Syms = reinterpret_cast(GlobalStart); - array_pod_sort(Syms, Syms + NumVisible - NumLocals, compareSym); } template @@ -894,7 +927,8 @@ CommonSymbols.push_back(C); if (!includeInSymtab(*Body)) continue; - SymTabSec.addSymbol(Name); + assert(Name == Body->getName()); + SymTabSec.addGlobalSymbol(Body); // FIXME: This adds way too much to the dynamic symbol table. We only // need to add the symbols use by dynamic relocations when producing @@ -910,7 +944,7 @@ for (const Elf_Sym &Sym : Syms) { ErrorOr SymName = Sym.getName(File.getStringTable()); if (SymName) - SymTabSec.addSymbol(*SymName, true); + SymTabSec.addLocalSymbol(*SymName); } } for (SectionChunk *C : File.getChunks()) {