Index: ELF/Relocations.h =================================================================== --- ELF/Relocations.h +++ ELF/Relocations.h @@ -112,7 +112,7 @@ template void scanRelocations(InputSectionBase &); template -void createThunks(ArrayRef OutputSections); +bool createThunks(ArrayRef OutputSections); // Return a int64_t to make sure we get the sign extension out of the way as // early as possible. Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -897,10 +897,11 @@ // finalized. If any Thunks are added to an OutputSection the output section // offsets of the InputSections will change. // +// Returns true if Thunks have been added. // FIXME: All Thunks are assumed to be in range of the relocation. Range // extension Thunks are not yet supported. template -void createThunks(ArrayRef OutputSections) { +bool createThunks(ArrayRef OutputSections) { // Track Symbols that already have a Thunk DenseMap *> ThunkedSymbols; // Track InputSections that have a ThunkSection placed in front @@ -982,6 +983,7 @@ // Merge all created synthetic ThunkSections back into OutputSection for (auto &KV : ThunkSections) mergeThunks(KV.first, KV.second); + return !ThunkSections.empty(); } template void scanRelocations(InputSectionBase &); @@ -989,9 +991,9 @@ template void scanRelocations(InputSectionBase &); template void scanRelocations(InputSectionBase &); -template void createThunks(ArrayRef); -template void createThunks(ArrayRef); -template void createThunks(ArrayRef); -template void createThunks(ArrayRef); +template bool createThunks(ArrayRef); +template bool createThunks(ArrayRef); +template bool createThunks(ArrayRef); +template bool createThunks(ArrayRef); } } Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -47,6 +47,12 @@ virtual ~SyntheticSection() = default; virtual void writeTo(uint8_t *Buf) = 0; virtual size_t getSize() const = 0; + // Finalize is split up into 3 parts to accommodate Thunks, early finalize + // should do as much as possible including finalizing the section size + virtual void earlyFinalize() {} + // If the size calculation needs to be updated during Thunk creation + virtual void updateAllocSize() {} + // Runs after all content has been added, must not alter section size virtual void finalize() {} virtual bool empty() const { return false; } @@ -66,7 +72,7 @@ GotSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } - void finalize() override; + void earlyFinalize() override; bool empty() const override; void addEntry(SymbolBody &Sym); @@ -128,7 +134,8 @@ MipsGotSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } - void finalize() override; + void earlyFinalize() override; + void updateAllocSize() override; bool empty() const override; void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr); bool addDynTlsEntry(SymbolBody &Sym); @@ -336,6 +343,7 @@ public: DynamicSection(); + void earlyFinalize() override; void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } @@ -382,6 +390,7 @@ typedef typename ELFT::uint uintX_t; SymbolTableSection(StringTableSection &StrTabSec); + void earlyFinalize() override; void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return getNumSymbols() * sizeof(Elf_Sym); } @@ -417,6 +426,7 @@ public: GnuHashTableSection(); + void earlyFinalize() override; void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return this->Size; } @@ -453,6 +463,7 @@ public: HashTableSection(); + void earlyFinalize() override; void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return this->Size; } @@ -495,7 +506,7 @@ public: GdbIndexSection(); - void finalize() override; + void earlyFinalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; bool empty() const override; @@ -571,6 +582,7 @@ public: VersionDefinitionSection(); + void earlyFinalize() override; void finalize() override; size_t getSize() const override; void writeTo(uint8_t *Buf) override; @@ -639,7 +651,7 @@ uintX_t Alignment); void addSection(MergeInputSection *MS); void writeTo(uint8_t *Buf) override; - void finalize() override; + void earlyFinalize() override; bool shouldTailMerge() const; size_t getSize() const override; Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -441,7 +441,7 @@ return B.GlobalDynIndex * sizeof(uintX_t); } -template void GotSection::finalize() { +template void GotSection::earlyFinalize() { Size = NumEntries * sizeof(uintX_t); } @@ -619,7 +619,11 @@ LocalEntries32.size(); } -template void MipsGotSection::finalize() { +template void MipsGotSection::earlyFinalize() { + updateAllocSize(); +} + +template void MipsGotSection::updateAllocSize() { PageEntriesNum = 0; for (std::pair &P : PageIndexMap) { // For each output section referenced by GOT page relocations calculate @@ -858,11 +862,7 @@ } // Add remaining entries to complete .dynamic contents. -template void DynamicSection::finalize() { - if (this->Size) - return; // Already finalized. - - this->Link = In::DynStrTab->OutSec->SectionIndex; +template void DynamicSection::earlyFinalize() { if (In::RelaDyn->OutSec->Size > 0) { bool IsRela = Config->Rela; add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); @@ -941,13 +941,17 @@ add({DT_MIPS_RLD_MAP, In::MipsRldMap}); } - this->OutSec->Entsize = this->Entsize; - this->OutSec->Link = this->Link; - // +1 for DT_NULL this->Size = (Entries.size() + 1) * this->Entsize; } +// Add remaining entries to complete .dynamic contents. +template void DynamicSection::finalize() { + this->Link = In::DynStrTab->OutSec->SectionIndex; + this->OutSec->Entsize = this->Entsize; + this->OutSec->Link = this->Link; +} + template void DynamicSection::writeTo(uint8_t *Buf) { auto *P = reinterpret_cast(Buf); @@ -1083,38 +1087,15 @@ return L->GotIndex < R->GotIndex; } -template void SymbolTableSection::finalize() { - this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex; - this->OutSec->Entsize = this->Entsize; - - if (!StrTabSec.isDynamic()) { - // All explictly added STB_LOCAL symbols without a Symbol are first - auto It = std::stable_partition( - Symbols.begin(), Symbols.end(), - [](const SymbolTableEntry &S) { return S.Symbol->isLocal(); }); - NumLocals = It - Symbols.begin(); - } - this->OutSec->Info = this->Info = 1 + NumLocals; - - if (Config->Relocatable) - return; - - if (!StrTabSec.isDynamic()) { - auto GlobBegin = Symbols.begin() + NumLocals; - auto It = std::stable_partition( - GlobBegin, Symbols.end(), [](const SymbolTableEntry &S) { - return S.Symbol->symbol()->computeBinding() == STB_LOCAL; - }); - // update sh_info with number of Global symbols output with computed - // binding of STB_LOCAL - this->OutSec->Info = this->Info = 1 + (It - Symbols.begin()); +template void SymbolTableSection::earlyFinalize() { + if (!StrTabSec.isDynamic()) return; - } if (In::GnuHashTab) // NB: It also sorts Symbols to meet the GNU hash table requirements. In::GnuHashTab->addSymbols(Symbols); - else if (Config->EMachine == EM_MIPS) + + if (Config->EMachine == EM_MIPS) std::stable_sort(Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &L, const SymbolTableEntry &R) { return sortMipsSymbols(L.Symbol, R.Symbol); @@ -1124,6 +1105,35 @@ S.Symbol->DynsymIndex = ++I; } +template void SymbolTableSection::finalize() { + this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex; + this->OutSec->Entsize = this->Entsize; + + if (StrTabSec.isDynamic()) { + this->OutSec->Info = this->Info = 1; + return; + } + // All explictly added STB_LOCAL symbols without a Symbol are first + auto It = std::stable_partition( + Symbols.begin(), Symbols.end(), + [](const SymbolTableEntry &S) { return S.Symbol->isLocal(); }); + NumLocals = It - Symbols.begin(); + this->OutSec->Info = this->Info = 1 + NumLocals; + + if (Config->Relocatable) + return; + + auto GlobBegin = Symbols.begin() + NumLocals; + It = std::stable_partition( + GlobBegin, Symbols.end(), [](const SymbolTableEntry &S) { + return S.Symbol->symbol()->computeBinding() == STB_LOCAL; + }); + // update sh_info with number of Global symbols output with computed + // binding of STB_LOCAL + this->OutSec->Info = this->Info = 1 + (It - Symbols.begin()); + return; +} + template void SymbolTableSection::addGlobal(SymbolBody *B) { Symbols.push_back({B, StrTabSec.addString(B->getName(), false)}); } @@ -1303,21 +1313,23 @@ return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off)); } -template void GnuHashTableSection::finalize() { +template void GnuHashTableSection::earlyFinalize() { 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::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 void GnuHashTableSection::finalize() { + this->OutSec->Entsize = this->Entsize; + this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; +} + template void GnuHashTableSection::writeTo(uint8_t *Buf) { writeHeader(Buf); if (Symbols.empty()) @@ -1381,7 +1393,7 @@ } // Add symbols to this symbol hash table. Note that this function -// destructively sort a given vector -- which is needed because +// destructively sorts a given vector -- which is needed because // GNU-style hash table places some sorting requirements. template void GnuHashTableSection::addSymbols(std::vector &V) { @@ -1416,10 +1428,7 @@ this->Entsize = sizeof(Elf_Word); } -template void HashTableSection::finalize() { - this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; - this->OutSec->Entsize = this->Entsize; - +template void HashTableSection::earlyFinalize() { unsigned NumEntries = 2; // nbucket and nchain. NumEntries += In::DynSymTab->getNumSymbols(); // The chain entries. @@ -1430,6 +1439,11 @@ this->Size = NumEntries * sizeof(Elf_Word); } +template void HashTableSection::finalize() { + this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; + this->OutSec->Entsize = this->Entsize; +} + template void HashTableSection::writeTo(uint8_t *Buf) { unsigned NumSymbols = In::DynSymTab->getNumSymbols(); auto *P = reinterpret_cast(Buf); @@ -1563,7 +1577,7 @@ } } -template void GdbIndexSection::finalize() { +template void GdbIndexSection::earlyFinalize() { if (Finalized) return; Finalized = true; @@ -1588,7 +1602,7 @@ } template size_t GdbIndexSection::getSize() const { - const_cast *>(this)->finalize(); + const_cast *>(this)->earlyFinalize(); return StringPoolOffset + StringPool.getSize(); } @@ -1710,11 +1724,14 @@ return Config->OutputFile; } -template void VersionDefinitionSection::finalize() { +template void VersionDefinitionSection::earlyFinalize() { + // Careful to only do this once FileDefNameOff = In::DynStrTab->addString(getFileDefName()); for (VersionDefinition &V : Config->VersionDefinitions) V.NameOff = In::DynStrTab->addString(V.Name); +} +template void VersionDefinitionSection::finalize() { this->OutSec->Link = this->Link = In::DynStrTab->OutSec->SectionIndex; // sh_info should be set to the number of definitions. This fact is missed in @@ -1927,7 +1944,7 @@ Builder.finalizeInOrder(); } -template void MergeSyntheticSection::finalize() { +template void MergeSyntheticSection::earlyFinalize() { if (Finalized) return; Finalized = true; @@ -1939,7 +1956,7 @@ template size_t MergeSyntheticSection::getSize() const { // We should finalize string builder to know the size. - const_cast *>(this)->finalize(); + const_cast *>(this)->earlyFinalize(); return Builder.getSize(); } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1029,10 +1029,11 @@ template static void -finalizeSynthetic(const std::vector *> &Sections) { +applySynthetic(const std::vector *> &Sections, + std::function *)> Fn) { for (SyntheticSection *SS : Sections) if (SS && SS->OutSec && !SS->empty()) { - SS->finalize(); + Fn(SS); SS->OutSec->Size = 0; SS->OutSec->assignOffsets(); } @@ -1109,10 +1110,10 @@ SymbolBody *Body = S->body(); if (!includeInSymtab(*Body)) - continue; + continue; if (In::SymTab) In::SymTab->addGlobal(Body); - + if (In::DynSymTab && S->includeInDynsym()) { In::DynSymTab->addGlobal(Body); if (auto *SS = dyn_cast>(Body)) @@ -1153,11 +1154,35 @@ fixHeaders(); } + // Dynamic section must be the last one in this list and dynamic + // symbol table section (DynSymTab) must be the first one. + std::vector *> Synthetics = { + In::DynSymTab, In::GnuHashTab, In::HashTab, + In::SymTab, In::ShStrTab, In::StrTab, + In::VerDef, In::DynStrTab, In::GdbIndex, + In::Got, In::MipsGot, In::IgotPlt, + In::GotPlt, In::RelaDyn, In::RelaIplt, + In::RelaPlt, In::Plt, In::Iplt, + In::Plt, In::EhFrameHdr, In::VerSym, + In::VerNeed, In::Dynamic}; + // Perform as much Finalization as we can prior to ThunkCreation + applySynthetic(Synthetics, + [](SyntheticSection *SS) { SS->earlyFinalize(); }); + // Some architectures use small displacements for jump instructions. // It is linker's responsibility to create thunks containing long // jump instructions if jump targets are too far. Create thunks. - if (Target->NeedsThunks) - createThunks(OutputSections); + if (Target->NeedsThunks) { + // FIXME: only ARM Interworking and Mips LA25 Thunks are implemented, these + // do not require address information. To support range extension Thunks + // we need to assign addresses so that we can tell if jump instructions + // are out of range. This will need to turn into a loop that converges + // when no more Thunks are added + if (createThunks(OutputSections)) + applySynthetic(Synthetics, [](SyntheticSection *SS) { + SS->updateAllocSize(); + }); + } // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result @@ -1165,17 +1190,8 @@ for (OutputSectionBase *Sec : OutputSections) Sec->finalize(); - // Dynamic section must be the last one in this list and dynamic - // symbol table section (DynSymTab) must be the first one. - finalizeSynthetic( - {In::DynSymTab, In::GnuHashTab, In::HashTab, - In::SymTab, In::ShStrTab, In::StrTab, - In::VerDef, In::DynStrTab, In::GdbIndex, - In::Got, In::MipsGot, In::IgotPlt, - In::GotPlt, In::RelaDyn, In::RelaIplt, - In::RelaPlt, In::Plt, In::Iplt, - In::Plt, In::EhFrameHdr, In::VerSym, - In::VerNeed, In::Dynamic}); + applySynthetic(Synthetics, + [](SyntheticSection *SS) { SS->finalize(); }); } template void Writer::addPredefinedSections() {