Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -176,16 +176,8 @@ void addSymbol(SymbolBody *Body); StringTableSection &getStrTabSec() const { return StrTabSec; } unsigned getNumSymbols() const { return NumVisible + 1; } - unsigned getNumGnuHashSymbols() const { return NumGnuHashed; } - struct SymbolData { - SymbolData(SymbolBody *Body, bool HasGnuHash); - SymbolBody *Body; - bool HasGnuHash; - uint32_t GnuHash; - }; - ArrayRef getSymbols() const { return Symbols; } - ArrayRef getGnuHashSymbols() const; + ArrayRef getSymbols() const { return Symbols; } private: void writeLocalSymbols(uint8_t *&Buf); @@ -195,10 +187,9 @@ SymbolTable &Table; StringTableSection &StrTabSec; - std::vector Symbols; + std::vector Symbols; unsigned NumVisible = 0; unsigned NumLocals = 0; - unsigned NumGnuHashed = 0; }; template @@ -304,16 +295,28 @@ GnuHashTableSection(); void finalize() override; void writeTo(uint8_t *Buf) override; - - static unsigned calcNBuckets(unsigned NumHashed); + void addSymbol() { ++NumHashed; } + // Updates the order of the dynamic symbol section symbols + // according to the GNU hash section requirements. + // Fills its own HashedSymbols as a side effect. + void sortSymbols(std::vector &Symbols); private: + static unsigned calcNBuckets(unsigned NumHashed); static unsigned calcMaskWords(unsigned NumHashed); void writeHeader(uint8_t *&Buf); void writeBloomFilter(uint8_t *&Buf); void writeHashTable(uint8_t *Buf); + struct HashedSymbolData { + SymbolBody *Body; + uint32_t Hash; + }; + + std::vector HashedSymbols; + + unsigned NumHashed = 0; unsigned MaskWords; unsigned NBuckets; unsigned Shift2; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -274,9 +274,7 @@ Elf_Word *Buckets = P; Elf_Word *Chains = P + NumSymbols; - for (const typename SymbolTableSection::SymbolData &Item : - Out::DynSymTab->getSymbols()) { - SymbolBody *Body = Item.Body; + for (SymbolBody *Body : Out::DynSymTab->getSymbols()) { StringRef Name = Body->getName(); unsigned I = Body->getDynamicSymbolTableIndex(); uint32_t Hash = hashSysv(Name) % NumSymbols; @@ -335,7 +333,6 @@ } template void GnuHashTableSection::finalize() { - const unsigned NumHashed = Out::DynSymTab->getNumGnuHashSymbols(); NBuckets = calcNBuckets(NumHashed); MaskWords = calcMaskWords(NumHashed); // Second hash shift estimation: just predefined values. @@ -349,6 +346,7 @@ } template void GnuHashTableSection::writeTo(uint8_t *Buf) { + assert(NumHashed == HashedSymbols.size() && "sortSymbols() was not called!"); writeHeader(Buf); if (!NBuckets) // There are no hashed symbols return; @@ -360,8 +358,7 @@ void GnuHashTableSection::writeHeader(uint8_t *&Buf) { auto *P = reinterpret_cast(Buf); *P++ = NBuckets; - *P++ = Out::DynSymTab->getNumSymbols() - - Out::DynSymTab->getNumGnuHashSymbols(); + *P++ = Out::DynSymTab->getNumSymbols() - NumHashed; *P++ = MaskWords; *P++ = Shift2; Buf = reinterpret_cast(P); @@ -372,11 +369,10 @@ unsigned C = sizeof(Elf_Off) * 8; auto *Masks = reinterpret_cast(Buf); - for (const typename SymbolTableSection::SymbolData &Item : - Out::DynSymTab->getGnuHashSymbols()) { - size_t Pos = (Item.GnuHash / C) & (MaskWords - 1); - uintX_t V = (uintX_t(1) << (Item.GnuHash % C)) | - (uintX_t(1) << ((Item.GnuHash >> Shift2) % C)); + for (const HashedSymbolData &Item : HashedSymbols) { + size_t Pos = (Item.Hash / C) & (MaskWords - 1); + uintX_t V = (uintX_t(1) << (Item.Hash % C)) | + (uintX_t(1) << ((Item.Hash >> Shift2) % C)); Masks[Pos] |= V; } Buf += sizeof(Elf_Off) * MaskWords; @@ -389,9 +385,8 @@ int PrevBucket = -1; int I = 0; - for (const typename SymbolTableSection::SymbolData &Item : - Out::DynSymTab->getGnuHashSymbols()) { - int Bucket = Item.GnuHash % NBuckets; + for (const HashedSymbolData &Item : HashedSymbols) { + int Bucket = Item.Hash % NBuckets; assert(PrevBucket <= Bucket); if (Bucket != PrevBucket) { Buckets[Bucket] = Item.Body->getDynamicSymbolTableIndex(); @@ -399,7 +394,7 @@ if (I > 0) Values[I - 1] |= 1; } - Values[I] = Item.GnuHash & ~1; + Values[I] = Item.Hash & ~1; ++I; } if (I > 0) @@ -407,6 +402,34 @@ } template +void GnuHashTableSection::sortSymbols( + std::vector &Symbols) { + if (!NumHashed) + return; + + std::vector NotHashed; + NotHashed.reserve(Symbols.size()); + HashedSymbols.reserve(Symbols.size()); + for (SymbolBody *B : Symbols) { + if (includeInGnuHashTable(*B)) + HashedSymbols.push_back(HashedSymbolData{B, hashGnu(B->getName())}); + else + NotHashed.push_back(B); + } + assert(NumHashed == HashedSymbols.size()); + + unsigned NBuckets = calcNBuckets(NumHashed); + std::stable_sort(HashedSymbols.begin(), HashedSymbols.end(), + [&](const HashedSymbolData &L, const HashedSymbolData &R) { + return L.Hash % NBuckets < R.Hash % NBuckets; + }); + + Symbols = std::move(NotHashed); + for (const HashedSymbolData &Item : HashedSymbols) + Symbols.push_back(Item.Body); +} + +template DynamicSection::DynamicSection(SymbolTable &SymTab) : OutputSectionBase(".dynamic", llvm::ELF::SHT_DYNAMIC, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE), @@ -852,12 +875,6 @@ } template -SymbolTableSection::SymbolData::SymbolData(SymbolBody *Body, - bool HasGnuHash) - : Body(Body), HasGnuHash(HasGnuHash), - GnuHash(HasGnuHash ? hashGnu(Body->getName()) : 0) {} - -template SymbolTableSection::SymbolTableSection( SymbolTable &Table, StringTableSection &StrTabSec) : OutputSectionBase( @@ -879,24 +896,17 @@ if (!StrTabSec.isDynamic()) { std::stable_sort(Symbols.begin(), Symbols.end(), - [](const SymbolData &L, const SymbolData &R) { - return getSymbolBinding(L.Body) == STB_LOCAL && - getSymbolBinding(R.Body) != STB_LOCAL; + [](SymbolBody *L, SymbolBody *R) { + return getSymbolBinding(L) == STB_LOCAL && + getSymbolBinding(R) != STB_LOCAL; }); return; } - if (NumGnuHashed) { - unsigned NBuckets = GnuHashTableSection::calcNBuckets(NumGnuHashed); - std::stable_sort(Symbols.begin(), Symbols.end(), - [NBuckets](const SymbolData &L, const SymbolData &R) { - if (!L.HasGnuHash || !R.HasGnuHash) - return R.HasGnuHash; - return L.GnuHash % NBuckets < R.GnuHash % NBuckets; - }); - } + if (Out::GnuHashTab) + Out::GnuHashTab->sortSymbols(Symbols); size_t I = 0; - for (const SymbolData &Item : Symbols) - Item.Body->setDynamicSymbolTableIndex(++I); + for (SymbolBody *B : Symbols) + B->setDynamicSymbolTableIndex(++I); } template @@ -909,12 +919,8 @@ template void SymbolTableSection::addSymbol(SymbolBody *Body) { StrTabSec.add(Body->getName()); - const bool HasGnuHash = StrTabSec.isDynamic() && Out::GnuHashTab && - includeInGnuHashTable(*Body); - Symbols.emplace_back(Body, HasGnuHash); + Symbols.push_back(Body); ++NumVisible; - if (HasGnuHash) - ++NumGnuHashed; } template void SymbolTableSection::writeTo(uint8_t *Buf) { @@ -968,8 +974,7 @@ // Write the internal symbol table contents to the output symbol table // pointed by Buf. auto *ESym = reinterpret_cast(Buf); - for (const SymbolData &Item : Symbols) { - SymbolBody *Body = Item.Body; + for (SymbolBody *Body : Symbols) { const OutputSectionBase *OutSec = nullptr; switch (Body->kind()) { @@ -1028,12 +1033,6 @@ return Body->isWeak() ? STB_WEAK : STB_GLOBAL; } -template -ArrayRef::SymbolData> -SymbolTableSection::getGnuHashSymbols() const { - return getSymbols().slice(Symbols.size() - NumGnuHashed); -} - namespace lld { namespace elf2 { template class OutputSectionBase; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -511,8 +511,11 @@ if (Out::SymTab) Out::SymTab->addSymbol(Body); - if (isOutputDynamic() && includeInDynamicSymtab(*Body)) + if (isOutputDynamic() && includeInDynamicSymtab(*Body)) { Out::DynSymTab->addSymbol(Body); + if (Out::GnuHashTab && includeInGnuHashTable(*Body)) + Out::GnuHashTab->addSymbol(); + } } addCommonSymbols(CommonSymbols);