[lld] r286580 - [ELF] Convert .got section to input section

Eugene Leviant via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 11 03:33:33 PST 2016


Author: evgeny777
Date: Fri Nov 11 05:33:32 2016
New Revision: 286580

URL: http://llvm.org/viewvc/llvm-project?rev=286580&view=rev
Log:
[ELF] Convert .got section to input section

Differential revision: https://reviews.llvm.org/D26498

Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/SyntheticSections.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=286580&r1=286579&r2=286580&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Fri Nov 11 05:33:32 2016
@@ -304,9 +304,9 @@ static typename ELFT::uint getSymVA(uint
   case R_TLSDESC_CALL:
     llvm_unreachable("cannot relocate hint relocs");
   case R_TLSLD:
-    return Out<ELFT>::Got->getTlsIndexOff() + A - Out<ELFT>::Got->Size;
+    return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
   case R_TLSLD_PC:
-    return Out<ELFT>::Got->getTlsIndexVA() + A - P;
+    return In<ELFT>::Got->getTlsIndexVA() + A - P;
   case R_THUNK_ABS:
     return Body.getThunkVA<ELFT>() + A;
   case R_THUNK_PC:
@@ -315,13 +315,14 @@ static typename ELFT::uint getSymVA(uint
   case R_PPC_TOC:
     return getPPC64TocBase() + A;
   case R_TLSGD:
-    return Out<ELFT>::Got->getGlobalDynOffset(Body) + A - Out<ELFT>::Got->Size;
+    return In<ELFT>::Got->getGlobalDynOffset(Body) + A -
+           In<ELFT>::Got->getSize();
   case R_TLSGD_PC:
-    return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+    return In<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
   case R_TLSDESC:
-    return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
+    return In<ELFT>::Got->getGlobalDynAddr(Body) + A;
   case R_TLSDESC_PAGE:
-    return getAArch64Page(Out<ELFT>::Got->getGlobalDynAddr(Body) + A) -
+    return getAArch64Page(In<ELFT>::Got->getGlobalDynAddr(Body) + A) -
            getAArch64Page(P);
   case R_PLT:
     return Body.getPltVA<ELFT>() + A;
@@ -331,12 +332,13 @@ static typename ELFT::uint getSymVA(uint
   case R_SIZE:
     return Body.getSize<ELFT>() + A;
   case R_GOTREL:
-    return Body.getVA<ELFT>(A) - Out<ELFT>::Got->Addr;
+    return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA();
   case R_GOTREL_FROM_END:
-    return Body.getVA<ELFT>(A) - Out<ELFT>::Got->Addr - Out<ELFT>::Got->Size;
+    return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA() -
+           In<ELFT>::Got->getSize();
   case R_RELAX_TLS_GD_TO_IE_END:
   case R_GOT_FROM_END:
-    return Body.getGotOffset<ELFT>() + A - Out<ELFT>::Got->Size;
+    return Body.getGotOffset<ELFT>() + A - In<ELFT>::Got->getSize();
   case R_RELAX_TLS_GD_TO_IE_ABS:
   case R_GOT:
     return Body.getGotVA<ELFT>() + A;
@@ -347,9 +349,9 @@ static typename ELFT::uint getSymVA(uint
   case R_GOT_PC:
     return Body.getGotVA<ELFT>() + A - P;
   case R_GOTONLY_PC:
-    return Out<ELFT>::Got->Addr + A - P;
+    return In<ELFT>::Got->getVA() + A - P;
   case R_GOTONLY_PC_FROM_END:
-    return Out<ELFT>::Got->Addr + A - P + Out<ELFT>::Got->Size;
+    return In<ELFT>::Got->getVA() + A - P + In<ELFT>::Got->getSize();
   case R_RELAX_TLS_LD_TO_LE:
   case R_RELAX_TLS_IE_TO_LE:
   case R_RELAX_TLS_GD_TO_LE:
@@ -378,19 +380,19 @@ static typename ELFT::uint getSymVA(uint
     // 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<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
+    return In<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(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<ELFT>::Got->getMipsGotOffset(Body, A);
+    return In<ELFT>::Got->getMipsGotOffset(Body, A);
   case R_MIPS_TLSGD:
-    return Out<ELFT>::Got->getGlobalDynOffset(Body) +
-           Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+    return In<ELFT>::Got->getGlobalDynOffset(Body) +
+           In<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
   case R_MIPS_TLSLD:
-    return Out<ELFT>::Got->getTlsIndexOff() +
-           Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+    return In<ELFT>::Got->getTlsIndexOff() + In<ELFT>::Got->getMipsTlsOffset() -
+           MipsGPOffset;
   case R_PPC_OPD: {
     uint64_t SymVA = Body.getVA<ELFT>(A);
     // If we have an undefined weak symbol, we might get here with a symbol

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=286580&r1=286579&r2=286580&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Fri Nov 11 05:33:32 2016
@@ -109,275 +109,6 @@ template <class ELFT> void GdbIndexSecti
 }
 
 template <class ELFT>
-GotSection<ELFT>::GotSection()
-    : OutputSectionBase(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
-  if (Config->EMachine == EM_MIPS)
-    this->Flags |= SHF_MIPS_GPREL;
-  this->Addralign = Target->GotEntrySize;
-}
-
-template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
-  Sym.GotIndex = Entries.size();
-  Entries.push_back(&Sym);
-}
-
-template <class ELFT>
-void GotSection<ELFT>::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<DefinedRegular<ELFT>>(&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 <class ELFT> bool GotSection<ELFT>::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 <class ELFT> bool GotSection<ELFT>::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 <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::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 <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::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 <class ELFT>
-typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() const {
-  return (getMipsLocalEntriesNum() + MipsGlobal.size()) * sizeof(uintX_t);
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
-  return this->Addr + B.GlobalDynIndex * sizeof(uintX_t);
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
-  return B.GlobalDynIndex * sizeof(uintX_t);
-}
-
-template <class ELFT>
-const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
-  return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
-}
-
-template <class ELFT>
-unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
-  return MipsPageEntries + MipsLocal.size() + MipsLocal32.size();
-}
-
-template <class ELFT> void GotSection<ELFT>::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->Size + 0x8000 + 0xfffe) / 0xffff;
-    }
-    EntriesNum += getMipsLocalEntriesNum() + MipsGlobal.size();
-  }
-  this->Size = EntriesNum * sizeof(uintX_t);
-}
-
-template <class ELFT>
-static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
-  typedef typename ELFT::uint uintX_t;
-  write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val);
-}
-
-template <class ELFT> void GotSection<ELFT>::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<typename ELFT::Off *>(Buf);
-  P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
-  // Write 'page address' entries to the local part of the GOT.
-  for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
-    uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
-    writeUint<ELFT>(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<ELFT>(SA.second);
-    writeUint<ELFT>(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<ELFT>(Buf + TlsIndexOff, 1);
-  for (const SymbolBody *B : Entries) {
-    if (!B || B->isPreemptible())
-      continue;
-    uintX_t VA = B->getVA<ELFT>();
-    if (B->GotIndex != -1U) {
-      uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
-      writeUint<ELFT>(Entry, VA - 0x7000);
-    }
-    if (B->GlobalDynIndex != -1U) {
-      uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
-      writeUint<ELFT>(Entry, 1);
-      Entry += sizeof(uintX_t);
-      writeUint<ELFT>(Entry, VA - 0x8000);
-    }
-  }
-}
-
-template <class ELFT> void GotSection<ELFT>::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<ELFT>();
-    writeUint<ELFT>(Entry, VA);
-  }
-}
-
-template <class ELFT>
 PltSection<ELFT>::PltSection()
     : OutputSectionBase(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) {
   this->Addralign = 16;
@@ -443,11 +174,11 @@ template <class ELFT> void RelocationSec
     if (Config->Rela)
       P->r_addend = Rel.getAddend();
     P->r_offset = Rel.getOffset();
-    if (Config->EMachine == EM_MIPS && Rel.getOutputSec() == Out<ELFT>::Got)
+    if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In<ELFT>::Got)
       // 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<ELFT>::Got->getMipsTlsOffset();
