[ELF][MIPS] Add MipsGotSection to handle MIPS GOT
authorSimon Atanasyan <simon@atanasyan.com>
Wed, 16 Nov 2016 21:01:02 +0000 (21:01 +0000)
committerSimon Atanasyan <simon@atanasyan.com>
Wed, 16 Nov 2016 21:01:02 +0000 (21:01 +0000)
MIPS GOT handling is very different from other targets so it is better
to keep the code in the separatre section class MipsGotSection. This
patch introduces the new section and moves all MIPS specific code from
GotSection to the new class. I did not rename fields and methods in the
MipsGotSection class to reduce the diff and plan to do that by the
separate commit.

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

llvm-svn: 287150

lld/ELF/InputSection.cpp
lld/ELF/Relocations.cpp
lld/ELF/Relocations.h
lld/ELF/SyntheticSections.cpp
lld/ELF/SyntheticSections.h
lld/ELF/Target.cpp
lld/ELF/Writer.cpp

index 28e1d71..7cec93d 100644 (file)
@@ -382,19 +382,21 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
     // 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 In<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
+    return In<ELFT>::MipsGot->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 In<ELFT>::Got->getMipsGotOffset(Body, A);
+    return In<ELFT>::MipsGot->getMipsGotOffset(Body, A);
+  case R_MIPS_GOTREL:
+    return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getVA() - MipsGPOffset;
   case R_MIPS_TLSGD:
-    return In<ELFT>::Got->getGlobalDynOffset(Body) +
-           In<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+    return In<ELFT>::MipsGot->getGlobalDynOffset(Body) +
+           In<ELFT>::MipsGot->getMipsTlsOffset() - MipsGPOffset;
   case R_MIPS_TLSLD:
-    return In<ELFT>::Got->getTlsIndexOff() + In<ELFT>::Got->getMipsTlsOffset() -
-           MipsGPOffset;
+    return In<ELFT>::MipsGot->getTlsIndexOff() +
+           In<ELFT>::MipsGot->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
index f68c9cf..c402bce 100644 (file)
@@ -94,30 +94,26 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
 // relocation even for non-preemptible symbols in applications. For static
 // linking support we must either resolve the module index relocation at static
 // link time, or hard code the module index (1) for the application in the GOT.
-template <class ELFT>
-static unsigned handleNoRelaxTlsRelocation(uint32_t Type, SymbolBody &Body,
-                                           InputSectionBase<ELFT> &C,
-                                           typename ELFT::uint Offset,
-                                           typename ELFT::uint Addend,
-                                           RelExpr Expr) {
+template <class ELFT, class GOT>
+static unsigned handleNoRelaxTlsRelocation(
+    GOT *Got, uint32_t Type, SymbolBody &Body, InputSectionBase<ELFT> &C,
+    typename ELFT::uint Offset, typename ELFT::uint Addend, RelExpr Expr) {
   if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) {
-    if (In<ELFT>::Got->addTlsIndex() &&
-        (Config->Pic || Config->EMachine == EM_ARM))
-      In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::Got,
-                                   In<ELFT>::Got->getTlsIndexOff(), false,
-                                   nullptr, 0});
+    if (Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM))
+      In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Got,
+                                   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 (In<ELFT>::Got->addDynTlsEntry(Body) &&
+    if (Got->addDynTlsEntry(Body) &&
         (Body.isPreemptible() || Config->EMachine == EM_ARM)) {
-      uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
+      uintX_t Off = Got->getGlobalDynOffset(Body);
       In<ELFT>::RelaDyn->addReloc(
-          {Target->TlsModuleIndexRel, In<ELFT>::Got, Off, false, &Body, 0});
+          {Target->TlsModuleIndexRel, Got, Off, false, &Body, 0});
       if (Body.isPreemptible())
-        In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::Got,
+        In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Got,
                                      Off + (uintX_t)sizeof(uintX_t), false,
                                      &Body, 0});
     }
