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 finalizeAllocSize() {} 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 finalizeAllocSize() override; bool empty() const override; void addEntry(SymbolBody &Sym); @@ -128,6 +130,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void finalize() override; + void finalizeAllocSize() override; bool empty() const override; void addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); bool addDynTlsEntry(SymbolBody &Sym); @@ -335,7 +338,9 @@ public: DynamicSection(); + void applyEntries(bool Reserve); void finalize() override; + void finalizeAllocSize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } @@ -382,6 +387,7 @@ SymbolTableSection(StringTableSection &StrTabSec); void finalize() override; + void finalizeAllocSize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return getNumSymbols() * sizeof(Elf_Sym); } void addGlobal(SymbolBody *Body); @@ -417,6 +423,7 @@ public: GnuHashTableSection(); void finalize() override; + void finalizeAllocSize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return this->Size; } @@ -453,6 +460,7 @@ public: HashTableSection(); void finalize() override; + void finalizeAllocSize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return this->Size; } @@ -571,6 +579,7 @@ public: VersionDefinitionSection(); void finalize() override; + void finalizeAllocSize() 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,14 @@ return B.GlobalDynIndex * sizeof(uintX_t); } -template void GotSection::finalize() { +template void GotSection::finalizeAllocSize() { Size = NumEntries * sizeof(uintX_t); } +template void GotSection::finalize() { + assert(Size == NumEntries * sizeof(uintX_t)); +} + 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 +623,7 @@ LocalEntries32.size(); } -template void MipsGotSection::finalize() { +template void MipsGotSection::finalizeAllocSize() { PageEntriesNum = 0; for (std::pair &P : PageIndexMap) { // For each output section referenced by GOT page relocations calculate @@ -635,6 +639,22 @@ sizeof(uintX_t); } +template void MipsGotSection::finalize() { + PageEntriesNum = 0; + for (std::pair &P : PageIndexMap) { + // For each output section referenced by GOT page relocations calculate + // and save into PageIndexMap an upper bound of MIPS GOT entries required + // to store page addresses of local symbols. We assume the worst case - + // each 64kb page of the output section has at least one GOT relocation + // against it. And take in account the case when the section intersects + // page boundaries. + P.second = PageEntriesNum; + PageEntriesNum += getMipsPageCount(P.first->Size); + } + assert (Size == (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * + sizeof(uintX_t)); +} + 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,17 +877,18 @@ 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; - if (In::RelaDyn->OutSec->Size > 0) { +template void DynamicSection::applyEntries(bool Reserve) { + auto Apply = [this, Reserve](Entry E){ + if (Reserve) + this->Size += this->Entsize; + else + this->Entries.push_back(E); + }; + if (!In::RelaDyn->empty()) { 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, + Apply({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); + Apply({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->OutSec->Size}); + Apply({IsRela ? DT_RELAENT : DT_RELENT, uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); // MIPS dynamic loader does not support RELCOUNT tag. @@ -876,76 +897,88 @@ if (Config->EMachine != EM_MIPS) { size_t NumRelativeRels = In::RelaDyn->getRelativeRelocCount(); if (Config->ZCombreloc && NumRelativeRels) - add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); + Apply({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, + if (!In::RelaPlt->empty()) { + Apply({DT_JMPREL, In::RelaPlt}); + Apply({DT_PLTRELSZ, In::RelaPlt->OutSec->Size}); + Apply({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, In::GotPlt}); - add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)}); + Apply({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()}); + Apply({DT_SYMTAB, In::DynSymTab}); + Apply({DT_SYMENT, sizeof(Elf_Sym)}); + Apply({DT_STRTAB, In::DynStrTab}); + Apply({DT_STRSZ, In::DynStrTab->getSize()}); if (In::GnuHashTab) - add({DT_GNU_HASH, In::GnuHashTab}); + Apply({DT_GNU_HASH, In::GnuHashTab}); if (In::HashTab) - add({DT_HASH, In::HashTab}); + Apply({DT_HASH, In::HashTab}); if (Out::PreinitArray) { - add({DT_PREINIT_ARRAY, Out::PreinitArray}); - add({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize}); + Apply({DT_PREINIT_ARRAY, Out::PreinitArray}); + Apply({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize}); } if (Out::InitArray) { - add({DT_INIT_ARRAY, Out::InitArray}); - add({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize}); + Apply({DT_INIT_ARRAY, Out::InitArray}); + Apply({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize}); } if (Out::FiniArray) { - add({DT_FINI_ARRAY, Out::FiniArray}); - add({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize}); + Apply({DT_FINI_ARRAY, Out::FiniArray}); + Apply({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize}); } if (SymbolBody *B = Symtab::X->findInCurrentDSO(Config->Init)) - add({DT_INIT, B}); + Apply({DT_INIT, B}); if (SymbolBody *B = Symtab::X->findInCurrentDSO(Config->Fini)) - add({DT_FINI, B}); + Apply({DT_FINI, B}); bool HasVerNeed = In::VerNeed->getNeedNum() != 0; if (HasVerNeed || In::VerDef) - add({DT_VERSYM, In::VerSym}); + Apply({DT_VERSYM, In::VerSym}); if (In::VerDef) { - add({DT_VERDEF, In::VerDef}); - add({DT_VERDEFNUM, getVerDefNum()}); + Apply({DT_VERDEF, In::VerDef}); + Apply({DT_VERDEFNUM, getVerDefNum()}); } if (HasVerNeed) { - add({DT_VERNEED, In::VerNeed}); - add({DT_VERNEEDNUM, In::VerNeed->getNeedNum()}); + Apply({DT_VERNEED, In::VerNeed}); + Apply({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()}); + Apply({DT_MIPS_RLD_VERSION, 1}); + Apply({DT_MIPS_FLAGS, RHF_NOTPOT}); + Apply({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); + Apply({DT_MIPS_SYMTABNO, In::DynSymTab->getNumSymbols()}); + Apply({DT_MIPS_LOCAL_GOTNO, In::MipsGot->getLocalEntriesNum()}); if (const SymbolBody *B = In::MipsGot->getFirstGlobalEntry()) - add({DT_MIPS_GOTSYM, B->DynsymIndex}); + Apply({DT_MIPS_GOTSYM, B->DynsymIndex}); else - add({DT_MIPS_GOTSYM, In::DynSymTab->getNumSymbols()}); - add({DT_PLTGOT, In::MipsGot}); + Apply({DT_MIPS_GOTSYM, In::DynSymTab->getNumSymbols()}); + Apply({DT_PLTGOT, In::MipsGot}); if (In::MipsRldMap) - add({DT_MIPS_RLD_MAP, In::MipsRldMap}); + Apply({DT_MIPS_RLD_MAP, In::MipsRldMap}); } +} + +// Add remaining entries to complete .dynamic contents. +template void DynamicSection::finalizeAllocSize() { + this->Size = (Entries.size() + 1) * this->Entsize; + applyEntries(true /*Reserve*/); +} + +// Add remaining entries to complete .dynamic contents. +template void DynamicSection::finalize() { + this->Link = In::DynStrTab->OutSec->SectionIndex; + applyEntries(false /*Reserve*/); this->OutSec->Entsize = this->Entsize; this->OutSec->Link = this->Link; // +1 for DT_NULL - this->Size = (Entries.size() + 1) * this->Entsize; + assert(this->Size == (Entries.size() + 1) * this->Entsize); } template void DynamicSection::writeTo(uint8_t *Buf) { @@ -1084,26 +1117,9 @@ return L->GotIndex < R->GotIndex; } -template void SymbolTableSection::finalize() { - this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex; - this->OutSec->Info = this->Info = NumLocals + 1; - this->OutSec->Entsize = this->Entsize; - - 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::finalizeAllocSize() { + if (Config->Relocatable || !StrTabSec.isDynamic()) return; - } - if (In::GnuHashTab) // NB: It also sorts Symbols to meet the GNU hash table requirements. In::GnuHashTab->addSymbols(Symbols); @@ -1117,6 +1133,23 @@ S.Symbol->DynsymIndex = ++I; } +template void SymbolTableSection::finalize() { + this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex; + this->OutSec->Info = this->Info = NumLocals + 1; + this->OutSec->Entsize = this->Entsize; + + if (Config->Relocatable || StrTabSec.isDynamic()) + return; + 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::addGlobal(SymbolBody *B) { Symbols.push_back({B, StrTabSec.addString(B->getName(), false)}); } @@ -1297,21 +1330,33 @@ return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off)); } -template void GnuHashTableSection::finalize() { +template void GnuHashTableSection::finalizeAllocSize() { 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() { + 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; + assert(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::writeTo(uint8_t *Buf) { writeHeader(Buf); if (Symbols.empty()) @@ -1410,6 +1455,17 @@ this->Entsize = sizeof(Elf_Word); } +template void HashTableSection::finalizeAllocSize() { + unsigned NumEntries = 2; // nbucket and nchain. + NumEntries += In::DynSymTab->getNumSymbols(); // The chain entries. + + // Create as many buckets as there are symbols. + // FIXME: This is simplistic. We can try to optimize it, but implementing + // support for SHT_GNU_HASH is probably even more profitable. + NumEntries += In::DynSymTab->getNumSymbols(); + this->Size = NumEntries * sizeof(Elf_Word); +} + template void HashTableSection::finalize() { this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; this->OutSec->Entsize = this->Entsize; @@ -1421,7 +1477,7 @@ // FIXME: This is simplistic. We can try to optimize it, but implementing // support for SHT_GNU_HASH is probably even more profitable. NumEntries += In::DynSymTab->getNumSymbols(); - this->Size = NumEntries * sizeof(Elf_Word); + assert(this->Size == NumEntries * sizeof(Elf_Word)); } template void HashTableSection::writeTo(uint8_t *Buf) { @@ -1704,11 +1760,13 @@ return Config->OutputFile; } -template void VersionDefinitionSection::finalize() { +template void VersionDefinitionSection::finalizeAllocSize() { 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 Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1037,6 +1037,19 @@ for (SyntheticSection *SS : Sections) if (SS && SS->OutSec && !SS->empty()) { SS->finalize(); + if (!(SS->OutSec->Flags & SHF_ALLOC)) { + SS->OutSec->Size = 0; + SS->OutSec->assignOffsets(); + } + } +} + +template +static void finalizeSyntheticAllocSize( + const std::vector *> &Sections) { + for (SyntheticSection *SS : Sections) + if (SS && SS->OutSec && !SS->empty()) { + SS->finalizeAllocSize(); SS->OutSec->Size = 0; SS->OutSec->assignOffsets(); } @@ -1107,21 +1120,13 @@ if (In::Iplt && !In::Iplt->empty()) In::Iplt->addSymbols(); - // 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); - - // Now that we have defined all possible symbols including linker- - // synthesized ones. Visit all symbols to give the finishing touches. + // Now that we have defined all possible global symbols including linker- + // synthesized ones. Visit all dynamic symbols to give the finishing touches. for (Symbol *S : Symtab::X->getSymbols()) { SymbolBody *Body = S->body(); if (!includeInSymtab(*Body)) continue; - if (In::SymTab) - In::SymTab->addGlobal(Body); if (In::DynSymTab && S->includeInDynsym()) { In::DynSymTab->addGlobal(Body); @@ -1163,6 +1168,36 @@ fixHeaders(); } + // Finalize the size of these SHF_ALLOC sections, this permits us to + // calculate addresses of SHF_ALLOC sections for Thunks. + 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}; + finalizeSyntheticAllocSize(Synthetics); + + // 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); + + // Now that we have defined all possible static symbols including linker- + // synthesized ones. Visit all static symbols to give the finishing touches. + for (Symbol *S : Symtab::X->getSymbols()) { + SymbolBody *Body = S->body(); + + if (!includeInSymtab(*Body)) + continue; + if (In::SymTab) + In::SymTab->addGlobal(Body); + } + // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. @@ -1170,16 +1205,9 @@ 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}); + // symbol table section (DynSymTab) must be the first one. The finalize + // must not change the size of a SHF_ALLOC section. + finalizeSynthetic(Synthetics); } template void Writer::addPredefinedSections() { @@ -1189,8 +1217,10 @@ OutputSections.push_back(Out::BssRelRo); auto OS = dyn_cast_or_null>(findSection(".ARM.exidx")); - if (OS && !OS->Sections.empty() && !Config->Relocatable) + if (OS && !OS->Sections.empty() && !Config->Relocatable) { OS->addSection(make>()); + OS->Size += 8; + } } // The linker is expected to define SECNAME_start and SECNAME_end