+      P->r_offset += In<ELFT>::Got->getMipsTlsOffset();
     P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
   }
 
@@ -794,12 +525,12 @@ template <class ELFT> void DynamicSectio
     Add({DT_MIPS_FLAGS, RHF_NOTPOT});
     Add({DT_MIPS_BASE_ADDRESS, Config->ImageBase});
     Add({DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols()});
-    Add({DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum()});
-    if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry())
+    Add({DT_MIPS_LOCAL_GOTNO, In<ELFT>::Got->getMipsLocalEntriesNum()});
+    if (const SymbolBody *B = In<ELFT>::Got->getMipsFirstGlobalEntry())
       Add({DT_MIPS_GOTSYM, B->DynsymIndex});
     else
       Add({DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()});
-    Add({DT_PLTGOT, Out<ELFT>::Got});
+    Add({DT_PLTGOT, In<ELFT>::Got});
     if (Out<ELFT>::MipsRldMap)
       Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap});
   }
@@ -1819,11 +1550,6 @@ template class EhFrameHeader<ELF32BE>;
 template class EhFrameHeader<ELF64LE>;
 template class EhFrameHeader<ELF64BE>;
 
-template class GotSection<ELF32LE>;
-template class GotSection<ELF32BE>;
-template class GotSection<ELF64LE>;
-template class GotSection<ELF64BE>;
-
 template class PltSection<ELF32LE>;
 template class PltSection<ELF32BE>;
 template class PltSection<ELF64LE>;

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=286580&r1=286579&r2=286580&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Fri Nov 11 05:33:32 2016
@@ -15,7 +15,6 @@
 #include "Relocations.h"
 
 #include "lld/Core/LLVM.h"
