diff options
| author | Eugene Leviant <eleviant@accesssoftek.com> | 2016-11-18 06:44:18 +0000 |
|---|---|---|
| committer | Eugene Leviant <eleviant@accesssoftek.com> | 2016-11-18 06:44:18 +0000 |
| commit | be809a7125c3214ab067d0861aa2fe848ac40b9d (patch) | |
| tree | 7f92a21a0e305da5a6efb5417f2102d49bc0351f | |
| parent | f9980200aa1da6df925b03b4f5cecb252dd57bdd (diff) | |
| download | bcm5719-llvm-be809a7125c3214ab067d0861aa2fe848ac40b9d.tar.gz bcm5719-llvm-be809a7125c3214ab067d0861aa2fe848ac40b9d.zip | |
[ELF] Convert GnuHashTableSection to input section
Differential revision: https://reviews.llvm.org/D26792
llvm-svn: 287322
| -rw-r--r-- | lld/ELF/OutputSections.cpp | 152 | ||||
| -rw-r--r-- | lld/ELF/OutputSections.h | 50 | ||||
| -rw-r--r-- | lld/ELF/SyntheticSections.cpp | 161 | ||||
| -rw-r--r-- | lld/ELF/SyntheticSections.h | 48 | ||||
| -rw-r--r-- | lld/ELF/Writer.cpp | 20 |
5 files changed, 212 insertions, 219 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index c98170dfc42..8270be0dc98 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -179,153 +179,6 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) { } } -static uint32_t hashGnu(StringRef Name) { - uint32_t H = 5381; - for (uint8_t C : Name) - H = (H << 5) + H + C; - return H; -} - -template <class ELFT> -GnuHashTableSection<ELFT>::GnuHashTableSection() - : OutputSectionBase(".gnu.hash", SHT_GNU_HASH, SHF_ALLOC) { - this->Entsize = ELFT::Is64Bits ? 0 : 4; - this->Addralign = sizeof(uintX_t); -} - -template <class ELFT> -unsigned GnuHashTableSection<ELFT>::calcNBuckets(unsigned NumHashed) { - if (!NumHashed) - return 0; - - // These values are prime numbers which are not greater than 2^(N-1) + 1. - // In result, for any particular NumHashed we return a prime number - // which is not greater than NumHashed. - static const unsigned Primes[] = { - 1, 1, 3, 3, 7, 13, 31, 61, 127, 251, - 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071}; - - return Primes[std::min<unsigned>(Log2_32_Ceil(NumHashed), - array_lengthof(Primes) - 1)]; -} - -// Bloom filter estimation: at least 8 bits for each hashed symbol. -// GNU Hash table requirement: it should be a power of 2, -// the minimum value is 1, even for an empty table. -// Expected results for a 32-bit target: -// calcMaskWords(0..4) = 1 -// calcMaskWords(5..8) = 2 -// calcMaskWords(9..16) = 4 -// For a 64-bit target: -// calcMaskWords(0..8) = 1 -// calcMaskWords(9..16) = 2 -// calcMaskWords(17..32) = 4 -template <class ELFT> -unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) { - if (!NumHashed) - return 1; - return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off)); -} - -template <class ELFT> void GnuHashTableSection<ELFT>::finalize() { - unsigned NumHashed = Symbols.size(); - NBuckets = calcNBuckets(NumHashed); - MaskWords = calcMaskWords(NumHashed); - // Second hash shift estimation: just predefined values. - Shift2 = ELFT::Is64Bits ? 6 : 5; - - this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex; - this->Size = sizeof(Elf_Word) * 4 // Header - + sizeof(Elf_Off) * MaskWords // Bloom Filter - + sizeof(Elf_Word) * NBuckets // Hash Buckets - + sizeof(Elf_Word) * NumHashed; // Hash Values -} - -template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) { - writeHeader(Buf); - if (Symbols.empty()) - return; - writeBloomFilter(Buf); - writeHashTable(Buf); -} - -template <class ELFT> -void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) { - auto *P = reinterpret_cast<Elf_Word *>(Buf); - *P++ = NBuckets; - *P++ = In<ELFT>::DynSymTab->getNumSymbols() - Symbols.size(); - *P++ = MaskWords; - *P++ = Shift2; - Buf = reinterpret_cast<uint8_t *>(P); -} - -template <class ELFT> -void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) { - unsigned C = sizeof(Elf_Off) * 8; - - auto *Masks = reinterpret_cast<Elf_Off *>(Buf); - for (const SymbolData &Sym : Symbols) { - size_t Pos = (Sym.Hash / C) & (MaskWords - 1); - uintX_t V = (uintX_t(1) << (Sym.Hash % C)) | - (uintX_t(1) << ((Sym.Hash >> Shift2) % C)); - Masks[Pos] |= V; - } - Buf += sizeof(Elf_Off) * MaskWords; -} - -template <class ELFT> -void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) { - Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf); - Elf_Word *Values = Buckets + NBuckets; - - int PrevBucket = -1; - int I = 0; - for (const SymbolData &Sym : Symbols) { - int Bucket = Sym.Hash % NBuckets; - assert(PrevBucket <= Bucket); - if (Bucket != PrevBucket) { - Buckets[Bucket] = Sym.Body->DynsymIndex; - PrevBucket = Bucket; - if (I > 0) - Values[I - 1] |= 1; - } - Values[I] = Sym.Hash & ~1; - ++I; - } - if (I > 0) - Values[I - 1] |= 1; -} - -// Add symbols to this symbol hash table. Note that this function -// destructively sort a given vector -- which is needed because -// GNU-style hash table places some sorting requirements. -template <class ELFT> -void GnuHashTableSection<ELFT>::addSymbols(std::vector<SymbolTableEntry> &V) { - // Ideally this will just be 'auto' but GCC 6.1 is not able - // to deduce it correctly. - std::vector<SymbolTableEntry>::iterator Mid = - std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { - return S.Symbol->isUndefined(); - }); - if (Mid == V.end()) - return; - for (auto I = Mid, E = V.end(); I != E; ++I) { - SymbolBody *B = I->Symbol; - size_t StrOff = I->StrTabOffset; - Symbols.push_back({B, StrOff, hashGnu(B->getName())}); - } - - unsigned NBuckets = calcNBuckets(Symbols.size()); - std::stable_sort(Symbols.begin(), Symbols.end(), - [&](const SymbolData &L, const SymbolData &R) { - return L.Hash % NBuckets < R.Hash % NBuckets; - }); - - V.erase(Mid, V.end()); - for (const SymbolData &Sym : Symbols) - V.push_back({Sym.Body, Sym.STName}); -} - // Returns the number of version definition entries. Because the first entry // is for the version definition itself, it is the number of versioned symbols // plus one. Note that we don't support multiple versions yet. @@ -1085,11 +938,6 @@ template class PltSection<ELF32BE>; template class PltSection<ELF64LE>; template class PltSection<ELF64BE>; -template class GnuHashTableSection<ELF32LE>; -template class GnuHashTableSection<ELF32BE>; -template class GnuHashTableSection<ELF64LE>; -template class GnuHashTableSection<ELF64BE>; - template class HashTableSection<ELF32LE>; template class HashTableSection<ELF32BE>; template class HashTableSection<ELF64LE>; diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index d842961bd17..bb51dcc92b6 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -44,7 +44,6 @@ public: Base, EHFrame, EHFrameHdr, - GnuHashTable, HashTable, Merge, Plt, @@ -150,11 +149,6 @@ private: std::vector<std::pair<const SymbolBody *, unsigned>> Entries; }; -struct SymbolTableEntry { - SymbolBody *Symbol; - size_t StrTabOffset; -}; - // For more information about .gnu.version and .gnu.version_r see: // https://www.akkadia.org/drepper/symbol-versioning @@ -336,48 +330,6 @@ public: } }; -// Outputs GNU Hash section. For detailed explanation see: -// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections -template <class ELFT> -class GnuHashTableSection final : public OutputSectionBase { - typedef typename ELFT::Off Elf_Off; - typedef typename ELFT::Word Elf_Word; - typedef typename ELFT::uint uintX_t; - -public: - GnuHashTableSection(); - void finalize() override; - void writeTo(uint8_t *Buf) override; - - // Adds symbols to the hash table. - // Sorts the input to satisfy GNU hash section requirements. - void addSymbols(std::vector<SymbolTableEntry> &Symbols); - Kind getKind() const override { return GnuHashTable; } - static bool classof(const OutputSectionBase *B) { - return B->getKind() == GnuHashTable; - } - -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 SymbolData { - SymbolBody *Body; - size_t STName; - uint32_t Hash; - }; - - std::vector<SymbolData> Symbols; - - unsigned MaskWords; - unsigned NBuckets; - unsigned Shift2; -}; - // --eh-frame-hdr option tells linker to construct a header for all the // .eh_frame sections. This header is placed to a section named .eh_frame_hdr // and also to a PT_GNU_EH_FRAME segment. @@ -420,7 +372,6 @@ template <class ELFT> struct Out { static EhFrameHeader<ELFT> *EhFrameHdr; static EhOutputSection<ELFT> *EhFrame; static GdbIndexSection<ELFT> *GdbIndex; - static GnuHashTableSection<ELFT> *GnuHashTab; static HashTableSection<ELFT> *HashTab; static OutputSection<ELFT> *Bss; static OutputSection<ELFT> *MipsRldMap; @@ -476,7 +427,6 @@ template <class ELFT> uint8_t Out<ELFT>::First; template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr; template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame; template <class ELFT> GdbIndexSection<ELFT> *Out<ELFT>::GdbIndex; -template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab; template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab; template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss; template <class ELFT> OutputSection<ELFT> *Out<ELFT>::MipsRldMap; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 413a76e51e9..b55c316e566 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -794,8 +794,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { add({DT_SYMENT, sizeof(Elf_Sym)}); add({DT_STRTAB, In<ELFT>::DynStrTab}); add({DT_STRSZ, In<ELFT>::DynStrTab->getSize()}); - if (Out<ELFT>::GnuHashTab) - add({DT_GNU_HASH, Out<ELFT>::GnuHashTab}); + if (In<ELFT>::GnuHashTab) + add({DT_GNU_HASH, In<ELFT>::GnuHashTab}); if (Out<ELFT>::HashTab) add({DT_HASH, Out<ELFT>::HashTab}); @@ -1021,9 +1021,9 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() { }); return; } - if (Out<ELFT>::GnuHashTab) + if (In<ELFT>::GnuHashTab) // NB: It also sorts Symbols to meet the GNU hash table requirements. - Out<ELFT>::GnuHashTab->addSymbols(Symbols); + In<ELFT>::GnuHashTab->addSymbols(Symbols); else if (Config->EMachine == EM_MIPS) std::stable_sort(Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &L, const SymbolTableEntry &R) { @@ -1142,6 +1142,154 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { return nullptr; } +template <class ELFT> +GnuHashTableSection<ELFT>::GnuHashTableSection() + : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_HASH, sizeof(uintX_t), + ".gnu.hash") { + this->Entsize = ELFT::Is64Bits ? 0 : 4; +} + +template <class ELFT> +unsigned GnuHashTableSection<ELFT>::calcNBuckets(unsigned NumHashed) { + if (!NumHashed) + return 0; + + // These values are prime numbers which are not greater than 2^(N-1) + 1. + // In result, for any particular NumHashed we return a prime number + // which is not greater than NumHashed. + static const unsigned Primes[] = { + 1, 1, 3, 3, 7, 13, 31, 61, 127, 251, + 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071}; + + return Primes[std::min<unsigned>(Log2_32_Ceil(NumHashed), + array_lengthof(Primes) - 1)]; +} + +// Bloom filter estimation: at least 8 bits for each hashed symbol. +// GNU Hash table requirement: it should be a power of 2, +// the minimum value is 1, even for an empty table. +// Expected results for a 32-bit target: +// calcMaskWords(0..4) = 1 +// calcMaskWords(5..8) = 2 +// calcMaskWords(9..16) = 4 +// For a 64-bit target: +// calcMaskWords(0..8) = 1 +// calcMaskWords(9..16) = 2 +// calcMaskWords(17..32) = 4 +template <class ELFT> +unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) { + if (!NumHashed) + return 1; + return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off)); +} + +template <class ELFT> void GnuHashTableSection<ELFT>::finalize() { + unsigned NumHashed = Symbols.size(); + NBuckets = calcNBuckets(NumHashed); + MaskWords = calcMaskWords(NumHashed); + // Second hash shift estimation: just predefined values. + Shift2 = ELFT::Is64Bits ? 6 : 5; + + this->OutSec->Entsize = this->Entsize; + this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex; + this->Size = sizeof(Elf_Word) * 4 // Header + + sizeof(Elf_Off) * MaskWords // Bloom Filter + + sizeof(Elf_Word) * NBuckets // Hash Buckets + + sizeof(Elf_Word) * NumHashed; // Hash Values +} + +template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) { + writeHeader(Buf); + if (Symbols.empty()) + return; + writeBloomFilter(Buf); + writeHashTable(Buf); +} + +template <class ELFT> +void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) { + auto *P = reinterpret_cast<Elf_Word *>(Buf); + *P++ = NBuckets; + *P++ = In<ELFT>::DynSymTab->getNumSymbols() - Symbols.size(); + *P++ = MaskWords; + *P++ = Shift2; + Buf = reinterpret_cast<uint8_t *>(P); +} + +template <class ELFT> +void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) { + unsigned C = sizeof(Elf_Off) * 8; + + auto *Masks = reinterpret_cast<Elf_Off *>(Buf); + for (const SymbolData &Sym : Symbols) { + size_t Pos = (Sym.Hash / C) & (MaskWords - 1); + uintX_t V = (uintX_t(1) << (Sym.Hash % C)) | + (uintX_t(1) << ((Sym.Hash >> Shift2) % C)); + Masks[Pos] |= V; + } + Buf += sizeof(Elf_Off) * MaskWords; +} + +template <class ELFT> +void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) { + Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf); + Elf_Word *Values = Buckets + NBuckets; + + int PrevBucket = -1; + int I = 0; + for (const SymbolData &Sym : Symbols) { + int Bucket = Sym.Hash % NBuckets; + assert(PrevBucket <= Bucket); + if (Bucket != PrevBucket) { + Buckets[Bucket] = Sym.Body->DynsymIndex; + PrevBucket = Bucket; + if (I > 0) + Values[I - 1] |= 1; + } + Values[I] = Sym.Hash & ~1; + ++I; + } + if (I > 0) + Values[I - 1] |= 1; +} + +static uint32_t hashGnu(StringRef Name) { + uint32_t H = 5381; + for (uint8_t C : Name) + H = (H << 5) + H + C; + return H; +} + +// Add symbols to this symbol hash table. Note that this function +// destructively sort a given vector -- which is needed because +// GNU-style hash table places some sorting requirements. +template <class ELFT> +void GnuHashTableSection<ELFT>::addSymbols(std::vector<SymbolTableEntry> &V) { + // Ideally this will just be 'auto' but GCC 6.1 is not able + // to deduce it correctly. + std::vector<SymbolTableEntry>::iterator Mid = + std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { + return S.Symbol->isUndefined(); + }); + if (Mid == V.end()) + return; + for (auto I = Mid, E = V.end(); I != E; ++I) { + SymbolBody *B = I->Symbol; + size_t StrOff = I->StrTabOffset; + Symbols.push_back({B, StrOff, hashGnu(B->getName())}); + } + + unsigned NBuckets = calcNBuckets(Symbols.size()); + std::stable_sort(Symbols.begin(), Symbols.end(), + [&](const SymbolData &L, const SymbolData &R) { + return L.Hash % NBuckets < R.Hash % NBuckets; + }); + + V.erase(Mid, V.end()); + for (const SymbolData &Sym : Symbols) + V.push_back({Sym.Body, Sym.STName}); +} + template InputSection<ELF32LE> *elf::createCommonSection(); template InputSection<ELF32BE> *elf::createCommonSection(); template InputSection<ELF64LE> *elf::createCommonSection(); @@ -1236,3 +1384,8 @@ template class elf::SymbolTableSection<ELF32LE>; template class elf::SymbolTableSection<ELF32BE>; template class elf::SymbolTableSection<ELF64LE>; template class elf::SymbolTableSection<ELF64BE>; + +template class elf::GnuHashTableSection<ELF32LE>; +template class elf::GnuHashTableSection<ELF32BE>; +template class elf::GnuHashTableSection<ELF64LE>; +template class elf::GnuHashTableSection<ELF64BE>; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 1fcb41c5433..8434959755b 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -11,7 +11,6 @@ #define LLD_ELF_SYNTHETIC_SECTION_H #include "InputSection.h" -#include "OutputSections.h" #include "llvm/ADT/SmallPtrSet.h" namespace lld { @@ -401,6 +400,11 @@ private: std::vector<DynamicReloc<ELFT>> Relocs; }; +struct SymbolTableEntry { + SymbolBody *Symbol; + size_t StrTabOffset; +}; + template <class ELFT> class SymbolTableSection final : public SyntheticSection<ELFT> { public: @@ -432,6 +436,46 @@ private: std::vector<SymbolTableEntry> Symbols; }; +// Outputs GNU Hash section. For detailed explanation see: +// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections +template <class ELFT> +class GnuHashTableSection final : public SyntheticSection<ELFT> { + typedef typename ELFT::Off Elf_Off; + typedef typename ELFT::Word Elf_Word; + typedef typename ELFT::uint uintX_t; + +public: + GnuHashTableSection(); + void finalize() override; + void writeTo(uint8_t *Buf) override; + size_t getSize() const override { return this->Size; } + + // Adds symbols to the hash table. + // Sorts the input to satisfy GNU hash section requirements. + void addSymbols(std::vector<SymbolTableEntry> &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 SymbolData { + SymbolBody *Body; + size_t STName; + uint32_t Hash; + }; + + std::vector<SymbolData> Symbols; + + unsigned MaskWords; + unsigned NBuckets; + unsigned Shift2; + uintX_t Size = 0; +}; + template <class ELFT> InputSection<ELFT> *createCommonSection(); template <class ELFT> InputSection<ELFT> *createInterpSection(); template <class ELFT> MergeInputSection<ELFT> *createCommentSection(); @@ -443,6 +487,7 @@ template <class ELFT> struct In { static DynamicSection<ELFT> *Dynamic; static StringTableSection<ELFT> *DynStrTab; static SymbolTableSection<ELFT> *DynSymTab; + static GnuHashTableSection<ELFT> *GnuHashTab; static GotSection<ELFT> *Got; static MipsGotSection<ELFT> *MipsGot; static GotPltSection<ELFT> *GotPlt; @@ -462,6 +507,7 @@ template <class ELFT> InputSection<ELFT> *In<ELFT>::Common; template <class ELFT> DynamicSection<ELFT> *In<ELFT>::Dynamic; template <class ELFT> StringTableSection<ELFT> *In<ELFT>::DynStrTab; template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::DynSymTab; +template <class ELFT> GnuHashTableSection<ELFT> *In<ELFT>::GnuHashTab; template <class ELFT> GotSection<ELFT> *In<ELFT>::Got; template <class ELFT> MipsGotSection<ELFT> *In<ELFT>::MipsGot; template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 619f3139d22..e8d06261536 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -239,7 +239,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { Out<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>(); if (Config->GnuHash) - Out<ELFT>::GnuHashTab = make<GnuHashTableSection<ELFT>>(); + In<ELFT>::GnuHashTab = make<GnuHashTableSection<ELFT>>(); if (Config->SysvHash) Out<ELFT>::HashTab = make<HashTableSection<ELFT>>(); if (Config->GdbIndex) @@ -943,23 +943,19 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { Sec->ShName = In<ELFT>::ShStrTab->addString(Sec->getName()); } - // FIXME: this should be removed after converting GnuHashTableSection - // to input section. - // Finalizers fix each section's size. - // .dynsym is finalized early since that may fill up .gnu.hash. - finalizeSynthetic<ELFT>({In<ELFT>::DynSymTab}); - // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. for (OutputSectionBase *Sec : OutputSections) Sec->finalize(); - // Dynamic section must be the last one in this list. + // Dynamic section must be the last one in this list and dynamic + // symbol table section (DynSymTab) must be the first one. finalizeSynthetic<ELFT>( - {In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab, - In<ELFT>::DynStrTab, In<ELFT>::Got, In<ELFT>::MipsGot, In<ELFT>::GotPlt, - In<ELFT>::RelaDyn, In<ELFT>::RelaPlt, In<ELFT>::Dynamic}); + {In<ELFT>::DynSymTab, In<ELFT>::GnuHashTab, In<ELFT>::SymTab, + In<ELFT>::ShStrTab, In<ELFT>::StrTab, In<ELFT>::DynStrTab, In<ELFT>::Got, + In<ELFT>::MipsGot, In<ELFT>::GotPlt, In<ELFT>::RelaDyn, + In<ELFT>::RelaPlt, In<ELFT>::Dynamic}); } template <class ELFT> bool Writer<ELFT>::needsGot() { @@ -1000,7 +996,7 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { if (HasVerNeed) Add(Out<ELFT>::VerNeed); - Add(Out<ELFT>::GnuHashTab); + addInputSec(In<ELFT>::GnuHashTab); Add(Out<ELFT>::HashTab); addInputSec(In<ELFT>::Dynamic); addInputSec(In<ELFT>::DynStrTab); |