@@ -141,9 +137,12 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
 
   typedef typename ELFT::uint uintX_t;
 
-  if (Config->EMachine == EM_MIPS || Config->EMachine == EM_ARM)
-    return handleNoRelaxTlsRelocation<ELFT>(Type, Body, C, Offset, Addend,
-                                            Expr);
+  if (Config->EMachine == EM_ARM)
+    return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::Got, Type, Body, C,
+                                            Offset, Addend, Expr);
+  if (Config->EMachine == EM_MIPS)
+    return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::MipsGot, Type, Body, C,
+                                            Offset, Addend, Expr);
 
   if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC_CALL) &&
       Config->Shared) {
@@ -300,8 +299,8 @@ static bool needsPlt(RelExpr Expr) {
 // file (PC, or GOT for example).
 static bool isRelExpr(RelExpr Expr) {
   return Expr == R_PC || Expr == R_GOTREL || Expr == R_GOTREL_FROM_END ||
-         Expr == R_PAGE_PC || Expr == R_RELAX_GOT_PC || Expr == R_THUNK_PC ||
-         Expr == R_THUNK_PLT_PC;
+         Expr == R_MIPS_GOTREL || Expr == R_PAGE_PC || Expr == R_RELAX_GOT_PC ||
+         Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC;
 }
 
 template <class ELFT>
@@ -515,11 +514,8 @@ static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File,
       // For details see p. 4-19 at
       // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
       Addend += 4;
-    if (Expr == R_GOTREL) {
-      Addend -= MipsGPOffset;
-      if (Body.isLocal())
-        Addend += File.MipsGp0;
-    }
+    if (Expr == R_MIPS_GOTREL && Body.isLocal())
+      Addend += File.MipsGp0;
   }
   if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC)
     Addend += getPPC64TocBase();
@@ -736,7 +732,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
       // a dynamic relocation.
       // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
       if (Config->EMachine == EM_MIPS)
-        In<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+        In<ELFT>::MipsGot->addEntry(Body, Addend, Expr);
       continue;
     }
 
@@ -771,10 +767,10 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
         // 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
-        In<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+        In<ELFT>::MipsGot->addEntry(Body, Addend, Expr);
         if (Body.isTls() && Body.isPreemptible())
-          AddDyn({Target->TlsGotRel, In<ELFT>::Got, Body.getGotOffset<ELFT>(),
-                  false, &Body, 0});
+          AddDyn({Target->TlsGotRel, In<ELFT>::MipsGot,
+                  Body.getGotOffset<ELFT>(), false, &Body, 0});
         continue;
       }
 
index d14b0a7..801f455 100644 (file)
@@ -37,6 +37,7 @@ enum RelExpr {
   R_MIPS_GOT_LOCAL_PAGE,
   R_MIPS_GOT_OFF,
   R_MIPS_GOT_OFF32,
+  R_MIPS_GOTREL,
   R_MIPS_TLSGD,
   R_MIPS_TLSLD,
   R_NEG_TLS,
index b84df2b..104e808 100644 (file)
@@ -198,7 +198,7 @@ MipsOptionsSection<ELFT>::MipsOptionsSection()
 template <class ELFT> void MipsOptionsSection<ELFT>::finalize() {
   if (!Config->Relocatable)
     getOptions()->getRegInfo().ri_gp_value =
-        In<ELFT>::Got->getVA() + MipsGPOffset;
+        In<ELFT>::MipsGot->getVA() + MipsGPOffset;
 }
 
 // MIPS .reginfo section.
@@ -226,7 +226,7 @@ MipsReginfoSection<ELFT>::MipsReginfoSection()
 
 template <class ELFT> void MipsReginfoSection<ELFT>::finalize() {
   if (!Config->Relocatable)
-    Reginfo.ri_gp_value = In<ELFT>::Got->getVA() + MipsGPOffset;
+    Reginfo.ri_gp_value = In<ELFT>::MipsGot->getVA() + MipsGPOffset;
 }
 
 static ArrayRef<uint8_t> createInterp() {
@@ -347,18 +347,70 @@ void BuildIdHexstring<ELFT>::writeBuildId(MutableArrayRef<uint8_t> Buf) {
 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;
-}
+                             Target->GotEntrySize, ".got") {}
 
 template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
   Sym.GotIndex = Entries.size();
   Entries.push_back(&Sym);
 }
 
