[lld] r273127 - [ELF][MIPS] Support GOT entries for non-preemptible symbols with different addends

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 19 14:39:38 PDT 2016


Author: atanasyan
Date: Sun Jun 19 16:39:37 2016
New Revision: 273127

URL: http://llvm.org/viewvc/llvm-project?rev=273127&view=rev
Log:
[ELF][MIPS]  Support GOT entries for non-preemptible symbols with different addends

There are two motivations for this patch. The first one is a preparation
for support MIPS TLS relocations. It might sound like a joke but for GOT
entries related to TLS relocations MIPS ABI uses almost regular approach
with creation of dynamic relocations for each GOT enty etc. But we need
to separate these 'regular' TLS related entries from MIPS specific local
and global parts of GOT. ABI declare simple solution - all TLS related
entries allocated at the end of GOT after local/global parts. The second
motivation it to support GOT relocations for non-preemptible symbols
with addends. If we have more than one GOT relocations against symbol S
with different addends we need to create GOT entries for each unique
Symbol/Addend pairs.

So we store all MIPS GOT entries in separate containers. For non-preemptible
symbols we have to maintain two data structures. The first one is MipsLocal
vector. Each entry corresponds to the GOT entry from the 'local' part
of the GOT contains the symbol's address plus addend. The second one
is MipsLocalMap. It is a map from Symbol/Addend pair to the GOT index.

Differential Revision: http://reviews.llvm.org/D21297

Added:
    lld/trunk/test/ELF/mips-64-disp.s
      - copied, changed from r273074, lld/trunk/test/ELF/mips-64-got.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Relocations.h
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/test/ELF/mips-64-got.s
    lld/trunk/test/ELF/mips-dynamic.s
    lld/trunk/test/ELF/mips-got16.s
    lld/trunk/test/ELF/mips-plt-copy.s
    lld/trunk/test/ELF/mips-sto-plt.s

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Sun Jun 19 16:39:37 2016
@@ -215,13 +215,11 @@ getSymVA(uint32_t Type, typename ELFT::u
     // 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));
-  case R_MIPS_GOT_LOCAL:
-    // For non-local symbols GOT entries should contain their full
-    // addresses. But if such symbol cannot be preempted, we do not
-    // have to put them into the "global" part of GOT and use dynamic
-    // linker to determine their actual addresses. That is why we
-    // create GOT entries for them in the "local" part of GOT.
-    return Out<ELFT>::Got->getMipsLocalEntryOffset(Body.getVA<ELFT>(A));
+  case R_MIPS_GOT_OFF:
+    // 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);
   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=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Sun Jun 19 16:39:37 2016
@@ -92,58 +92,67 @@ GotSection<ELFT>::GotSection()
   this->Header.sh_addralign = sizeof(uintX_t);
 }
 
-template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
-  if (Config->EMachine == EM_MIPS) {
-    // 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 (Sym.isLocal()) {
-      // 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.isPreemptible()) {
-      // In case of non-local symbols require an entry in the local part
-      // of MIPS GOT, we set GotIndex to 1 just to accent that this symbol
-      // has the GOT entry and escape creation more redundant GOT entries.
-      // FIXME (simon): We can try to store such symbols in the `Entries`
-      // container. But in that case we have to sort out that container
-      // and update GotIndex assigned to symbols.
-      Sym.GotIndex = 1;
-      ++MipsLocalEntries;
-      return;
-    }
-  }
+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;
+  }
+  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
+    AddEntry(Sym, Addend, MipsLocal);
+}
+
 template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
   if (Sym.GlobalDynIndex != -1U)
     return false;
