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 @@ -856,10 +856,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 @@ -941,6 +942,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 &); @@ -948,9 +950,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 @@ -48,6 +48,7 @@ virtual void writeTo(uint8_t *Buf) = 0; virtual size_t getSize() const = 0; virtual void finalize() {} + virtual void updateAllocSize() {} virtual bool empty() const { return false; } uintX_t getVA() const { @@ -67,6 +68,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void finalize() override; + void updateAllocSize() override; bool empty() const override; void addEntry(SymbolBody &Sym); @@ -129,6 +131,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void finalize() override; + void updateAllocSize() override; bool empty() const override; void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr); bool addDynTlsEntry(SymbolBody &Sym); @@ -337,11 +340,13 @@ public: DynamicSection(); void finalize() override; + void updateAllocSize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } private: void addEntries(); + std::vector addLateEntries(); void add(Entry E) { Entries.push_back(E); } uintX_t Size = 0; }; @@ -394,6 +399,7 @@ ArrayRef getSymbols() const { return Symbols; } static const OutputSectionBase *getOutputSection(SymbolBody *Sym); + void addSymbolsToGnuHashTab(); private: void writeLocalSymbols(uint8_t *&Buf); @@ -418,6 +424,7 @@ public: GnuHashTableSection(); void finalize() override; + void updateAllocSize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return this->Size; } @@ -454,6 +461,7 @@ public: HashTableSection(); void finalize() override; + void updateAllocSize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return this->Size; } @@ -572,6 +580,7 @@ public: VersionDefinitionSection(); void finalize() override; + void updateAllocSize() override; size_t getSize() const override; void writeTo(uint8_t *Buf) override; Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -441,10 +441,12 @@ return B.GlobalDynIndex * sizeof(uintX_t); } -template void GotSection::finalize() { +template void GotSection::updateAllocSize() { Size = NumEntries * sizeof(uintX_t); } +template void GotSection::finalize() { updateAllocSize(); } + template bool GotSection::empty() const { // If we have a relocation that is relative to GOT (such as GOTOFFREL), // we need to emit a GOT even if it's empty. @@ -619,7 +621,7 @@ LocalEntries32.size(); } -template void MipsGotSection::finalize() { +template void MipsGotSection::updateAllocSize() { PageEntriesNum = 0; for (std::pair &P : PageIndexMap) { // For each output section referenced by GOT page relocations calculate @@ -635,6 +637,10 @@ sizeof(uintX_t); } +template void MipsGotSection::finalize() { + updateAllocSize(); +} + template bool MipsGotSection::empty() const { // We add the .got section to the result for dynamic MIPS target because // its address and properties are mentioned in the .dynamic section. @@ -857,18 +863,17 @@ add({DT_DEBUG, (uint64_t)0}); } -// Add remaining entries to complete .dynamic contents. -template void DynamicSection::finalize() { - if (this->Size) - return; // Already finalized. - - this->Link = In::DynStrTab->OutSec->SectionIndex; +template +std::vector::Entry> +DynamicSection::addLateEntries() { + std::vector LateEntries; + auto AddLate = [&](Entry E) { LateEntries.push_back(E); }; if (In::RelaDyn->OutSec->Size > 0) { bool IsRela = Config->Rela; - add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); - add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->OutSec->Size}); - add({IsRela ? DT_RELAENT : DT_RELENT, - uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); + AddLate({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); + AddLate({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->OutSec->Size}); + AddLate({IsRela ? DT_RELAENT : DT_RELENT, + uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); // MIPS dynamic loader does not support RELCOUNT tag. // The problem is in the tight relation between dynamic @@ -876,74 +881,87 @@ if (Config->EMachine != EM_MIPS) { size_t NumRelativeRels = In::RelaDyn->getRelativeRelocCount(); if (Config->ZCombreloc && NumRelativeRels) - add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); + AddLate({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); } } if (In::RelaPlt->OutSec->Size > 0) { - add({DT_JMPREL, In::RelaPlt}); - add({DT_PLTRELSZ, In::RelaPlt->OutSec->Size}); - add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, - In::GotPlt}); - add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)}); + AddLate({DT_JMPREL, In::RelaPlt}); + AddLate({DT_PLTRELSZ, In::RelaPlt->OutSec->Size}); + AddLate({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, + In::GotPlt}); + AddLate({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)}); } - add({DT_SYMTAB, In::DynSymTab}); - add({DT_SYMENT, sizeof(Elf_Sym)}); - add({DT_STRTAB, In::DynStrTab}); - add({DT_STRSZ, In::DynStrTab->getSize()}); + AddLate({DT_SYMTAB, In::DynSymTab}); + AddLate({DT_SYMENT, sizeof(Elf_Sym)}); + AddLate({DT_STRTAB, In::DynStrTab}); + AddLate({DT_STRSZ, In::DynStrTab->getSize()}); if (In::GnuHashTab) - add({DT_GNU_HASH, In::GnuHashTab}); + AddLate({DT_GNU_HASH, In::GnuHashTab}); if (In::HashTab) - add({DT_HASH, In::HashTab}); + AddLate({DT_HASH, In::HashTab}); if (Out::PreinitArray) { - add({DT_PREINIT_ARRAY, Out::PreinitArray}); - add({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize}); + AddLate({DT_PREINIT_ARRAY, Out::PreinitArray}); + AddLate({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize}); } if (Out::InitArray) { - add({DT_INIT_ARRAY, Out::InitArray}); - add({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize}); + AddLate({DT_INIT_ARRAY, Out::InitArray}); + AddLate({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize}); } if (Out::FiniArray) { - add({DT_FINI_ARRAY, Out::FiniArray}); - add({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize}); + AddLate({DT_FINI_ARRAY, Out::FiniArray}); + AddLate({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize}); } if (SymbolBody *B = Symtab::X->findInCurrentDSO(Config->Init)) - add({DT_INIT, B}); + AddLate({DT_INIT, B}); if (SymbolBody *B = Symtab::X->findInCurrentDSO(Config->Fini)) - add({DT_FINI, B}); + AddLate({DT_FINI, B}); bool HasVerNeed = In::VerNeed->getNeedNum() != 0; if (HasVerNeed || In::VerDef) - add({DT_VERSYM, In::VerSym}); + AddLate({DT_VERSYM, In::VerSym}); if (In::VerDef) { - add({DT_VERDEF, In::VerDef}); - add({DT_VERDEFNUM, getVerDefNum()}); + AddLate({DT_VERDEF, In::VerDef}); + AddLate({DT_VERDEFNUM, getVerDefNum()}); } if (HasVerNeed) { - add({DT_VERNEED, In::VerNeed}); - add({DT_VERNEEDNUM, In::VerNeed->getNeedNum()}); + AddLate({DT_VERNEED, In::VerNeed}); + AddLate({DT_VERNEEDNUM, In::VerNeed->getNeedNum()}); } if (Config->EMachine == EM_MIPS) { - add({DT_MIPS_RLD_VERSION, 1}); - add({DT_MIPS_FLAGS, RHF_NOTPOT}); - add({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); - add({DT_MIPS_SYMTABNO, In::DynSymTab->getNumSymbols()}); - add({DT_MIPS_LOCAL_GOTNO, In::MipsGot->getLocalEntriesNum()}); + AddLate({DT_MIPS_RLD_VERSION, 1}); + AddLate({DT_MIPS_FLAGS, RHF_NOTPOT}); + AddLate({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); + AddLate({DT_MIPS_SYMTABNO, In::DynSymTab->getNumSymbols()}); + AddLate({DT_MIPS_LOCAL_GOTNO, In::MipsGot->getLocalEntriesNum()}); if (const SymbolBody *B = In::MipsGot->getFirstGlobalEntry()) - add({DT_MIPS_GOTSYM, B->DynsymIndex}); + AddLate({DT_MIPS_GOTSYM, B->DynsymIndex}); else - add({DT_MIPS_GOTSYM, In::DynSymTab->getNumSymbols()}); - add({DT_PLTGOT, In::MipsGot}); + AddLate({DT_MIPS_GOTSYM, In::DynSymTab->getNumSymbols()}); + AddLate({DT_PLTGOT, In::MipsGot}); if (In::MipsRldMap) - add({DT_MIPS_RLD_MAP, In::MipsRldMap}); + AddLate({DT_MIPS_RLD_MAP, In::MipsRldMap}); } + return LateEntries; +} +// Add remaining entries to complete .dynamic contents. +template void DynamicSection::updateAllocSize() { + std::vector LateEntries = addLateEntries(); + // +1 for DT_NULL + this->Size = (Entries.size() + LateEntries.size() + 1) * this->Entsize; +} + +// Add remaining entries to complete .dynamic contents. +template void DynamicSection::finalize() { + this->Link = In::DynStrTab->OutSec->SectionIndex; + std::vector LateEntries = addLateEntries(); + Entries.insert(Entries.end(), LateEntries.begin(), LateEntries.end()); this->OutSec->Entsize = this->Entsize; this->OutSec->Link = this->Link; - // +1 for DT_NULL this->Size = (Entries.size() + 1) * this->Entsize; } @@ -1111,10 +1129,7 @@ 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); @@ -1262,6 +1277,12 @@ return nullptr; } +template void SymbolTableSection::addSymbolsToGnuHashTab() { + assert(In::GnuHashTab && StrTabSec.isDynamic()); + // NB: It also sorts Symbols to meet the GNU hash table requirements. + In::GnuHashTab->addSymbols(Symbols); +} + template GnuHashTableSection::GnuHashTableSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, sizeof(uintX_t), @@ -1303,21 +1324,24 @@ return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off)); } -template void GnuHashTableSection::finalize() { +template void GnuHashTableSection::updateAllocSize() { 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() { + updateAllocSize(); + 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 +1405,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 +1440,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::updateAllocSize() { unsigned NumEntries = 2; // nbucket and nchain. NumEntries += In::DynSymTab->getNumSymbols(); // The chain entries. @@ -1430,6 +1451,12 @@ this->Size = NumEntries * sizeof(Elf_Word); } +template void HashTableSection::finalize() { + updateAllocSize(); + 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); @@ -1710,11 +1737,15 @@ return Config->OutputFile; } -template void VersionDefinitionSection::finalize() { +template void VersionDefinitionSection::updateAllocSize() { + // 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() { + updateAllocSize(); this->OutSec->Link = this->Link = In::DynStrTab->OutSec->SectionIndex; // sh_info should be set to the number of definitions. This fact is missed in Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1047,6 +1047,17 @@ } } +template +static void updateSyntheticAllocSize( + const std::vector *> &Sections) { + for (SyntheticSection *SS : Sections) + if (SS && SS->OutSec && !SS->empty()) { + SS->updateAllocSize(); + SS->OutSec->Size = 0; + SS->OutSec->assignOffsets(); + } +} + // We need to add input synthetic sections early in createSyntheticSections() // to make them visible from linkescript side. But not all sections are always // required to be in output. For example we don't need dynamic section content @@ -1118,10 +1129,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)) @@ -1129,6 +1140,8 @@ In::VerNeed->addSymbol(SS); } } + if (In::GnuHashTab && In::DynSymTab) + In::DynSymTab->addSymbolsToGnuHashTab(); // Do not proceed if there was an undefined symbol. if (ErrorCount) @@ -1162,11 +1175,29 @@ fixHeaders(); } + 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}; + // 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 + updateSyntheticAllocSize(Synthetics); + if (createThunks(OutputSections)) + updateSyntheticAllocSize(Synthetics); + } // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result @@ -1176,15 +1207,7 @@ // 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}); + finalizeSynthetic(Synthetics); } template void Writer::addPredefinedSections() {