Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -15,6 +15,7 @@ #include "Thunks.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" @@ -222,10 +223,11 @@ public: InputSection(ObjectFile *F, const Elf_Shdr *Header, StringRef Name); + virtual ~InputSection() = default; // Write this section to a mmap'ed file, assuming Buf is pointing to // beginning of the output section. - void writeTo(uint8_t *Buf); + virtual void writeTo(uint8_t *Buf); // Relocation sections that refer to this one. llvm::TinyPtrVector RelocSections; @@ -327,6 +329,124 @@ static typename ELFT::Shdr Hdr; }; +template T *zero(T *Val) { + void *P = memset(Val, 0, sizeof(*Val)); + return static_cast(P); +} + +template class SyntheticInputSection : public InputSection { +public: + typedef typename ELFT::uint uintX_t; + + SyntheticInputSection(StringRef Name, uint32_t Type, uintX_t Flags) + : InputSection(nullptr, zero(&Header), Name) { + Header.sh_type = Type; + Header.sh_flags = Flags; + } + + virtual void finalize() = 0; + virtual bool needed() const { return true; } + +protected: + typename ELFT::Shdr Header; +}; + +// Linker-generated GOT section. +template +class GotSection final : public SyntheticInputSection { + typedef OutputSectionBase Base; + typedef typename ELFT::uint uintX_t; + +public: + GotSection(); + void finalize() override; + bool needed() const override; + void writeTo(uint8_t *Buf) override; + void addEntry(SymbolBody &Sym); + void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); + bool addDynTlsEntry(SymbolBody &Sym); + bool addTlsIndex(); + bool empty() const { return MipsPageEntries == 0 && Entries.empty(); } + uintX_t getMipsLocalPageOffset(uintX_t Addr); + uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const; + uintX_t getGlobalDynAddr(const SymbolBody &B) const; + uintX_t getGlobalDynOffset(const SymbolBody &B) const; + + // Returns the symbol which corresponds to the first entry of the global part + // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic + // table properties. + // Returns nullptr if the global part is empty. + const SymbolBody *getMipsFirstGlobalEntry() const; + + // Returns the number of entries in the local part of GOT including + // the number of reserved entries. This method is MIPS-specific. + unsigned getMipsLocalEntriesNum() const; + + // Returns offset of TLS part of the MIPS GOT table. This part goes + // after 'local' and 'global' entries. + uintX_t getMipsTlsOffset() const; + + uintX_t getTlsIndexVA() { return this->OutSec->getVA() + TlsIndexOff; } + uint32_t getTlsIndexOff() const { return TlsIndexOff; } + + // Flag to force GOT to be in output if we have relocations + // that relies on its address. + bool HasGotOffRel = false; + +private: + std::vector Entries; + uint32_t TlsIndexOff = -1; + uint32_t MipsPageEntries = 0; + // Output sections referenced by MIPS GOT relocations. + llvm::SmallPtrSet *, 10> MipsOutSections; + llvm::DenseMap MipsLocalGotPos; + + // MIPS ABI requires to create unique GOT entry for each Symbol/Addend + // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal` + // or `MipsGlobal` vectors. In general it does not have a sence to take in + // account addend for preemptible symbols because the corresponding + // GOT entries should have one-to-one mapping with dynamic symbols table. + // But we use the same container's types for both kind of GOT entries + // to handle them uniformly. + typedef std::pair MipsGotEntry; + typedef std::vector MipsGotEntries; + llvm::DenseMap MipsGotMap; + MipsGotEntries MipsLocal; + MipsGotEntries MipsLocal32; + MipsGotEntries MipsGlobal; + + // Write MIPS-specific parts of the GOT. + void writeMipsGot(uint8_t *Buf); +}; + +template +class GotPltSection final : public SyntheticInputSection { + typedef typename ELFT::uint uintX_t; + typedef OutputSectionBase Base; + +public: + GotPltSection(); + void finalize() override; + bool needed() const override { return !empty(); } + void writeTo(uint8_t *Buf) override; + void addEntry(SymbolBody &Sym); + bool empty() const; + +private: + std::vector Entries; +}; + +// Linker generated sections which can be used as inputs. +template struct In { + static GotSection *Got; + static GotPltSection *GotPlt; + static std::vector *> Sections; +}; + +template GotPltSection *In::GotPlt; +template GotSection *In::Got; +template +std::vector *> In::Sections; template CommonInputSection *CommonInputSection::X; template typename ELFT::Shdr CommonInputSection::Hdr; Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -247,9 +247,10 @@ case R_TLSDESC_CALL: llvm_unreachable("cannot relocate hint relocs"); case R_TLSLD: - return Out::Got->getTlsIndexOff() + A - Out::Got->getSize(); + return In::Got->getTlsIndexOff() + A - + In::Got->OutSec->getSize(); case R_TLSLD_PC: - return Out::Got->getTlsIndexVA() + A - P; + return In::Got->getTlsIndexVA() + A - P; case R_THUNK_ABS: return Body.getThunkVA() + A; case R_THUNK_PC: @@ -258,14 +259,14 @@ case R_PPC_TOC: return getPPC64TocBase() + A; case R_TLSGD: - return Out::Got->getGlobalDynOffset(Body) + A - - Out::Got->getSize(); + return In::Got->getGlobalDynOffset(Body) + A - + In::Got->OutSec->getSize(); case R_TLSGD_PC: - return Out::Got->getGlobalDynAddr(Body) + A - P; + return In::Got->getGlobalDynAddr(Body) + A - P; case R_TLSDESC: - return Out::Got->getGlobalDynAddr(Body) + A; + return In::Got->getGlobalDynAddr(Body) + A; case R_TLSDESC_PAGE: - return getAArch64Page(Out::Got->getGlobalDynAddr(Body) + A) - + return getAArch64Page(In::Got->getGlobalDynAddr(Body) + A) - getAArch64Page(P); case R_PLT: return Body.getPltVA() + A; @@ -275,13 +276,13 @@ case R_SIZE: return Body.getSize() + A; case R_GOTREL: - return Body.getVA(A) - Out::Got->getVA(); + return Body.getVA(A) - In::Got->OutSec->getVA(); case R_GOTREL_FROM_END: - return Body.getVA(A) - Out::Got->getVA() - - Out::Got->getSize(); + return Body.getVA(A) - In::Got->OutSec->getVA() - + In::Got->OutSec->getSize(); case R_RELAX_TLS_GD_TO_IE_END: case R_GOT_FROM_END: - return Body.getGotOffset() + A - Out::Got->getSize(); + return Body.getGotOffset() + A - In::Got->OutSec->getSize(); case R_RELAX_TLS_GD_TO_IE_ABS: case R_GOT: return Body.getGotVA() + A; @@ -292,9 +293,10 @@ case R_GOT_PC: return Body.getGotVA() + A - P; case R_GOTONLY_PC: - return Out::Got->getVA() + A - P; + return In::Got->OutSec->getVA() + A - P; case R_GOTONLY_PC_FROM_END: - return Out::Got->getVA() + A - P + Out::Got->getSize(); + return In::Got->OutSec->getVA() + A - P + + In::Got->OutSec->getSize(); case R_RELAX_TLS_LD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_GD_TO_LE: @@ -323,19 +325,19 @@ // If relocation against MIPS local symbol requires GOT entry, this entry // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. - return Out::Got->getMipsLocalPageOffset(Body.getVA(A)); + return In::Got->getMipsLocalPageOffset(Body.getVA(A)); case R_MIPS_GOT_OFF: case R_MIPS_GOT_OFF32: // In case of MIPS if a GOT relocation has non-zero addend this addend // should be applied to the GOT entry content not to the GOT entry offset. // That is why we use separate expression type. - return Out::Got->getMipsGotOffset(Body, A); + return In::Got->getMipsGotOffset(Body, A); case R_MIPS_TLSGD: - return Out::Got->getGlobalDynOffset(Body) + - Out::Got->getMipsTlsOffset() - MipsGPOffset; + return In::Got->getGlobalDynOffset(Body) + + In::Got->getMipsTlsOffset() - MipsGPOffset; case R_MIPS_TLSLD: - return Out::Got->getTlsIndexOff() + - Out::Got->getMipsTlsOffset() - MipsGPOffset; + return In::Got->getTlsIndexOff() + In::Got->getMipsTlsOffset() - + MipsGPOffset; case R_PPC_OPD: { uint64_t SymVA = Body.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol @@ -828,6 +830,319 @@ } } +template +GotPltSection::GotPltSection() + : SyntheticInputSection(".got.plt", SHT_PROGBITS, + SHF_ALLOC | SHF_WRITE) { + this->Header.sh_addralign = this->Alignment = Target->GotPltEntrySize; +} + +template void GotPltSection::addEntry(SymbolBody &Sym) { + Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); + Entries.push_back(&Sym); +} + +template bool GotPltSection::empty() const { + return Entries.empty(); +} + +template void GotPltSection::finalize() { + this->Header.sh_size = (Target->GotPltHeaderEntriesNum + Entries.size()) * + Target->GotPltEntrySize; +} + +template void GotPltSection::writeTo(uint8_t *Buf) { + Target->writeGotPltHeader(Buf); + Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; + for (const SymbolBody *B : Entries) { + Target->writeGotPlt(Buf, *B); + Buf += sizeof(uintX_t); + } +} + +template +GotSection::GotSection() + : SyntheticInputSection(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) { + if (Config->EMachine == EM_MIPS) + this->Header.sh_flags |= SHF_MIPS_GPREL; + this->Header.sh_addralign = this->Alignment = Target->GotEntrySize; +} + +template void GotSection::addEntry(SymbolBody &Sym) { + Sym.GotIndex = Entries.size(); + Entries.push_back(&Sym); +} + +template +void GotSection::addMipsEntry(SymbolBody &Sym, uintX_t Addend, + RelExpr Expr) { + // For "true" local symbols which can be referenced from the same module + // only compiler creates two instructions for address loading: + // + // lw $8, 0($gp) # R_MIPS_GOT16 + // addi $8, $8, 0 # R_MIPS_LO16 + // + // The first instruction loads high 16 bits of the symbol address while + // the second adds an offset. That allows to reduce number of required + // GOT entries because only one global offset table entry is necessary + // for every 64 KBytes of local data. So for local symbols we need to + // allocate number of GOT entries to hold all required "page" addresses. + // + // All global symbols (hidden and regular) considered by compiler uniformly. + // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation + // to load address of the symbol. So for each such symbol we need to + // allocate dedicated GOT entry to store its address. + // + // If a symbol is preemptible we need help of dynamic linker to get its + // final address. The corresponding GOT entries are allocated in the + // "global" part of GOT. Entries for non preemptible global symbol allocated + // in the "local" part of GOT. + // + // See "Global Offset Table" in Chapter 5: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Expr == R_MIPS_GOT_LOCAL_PAGE) { + // At this point we do not know final symbol value so to reduce number + // of allocated GOT entries do the following trick. Save all output + // sections referenced by GOT relocations. Then later in the `finalize` + // method calculate number of "pages" required to cover all saved output + // section and allocate appropriate number of GOT entries. + auto *OutSec = cast>(&Sym)->Section->OutSec; + MipsOutSections.insert(OutSec); + return; + } + if (Sym.isTls()) { + // GOT entries created for MIPS TLS relocations behave like + // almost GOT entries from other ABIs. They go to the end + // of the global offset table. + Sym.GotIndex = Entries.size(); + Entries.push_back(&Sym); + return; + } + auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) { + if (S.isInGot() && !A) + return; + size_t NewIndex = Items.size(); + if (!MipsGotMap.insert({{&S, A}, NewIndex}).second) + return; + Items.emplace_back(&S, A); + if (!A) + S.GotIndex = NewIndex; + }; + if (Sym.isPreemptible()) { + // Ignore addends for preemptible symbols. They got single GOT entry anyway. + AddEntry(Sym, 0, MipsGlobal); + Sym.IsInGlobalMipsGot = true; + } else if (Expr == R_MIPS_GOT_OFF32) { + AddEntry(Sym, Addend, MipsLocal32); + Sym.Is32BitMipsGot = true; + } else { + // Hold local GOT entries accessed via a 16-bit index separately. + // That allows to write them in the beginning of the GOT and keep + // their indexes as less as possible to escape relocation's overflow. + AddEntry(Sym, Addend, MipsLocal); + } +} + +template bool GotSection::addDynTlsEntry(SymbolBody &Sym) { + if (Sym.GlobalDynIndex != -1U) + return false; + Sym.GlobalDynIndex = Entries.size(); + // Global Dynamic TLS entries take two GOT slots. + Entries.push_back(nullptr); + Entries.push_back(&Sym); + return true; +} + +// Reserves TLS entries for a TLS module ID and a TLS block offset. +// In total it takes two GOT slots. +template bool GotSection::addTlsIndex() { + if (TlsIndexOff != uint32_t(-1)) + return false; + TlsIndexOff = Entries.size() * sizeof(uintX_t); + Entries.push_back(nullptr); + Entries.push_back(nullptr); + return true; +} + +template +typename GotSection::uintX_t +GotSection::getMipsLocalPageOffset(uintX_t EntryValue) { + // Initialize the entry by the %hi(EntryValue) expression + // but without right-shifting. + EntryValue = (EntryValue + 0x8000) & ~0xffff; + // Take into account MIPS GOT header. + // See comment in the GotSection::writeTo. + size_t NewIndex = MipsLocalGotPos.size() + 2; + auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex)); + assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries); + return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset; +} + +template +typename GotSection::uintX_t +GotSection::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const { + // Calculate offset of the GOT entries block: TLS, global, local. + uintX_t GotBlockOff; + if (B.isTls()) + GotBlockOff = getMipsTlsOffset(); + else if (B.IsInGlobalMipsGot) + GotBlockOff = getMipsLocalEntriesNum() * sizeof(uintX_t); + else if (B.Is32BitMipsGot) + GotBlockOff = (MipsPageEntries + MipsLocal.size()) * sizeof(uintX_t); + else + GotBlockOff = MipsPageEntries * sizeof(uintX_t); + // Calculate index of the GOT entry in the block. + uintX_t GotIndex; + if (B.isInGot()) + GotIndex = B.GotIndex; + else { + auto It = MipsGotMap.find({&B, Addend}); + assert(It != MipsGotMap.end()); + GotIndex = It->second; + } + return GotBlockOff + GotIndex * sizeof(uintX_t) - MipsGPOffset; +} + +template +typename GotSection::uintX_t GotSection::getMipsTlsOffset() const { + return (getMipsLocalEntriesNum() + MipsGlobal.size()) * sizeof(uintX_t); +} + +template +typename GotSection::uintX_t +GotSection::getGlobalDynAddr(const SymbolBody &B) const { + return this->OutSec->getVA() + B.GlobalDynIndex * sizeof(uintX_t); +} + +template +typename GotSection::uintX_t +GotSection::getGlobalDynOffset(const SymbolBody &B) const { + return B.GlobalDynIndex * sizeof(uintX_t); +} + +template +const SymbolBody *GotSection::getMipsFirstGlobalEntry() const { + return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first; +} + +template +unsigned GotSection::getMipsLocalEntriesNum() const { + return MipsPageEntries + MipsLocal.size() + MipsLocal32.size(); +} + +template void GotSection::finalize() { + size_t EntriesNum = Entries.size(); + if (Config->EMachine == EM_MIPS) { + // Take into account MIPS GOT header. + // See comment in the GotSection::writeTo. + MipsPageEntries += 2; + for (const OutputSectionBase *OutSec : MipsOutSections) { + // Calculate 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. + // Add 0x8000 to the section's size because the page address stored + // in the GOT entry is calculated as (value + 0x8000) & ~0xffff. + MipsPageEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff; + } + EntriesNum += getMipsLocalEntriesNum() + MipsGlobal.size(); + } + this->Header.sh_size = EntriesNum * sizeof(uintX_t); +} + +template bool GotSection::needed() const { + if (!empty()) + return true; + + // We add the .got section to the result for dynamic MIPS target because + // its address and properties are mentioned in the .dynamic section. + if (Config->EMachine == EM_MIPS && !Config->Relocatable) + return true; + + // If we have a relocation that is relative to GOT (such as GOTOFFREL), + // we need to emit a GOT even if it's empty. + return HasGotOffRel; +} + +template +static void writeUint(uint8_t *Buf, typename ELFT::uint Val) { + typedef typename ELFT::uint uintX_t; + write(Buf, Val); +} + +template void GotSection::writeMipsGot(uint8_t *Buf) { + // Set the MSB of the second GOT slot. This is not required by any + // MIPS ABI documentation, though. + // + // There is a comment in glibc saying that "The MSB of got[1] of a + // gnu object is set to identify gnu objects," and in GNU gold it + // says "the second entry will be used by some runtime loaders". + // But how this field is being used is unclear. + // + // We are not really willing to mimic other linkers behaviors + // without understanding why they do that, but because all files + // generated by GNU tools have this special GOT value, and because + // we've been doing this for years, it is probably a safe bet to + // keep doing this for now. We really need to revisit this to see + // if we had to do this. + auto *P = reinterpret_cast(Buf); + P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); + // Write 'page address' entries to the local part of the GOT. + for (std::pair &L : MipsLocalGotPos) { + uint8_t *Entry = Buf + L.second * sizeof(uintX_t); + writeUint(Entry, L.first); + } + Buf += MipsPageEntries * sizeof(uintX_t); + auto AddEntry = [&](const MipsGotEntry &SA) { + uint8_t *Entry = Buf; + Buf += sizeof(uintX_t); + const SymbolBody *Body = SA.first; + uintX_t VA = Body->template getVA(SA.second); + writeUint(Entry, VA); + }; + std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry); + std::for_each(std::begin(MipsLocal32), std::end(MipsLocal32), AddEntry); + std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry); + // Initialize TLS-related GOT entries. If the entry has a corresponding + // dynamic relocations, leave it initialized by zero. Write down adjusted + // TLS symbol's values otherwise. To calculate the adjustments use offsets + // for thread-local storage. + // https://www.linux-mips.org/wiki/NPTL + if (TlsIndexOff != -1U && !Config->Pic) + writeUint(Buf + TlsIndexOff, 1); + for (const SymbolBody *B : Entries) { + if (!B || B->isPreemptible()) + continue; + uintX_t VA = B->getVA(); + if (B->GotIndex != -1U) { + uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t); + writeUint(Entry, VA - 0x7000); + } + if (B->GlobalDynIndex != -1U) { + uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t); + writeUint(Entry, 1); + Entry += sizeof(uintX_t); + writeUint(Entry, VA - 0x8000); + } + } +} + +template void GotSection::writeTo(uint8_t *Buf) { + if (Config->EMachine == EM_MIPS) { + writeMipsGot(Buf); + return; + } + for (const SymbolBody *B : Entries) { + uint8_t *Entry = Buf; + Buf += sizeof(uintX_t); + if (!B) + continue; + if (B->isPreemptible()) + continue; // The dynamic linker will take care of it. + uintX_t VA = B->getVA(); + writeUint(Entry, VA); + } +} + template class elf::InputSectionBase; template class elf::InputSectionBase; template class elf::InputSectionBase; @@ -867,3 +1182,18 @@ template class elf::CommonInputSection; template class elf::CommonInputSection; template class elf::CommonInputSection; + +template class elf::GotPltSection; +template class elf::GotPltSection; +template class elf::GotPltSection; +template class elf::GotPltSection; + +template class elf::GotSection; +template class elf::GotSection; +template class elf::GotSection; +template class elf::GotSection; + +template class elf::DynamicSection; +template class elf::DynamicSection; +template class elf::DynamicSection; +template class elf::DynamicSection; Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -27,7 +27,6 @@ class SymbolBody; struct EhSectionPiece; template class SymbolTable; -template class SymbolTableSection; template class StringTableSection; template class EhInputSection; template class InputSection; @@ -56,8 +55,6 @@ EHFrame, EHFrameHdr, GnuHashTable, - Got, - GotPlt, HashTable, Interp, Merge, @@ -157,91 +154,6 @@ uint32_t CuTypesOffset; }; -template class GotSection final : public OutputSectionBase { - typedef OutputSectionBase Base; - typedef typename ELFT::uint uintX_t; - -public: - GotSection(); - void finalize() override; - void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody &Sym); - void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); - bool addDynTlsEntry(SymbolBody &Sym); - bool addTlsIndex(); - bool empty() const { return MipsPageEntries == 0 && Entries.empty(); } - uintX_t getMipsLocalPageOffset(uintX_t Addr); - uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const; - uintX_t getGlobalDynAddr(const SymbolBody &B) const; - uintX_t getGlobalDynOffset(const SymbolBody &B) const; - typename Base::Kind getKind() const override { return Base::Got; } - static bool classof(const Base *B) { return B->getKind() == Base::Got; } - - // Returns the symbol which corresponds to the first entry of the global part - // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic - // table properties. - // Returns nullptr if the global part is empty. - const SymbolBody *getMipsFirstGlobalEntry() const; - - // Returns the number of entries in the local part of GOT including - // the number of reserved entries. This method is MIPS-specific. - unsigned getMipsLocalEntriesNum() const; - - // Returns offset of TLS part of the MIPS GOT table. This part goes - // after 'local' and 'global' entries. - uintX_t getMipsTlsOffset() const; - - uintX_t getTlsIndexVA() { return Base::getVA() + TlsIndexOff; } - uint32_t getTlsIndexOff() const { return TlsIndexOff; } - - // Flag to force GOT to be in output if we have relocations - // that relies on its address. - bool HasGotOffRel = false; - -private: - std::vector Entries; - uint32_t TlsIndexOff = -1; - uint32_t MipsPageEntries = 0; - // Output sections referenced by MIPS GOT relocations. - llvm::SmallPtrSet *, 10> MipsOutSections; - llvm::DenseMap MipsLocalGotPos; - - // MIPS ABI requires to create unique GOT entry for each Symbol/Addend - // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal` - // or `MipsGlobal` vectors. In general it does not have a sence to take in - // account addend for preemptible symbols because the corresponding - // GOT entries should have one-to-one mapping with dynamic symbols table. - // But we use the same container's types for both kind of GOT entries - // to handle them uniformly. - typedef std::pair MipsGotEntry; - typedef std::vector MipsGotEntries; - llvm::DenseMap MipsGotMap; - MipsGotEntries MipsLocal; - MipsGotEntries MipsLocal32; - MipsGotEntries MipsGlobal; - - // Write MIPS-specific parts of the GOT. - void writeMipsGot(uint8_t *Buf); -}; - -template -class GotPltSection final : public OutputSectionBase { - typedef typename ELFT::uint uintX_t; - typedef OutputSectionBase Base; - -public: - GotPltSection(); - void finalize() override; - void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody &Sym); - bool empty() const; - typename Base::Kind getKind() const override { return Base::GotPlt; } - static bool classof(const Base *B) { return B->getKind() == Base::GotPlt; } - -private: - std::vector Entries; -}; - template class PltSection final : public OutputSectionBase { typedef OutputSectionBase Base; typedef typename ELFT::uint uintX_t; @@ -626,12 +538,15 @@ int32_t Tag; union { OutputSectionBase *OutSec; + InputSection *InSec; uint64_t Val; const SymbolBody *Sym; }; - enum KindT { SecAddr, SecSize, SymAddr, PlainInt } Kind; + enum KindT { InSecAddr, SecAddr, SecSize, SymAddr, PlainInt } Kind; Entry(int32_t Tag, OutputSectionBase *OutSec, KindT Kind = SecAddr) : Tag(Tag), OutSec(OutSec), Kind(Kind) {} + Entry(int32_t Tag, InputSection *InSec, KindT Kind = InSecAddr) + : Tag(Tag), InSec(InSec), Kind(Kind) {} 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) {} @@ -797,8 +712,6 @@ static EhOutputSection *EhFrame; static GdbIndexSection *GdbIndex; static GnuHashTableSection *GnuHashTab; - static GotPltSection *GotPlt; - static GotSection *Got; static HashTableSection *HashTab; static InterpSection *Interp; static OutputSection *Bss; @@ -868,8 +781,6 @@ template EhOutputSection *Out::EhFrame; template GdbIndexSection *Out::GdbIndex; template GnuHashTableSection *Out::GnuHashTab; -template GotPltSection *Out::GotPlt; -template GotSection *Out::Got; template HashTableSection *Out::HashTab; template InterpSection *Out::Interp; template OutputSection *Out::Bss; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -102,304 +102,6 @@ } template -GotPltSection::GotPltSection() - : OutputSectionBase(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) { - this->Header.sh_addralign = Target->GotPltEntrySize; -} - -template void GotPltSection::addEntry(SymbolBody &Sym) { - Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); - Entries.push_back(&Sym); -} - -template bool GotPltSection::empty() const { - return Entries.empty(); -} - -template void GotPltSection::finalize() { - this->Header.sh_size = (Target->GotPltHeaderEntriesNum + Entries.size()) * - Target->GotPltEntrySize; -} - -template void GotPltSection::writeTo(uint8_t *Buf) { - Target->writeGotPltHeader(Buf); - Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; - for (const SymbolBody *B : Entries) { - Target->writeGotPlt(Buf, *B); - Buf += sizeof(uintX_t); - } -} - -template -GotSection::GotSection() - : OutputSectionBase(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) { - if (Config->EMachine == EM_MIPS) - this->Header.sh_flags |= SHF_MIPS_GPREL; - this->Header.sh_addralign = Target->GotEntrySize; -} - -template void GotSection::addEntry(SymbolBody &Sym) { - Sym.GotIndex = Entries.size(); - Entries.push_back(&Sym); -} - -template -void GotSection::addMipsEntry(SymbolBody &Sym, uintX_t Addend, - RelExpr Expr) { - // For "true" local symbols which can be referenced from the same module - // only compiler creates two instructions for address loading: - // - // lw $8, 0($gp) # R_MIPS_GOT16 - // addi $8, $8, 0 # R_MIPS_LO16 - // - // The first instruction loads high 16 bits of the symbol address while - // the second adds an offset. That allows to reduce number of required - // GOT entries because only one global offset table entry is necessary - // for every 64 KBytes of local data. So for local symbols we need to - // allocate number of GOT entries to hold all required "page" addresses. - // - // All global symbols (hidden and regular) considered by compiler uniformly. - // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation - // to load address of the symbol. So for each such symbol we need to - // allocate dedicated GOT entry to store its address. - // - // If a symbol is preemptible we need help of dynamic linker to get its - // final address. The corresponding GOT entries are allocated in the - // "global" part of GOT. Entries for non preemptible global symbol allocated - // in the "local" part of GOT. - // - // See "Global Offset Table" in Chapter 5: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Expr == R_MIPS_GOT_LOCAL_PAGE) { - // At this point we do not know final symbol value so to reduce number - // of allocated GOT entries do the following trick. Save all output - // sections referenced by GOT relocations. Then later in the `finalize` - // method calculate number of "pages" required to cover all saved output - // section and allocate appropriate number of GOT entries. - auto *OutSec = cast>(&Sym)->Section->OutSec; - MipsOutSections.insert(OutSec); - return; - } - if (Sym.isTls()) { - // GOT entries created for MIPS TLS relocations behave like - // almost GOT entries from other ABIs. They go to the end - // of the global offset table. - Sym.GotIndex = Entries.size(); - Entries.push_back(&Sym); - return; - } - auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) { - if (S.isInGot() && !A) - return; - size_t NewIndex = Items.size(); - if (!MipsGotMap.insert({{&S, A}, NewIndex}).second) - return; - Items.emplace_back(&S, A); - if (!A) - S.GotIndex = NewIndex; - }; - if (Sym.isPreemptible()) { - // Ignore addends for preemptible symbols. They got single GOT entry anyway. - AddEntry(Sym, 0, MipsGlobal); - Sym.IsInGlobalMipsGot = true; - } else if (Expr == R_MIPS_GOT_OFF32) { - AddEntry(Sym, Addend, MipsLocal32); - Sym.Is32BitMipsGot = true; - } else { - // Hold local GOT entries accessed via a 16-bit index separately. - // That allows to write them in the beginning of the GOT and keep - // their indexes as less as possible to escape relocation's overflow. - AddEntry(Sym, Addend, MipsLocal); - } -} - -template bool GotSection::addDynTlsEntry(SymbolBody &Sym) { - if (Sym.GlobalDynIndex != -1U) - return false; - Sym.GlobalDynIndex = Entries.size(); - // Global Dynamic TLS entries take two GOT slots. - Entries.push_back(nullptr); - Entries.push_back(&Sym); - return true; -} - -// Reserves TLS entries for a TLS module ID and a TLS block offset. -// In total it takes two GOT slots. -template bool GotSection::addTlsIndex() { - if (TlsIndexOff != uint32_t(-1)) - return false; - TlsIndexOff = Entries.size() * sizeof(uintX_t); - Entries.push_back(nullptr); - Entries.push_back(nullptr); - return true; -} - -template -typename GotSection::uintX_t -GotSection::getMipsLocalPageOffset(uintX_t EntryValue) { - // Initialize the entry by the %hi(EntryValue) expression - // but without right-shifting. - EntryValue = (EntryValue + 0x8000) & ~0xffff; - // Take into account MIPS GOT header. - // See comment in the GotSection::writeTo. - size_t NewIndex = MipsLocalGotPos.size() + 2; - auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex)); - assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries); - return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset; -} - -template -typename GotSection::uintX_t -GotSection::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const { - // Calculate offset of the GOT entries block: TLS, global, local. - uintX_t GotBlockOff; - if (B.isTls()) - GotBlockOff = getMipsTlsOffset(); - else if (B.IsInGlobalMipsGot) - GotBlockOff = getMipsLocalEntriesNum() * sizeof(uintX_t); - else if (B.Is32BitMipsGot) - GotBlockOff = (MipsPageEntries + MipsLocal.size()) * sizeof(uintX_t); - else - GotBlockOff = MipsPageEntries * sizeof(uintX_t); - // Calculate index of the GOT entry in the block. - uintX_t GotIndex; - if (B.isInGot()) - GotIndex = B.GotIndex; - else { - auto It = MipsGotMap.find({&B, Addend}); - assert(It != MipsGotMap.end()); - GotIndex = It->second; - } - return GotBlockOff + GotIndex * sizeof(uintX_t) - MipsGPOffset; -} - -template -typename GotSection::uintX_t GotSection::getMipsTlsOffset() const { - return (getMipsLocalEntriesNum() + MipsGlobal.size()) * sizeof(uintX_t); -} - -template -typename GotSection::uintX_t -GotSection::getGlobalDynAddr(const SymbolBody &B) const { - return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t); -} - -template -typename GotSection::uintX_t -GotSection::getGlobalDynOffset(const SymbolBody &B) const { - return B.GlobalDynIndex * sizeof(uintX_t); -} - -template -const SymbolBody *GotSection::getMipsFirstGlobalEntry() const { - return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first; -} - -template -unsigned GotSection::getMipsLocalEntriesNum() const { - return MipsPageEntries + MipsLocal.size() + MipsLocal32.size(); -} - -template void GotSection::finalize() { - size_t EntriesNum = Entries.size(); - if (Config->EMachine == EM_MIPS) { - // Take into account MIPS GOT header. - // See comment in the GotSection::writeTo. - MipsPageEntries += 2; - for (const OutputSectionBase *OutSec : MipsOutSections) { - // Calculate 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. - // Add 0x8000 to the section's size because the page address stored - // in the GOT entry is calculated as (value + 0x8000) & ~0xffff. - MipsPageEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff; - } - EntriesNum += getMipsLocalEntriesNum() + MipsGlobal.size(); - } - this->Header.sh_size = EntriesNum * sizeof(uintX_t); -} - -template -static void writeUint(uint8_t *Buf, typename ELFT::uint Val) { - typedef typename ELFT::uint uintX_t; - write(Buf, Val); -} - -template void GotSection::writeMipsGot(uint8_t *Buf) { - // Set the MSB of the second GOT slot. This is not required by any - // MIPS ABI documentation, though. - // - // There is a comment in glibc saying that "The MSB of got[1] of a - // gnu object is set to identify gnu objects," and in GNU gold it - // says "the second entry will be used by some runtime loaders". - // But how this field is being used is unclear. - // - // We are not really willing to mimic other linkers behaviors - // without understanding why they do that, but because all files - // generated by GNU tools have this special GOT value, and because - // we've been doing this for years, it is probably a safe bet to - // keep doing this for now. We really need to revisit this to see - // if we had to do this. - auto *P = reinterpret_cast(Buf); - P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); - // Write 'page address' entries to the local part of the GOT. - for (std::pair &L : MipsLocalGotPos) { - uint8_t *Entry = Buf + L.second * sizeof(uintX_t); - writeUint(Entry, L.first); - } - Buf += MipsPageEntries * sizeof(uintX_t); - auto AddEntry = [&](const MipsGotEntry &SA) { - uint8_t *Entry = Buf; - Buf += sizeof(uintX_t); - const SymbolBody *Body = SA.first; - uintX_t VA = Body->template getVA(SA.second); - writeUint(Entry, VA); - }; - std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry); - std::for_each(std::begin(MipsLocal32), std::end(MipsLocal32), AddEntry); - std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry); - // Initialize TLS-related GOT entries. If the entry has a corresponding - // dynamic relocations, leave it initialized by zero. Write down adjusted - // TLS symbol's values otherwise. To calculate the adjustments use offsets - // for thread-local storage. - // https://www.linux-mips.org/wiki/NPTL - if (TlsIndexOff != -1U && !Config->Pic) - writeUint(Buf + TlsIndexOff, 1); - for (const SymbolBody *B : Entries) { - if (!B || B->isPreemptible()) - continue; - uintX_t VA = B->getVA(); - if (B->GotIndex != -1U) { - uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t); - writeUint(Entry, VA - 0x7000); - } - if (B->GlobalDynIndex != -1U) { - uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t); - writeUint(Entry, 1); - Entry += sizeof(uintX_t); - writeUint(Entry, VA - 0x8000); - } - } -} - -template void GotSection::writeTo(uint8_t *Buf) { - if (Config->EMachine == EM_MIPS) { - writeMipsGot(Buf); - return; - } - for (const SymbolBody *B : Entries) { - uint8_t *Entry = Buf; - Buf += sizeof(uintX_t); - if (!B) - continue; - if (B->isPreemptible()) - continue; // The dynamic linker will take care of it. - uintX_t VA = B->getVA(); - writeUint(Entry, VA); - } -} - -template PltSection::PltSection() : OutputSectionBase(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) { this->Header.sh_addralign = 16; @@ -467,11 +169,12 @@ if (Config->Rela) P->r_addend = Rel.getAddend(); P->r_offset = Rel.getOffset(); - if (Config->EMachine == EM_MIPS && Rel.getOutputSec() == Out::Got) + if (Config->EMachine == EM_MIPS && + Rel.getOutputSec() == In::Got->OutSec) // Dynamic relocation against MIPS GOT section make deal TLS entries // allocated in the end of the GOT. We need to adjust the offset to take // in account 'local' and 'global' GOT entries. - P->r_offset += Out::Got->getMipsTlsOffset(); + P->r_offset += In::Got->getMipsTlsOffset(); P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL); } @@ -769,7 +472,7 @@ Add({DT_JMPREL, Out::RelaPlt}); Add({DT_PLTRELSZ, Out::RelaPlt->getSize()}); Add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, - Out::GotPlt}); + In::GotPlt}); Add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)}); } @@ -840,12 +543,12 @@ Add({DT_MIPS_FLAGS, RHF_NOTPOT}); Add({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); Add({DT_MIPS_SYMTABNO, Out::DynSymTab->getNumSymbols()}); - Add({DT_MIPS_LOCAL_GOTNO, Out::Got->getMipsLocalEntriesNum()}); - if (const SymbolBody *B = Out::Got->getMipsFirstGlobalEntry()) + Add({DT_MIPS_LOCAL_GOTNO, In::Got->getMipsLocalEntriesNum()}); + if (const SymbolBody *B = In::Got->getMipsFirstGlobalEntry()) Add({DT_MIPS_GOTSYM, B->DynsymIndex}); else Add({DT_MIPS_GOTSYM, Out::DynSymTab->getNumSymbols()}); - Add({DT_PLTGOT, Out::Got}); + Add({DT_PLTGOT, In::Got}); if (Out::MipsRldMap) Add({DT_MIPS_RLD_MAP, Out::MipsRldMap}); } @@ -863,6 +566,9 @@ case Entry::SecAddr: P->d_un.d_ptr = E.OutSec->getVA(); break; + case Entry::InSecAddr: + P->d_un.d_ptr = E.InSec->OutSec->getVA() + E.InSec->OutSecOff; + break; case Entry::SecSize: P->d_un.d_val = E.OutSec->getSize(); break; @@ -1810,7 +1516,7 @@ if (Config->Relocatable) R->ri_gp_value = 0; else - R->ri_gp_value = Out::Got->getVA() + MipsGPOffset; + R->ri_gp_value = In::Got->OutSec->getVA() + MipsGPOffset; R->ri_gprmask = GprMask; } @@ -1842,7 +1548,7 @@ if (Config->Relocatable) Reg->ri_gp_value = 0; else - Reg->ri_gp_value = Out::Got->getVA() + MipsGPOffset; + Reg->ri_gp_value = In::Got->OutSec->getVA() + MipsGPOffset; Reg->ri_gprmask = GprMask; } @@ -2008,16 +1714,6 @@ template class EhFrameHeader; template class EhFrameHeader; -template class GotPltSection; -template class GotPltSection; -template class GotPltSection; -template class GotPltSection; - -template class GotSection; -template class GotSection; -template class GotSection; -template class GotSection; - template class PltSection; template class PltSection; template class PltSection; Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -100,23 +100,23 @@ typename ELFT::uint Addend, RelExpr Expr) { if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) { - if (Out::Got->addTlsIndex() && + if (In::Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM)) - Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, - Out::Got->getTlsIndexOff(), false, + Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, In::Got, + In::Got->getTlsIndexOff(), false, nullptr, 0}); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } typedef typename ELFT::uint uintX_t; if (Target->isTlsGlobalDynamicRel(Type)) { - if (Out::Got->addDynTlsEntry(Body) && + if (In::Got->addDynTlsEntry(Body) && (Body.isPreemptible() || Config->EMachine == EM_ARM)) { - uintX_t Off = Out::Got->getGlobalDynOffset(Body); + uintX_t Off = In::Got->getGlobalDynOffset(Body); Out::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, Out::Got, Off, false, &Body, 0}); + {Target->TlsModuleIndexRel, In::Got, Off, false, &Body, 0}); if (Body.isPreemptible()) - Out::RelaDyn->addReloc({Target->TlsOffsetRel, Out::Got, + Out::RelaDyn->addReloc({Target->TlsOffsetRel, In::Got, Off + (uintX_t)sizeof(uintX_t), false, &Body, 0}); } @@ -146,10 +146,10 @@ if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC_CALL) && Config->Shared) { - if (Out::Got->addDynTlsEntry(Body)) { - uintX_t Off = Out::Got->getGlobalDynOffset(Body); + if (In::Got->addDynTlsEntry(Body)) { + uintX_t Off = In::Got->getGlobalDynOffset(Body); Out::RelaDyn->addReloc( - {Target->TlsDescRel, Out::Got, Off, false, &Body, 0}); + {Target->TlsDescRel, In::Got, Off, false, &Body, 0}); } if (Expr != R_TLSDESC_CALL) C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); @@ -163,9 +163,9 @@ {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); return 2; } - if (Out::Got->addTlsIndex()) - Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, - Out::Got->getTlsIndexOff(), false, + if (In::Got->addTlsIndex()) + Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, In::Got, + In::Got->getTlsIndexOff(), false, nullptr, 0}); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; @@ -181,15 +181,15 @@ if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_TLSDESC_CALL || Target->isTlsGlobalDynamicRel(Type)) { if (Config->Shared) { - if (Out::Got->addDynTlsEntry(Body)) { - uintX_t Off = Out::Got->getGlobalDynOffset(Body); + if (In::Got->addDynTlsEntry(Body)) { + uintX_t Off = In::Got->getGlobalDynOffset(Body); Out::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, Out::Got, Off, false, &Body, 0}); + {Target->TlsModuleIndexRel, In::Got, Off, false, &Body, 0}); // If the symbol is preemptible we need the dynamic linker to write // the offset too. if (isPreemptible(Body, Type)) - Out::RelaDyn->addReloc({Target->TlsOffsetRel, Out::Got, + Out::RelaDyn->addReloc({Target->TlsOffsetRel, In::Got, Off + (uintX_t)sizeof(uintX_t), false, &Body, 0}); } @@ -204,8 +204,8 @@ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, Offset, Addend, &Body}); if (!Body.isInGot()) { - Out::Got->addEntry(Body); - Out::RelaDyn->addReloc({Target->TlsGotRel, Out::Got, + In::Got->addEntry(Body); + Out::RelaDyn->addReloc({Target->TlsGotRel, In::Got, Body.getGotOffset(), false, &Body, 0}); } @@ -613,7 +613,7 @@ // needs it to be created. Here we request for that. if (Expr == R_GOTONLY_PC || Expr == R_GOTONLY_PC_FROM_END || Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || Expr == R_PPC_TOC) - Out::Got->HasGotOffRel = true; + In::Got->HasGotOffRel = true; uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body); @@ -667,7 +667,7 @@ // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 if (Config->EMachine == EM_MIPS) - Out::Got->addMipsEntry(Body, Addend, Expr); + In::Got->addMipsEntry(Body, Addend, Expr); continue; } @@ -686,8 +686,8 @@ else Rel = Target->PltRel; - Out::GotPlt->addEntry(Body); - Out::RelaPlt->addReloc({Rel, Out::GotPlt, + In::GotPlt->addEntry(Body); + Out::RelaPlt->addReloc({Rel, In::GotPlt, Body.getGotPltOffset(), !Preemptible, &Body, 0}); continue; @@ -702,9 +702,9 @@ // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Out::Got->addMipsEntry(Body, Addend, Expr); + In::Got->addMipsEntry(Body, Addend, Expr); if (Body.isTls() && Body.isPreemptible()) - AddDyn({Target->TlsGotRel, Out::Got, Body.getGotOffset(), + AddDyn({Target->TlsGotRel, In::Got, Body.getGotOffset(), false, &Body, 0}); continue; } @@ -712,7 +712,7 @@ if (Body.isInGot()) continue; - Out::Got->addEntry(Body); + In::Got->addEntry(Body); if (Preemptible || (Config->Pic && !isAbsolute(Body))) { uint32_t DynType; if (Body.isTls()) @@ -721,8 +721,8 @@ DynType = Target->GotRel; else DynType = Target->RelativeRel; - AddDyn({DynType, Out::Got, Body.getGotOffset(), - !Preemptible, &Body, 0}); + AddDyn({DynType, In::Got, Body.getGotOffset(), !Preemptible, + &Body, 0}); } continue; } Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -151,7 +151,7 @@ } template typename ELFT::uint SymbolBody::getGotVA() const { - return Out::Got->getVA() + getGotOffset(); + return In::Got->OutSec->getVA() + getGotOffset(); } template typename ELFT::uint SymbolBody::getGotOffset() const { @@ -159,7 +159,7 @@ } template typename ELFT::uint SymbolBody::getGotPltVA() const { - return Out::GotPlt->getVA() + getGotPltOffset(); + return In::GotPlt->OutSec->getVA() + getGotPltOffset(); } template typename ELFT::uint SymbolBody::getGotPltOffset() const { Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -401,7 +401,7 @@ 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop }; memcpy(Buf, PltData, sizeof(PltData)); - uint32_t Got = Out::GotPlt->getVA(); + uint32_t Got = In::GotPlt->OutSec->getVA(); write32le(Buf + 2, Got + 4); write32le(Buf + 8, Got + 8); } @@ -418,7 +418,7 @@ // jmp *foo@GOT(%ebx) or jmp *foo_in_GOT Buf[1] = Config->Pic ? 0xa3 : 0x25; - uint32_t Got = Out::GotPlt->getVA(); + uint32_t Got = In::GotPlt->OutSec->getVA(); write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr); write32le(Buf + 7, RelOff); write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); @@ -611,7 +611,7 @@ 0x0f, 0x1f, 0x40, 0x00 // nopl 0x0(rax) }; memcpy(Buf, PltData, sizeof(PltData)); - uint64_t Got = Out::GotPlt->getVA(); + uint64_t Got = In::GotPlt->OutSec->getVA(); uint64_t Plt = Out::Plt->getVA(); write32le(Buf + 2, Got - Plt + 2); // GOT+8 write32le(Buf + 8, Got - Plt + 4); // GOT+16 @@ -1004,7 +1004,7 @@ // TOC starts where the first of these sections starts. We always create a // .got when we see a relocation that uses it, so for us the start is always // the .got. - uint64_t TocVA = Out::Got->getVA(); + uint64_t TocVA = In::Got->OutSec->getVA(); // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. Note that the glibc startup @@ -1259,7 +1259,7 @@ }; memcpy(Buf, PltData, sizeof(PltData)); - uint64_t Got = Out::GotPlt->getVA(); + uint64_t Got = In::GotPlt->OutSec->getVA(); uint64_t Plt = Out::Plt->getVA(); relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); @@ -1613,7 +1613,7 @@ 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8 }; memcpy(Buf, PltData, sizeof(PltData)); - uint64_t GotPlt = Out::GotPlt->getVA(); + uint64_t GotPlt = In::GotPlt->OutSec->getVA(); uint64_t L1 = Out::Plt->getVA() + 8; write32le(Buf + 16, GotPlt - L1 - 8); } @@ -2038,7 +2038,7 @@ write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 write32(Buf + 24, 0x0320f809); // jalr $25 write32(Buf + 28, 0x2718fffe); // subu $24, $24, 2 - uint64_t Got = Out::GotPlt->getVA(); + uint64_t Got = In::GotPlt->OutSec->getVA(); writeMipsHi16(Buf, Got); writeMipsLo16(Buf + 4, Got); writeMipsLo16(Buf + 8, Got); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -50,13 +50,14 @@ void copyLocalSymbols(); void addReservedSymbols(); + void addInputSec(InputSectionBase *S); void createSections(); void forEachRelSec(std::function &, const typename ELFT::Shdr &)> Fn); void sortSections(); + void addLinkerGeneratedSections(); void finalizeSections(); void addPredefinedSections(); - bool needsGot(); std::vector createPhdrs(); void assignAddresses(); @@ -218,8 +219,6 @@ Out::EhFrameHdr = EhFrameHdr.get(); Out::GdbIndex = GdbIndex.get(); Out::GnuHashTab = GnuHashTab.get(); - Out::Got = &Got; - Out::GotPlt = GotPlt.get(); Out::HashTab = HashTab.get(); Out::Interp = Interp.get(); Out::Plt = &Plt; @@ -242,6 +241,11 @@ Out::InitArray = nullptr; Out::FiniArray = nullptr; + // Initialize linker generated sections. + In::Got = &Got; + In::GotPlt = GotPlt.get(); + In::Sections = {&Got, GotPlt.get()}; + Writer().run(); Out::Pool.clear(); } @@ -426,9 +430,9 @@ if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY || Type == SHT_PREINIT_ARRAY) return true; - if (Sec == Out::GotPlt) + if (Sec == In::GotPlt->OutSec) return Config->ZNow; - if (Sec == Out::Dynamic || Sec == Out::Got) + if (Sec == Out::Dynamic || Sec == In::Got->OutSec) return true; StringRef S = Sec->getName(); return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || @@ -548,15 +552,23 @@ } template +static bool shouldAddOptional(StringRef Name, Symbol *&Result) { + Result = nullptr; + if (SymbolBody *S = Symtab::X->find(Name)) { + Result = S->symbol(); + return S->isUndefined() || S->isShared(); + } + return false; +} + +template static Symbol * addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec, typename ELFT::uint Val, uint8_t StOther = STV_HIDDEN) { - SymbolBody *S = Symtab::X->find(Name); - if (!S) - return nullptr; - if (!S->isUndefined() && !S->isShared()) - return S->symbol(); - return Symtab::X->addSynthetic(Name, Sec, Val, StOther); + Symbol *Ret; + if (shouldAddOptional(Name, Ret)) + Ret = Symtab::X->addSynthetic(Name, Sec, Val, StOther); + return Ret; } template @@ -567,6 +579,26 @@ Symtab::X->addSynthetic(Name, Sec, Val, STV_HIDDEN); } +template +static Symbol *addRegular(StringRef Name, InputSectionBase *IS, + typename ELFT::uint Value) { + typename ELFT::Sym LocalHidden; + LocalHidden.setBindingAndType(STB_LOCAL, STT_NOTYPE); + LocalHidden.setVisibility(STV_HIDDEN); + Symbol *S = Symtab::X->addRegular(Name, LocalHidden, IS); + cast>(S->body())->Value = Value; + return S; +} + +template +static Symbol *addOptionalRegular(StringRef Name, InputSectionBase *S, + typename ELFT::uint Value) { + Symbol *Ret; + if (shouldAddOptional(Name, Ret)) + Ret = addRegular(Name, S, Value); + return Ret; +} + // The beginning and the ending of .rel[a].plt section are marked // with __rel[a]_iplt_{start,end} symbols if it is a statically linked // executable. The runtime needs these symbols in order to resolve @@ -592,13 +624,11 @@ // so that it points to an absolute address which is relative to GOT. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Symtab::X->addSynthetic("_gp", Out::Got, MipsGPOffset, - STV_HIDDEN); + addRegular("_gp", In::Got, MipsGPOffset); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. - Symbol *Sym = - addOptionalSynthetic("_gp_disp", Out::Got, MipsGPOffset); + Symbol *Sym = addOptionalRegular("_gp_disp", In::Got, MipsGPOffset); if (Sym) ElfSym::MipsGpDisp = Sym->body(); @@ -606,7 +636,7 @@ // pointer. This symbol is used in the code generated by .cpload pseudo-op // in case of using -mno-shared option. // https://sourceware.org/ml/binutils/2004-12/msg00094.html - addOptionalSynthetic("__gnu_local_gp", Out::Got, MipsGPOffset); + addOptionalRegular("__gnu_local_gp", In::Got, MipsGPOffset); } // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol @@ -697,6 +727,17 @@ } } +template +void Writer::addInputSec(InputSectionBase *IS) { + OutputSectionBase *Sec; + bool IsNew; + StringRef OutsecName = getOutputSectionName(IS->Name, Alloc); + std::tie(Sec, IsNew) = Factory.create(IS, OutsecName); + if (IsNew) + OutputSections.push_back(Sec); + Sec->addSection(IS); +} + template void Writer::createSections() { for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) { for (InputSectionBase *IS : F->getSections()) { @@ -704,13 +745,7 @@ reportDiscarded(IS); continue; } - OutputSectionBase *Sec; - bool IsNew; - StringRef OutsecName = getOutputSectionName(IS->Name, Alloc); - std::tie(Sec, IsNew) = Factory.create(IS, OutsecName); - if (IsNew) - OutputSections.push_back(Sec); - Sec->addSection(IS); + addInputSec(IS); } } @@ -773,6 +808,12 @@ } } +template void Writer::addLinkerGeneratedSections() { + for (SyntheticInputSection *S : In::Sections) + if (S && S->needed()) + addInputSec(S); +} + // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { Out::DebugInfo = findSection(".debug_info"); @@ -842,6 +883,10 @@ // This function adds linker-created Out::* sections. addPredefinedSections(); + // Adds .got, .got.plt and other linker generated input sections to + // corresponding output sections. + addLinkerGeneratedSections(); + sortSections(); unsigned I = 1; @@ -850,6 +895,13 @@ Sec->setSHName(Out::ShStrTab->addString(Sec->getName())); } + // Finalize linker generated sections. + for (SyntheticInputSection *S : In::Sections) + if (S->OutSec) { + S->finalize(); + S->OutSec->assignOffsets(); + } + // Finalizers fix each section's size. // .dynsym is finalized early since that may fill up .gnu.hash. if (Out::DynSymTab) @@ -873,20 +925,6 @@ Sec->finalizePieces(); } -template bool Writer::needsGot() { - if (!Out::Got->empty()) - return true; - - // We add the .got section to the result for dynamic MIPS target because - // its address and properties are mentioned in the .dynamic section. - if (Config->EMachine == EM_MIPS && !Config->Relocatable) - return true; - - // If we have a relocation that is relative to GOT (such as GOTOFFREL), - // we need to emit a GOT even if it's empty. - return Out::Got->HasGotOffRel; -} - // This function add Out::* sections to OutputSections. template void Writer::addPredefinedSections() { auto Add = [&](OutputSectionBase *OS) { @@ -936,10 +974,6 @@ if (Out::RelaPlt && Out::RelaPlt->hasRelocs()) Add(Out::RelaPlt); - if (needsGot()) - Add(Out::Got); - if (Out::GotPlt && !Out::GotPlt->empty()) - Add(Out::GotPlt); if (!Out::Plt->empty()) Add(Out::Plt); if (!Out::EhFrame->empty())