@@ -170,22 +179,33 @@ typename GotSection<ELFT>::uintX_t
 GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) {
   // Initialize the entry by the %hi(EntryValue) expression
   // but without right-shifting.
-  return getMipsLocalEntryOffset((EntryValue + 0x8000) & ~0xffff);
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getMipsLocalEntryOffset(uintX_t EntryValue) {
+  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() <= MipsLocalEntries);
+  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 {
+  uintX_t Off = MipsPageEntries;
+  if (B.IsInGlobalMipsGot)
+    Off += MipsLocal.size() + B.GotIndex;
+  else if (B.isInGot())
+    Off += B.GotIndex;
+  else {
+    auto It = MipsGotMap.find({&B, Addend});
+    assert(It != MipsGotMap.end());
+    Off += It->second;
+  }
+  return Off * sizeof(uintX_t) - MipsGPOffset;
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
 GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
   return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
 }
@@ -198,12 +218,12 @@ GotSection<ELFT>::getGlobalDynOffset(con
 
 template <class ELFT>
 const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
-  return Entries.empty() ? nullptr : Entries.front();
+  return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
 }
 
 template <class ELFT>
 unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
-  return MipsLocalEntries;
+  return MipsPageEntries + MipsLocal.size();
 }
 
 template <class ELFT> void GotSection<ELFT>::finalize() {
@@ -211,55 +231,62 @@ template <class ELFT> void GotSection<EL
   if (Config->EMachine == EM_MIPS) {
     // Take into account MIPS GOT header.
     // See comment in the GotSection::writeTo.
-    MipsLocalEntries += 2;
+    MipsPageEntries += 2;
     for (const OutputSectionBase<ELFT> *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.
-      MipsLocalEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff;
+      MipsPageEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff;
     }
-    EntriesNum += MipsLocalEntries;
+    EntriesNum += MipsPageEntries + MipsLocal.size() + MipsGlobal.size();
   }
   this->Header.sh_size = EntriesNum * sizeof(uintX_t);
 }
 
-template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
-  if (Config->EMachine == EM_MIPS) {
-    // 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);
-    for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
-      uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
-      write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first);
-    }
-    Buf += MipsLocalEntries * sizeof(uintX_t);
+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);
+    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first);
   }
+  Buf += MipsPageEntries * sizeof(uintX_t);
+  auto AddEntry = [&](const MipsGotEntry &SA) {
+    uint8_t *Entry = Buf;
+    Buf += sizeof(uintX_t);
+    uintX_t VA = SA.first->template getVA<ELFT>(SA.second);
+    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
+  };
+  std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
+  std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
+}
+
+template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
+  if (Config->EMachine == EM_MIPS)
+    writeMipsGot(Buf);
   for (const SymbolBody *B : Entries) {
     uint8_t *Entry = Buf;
     Buf += sizeof(uintX_t);
     if (!B)
       continue;
-    // MIPS has special rules to fill up GOT entries.
-    // 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
-    // As the first approach, we can just store addresses for all symbols.
-    if (Config->EMachine != EM_MIPS && B->isPreemptible())
+    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);
@@ -1249,10 +1276,8 @@ static bool sortMipsSymbols(const std::p
                             const std::pair<SymbolBody *, unsigned> &R) {
   // Sort entries related to non-local preemptible symbols by GOT indexes.
   // All other entries go to the first part of GOT in arbitrary order.
-  bool LIsInLocalGot = !L.first->isInGot() || !L.first->isPreemptible();
-  bool RIsInLocalGot = !R.first->isInGot() || !R.first->isPreemptible();
-  if (LIsInLocalGot || RIsInLocalGot)
-    return !RIsInLocalGot;
+  if (!L.first->IsInGlobalMipsGot || !R.first->IsInGlobalMipsGot)
+    return !L.first->IsInGlobalMipsGot;
   return L.first->GotIndex < R.first->GotIndex;
 }
 

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Sun Jun 19 16:39:37 2016
@@ -11,6 +11,7 @@
 #define LLD_ELF_OUTPUT_SECTIONS_H
 
 #include "Config.h"
+#include "Relocations.h"
 
 #include "lld/Core/LLVM.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -113,11 +114,12 @@ public:
   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 MipsLocalEntries == 0 && Entries.empty(); }
-  uintX_t getMipsLocalEntryOffset(uintX_t EntryValue);
+  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;
   uintX_t getNumEntries() const { return Entries.size(); }
@@ -142,10 +144,26 @@ public:
 private:
   std::vector<const SymbolBody *> Entries;
   uint32_t TlsIndexOff = -1;