+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>
-void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_t Addend,
+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> void GotSection<ELFT>::finalize() {
+  Size = Entries.size() * sizeof(uintX_t);
+}
+
+template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
+  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>();
+    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
+  }
+}
+
+template <class ELFT>
+MipsGotSection<ELFT>::MipsGotSection()
+    : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL,
+                             SHT_PROGBITS, Target->GotEntrySize, ".got") {}
+
+template <class ELFT>
+void MipsGotSection<ELFT>::addEntry(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:
@@ -427,7 +479,7 @@ void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_t Addend,
   }
 }
 
-template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+template <class ELFT> bool MipsGotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
   if (Sym.GlobalDynIndex != -1U)
     return false;
   Sym.GlobalDynIndex = Entries.size();
@@ -439,7 +491,7 @@ template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
 
 // 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() {
+template <class ELFT> bool MipsGotSection<ELFT>::addTlsIndex() {
   if (TlsIndexOff != uint32_t(-1))
     return false;
   TlsIndexOff = Entries.size() * sizeof(uintX_t);
@@ -449,13 +501,13 @@ template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
 }
 
 template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) {
+typename MipsGotSection<ELFT>::uintX_t
+MipsGotSection<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.
+  // See comment in the MipsGotSection::writeTo.
   size_t NewIndex = MipsLocalGotPos.size() + 2;
   auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex));
   assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries);
@@ -463,8 +515,8 @@ GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) {
 }
 
 template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const {
+typename MipsGotSection<ELFT>::uintX_t
+MipsGotSection<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())
@@ -488,48 +540,40 @@ GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const {
 }
 
 template <class ELFT>
-typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() const {
+typename MipsGotSection<ELFT>::uintX_t MipsGotSection<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 {
+typename MipsGotSection<ELFT>::uintX_t
+MipsGotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
   return B.GlobalDynIndex * sizeof(uintX_t);
 }
 
 template <class ELFT>
-const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
+const SymbolBody *MipsGotSection<ELFT>::getMipsFirstGlobalEntry() const {
   return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
 }
 
 template <class ELFT>
-unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
+unsigned MipsGotSection<ELFT>::getMipsLocalEntriesNum() const {
   return MipsPageEntries + MipsLocal.size() + MipsLocal32.size();
 }
 
-template <class ELFT> void GotSection<ELFT>::finalize() {
+template <class ELFT> void MipsGotSection<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();
+  // Take into account MIPS GOT header.
+  // See comment in the MipsGotSection::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);
 }
 
@@ -539,7 +583,7 @@ static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
   write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val);
 }
 
-template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *Buf) {
+template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) {
   // Set the MSB of the second GOT slot. This is not required by any
   // MIPS ABI documentation, though.
   //
@@ -596,23 +640,6 @@ template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *Buf) {
   }
 }
 
-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,
@@ -805,12 +832,12 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
     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, In<ELFT>::Got->getMipsLocalEntriesNum()});
-    if (const SymbolBody *B = In<ELFT>::Got->getMipsFirstGlobalEntry())
+    Add({DT_MIPS_LOCAL_GOTNO, In<ELFT>::MipsGot->getMipsLocalEntriesNum()});
+    if (const SymbolBody *B = In<ELFT>::MipsGot->getMipsFirstGlobalEntry())
       Add({DT_MIPS_GOTSYM, B->DynsymIndex});
     else
       Add({DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()});