-#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/MC/StringTableBuilder.h"
 #include "llvm/Object/ELF.h"
 
@@ -50,7 +49,6 @@ public:
     EHFrame,
     EHFrameHdr,
     GnuHashTable,
-    Got,
     HashTable,
     Merge,
     Plt,
@@ -142,74 +140,6 @@ private:
   uint32_t CuTypesOffset;
 };
 
-template <class ELFT> class GotSection final : public OutputSectionBase {
-  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;
-  Kind getKind() const override { return Got; }
-  static bool classof(const OutputSectionBase *B) {
-    return B->getKind() == 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 this->Addr + 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<const SymbolBody *> Entries;
-  uint32_t TlsIndexOff = -1;
-  uint32_t MipsPageEntries = 0;
-  // Output sections referenced by MIPS GOT relocations.
-  llvm::SmallPtrSet<const OutputSectionBase *, 10> MipsOutSections;
-  llvm::DenseMap<uintX_t, size_t> 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<const SymbolBody *, uintX_t> MipsGotEntry;
-  typedef std::vector<MipsGotEntry> MipsGotEntries;
-  llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap;
-  MipsGotEntries MipsLocal;
-  MipsGotEntries MipsLocal32;
-  MipsGotEntries MipsGlobal;
-
-  // Write MIPS-specific parts of the GOT.
-  void writeMipsGot(uint8_t *Buf);
-};
-
 template <class ELFT> class PltSection final : public OutputSectionBase {
   typedef typename ELFT::uint uintX_t;
 
@@ -248,6 +178,7 @@ public:
   uintX_t getAddend() const;
   uint32_t getSymIndex() const;
   const OutputSectionBase *getOutputSec() const { return OutputSec; }
+  const InputSectionBase<ELFT> *getInputSec() const { return InputSec; }
 
   uint32_t Type;
 
@@ -661,7 +592,6 @@ template <class ELFT> struct Out {
   static EhOutputSection<ELFT> *EhFrame;
   static GdbIndexSection<ELFT> *GdbIndex;
   static GnuHashTableSection<ELFT> *GnuHashTab;
-  static GotSection<ELFT> *Got;
   static HashTableSection<ELFT> *HashTab;
   static OutputSection<ELFT> *Bss;
   static OutputSection<ELFT> *MipsRldMap;
@@ -726,7 +656,6 @@ template <class ELFT> EhFrameHeader<ELFT
 template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
 template <class ELFT> GdbIndexSection<ELFT> *Out<ELFT>::GdbIndex;
 template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab;
-template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got;
 template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab;
 template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
 template <class ELFT> OutputSection<ELFT> *Out<ELFT>::MipsRldMap;

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=286580&r1=286579&r2=286580&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Fri Nov 11 05:33:32 2016
@@ -101,23 +101,23 @@ static unsigned handleNoRelaxTlsRelocati
                                            typename ELFT::uint Addend,
                                            RelExpr Expr) {
   if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) {
-    if (Out<ELFT>::Got->addTlsIndex() &&
+    if (In<ELFT>::Got->addTlsIndex() &&
         (Config->Pic || Config->EMachine == EM_ARM))
-      Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
-                                    Out<ELFT>::Got->getTlsIndexOff(), false,
+      Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::Got,
+                                    In<ELFT>::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<ELFT>::Got->addDynTlsEntry(Body) &&
+    if (In<ELFT>::Got->addDynTlsEntry(Body) &&
         (Body.isPreemptible() || Config->EMachine == EM_ARM)) {
-      uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+      uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
       Out<ELFT>::RelaDyn->addReloc(
-          {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
+          {Target->TlsModuleIndexRel, In<ELFT>::Got, Off, false, &Body, 0});
       if (Body.isPreemptible())
-        Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
+        Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::Got,
                                       Off + (uintX_t)sizeof(uintX_t), false,
                                       &Body, 0});
     }
@@ -147,10 +147,10 @@ static unsigned handleTlsRelocation(uint
 
   if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC_CALL) &&
       Config->Shared) {
-    if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
-      uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+    if (In<ELFT>::Got->addDynTlsEntry(Body)) {
+      uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
       Out<ELFT>::RelaDyn->addReloc(
-          {Target->TlsDescRel, Out<ELFT>::Got, Off, false, &Body, 0});
+          {Target->TlsDescRel, In<ELFT>::Got, Off, false, &Body, 0});
     }
     if (Expr != R_TLSDESC_CALL)
       C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
@@ -164,9 +164,9 @@ static unsigned handleTlsRelocation(uint
           {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
       return 2;
     }
-    if (Out<ELFT>::Got->addTlsIndex())
-      Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
-                                    Out<ELFT>::Got->getTlsIndexOff(), false,
+    if (In<ELFT>::Got->addTlsIndex())
+      Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::Got,
+                                    In<ELFT>::Got->getTlsIndexOff(), false,
                                     nullptr, 0});
     C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
     return 1;
@@ -182,15 +182,15 @@ static unsigned handleTlsRelocation(uint
   if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_TLSDESC_CALL ||
       Target->isTlsGlobalDynamicRel(Type)) {
     if (Config->Shared) {
-      if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
-        uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+      if (In<ELFT>::Got->addDynTlsEntry(Body)) {
+        uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
         Out<ELFT>::RelaDyn->addReloc(
-            {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
+            {Target->TlsModuleIndexRel, In<ELFT>::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<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
+          Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::Got,
                                         Off + (uintX_t)sizeof(uintX_t), false,
                                         &Body, 0});
       }
@@ -205,8 +205,8 @@ static unsigned handleTlsRelocation(uint
           {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
            Offset, Addend, &Body});
       if (!Body.isInGot()) {
-        Out<ELFT>::Got->addEntry(Body);
-        Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got,
+        In<ELFT>::Got->addEntry(Body);
+        Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, In<ELFT>::Got,
                                       Body.getGotOffset<ELFT>(), false, &Body,
                                       0});
       }
@@ -671,7 +671,7 @@ static void scanRelocs(InputSectionBase<
     // 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<ELFT>::Got->HasGotOffRel = true;
+      In<ELFT>::Got->HasGotOffRel = true;
 
     uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body);
 
@@ -725,7 +725,7 @@ static void scanRelocs(InputSectionBase<
       // a dynamic relocation.
       // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
       if (Config->EMachine == EM_MIPS)
-        Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+        In<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
       continue;
     }
 
@@ -760,9 +760,9 @@ static void scanRelocs(InputSectionBase<
         // 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<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+        In<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
         if (Body.isTls() && Body.isPreemptible())
-          AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
+          AddDyn({Target->TlsGotRel, In<ELFT>::Got, Body.getGotOffset<ELFT>(),
                   false, &Body, 0});
         continue;
       }
@@ -770,7 +770,7 @@ static void scanRelocs(InputSectionBase<
       if (Body.isInGot())
         continue;
 
-      Out<ELFT>::Got->addEntry(Body);
+      In<ELFT>::Got->addEntry(Body);
       if (Preemptible || (Config->Pic && !isAbsolute<ELFT>(Body))) {
         uint32_t DynType;
         if (Body.isTls())
@@ -779,8 +779,8 @@ static void scanRelocs(InputSectionBase<
           DynType = Target->GotRel;
         else
           DynType = Target->RelativeRel;
-        AddDyn({DynType, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
-                !Preemptible, &Body, 0});
+        AddDyn({DynType, In<ELFT>::Got, Body.getGotOffset<ELFT>(), !Preemptible,
+                &Body, 0});
       }
       continue;
     }

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=286580&r1=286579&r2=286580&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Fri Nov 11 05:33:32 2016
@@ -151,7 +151,7 @@ typename ELFT::uint SymbolBody::getVA(ty
 }
 
 template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
-  return Out<ELFT>::Got->Addr + getGotOffset<ELFT>();
+  return In<ELFT>::Got->getVA() + getGotOffset<ELFT>();
 }
 
 template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=286580&r1=286579&r2=286580&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Fri Nov 11 05:33:32 2016
@@ -198,7 +198,7 @@ MipsOptionsSection<ELFT>::MipsOptionsSec
 template <class ELFT> void MipsOptionsSection<ELFT>::finalize() {
   if (!Config->Relocatable)
     getOptions()->getRegInfo().ri_gp_value =
-        Out<ELFT>::Got->Addr + MipsGPOffset;
+        In<ELFT>::Got->getVA() + MipsGPOffset;
 }
 
 // MIPS .reginfo section.
@@ -226,7 +226,7 @@ MipsReginfoSection<ELFT>::MipsReginfoSec
 
 template <class ELFT> void MipsReginfoSection<ELFT>::finalize() {
   if (!Config->Relocatable)
-    Reginfo.ri_gp_value = Out<ELFT>::Got->Addr + MipsGPOffset;
+    Reginfo.ri_gp_value = In<ELFT>::Got->getVA() + MipsGPOffset;
 }
 
 static ArrayRef<uint8_t> createInterp() {
@@ -345,6 +345,275 @@ void BuildIdHexstring<ELFT>::writeBuildI
 }
 
 template <class ELFT>
+GotSection<ELFT>::GotSection()
+    : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+                             Target->GotEntrySize, ".got") {
+  if (Config->EMachine == EM_MIPS)
+    this->Flags |= SHF_MIPS_GPREL;
+}
+
+template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
+  Sym.GotIndex = Entries.size();
+  Entries.push_back(&Sym);
+}
+
+template <class ELFT>
+void GotSection<ELFT>::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<DefinedRegular<ELFT>>(&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 <class ELFT> bool GotSection<ELFT>::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 <class ELFT> bool GotSection<ELFT>::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 <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::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 <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::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 <class ELFT>
+typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() const {
+  return (getMipsLocalEntriesNum() + MipsGlobal.size()) * sizeof(uintX_t);
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
+  return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
+  return B.GlobalDynIndex * sizeof(uintX_t);
+}
+
+template <class ELFT>
+const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
+  return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
+}
+
+template <class ELFT>
+unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
+  return MipsPageEntries + MipsLocal.size() + MipsLocal32.size();
+}
+
+template <class ELFT> void GotSection<ELFT>::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->Size + 0x8000 + 0xfffe) / 0xffff;
+    }
+    EntriesNum += getMipsLocalEntriesNum() + MipsGlobal.size();
+  }
+  Size = EntriesNum * sizeof(uintX_t);
+}
+
+template <class ELFT>
+static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
+  typedef typename ELFT::uint uintX_t;
+  write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val);
+}
+
+template <class ELFT> void GotSection<ELFT>::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<typename ELFT::Off *>(Buf);
+  P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
+  // Write 'page address' entries to the local part of the GOT.
+  for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
+    uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
+    writeUint<ELFT>(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<ELFT>(SA.second);
+    writeUint<ELFT>(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<ELFT>(Buf + TlsIndexOff, 1);
+  for (const SymbolBody *B : Entries) {
+    if (!B || B->isPreemptible())
+      continue;
+    uintX_t VA = B->getVA<ELFT>();
+    if (B->GotIndex != -1U) {
+      uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
+      writeUint<ELFT>(Entry, VA - 0x7000);
+    }
+    if (B->GlobalDynIndex != -1U) {
+      uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
+      writeUint<ELFT>(Entry, 1);
+      Entry += sizeof(uintX_t);
+      writeUint<ELFT>(Entry, VA - 0x8000);
+    }
+  }
+}
+
+template <class ELFT> void GotSection<ELFT>::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<ELFT>();
+    writeUint<ELFT>(Entry, VA);
+  }
+}
+
+template <class ELFT>
 GotPltSection<ELFT>::GotPltSection()
     : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
                              Target->GotPltEntrySize, ".got.plt") {
@@ -434,6 +703,11 @@ template class elf::BuildIdHexstring<ELF
 template class elf::BuildIdHexstring<ELF64LE>;
 template class elf::BuildIdHexstring<ELF64BE>;
 
+template class elf::GotSection<ELF32LE>;
+template class elf::GotSection<ELF32BE>;
+template class elf::GotSection<ELF64LE>;
+template class elf::GotSection<ELF64BE>;
+
 template class elf::GotPltSection<ELF32LE>;
 template class elf::GotPltSection<ELF32BE>;
 template class elf::GotPltSection<ELF64LE>;

Modified: lld/trunk/ELF/SyntheticSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.h?rev=286580&r1=286579&r2=286580&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.h (original)
+++ lld/trunk/ELF/SyntheticSections.h Fri Nov 11 05:33:32 2016
@@ -11,6 +11,7 @@
 #define LLD_ELF_SYNTHETIC_SECTION_H
 
 #include "InputSection.h"
+#include "llvm/ADT/SmallPtrSet.h"
 
 namespace lld {
 namespace elf {
@@ -69,6 +70,9 @@ public:
 
   virtual void writeTo(uint8_t *Buf) = 0;
   virtual size_t getSize() const { return this->Data.size(); }
+  uintX_t getVA() const {
+    return this->OutSec ? this->OutSec->Addr + this->OutSecOff : 0;
+  }
 
   static bool classof(const InputSectionData *D) {
     return D->kind() == InputSectionData::Synthetic;
@@ -131,6 +135,72 @@ public:
   void writeBuildId(llvm::MutableArrayRef<uint8_t>) override;
 };
 
+template <class ELFT> class GotSection final : public SyntheticSection<ELFT> {
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  GotSection();
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override { return Size; }
+  void finalize();
+  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->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<const SymbolBody *> Entries;
+  uint32_t TlsIndexOff = -1;
+  uint32_t MipsPageEntries = 0;
+  uintX_t Size = 0;
+  // Output sections referenced by MIPS GOT relocations.
+  llvm::SmallPtrSet<const OutputSectionBase *, 10> MipsOutSections;
+  llvm::DenseMap<uintX_t, size_t> 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<const SymbolBody *, uintX_t> MipsGotEntry;
+  typedef std::vector<MipsGotEntry> MipsGotEntries;
+  llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap;
+  MipsGotEntries MipsLocal;
+  MipsGotEntries MipsLocal32;
+  MipsGotEntries MipsGlobal;
+
+  // Write MIPS-specific parts of the GOT.
+  void writeMipsGot(uint8_t *Buf);
+};
+
 template <class ELFT>
 class GotPltSection final : public SyntheticSection<ELFT> {
   typedef typename ELFT::uint uintX_t;
@@ -141,7 +211,6 @@ public:
   bool empty() const;
   size_t getSize() const override;
   void writeTo(uint8_t *Buf) override;
-  uintX_t getVA() { return this->OutSec->Addr + this->OutSecOff; }
 
 private:
   std::vector<const SymbolBody *> Entries;
@@ -155,6 +224,7 @@ template <class ELFT> MergeInputSection<
 template <class ELFT> struct In {
   static BuildIdSection<ELFT> *BuildId;
   static InputSection<ELFT> *Common;
+  static GotSection<ELFT> *Got;
   static GotPltSection<ELFT> *GotPlt;
   static InputSection<ELFT> *Interp;
   static MipsAbiFlagsSection<ELFT> *MipsAbiFlags;
@@ -164,6 +234,7 @@ template <class ELFT> struct In {
 
 template <class ELFT> BuildIdSection<ELFT> *In<ELFT>::BuildId;
 template <class ELFT> InputSection<ELFT> *In<ELFT>::Common;
+template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
 template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt;
 template <class ELFT> InputSection<ELFT> *In<ELFT>::Interp;
 template <class ELFT> MipsAbiFlagsSection<ELFT> *In<ELFT>::MipsAbiFlags;

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=286580&r1=286579&r2=286580&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Fri Nov 11 05:33:32 2016
@@ -1020,7 +1020,7 @@ uint64_t getPPC64TocBase() {
   // 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<ELF64BE>::Got->Addr;
+  uint64_t TocVA = In<ELF64BE>::Got->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

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=286580&r1=286579&r2=286580&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Fri Nov 11 05:33:32 2016
@@ -212,7 +212,6 @@ template <class ELFT> void Writer<ELFT>:
   Out<ELFT>::DynStrTab = make<StringTableSection<ELFT>>(".dynstr", true);
   Out<ELFT>::Dynamic = make<DynamicSection<ELFT>>();
   Out<ELFT>::EhFrame = make<EhOutputSection<ELFT>>();
-  Out<ELFT>::Got = make<GotSection<ELFT>>();
   Out<ELFT>::Plt = make<PltSection<ELFT>>();
   Out<ELFT>::RelaDyn = make<RelocationSection<ELFT>>(
       Config->Rela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
@@ -313,6 +312,7 @@ template <class ELFT> void Writer<ELFT>:
     }
   }
 
+  In<ELFT>::Got = make<GotSection<ELFT>>();
   In<ELFT>::GotPlt = make<GotPltSection<ELFT>>();
 }
 
@@ -427,7 +427,7 @@ template <class ELFT> bool elf::isRelroS
     return true;
   if (Sec == In<ELFT>::GotPlt->OutSec)
     return Config->ZNow;
-  if (Sec == Out<ELFT>::Dynamic || Sec == Out<ELFT>::Got)
+  if (Sec == Out<ELFT>::Dynamic || Sec == In<ELFT>::Got->OutSec)
     return true;
   StringRef S = Sec->getName();
   return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
@@ -557,6 +557,28 @@ static Symbol *addOptionalSynthetic(Stri
   return Symtab<ELFT>::X->addSynthetic(Name, Sec, Val, StOther);
 }
 
+template <class ELFT>
+static Symbol *addRegular(StringRef Name, InputSectionBase<ELFT> *IS,
+                          typename ELFT::uint Value) {
+  typename ELFT::Sym LocalHidden = {};
+  LocalHidden.setBindingAndType(STB_LOCAL, STT_NOTYPE);
+  LocalHidden.setVisibility(STV_HIDDEN);
+  Symbol *S = Symtab<ELFT>::X->addRegular(Name, LocalHidden, IS);
+  cast<DefinedRegular<ELFT>>(S->body())->Value = Value;
+  return S;
+}
+
+template <class ELFT>
+static Symbol *addOptionalRegular(StringRef Name, InputSectionBase<ELFT> *IS,
+                                  typename ELFT::uint Value) {
+  SymbolBody *S = Symtab<ELFT>::X->find(Name);
+  if (!S)
+    return nullptr;
+  if (!S->isUndefined() && !S->isShared())
+    return S->symbol();
+  return addRegular(Name, IS, Value);
+}
+
 // 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
@@ -582,13 +604,11 @@ template <class ELFT> void Writer<ELFT>:
     // 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<ELFT>::X->addSynthetic("_gp", Out<ELFT>::Got, MipsGPOffset,
-                                  STV_HIDDEN);
+    addRegular("_gp", In<ELFT>::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<ELFT>("_gp_disp", Out<ELFT>::Got, MipsGPOffset);
+    Symbol *Sym = addOptionalRegular("_gp_disp", In<ELFT>::Got, MipsGPOffset);
     if (Sym)
       ElfSym<ELFT>::MipsGpDisp = Sym->body();
 
@@ -596,7 +616,7 @@ template <class ELFT> void Writer<ELFT>:
     // 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<ELFT>("__gnu_local_gp", Out<ELFT>::Got, MipsGPOffset);
+    addOptionalRegular("__gnu_local_gp", In<ELFT>::Got, MipsGPOffset);
   }
 
   // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
@@ -888,13 +908,6 @@ template <class ELFT> void Writer<ELFT>:
   // This function adds linker-created Out<ELFT>::* sections.
   addPredefinedSections();
 
-  // We fill .got.plt section in scanRelocs(). This is the
-  // reason we don't add it earlier in createSections().
-  if (!In<ELFT>::GotPlt->empty()) {
-    addInputSec(In<ELFT>::GotPlt);
-    In<ELFT>::GotPlt->OutSec->assignOffsets();
-  }
-
   sortSections();
 
   unsigned I = 1;
@@ -925,7 +938,7 @@ template <class ELFT> void Writer<ELFT>:
 }
 
 template <class ELFT> bool Writer<ELFT>::needsGot() {
-  if (!Out<ELFT>::Got->empty())
+  if (!In<ELFT>::Got->empty())
     return true;
 
   // We add the .got section to the result for dynamic MIPS target because
@@ -935,7 +948,7 @@ template <class ELFT> bool Writer<ELFT>:
 
   // 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<ELFT>::Got->HasGotOffRel;
+  return In<ELFT>::Got->HasGotOffRel;
 }
 
 // This function add Out<ELFT>::* sections to OutputSections.
@@ -976,8 +989,19 @@ template <class ELFT> void Writer<ELFT>:
   if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs())
     Add(Out<ELFT>::RelaPlt);
 
-  if (needsGot())
-    Add(Out<ELFT>::Got);
+  // We fill .got and .got.plt sections in scanRelocs(). This is the
+  // reason we don't add it earlier in createSections().
+  if (needsGot()) {
+    In<ELFT>::Got->finalize();
+    addInputSec(In<ELFT>::Got);
+    In<ELFT>::Got->OutSec->assignOffsets();
+  }
+
+  if (!In<ELFT>::GotPlt->empty()) {
+    addInputSec(In<ELFT>::GotPlt);
+    In<ELFT>::GotPlt->OutSec->assignOffsets();
+  }
+
   if (!Out<ELFT>::Plt->empty())
     Add(Out<ELFT>::Plt);
   if (!Out<ELFT>::EhFrame->empty())




More information about the llvm-commits mailing list