-  uint32_t MipsLocalEntries = 0;
+  uint32_t MipsPageEntries = 0;
   // Output sections referenced by MIPS GOT relocations.
   llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 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 MipsGlobal;
+
+  // Write MIPS-specific parts of the GOT.
+  void writeMipsGot(uint8_t *&Buf);
 };
 
 template <class ELFT>

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Sun Jun 19 16:39:37 2016
@@ -59,10 +59,10 @@ namespace lld {
 namespace elf {
 
 static bool refersToGotEntry(RelExpr Expr) {
-  return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL ||
-         Expr == R_MIPS_GOT_LOCAL_PAGE || Expr == R_GOT_PAGE_PC ||
-         Expr == R_GOT_PC || Expr == R_GOT_FROM_END || Expr == R_TLSGD ||
-         Expr == R_TLSGD_PC || Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE;
+  return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL_PAGE ||
+         Expr == R_MIPS_GOT_OFF || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC ||
+         Expr == R_GOT_FROM_END || Expr == R_TLSGD || Expr == R_TLSGD_PC ||
+         Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE;
 }
 
 static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
@@ -271,9 +271,9 @@ static bool isStaticLinkTimeConstant(Rel
                                      const SymbolBody &Body) {
   // These expressions always compute a constant
   if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF ||
-      E == R_MIPS_GOT_LOCAL || E == R_MIPS_GOT_LOCAL_PAGE ||
-      E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC ||
-      E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || E == R_HINT)
+      E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_GOT_PAGE_PC ||
+      E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || E == R_TLSGD ||
+      E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || E == R_HINT)
     return true;
 
   // These never do, except if the entire file is position dependent or if
@@ -466,8 +466,6 @@ static typename ELFT::uint computeAddend
       // For details see p. 4-19 at
       // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
       Addend += 4;
-    if (Expr == R_GOT_OFF)
-      Addend -= MipsGPOffset;
     if (Expr == R_GOTREL) {
       Addend -= MipsGPOffset;
       if (Body.isLocal())
@@ -574,8 +572,8 @@ static void scanRelocs(InputSectionBase<
       // to the GOT entry and reads the GOT entry when it needs to perform
       // a dynamic relocation.
       // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
-      if (Config->EMachine == EM_MIPS && !Body.isInGot())
-        Out<ELFT>::Got->addEntry(Body);
+      if (Config->EMachine == EM_MIPS)
+        Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
       continue;
     }
 
@@ -605,18 +603,20 @@ static void scanRelocs(InputSectionBase<
     }
 
     if (refersToGotEntry(Expr)) {
-      if (Body.isInGot())
-        continue;
-      Out<ELFT>::Got->addEntry(Body);
-
-      if (Config->EMachine == EM_MIPS)
+      if (Config->EMachine == EM_MIPS) {
         // MIPS ABI has special rules to process GOT entries
         // and doesn't require relocation entries for them.
         // 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);
+        continue;
+      }
+
+      if (Body.isInGot())
         continue;
 
+      Out<ELFT>::Got->addEntry(Body);
       if (Preemptible || (Config->Pic && !isAbsolute<ELFT>(Body))) {
         uint32_t DynType;
         if (Body.isTls())

Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Sun Jun 19 16:39:37 2016
@@ -28,8 +28,8 @@ enum RelExpr {
   R_GOT_PAGE_PC,
   R_GOT_PC,
   R_HINT,
-  R_MIPS_GOT_LOCAL,
   R_MIPS_GOT_LOCAL_PAGE,
+  R_MIPS_GOT_OFF,
   R_NEG_TLS,
   R_PAGE_PC,
   R_PC,

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Sun Jun 19 16:39:37 2016
@@ -92,12 +92,14 @@ static typename ELFT::uint getSymVA(cons
 
 SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
                        uint8_t Type)
-    : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true), Type(Type),
-      StOther(StOther), NameOffset(NameOffset) {}
+    : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true),
+      IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
+      NameOffset(NameOffset) {}
 
 SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
-    : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false), Type(Type),
-      StOther(StOther), Name({Name.data(), Name.size()}) {}
+    : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false),
+      IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
+      Name({Name.data(), Name.size()}) {}
 
 // Returns true if a symbol can be replaced at load-time by a symbol
 // with the same name defined in other ELF executable or DSO.
@@ -149,8 +151,7 @@ template <class ELFT> typename ELFT::uin
 }
 
 template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