-    Add({DT_PLTGOT, In<ELFT>::Got});
+    Add({DT_PLTGOT, In<ELFT>::MipsGot});
     if (Out<ELFT>::MipsRldMap)
       Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap});
   }
@@ -902,11 +929,11 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
     if (Config->Rela)
       P->r_addend = Rel.getAddend();
     P->r_offset = Rel.getOffset();
-    if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In<ELFT>::Got)
+    if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In<ELFT>::MipsGot)
       // 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 += In<ELFT>::Got->getMipsTlsOffset();
+      P->r_offset += In<ELFT>::MipsGot->getMipsTlsOffset();
     P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
   }
 
@@ -999,6 +1026,11 @@ template class elf::GotSection<ELF32BE>;
 template class elf::GotSection<ELF64LE>;
 template class elf::GotSection<ELF64BE>;
 
+template class elf::MipsGotSection<ELF32LE>;
+template class elf::MipsGotSection<ELF32BE>;
+template class elf::MipsGotSection<ELF64LE>;
+template class elf::MipsGotSection<ELF64BE>;
+
 template class elf::GotPltSection<ELF32LE>;
 template class elf::GotPltSection<ELF32BE>;
 template class elf::GotPltSection<ELF64LE>;
index f420f9b..0a3774e 100644 (file)
@@ -147,13 +147,39 @@ public:
   size_t getSize() const override { return Size; }
   void finalize() override;
   void addEntry(SymbolBody &Sym);
-  void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
+  bool addDynTlsEntry(SymbolBody &Sym);
+  bool addTlsIndex();
+  bool empty() const { return Entries.empty(); }
+  uintX_t getGlobalDynAddr(const SymbolBody &B) const;
+  uintX_t getGlobalDynOffset(const SymbolBody &B) 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;
+  uintX_t Size = 0;
+};
+
+template <class ELFT> class MipsGotSection final : public SyntheticSection<ELFT> {
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  MipsGotSection();
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override { return Size; }
+  void finalize() override;
+  void addEntry(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
@@ -170,13 +196,8 @@ public:
   // 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;
@@ -199,9 +220,6 @@ private:
   MipsGotEntries MipsLocal;
   MipsGotEntries MipsLocal32;
   MipsGotEntries MipsGlobal;
-
-  // Write MIPS-specific parts of the GOT.
-  void writeMipsGot(uint8_t *Buf);
 };
 
 template <class ELFT>
@@ -353,6 +371,7 @@ template <class ELFT> struct In {
   static DynamicSection<ELFT> *Dynamic;
   static StringTableSection<ELFT> *DynStrTab;
   static GotSection<ELFT> *Got;
+  static MipsGotSection<ELFT> *MipsGot;
   static GotPltSection<ELFT> *GotPlt;
   static InputSection<ELFT> *Interp;
   static MipsAbiFlagsSection<ELFT> *MipsAbiFlags;
@@ -369,6 +388,7 @@ template <class ELFT> InputSection<ELFT> *In<ELFT>::Common;
 template <class ELFT> DynamicSection<ELFT> *In<ELFT>::Dynamic;
 template <class ELFT> StringTableSection<ELFT> *In<ELFT>::DynStrTab;
 template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
+template <class ELFT> MipsGotSection<ELFT> *In<ELFT>::MipsGot;
 template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt;
 template <class ELFT> InputSection<ELFT> *In<ELFT>::Interp;
 template <class ELFT> MipsAbiFlagsSection<ELFT> *In<ELFT>::MipsAbiFlags;
index 447490c..3ad2316 100644 (file)
@@ -1933,7 +1933,7 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
     return R_HINT;
   case R_MIPS_GPREL16:
   case R_MIPS_GPREL32:
-    return R_GOTREL;
+    return R_MIPS_GOTREL;
   case R_MIPS_26:
     return R_PLT;
   case R_MIPS_HI16:
index 9b749c7..2fecbc0 100644 (file)
@@ -312,7 +312,11 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
     }
   }
 
