Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -403,6 +403,23 @@ typedef typename llvm::object::ELFFile::Elf_Rela Elf_Rela; typedef typename llvm::object::ELFFile::Elf_Shdr Elf_Shdr; typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; + typedef typename llvm::object::ELFFile::uintX_t uintX_t; + + struct Entry { + int32_t Tag; + union { + OutputSectionBase *OutSec; + uint64_t Val; + const SymbolBody *Sym; + }; + enum KindT { SecAddr, SymAddr, PlainInt } Kind; + Entry(int32_t Tag, OutputSectionBase *OutSec) + : Tag(Tag), OutSec(OutSec), Kind(SecAddr) {} + Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {} + Entry(int32_t Tag, const SymbolBody *Sym) + : Tag(Tag), Sym(Sym), Kind(SymAddr) {} + }; + std::vector Entries; public: DynamicSection(SymbolTable &SymTab); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -593,60 +593,76 @@ Elf_Shdr &Header = this->Header; Header.sh_link = Out::DynStrTab->SectionIndex; - unsigned NumEntries = 0; + // Reserve strings + if (!Config->RPath.empty()) + Out::DynStrTab->reserve(Config->RPath); + if (!Config->SoName.empty()) + Out::DynStrTab->reserve(Config->SoName); + for (const std::unique_ptr> &F : SymTab.getSharedFiles()) + if (F->isNeeded()) + Out::DynStrTab->reserve(F->getSoName()); + Out::DynStrTab->finalize(); + if (Out::RelaDyn->hasRelocs()) { - ++NumEntries; // DT_RELA / DT_REL - ++NumEntries; // DT_RELASZ / DT_RELSZ - ++NumEntries; // DT_RELAENT / DT_RELENT + bool IsRela = Out::RelaDyn->isRela(); + Entries.push_back({IsRela ? DT_RELA : DT_REL, Out::RelaDyn}); + Entries.push_back( + {IsRela ? DT_RELASZ : DT_RELSZ, Out::RelaDyn->getSize()}); + Entries.push_back({IsRela ? DT_RELAENT : DT_RELENT, + uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); } if (Out::RelaPlt && Out::RelaPlt->hasRelocs()) { - ++NumEntries; // DT_JMPREL - ++NumEntries; // DT_PLTRELSZ - ++NumEntries; // DT_PLTGOT / DT_MIPS_PLTGOT - ++NumEntries; // DT_PLTREL + Entries.push_back({DT_JMPREL, Out::RelaPlt}); + Entries.push_back({DT_PLTRELSZ, Out::RelaPlt->getSize()}); + Entries.push_back({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, + Out::GotPlt}); + Entries.push_back( + {DT_PLTREL, Out::RelaPlt->isRela() ? DT_RELA : DT_REL}); } - ++NumEntries; // DT_SYMTAB - ++NumEntries; // DT_SYMENT - ++NumEntries; // DT_STRTAB - ++NumEntries; // DT_STRSZ + Entries.push_back({DT_SYMTAB, Out::DynSymTab}); + Entries.push_back({DT_SYMENT, sizeof(Elf_Sym)}); + Entries.push_back({DT_STRTAB, Out::DynStrTab}); + Entries.push_back({DT_STRSZ, Out::DynStrTab->getSize()}); if (Out::GnuHashTab) - ++NumEntries; // DT_GNU_HASH + Entries.push_back({DT_GNU_HASH, Out::GnuHashTab}); if (Out::HashTab) - ++NumEntries; // DT_HASH + Entries.push_back({DT_HASH, Out::HashTab}); - if (!Config->RPath.empty()) { - ++NumEntries; // DT_RUNPATH / DT_RPATH - Out::DynStrTab->reserve(Config->RPath); - } - - if (!Config->SoName.empty()) { - ++NumEntries; // DT_SONAME - Out::DynStrTab->reserve(Config->SoName); - } + if (!Config->RPath.empty()) + Entries.push_back({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, + Out::DynStrTab->addString(Config->RPath)}); - if (PreInitArraySec) - NumEntries += 2; - if (InitArraySec) - NumEntries += 2; - if (FiniArraySec) - NumEntries += 2; + if (!Config->SoName.empty()) + Entries.push_back( + {DT_SONAME, Out::DynStrTab->addString(Config->SoName)}); - for (const std::unique_ptr> &F : SymTab.getSharedFiles()) { - if (!F->isNeeded()) - continue; - Out::DynStrTab->reserve(F->getSoName()); - ++NumEntries; + if (PreInitArraySec) { + Entries.push_back({DT_PREINIT_ARRAY, PreInitArraySec}); + Entries.push_back({DT_PREINIT_ARRAYSZ, PreInitArraySec->getSize()}); + } + if (InitArraySec) { + Entries.push_back({DT_INIT_ARRAY, InitArraySec}); + Entries.push_back({DT_INIT_ARRAYSZ, (uintX_t)InitArraySec->getSize()}); + } + if (FiniArraySec) { + Entries.push_back({DT_FINI_ARRAY, FiniArraySec}); + Entries.push_back({DT_FINI_ARRAYSZ, (uintX_t)FiniArraySec->getSize()}); } + for (const std::unique_ptr> &F : SymTab.getSharedFiles()) + if (F->isNeeded()) + Entries.push_back( + {DT_NEEDED, Out::DynStrTab->addString(F->getSoName())}); + if (Symbol *S = SymTab.getSymbols().lookup(Config->Init)) InitSym = S->Body; if (Symbol *S = SymTab.getSymbols().lookup(Config->Fini)) FiniSym = S->Body; if (InitSym) - ++NumEntries; // DT_INIT + Entries.push_back({DT_INIT, InitSym}); if (FiniSym) - ++NumEntries; // DT_FINI + Entries.push_back({DT_FINI, FiniSym}); if (Config->Bsymbolic) DtFlags |= DF_SYMBOLIC; @@ -662,28 +678,33 @@ } if (DtFlags) - ++NumEntries; // DT_FLAGS + Entries.push_back({DT_FLAGS, DtFlags}); if (DtFlags1) - ++NumEntries; // DT_FLAGS_1 + Entries.push_back({DT_FLAGS_1, DtFlags1}); if (!Config->Entry.empty()) - ++NumEntries; // DT_DEBUG + Entries.push_back({DT_DEBUG, (uintX_t)0}); if (Config->EMachine == EM_MIPS) { - ++NumEntries; // DT_MIPS_RLD_VERSION - ++NumEntries; // DT_MIPS_FLAGS - ++NumEntries; // DT_MIPS_BASE_ADDRESS - ++NumEntries; // DT_MIPS_SYMTABNO - ++NumEntries; // DT_MIPS_LOCAL_GOTNO - ++NumEntries; // DT_MIPS_GOTSYM; - ++NumEntries; // DT_PLTGOT + Entries.push_back({DT_MIPS_RLD_VERSION, 1}); + Entries.push_back({DT_MIPS_FLAGS, RHF_NOTPOT}); + Entries.push_back({DT_MIPS_BASE_ADDRESS, (uintX_t)Target->getVAStart()}); + Entries.push_back( + {DT_MIPS_SYMTABNO, Out::DynSymTab->getNumSymbols()}); + Entries.push_back( + {DT_MIPS_LOCAL_GOTNO, Out::Got->getMipsLocalEntriesNum()}); + if (const SymbolBody *B = Out::Got->getMipsFirstGlobalEntry()) + Entries.push_back({DT_MIPS_GOTSYM, B->DynamicSymbolTableIndex}); + else + Entries.push_back( + {DT_MIPS_GOTSYM, Out::DynSymTab->getNumSymbols()}); + Entries.push_back({DT_PLTGOT, Out::Got}); if (Out::MipsRldMap) - ++NumEntries; // DT_MIPS_RLD_MAP + Entries.push_back({DT_MIPS_RLD_MAP, Out::MipsRldMap}); } - ++NumEntries; // DT_NULL - - Header.sh_size = NumEntries * Header.sh_entsize; + // +1 for DT_NULL + Header.sh_size = (Entries.size() + 1) * Header.sh_entsize; } template void DynamicSection::writeTo(uint8_t *Buf) { @@ -701,94 +722,19 @@ ++P; }; - if (Out::RelaDyn->hasRelocs()) { - bool IsRela = Out::RelaDyn->isRela(); - WritePtr(IsRela ? DT_RELA : DT_REL, Out::RelaDyn->getVA()); - WriteVal(IsRela ? DT_RELASZ : DT_RELSZ, Out::RelaDyn->getSize()); - WriteVal(IsRela ? DT_RELAENT : DT_RELENT, - IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); - } - if (Out::RelaPlt && Out::RelaPlt->hasRelocs()) { - WritePtr(DT_JMPREL, Out::RelaPlt->getVA()); - WriteVal(DT_PLTRELSZ, Out::RelaPlt->getSize()); - // On MIPS, the address of the .got.plt section is stored in - // the DT_MIPS_PLTGOT entry because the DT_PLTGOT entry points to - // the .got section. See "Dynamic Section" in the following document: - // https://sourceware.org/ml/binutils/2008-07/txt00000.txt - WritePtr((Config->EMachine == EM_MIPS) ? DT_MIPS_PLTGOT : DT_PLTGOT, - Out::GotPlt->getVA()); - WriteVal(DT_PLTREL, Out::RelaPlt->isRela() ? DT_RELA : DT_REL); - } - - WritePtr(DT_SYMTAB, Out::DynSymTab->getVA()); - WritePtr(DT_SYMENT, sizeof(Elf_Sym)); - WritePtr(DT_STRTAB, Out::DynStrTab->getVA()); - WriteVal(DT_STRSZ, Out::DynStrTab->getSize()); - if (Out::GnuHashTab) - WritePtr(DT_GNU_HASH, Out::GnuHashTab->getVA()); - if (Out::HashTab) - WritePtr(DT_HASH, Out::HashTab->getVA()); - - // If --enable-new-dtags is set, lld emits DT_RUNPATH - // instead of DT_RPATH. The two tags are functionally - // equivalent except for the following: - // - DT_RUNPATH is searched after LD_LIBRARY_PATH, while - // DT_RPATH is searched before. - // - DT_RUNPATH is used only to search for direct - // dependencies of the object it's contained in, while - // DT_RPATH is used for indirect dependencies as well. - if (!Config->RPath.empty()) - WriteVal(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, - Out::DynStrTab->addString(Config->RPath)); - - if (!Config->SoName.empty()) - WriteVal(DT_SONAME, Out::DynStrTab->addString(Config->SoName)); - - auto WriteArray = [&](int32_t T1, int32_t T2, - const OutputSectionBase *Sec) { - if (!Sec) - return; - WritePtr(T1, Sec->getVA()); - WriteVal(T2, Sec->getSize()); - }; - WriteArray(DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ, PreInitArraySec); - WriteArray(DT_INIT_ARRAY, DT_INIT_ARRAYSZ, InitArraySec); - WriteArray(DT_FINI_ARRAY, DT_FINI_ARRAYSZ, FiniArraySec); - - for (const std::unique_ptr> &F : SymTab.getSharedFiles()) - if (F->isNeeded()) - WriteVal(DT_NEEDED, Out::DynStrTab->addString(F->getSoName())); - - if (InitSym) - WritePtr(DT_INIT, getSymVA(*InitSym)); - if (FiniSym) - WritePtr(DT_FINI, getSymVA(*FiniSym)); - if (DtFlags) - WriteVal(DT_FLAGS, DtFlags); - if (DtFlags1) - WriteVal(DT_FLAGS_1, DtFlags1); - if (!Config->Entry.empty()) - WriteVal(DT_DEBUG, 0); - - // See "Dynamic Section" in Chapter 5 in the following document - // for detailed description: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Config->EMachine == EM_MIPS) { - WriteVal(DT_MIPS_RLD_VERSION, 1); - WriteVal(DT_MIPS_FLAGS, RHF_NOTPOT); - WritePtr(DT_MIPS_BASE_ADDRESS, Target->getVAStart()); - WriteVal(DT_MIPS_SYMTABNO, Out::DynSymTab->getNumSymbols()); - WriteVal(DT_MIPS_LOCAL_GOTNO, Out::Got->getMipsLocalEntriesNum()); - if (const SymbolBody *B = Out::Got->getMipsFirstGlobalEntry()) - WriteVal(DT_MIPS_GOTSYM, B->DynamicSymbolTableIndex); - else - WriteVal(DT_MIPS_GOTSYM, Out::DynSymTab->getNumSymbols()); - WritePtr(DT_PLTGOT, Out::Got->getVA()); - if (Out::MipsRldMap) - WritePtr(DT_MIPS_RLD_MAP, Out::MipsRldMap->getVA()); + for (const Entry &E : Entries) { + switch (E.Kind) { + case Entry::SecAddr: + WritePtr(E.Tag, E.OutSec->getVA()); + break; + case Entry::SymAddr: + WritePtr(E.Tag, getSymVA(*E.Sym)); + break; + case Entry::PlainInt: + WriteVal(E.Tag, E.Val); + break; + } } - - WriteVal(DT_NULL, 0); } template Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -874,16 +874,15 @@ Out::ShStrTab->reserve(Sec->getName()); // Finalizers fix each section's size. - // .dynamic section's finalizer may add strings to .dynstr, - // so finalize that early. - // Likewise, .dynsym is finalized early since that may fill up .gnu.hash. - Out::Dynamic->finalize(); + // .dynsym is finalized early since that may fill up .gnu.hash. if (isOutputDynamic()) Out::DynSymTab->finalize(); - // Fill other section headers. + // Fill other section headers. The dynamic string table in finalized + // once the .dynamic finalizer has added a few last strings. for (OutputSectionBase *Sec : OutputSections) - Sec->finalize(); + if (Sec != Out::DynStrTab) + Sec->finalize(); } // This function add Out::* sections to OutputSections.