-  return (Out<ELFT>::Got->getMipsLocalEntriesNum() + GotIndex) *
-         sizeof(typename ELFT::uint);
+  return GotIndex * sizeof(typename ELFT::uint);
 }
 
 template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Sun Jun 19 16:39:37 2016
@@ -127,6 +127,9 @@ public:
   // True if this is a local symbol.
   unsigned IsLocal : 1;
 
+  // True if this symbol has an entry in the global part of MIPS GOT.
+  unsigned IsInGlobalMipsGot : 1;
+
   // The following fields have the same meaning as the ELF symbol attributes.
   uint8_t Type;    // symbol type
   uint8_t StOther; // st_other field value

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Sun Jun 19 16:39:37 2016
@@ -1745,9 +1745,7 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr
   // fallthrough
   case R_MIPS_CALL16:
   case R_MIPS_GOT_DISP:
-    if (!S.isPreemptible())
-      return R_MIPS_GOT_LOCAL;
-    return R_GOT_OFF;
+    return R_MIPS_GOT_OFF;
   case R_MIPS_GOT_PAGE:
     return R_MIPS_GOT_LOCAL_PAGE;
   }

Copied: lld/trunk/test/ELF/mips-64-disp.s (from r273074, lld/trunk/test/ELF/mips-64-got.s)
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-64-disp.s?p2=lld/trunk/test/ELF/mips-64-disp.s&p1=lld/trunk/test/ELF/mips-64-got.s&r1=273074&r2=273127&rev=273127&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-64-got.s (original)
+++ lld/trunk/test/ELF/mips-64-disp.s Sun Jun 19 16:39:37 2016
@@ -1,4 +1,4 @@
-# Check MIPS N64 ABI GOT relocations
+# Check R_MIPS_GOT_DISP relocations against various kind of symbols.
 
 # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
 # RUN:         %p/Inputs/mips-pic.s -o %t.so.o
@@ -11,16 +11,16 @@
 # REQUIRES: mips
 
 # CHECK:      __start:
-
-# CHECK-NEXT:    20000:   df 82 80 20   ld      $2, -32736($gp)
-# CHECK-NEXT:    20004:   64 42 00 14   daddiu  $2,  $2, 20
-# CHECK-NEXT:    20008:   24 42 80 30   addiu   $2,  $2, -32720
-# CHECK-NEXT:    2000c:   24 42 80 28   addiu   $2,  $2, -32728
-
-# CHECK: 0000000000020014   .text   00000000 foo
-# CHECK: 0000000000037ff0   .got    00000000 .hidden _gp
-# CHECK: 0000000000020000   .text   00000000 __start
-# CHECK: 0000000000020010   .text   00000000 bar
+# CHECK-NEXT:    20000:   24 42 80 40   addiu   $2, $2, -32704
+# CHECK-NEXT:    20004:   24 42 80 20   addiu   $2, $2, -32736
+# CHECK-NEXT:    20008:   24 42 80 28   addiu   $2, $2, -32728
+# CHECK-NEXT:    2000c:   24 42 80 30   addiu   $2, $2, -32720
+# CHECK-NEXT:    20010:   24 42 80 38   addiu   $2, $2, -32712
+
+# CHECK: 0000000000020014     .text   00000000 foo
+# CHECK: 0000000000037ff0     .got    00000000 .hidden _gp
+# CHECK: 0000000000020000     .text   00000000 __start
+# CHECK: 0000000000000000 g F *UND*   00000000 foo1a
 
 # GOT:      Relocations [
 # GOT-NEXT: ]
@@ -44,18 +44,28 @@
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x30010
 # GOT-NEXT:       Access: -32736
-# GOT-NEXT:       Initial: 0x20000
+# GOT-NEXT:       Initial: 0x20014
 # GOT-NEXT:     }
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x30018
 # GOT-NEXT:       Access: -32728