-  In<ELFT>::Got = make<GotSection<ELFT>>();
+  if (Config->EMachine == EM_MIPS)
+    In<ELFT>::MipsGot = make<MipsGotSection<ELFT>>();
+  else
+    In<ELFT>::Got = make<GotSection<ELFT>>();
+
   In<ELFT>::GotPlt = make<GotPltSection<ELFT>>();
 }
 
@@ -427,7 +431,11 @@ template <class ELFT> bool elf::isRelroSection(const OutputSectionBase *Sec) {
     return true;
   if (Sec == In<ELFT>::GotPlt->OutSec)
     return Config->ZNow;
-  if (Sec == In<ELFT>::Dynamic->OutSec || Sec == In<ELFT>::Got->OutSec)
+  if (Sec == In<ELFT>::Dynamic->OutSec)
+    return true;
+  if (In<ELFT>::Got && Sec == In<ELFT>::Got->OutSec)
+    return true;
+  if (In<ELFT>::MipsGot && Sec == In<ELFT>::MipsGot->OutSec)
     return true;
   StringRef S = Sec->getName();
   return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
@@ -603,11 +611,12 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
     // 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
-    addRegular("_gp", In<ELFT>::Got, MipsGPOffset);
+    addRegular("_gp", In<ELFT>::MipsGot, MipsGPOffset);
 
     // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
     // start of function and 'gp' pointer into GOT.
-    Symbol *Sym = addOptionalRegular("_gp_disp", In<ELFT>::Got, MipsGPOffset);
+    Symbol *Sym =
+        addOptionalRegular("_gp_disp", In<ELFT>::MipsGot, MipsGPOffset);
     if (Sym)
       ElfSym<ELFT>::MipsGpDisp = Sym->body();
 
@@ -615,7 +624,7 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
     // 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
-    addOptionalRegular("__gnu_local_gp", In<ELFT>::Got, MipsGPOffset);
+    addOptionalRegular("__gnu_local_gp", In<ELFT>::MipsGot, MipsGPOffset);
   }
 
   // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
@@ -945,10 +954,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
     Sec->finalize();
 
   // Dynamic section must be the last one in this list.
-  finalizeSynthetic<ELFT>({In<ELFT>::ShStrTab, In<ELFT>::StrTab,
-                           In<ELFT>::DynStrTab, In<ELFT>::Got, In<ELFT>::GotPlt,
-                           In<ELFT>::RelaDyn, In<ELFT>::RelaPlt,
-                           In<ELFT>::Dynamic});
+  finalizeSynthetic<ELFT>(
+      {In<ELFT>::ShStrTab, In<ELFT>::StrTab, In<ELFT>::DynStrTab, In<ELFT>::Got,
+       In<ELFT>::MipsGot, In<ELFT>::GotPlt, In<ELFT>::RelaDyn,
+       In<ELFT>::RelaPlt, In<ELFT>::Dynamic});
 
   // Now that all output offsets are fixed. Finalize mergeable sections
   // to fix their maps from input offsets to output offsets.
@@ -957,12 +966,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
 }
 
 template <class ELFT> bool Writer<ELFT>::needsGot() {
-  if (!In<ELFT>::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)
+  if (Config->EMachine == EM_MIPS)
+    return !Config->Relocatable;
+
+  if (!In<ELFT>::Got->empty())
     return true;
 
   // If we have a relocation that is relative to GOT (such as GOTOFFREL),
@@ -1010,8 +1019,12 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
 
   // We fill .got and .got.plt sections in scanRelocs(). This is the
   // reason we don't add it earlier in createSections().
-  if (needsGot())
-    addInputSec(In<ELFT>::Got);
+  if (needsGot()) {
+    if (Config->EMachine == EM_MIPS)
+      addInputSec(In<ELFT>::MipsGot);
+    else
+      addInputSec(In<ELFT>::Got);
+  }
 
   if (!In<ELFT>::GotPlt->empty())
     addInputSec(In<ELFT>::GotPlt);