-# GOT-NEXT:       Initial: 0x20010
+# GOT-NEXT:       Initial: 0x20004
 # GOT-NEXT:     }
-# GOT-NEXT:   ]
-# GOT-NEXT:   Global entries [
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x30020
 # GOT-NEXT:       Access: -32720
+# GOT-NEXT:       Initial: 0x20008
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30028
+# GOT-NEXT:       Access: -32712
+# GOT-NEXT:       Initial: 0x2000C
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30030
+# GOT-NEXT:       Access: -32704
 # GOT-NEXT:       Initial: 0x0
 # GOT-NEXT:       Value: 0x0
 # GOT-NEXT:       Type: Function
@@ -67,14 +77,13 @@
 # GOT-NEXT: }
 
   .text
-  .global  __start, bar
+  .global  __start
 __start:
-  ld      $v0,%got_page(foo)($gp)             # R_MIPS_GOT_PAGE
-  daddiu  $v0,$v0,%got_ofst(foo)              # R_MIPS_GOT_OFST
   addiu   $v0,$v0,%got_disp(foo1a)            # R_MIPS_GOT_DISP
-  addiu   $v0,$v0,%got_disp(bar)              # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(foo)              # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(.text+4)          # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(.text+8)          # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(.text+12)         # R_MIPS_GOT_DISP
 
-bar:
-  nop
 foo:
   nop

Modified: lld/trunk/test/ELF/mips-64-got.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-64-got.s?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-64-got.s (original)
+++ lld/trunk/test/ELF/mips-64-got.s Sun Jun 19 16:39:37 2016
@@ -13,14 +13,15 @@
 # CHECK:      __start:
 
 # CHECK-NEXT:    20000:   df 82 80 20   ld      $2, -32736($gp)
-# CHECK-NEXT:    20004:   64 42 00 14   daddiu  $2,  $2, 20
-# CHECK-NEXT:    20008:   24 42 80 30   addiu   $2,  $2, -32720
+# CHECK-NEXT:    20004:   64 42 00 18   daddiu  $2,  $2, 24
+# CHECK-NEXT:    20008:   24 42 80 38   addiu   $2,  $2, -32712
 # CHECK-NEXT:    2000c:   24 42 80 28   addiu   $2,  $2, -32728
+# CHECK-NEXT:    20010:   24 42 80 30   addiu   $2,  $2, -32720
 
-# CHECK: 0000000000020014   .text   00000000 foo
+# CHECK: 0000000000020018   .text   00000000 foo
 # CHECK: 0000000000037ff0   .got    00000000 .hidden _gp
 # CHECK: 0000000000020000   .text   00000000 __start
-# CHECK: 0000000000020010   .text   00000000 bar
+# CHECK: 0000000000020014   .text   00000000 bar
 
 # GOT:      Relocations [
 # GOT-NEXT: ]
@@ -49,13 +50,18 @@
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x30018
 # GOT-NEXT:       Access: -32728
-# GOT-NEXT:       Initial: 0x20010
+# GOT-NEXT:       Initial: 0x20014
 # GOT-NEXT:     }
-# GOT-NEXT:   ]
-# GOT-NEXT:   Global entries [
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x30020
 # GOT-NEXT:       Access: -32720
+# GOT-NEXT:       Initial: 0x20018
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x30028
+# GOT-NEXT:       Access: -32712
 # GOT-NEXT:       Initial: 0x0
 # GOT-NEXT:       Value: 0x0
 # GOT-NEXT:       Type: Function
@@ -73,6 +79,7 @@ __start:
   daddiu  $v0,$v0,%got_ofst(foo)              # R_MIPS_GOT_OFST
   addiu   $v0,$v0,%got_disp(foo1a)            # R_MIPS_GOT_DISP
   addiu   $v0,$v0,%got_disp(bar)              # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(foo)              # R_MIPS_GOT_DISP
 
 bar:
   nop

Modified: lld/trunk/test/ELF/mips-dynamic.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-dynamic.s?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-dynamic.s (original)
+++ lld/trunk/test/ELF/mips-dynamic.s Sun Jun 19 16:39:37 2016
@@ -71,8 +71,8 @@
 # DSO:      ]
 # DSO:      DynamicSymbols [
 # DSO:          Name: @
-# DSO:          Name: __start@
 # DSO:          Name: _foo@
+# DSO:          Name: __start@
 # DSO:      ]
 # DSO:      DynamicSection [
 # DSO-NEXT:   Tag        Type                 Name/Value

Modified: lld/trunk/test/ELF/mips-got16.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-got16.s?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-got16.s (original)
+++ lld/trunk/test/ELF/mips-got16.s Sun Jun 19 16:39:37 2016
@@ -17,7 +17,7 @@
 # CHECK-NEXT:    10014:       21 08 90 04     addi    $8, $8, -28668
 # CHECK-NEXT:    10018:       8f 88 80 20     lw      $8, -32736($gp)
 # CHECK-NEXT:    1001c:       21 08 10 04     addi    $8, $8, 4100
-# CHECK-NEXT:    10020:       8f 88 80 24     lw      $8, -32732($gp)
+# CHECK-NEXT:    10020:       8f 88 80 28     lw      $8, -32728($gp)
 # CHECK-NEXT:    10024:       21 08 10 08     addi    $8, $8, 4104
 # CHECK-NEXT:    10028:       8f 88 80 2c     lw      $8, -32724($gp)
 #
@@ -67,14 +67,14 @@
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x20014
 # GOT-NEXT:       Access: -32732
-# GOT-NEXT:       Initial: 0x51008
-#                          ^-- 'bar' address
+# GOT-NEXT:       Initial: 0x0
+#                          ^-- redundant unused entry
 # GOT-NEXT:     }
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x20018
-# GOT-NEXT:       Access: -32728
-# GOT-NEXT:       Initial: 0x0
-#                          ^-- redundant unused entry
+# GOT-NEXT:       Access: -327
+# GOT-NEXT:       Initial: 0x51008
+#                          ^-- 'bar' address
 # GOT-NEXT:     }
 # GOT-NEXT:   ]
 # GOT-NEXT:   Global entries [

Modified: lld/trunk/test/ELF/mips-plt-copy.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-plt-copy.s?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-plt-copy.s (original)
+++ lld/trunk/test/ELF/mips-plt-copy.s Sun Jun 19 16:39:37 2016
@@ -12,8 +12,8 @@
 
 # CHECK:      Relocations [
 # CHECK-NEXT:   Section ({{.*}}) .rel.dyn {
-# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
 # CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Section ({{.*}}) .rel.plt {
 # CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0

Modified: lld/trunk/test/ELF/mips-sto-plt.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-sto-plt.s?rev=273127&r1=273126&r2=273127&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-sto-plt.s (original)
+++ lld/trunk/test/ELF/mips-sto-plt.s Sun Jun 19 16:39:37 2016
@@ -10,23 +10,23 @@
 # REQUIRES: mips
 
 # CHECK:      Symbol {
-# CHECK:        Name: foo0@
-# CHECK-NEXT:   Value: 0x0
+# CHECK:        Name: foo1@
+# CHECK-NEXT:   Value: 0x20050
 # CHECK-NEXT:   Size: 0
 # CHECK-NEXT:   Binding: Global
 # CHECK-NEXT:   Type: Function
-# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Other [ (0x8)
+# CHECK-NEXT:     STO_MIPS_PLT
+# CHECK-NEXT:   ]
 # CHECK-NEXT:   Section: Undefined
 # CHECK-NEXT: }
 # CHECK:      Symbol {
-# CHECK:        Name: foo1@
-# CHECK-NEXT:   Value: 0x20050
+# CHECK:        Name: foo0@
+# CHECK-NEXT:   Value: 0x0
 # CHECK-NEXT:   Size: 0
 # CHECK-NEXT:   Binding: Global
 # CHECK-NEXT:   Type: Function
-# CHECK-NEXT:   Other [ (0x8)
-# CHECK-NEXT:     STO_MIPS_PLT
-# CHECK-NEXT:   ]
+# CHECK-NEXT:   Other: 0
 # CHECK-NEXT:   Section: Undefined
 # CHECK-NEXT: }
 




More information about the llvm-commits mailing list