[lld] r334390 - [ELF][MIPS] Multi-GOT implementation

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 11 00:24:32 PDT 2018


Author: atanasyan
Date: Mon Jun 11 00:24:31 2018
New Revision: 334390

URL: http://llvm.org/viewvc/llvm-project?rev=334390&view=rev
Log:
[ELF][MIPS] Multi-GOT implementation

Almost all entries inside MIPS GOT are referenced by signed 16-bit
index. Zero entry lies approximately in the middle of the GOT. So the
total number of GOT entries cannot exceed ~16384 for 32-bit architecture
and ~8192 for 64-bit architecture. This limitation makes impossible to
link rather large application like for example LLVM+Clang. There are two
workaround for this problem. The first one is using the -mxgot
compiler's flag. It enables using a 32-bit index to access GOT entries.
But each access requires two assembly instructions two load GOT entry
index to a register. Another workaround is multi-GOT. This patch
implements it.

Here is a brief description of multi-GOT for detailed one see the
following link https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT.

If the sum of local, global and tls entries is less than 64K only single
got is enough. Otherwise, multi-got is created. Series of primary and
multiple secondary GOTs have the following layout:
```
- Primary GOT
    Header
    Local entries
    Global entries
    Relocation only entries
    TLS entries

- Secondary GOT
    Local entries
    Global entries
    TLS entries
...
```

All GOT entries required by relocations from a single input file
entirely belong to either primary or one of secondary GOTs. To reference
GOT entries each GOT has its own _gp value points to the "middle" of the
GOT. In the code this value loaded to the register which is used for GOT
access.

MIPS 32 function's prologue:
```
lui     v0,0x0
0: R_MIPS_HI16  _gp_disp
addiu   v0,v0,0
4: R_MIPS_LO16  _gp_disp
```

MIPS 64 function's prologue:
```
lui     at,0x0
14: R_MIPS_GPREL16  main
```

Dynamic linker does not know anything about secondary GOTs and cannot
use a regular MIPS mechanism for GOT entries initialization. So we have
to use an approach accepted by other architectures and create dynamic
relocations R_MIPS_REL32 to initialize global entries (and local in case
of PIC code) in secondary GOTs. But ironically MIPS dynamic linker
requires GOT entries and correspondingly ordered dynamic symbol table
entries to deal with dynamic relocations. To handle this problem
relocation-only section in the primary GOT contains entries for all
symbols referenced in global parts of secondary GOTs. Although the sum
of local and normal global entries of the primary got should be less
than 64K, the size of the primary got (including relocation-only entries
can be greater than 64K, because parts of the primary got that overflow
the 64K limit are used only by the dynamic linker at dynamic link-time
and not by 16-bit gp-relative addressing at run-time.

The patch affects common LLD code in the following places:

- Added new hidden -mips-got-size flag. This flag required to set low
maximum size of a single GOT to be able to test the implementation using
small test cases.

- Added InputFile argument to the getRelocTargetVA function. The same
symbol referenced by GOT relocation from different input file might be
allocated in different GOT. So result of relocation depends on the file.

- Added new ctor to the DynamicReloc class. This constructor records
settings of dynamic relocation which used to adjust address of 64kb page
lies inside a specific output section.

With the patch LLD is able to link all LLVM+Clang+LLD applications and
libraries for MIPS 32/64 targets.

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

Added:
    lld/trunk/test/ELF/Inputs/mips-mgot-1.s
    lld/trunk/test/ELF/Inputs/mips-mgot-2.s
    lld/trunk/test/ELF/mips-abs-got.s
    lld/trunk/test/ELF/mips-mgot.s
Modified:
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Options.td
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/SyntheticSections.h
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/mips-dynamic.s
    lld/trunk/test/ELF/mips-got-script.s
    lld/trunk/test/ELF/mips-got-weak.s
    lld/trunk/test/ELF/mips-plt-copy.s
    lld/trunk/test/ELF/mips-sto-plt.s
    lld/trunk/test/ELF/mips-tls-64.s
    lld/trunk/test/ELF/mips-tls-static.s
    lld/trunk/test/ELF/mips-tls.s

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Mon Jun 11 00:24:31 2018
@@ -194,6 +194,7 @@ struct Configuration {
   uint16_t EMachine = llvm::ELF::EM_NONE;
   llvm::Optional<uint64_t> ImageBase;
   uint64_t MaxPageSize;
+  uint64_t MipsGotSize;
   uint64_t ZStackSize;
   unsigned LTOPartitions;
   unsigned LTOO;

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Mon Jun 11 00:24:31 2018
@@ -725,6 +725,7 @@ void LinkerDriver::readConfigs(opt::Inpu
   Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
   Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile);
   Config->MapFile = Args.getLastArgValue(OPT_Map);
+  Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0);
   Config->MergeArmExidx =
       Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
   Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Mon Jun 11 00:24:31 2018
@@ -120,6 +120,9 @@ public:
   static bool IsInGroup;
   static uint32_t NextGroupId;
 
+  // Index of MIPS GOT built for this file.
+  llvm::Optional<size_t> MipsGotIndex;
+
 protected:
   InputFile(Kind K, MemoryBufferRef M);
   std::vector<InputSectionBase *> Sections;

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Mon Jun 11 00:24:31 2018
@@ -477,8 +477,8 @@ static uint64_t getARMStaticBase(const S
   return OS->PtLoad->FirstSec->Addr;
 }
 
-static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
-                                 const Symbol &Sym, RelExpr Expr) {
+static uint64_t getRelocTargetVA(const InputFile &File, RelType Type, int64_t A,
+                                 uint64_t P, const Symbol &Sym, RelExpr Expr) {
   switch (Expr) {
   case R_INVALID:
     return 0;
@@ -516,9 +516,9 @@ static uint64_t getRelocTargetVA(RelType
   case R_TLSDESC_CALL:
     llvm_unreachable("cannot relocate hint relocs");
   case R_MIPS_GOTREL:
-    return Sym.getVA(A) - InX::MipsGot->getGp();
+    return Sym.getVA(A) - InX::MipsGot->getGp(&File);
   case R_MIPS_GOT_GP:
-    return InX::MipsGot->getGp() + A;
+    return InX::MipsGot->getGp(&File) + A;
   case R_MIPS_GOT_GP_PC: {
     // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
     // is _gp_disp symbol. In that case we should use the following
@@ -527,7 +527,7 @@ static uint64_t getRelocTargetVA(RelType
     // microMIPS variants of these relocations use slightly different
     // expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi()
     // to correctly handle less-sugnificant bit of the microMIPS symbol.
-    uint64_t V = InX::MipsGot->getGp() + A - P;
+    uint64_t V = InX::MipsGot->getGp(&File) + A - P;
     if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
       V += 4;
     if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16)
@@ -538,21 +538,24 @@ static uint64_t getRelocTargetVA(RelType
     // 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 InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Sym, A) -
-           InX::MipsGot->getGp();
+    return InX::MipsGot->getVA() +
+           InX::MipsGot->getPageEntryOffset(File, Sym, A) -
+           InX::MipsGot->getGp(&File);
   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 InX::MipsGot->getVA() + InX::MipsGot->getSymEntryOffset(Sym, A) -
-           InX::MipsGot->getGp();
+    return InX::MipsGot->getVA() +
+           InX::MipsGot->getSymEntryOffset(File, Sym, A) -
+           InX::MipsGot->getGp(&File);
   case R_MIPS_TLSGD:
-    return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
-           InX::MipsGot->getGlobalDynOffset(Sym) - InX::MipsGot->getGp();
+    return InX::MipsGot->getVA() +
+           InX::MipsGot->getGlobalDynOffset(File, Sym) -
+           InX::MipsGot->getGp(&File);
   case R_MIPS_TLSLD:
-    return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
-           InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp();
+    return InX::MipsGot->getVA() + InX::MipsGot->getTlsIndexOffset(File) -
+           InX::MipsGot->getGp(&File);
   case R_PAGE_PC:
   case R_PLT_PAGE_PC: {
     uint64_t Dest;
@@ -751,7 +754,8 @@ void InputSectionBase::relocateAlloc(uin
     uint64_t AddrLoc = getOutputSection()->Addr + Offset;
     RelExpr Expr = Rel.Expr;
     uint64_t TargetVA = SignExtend64(
-        getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits);
+        getRelocTargetVA(*File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr),
+        Bits);
 
     switch (Expr) {
     case R_RELAX_GOT_PC:

Modified: lld/trunk/ELF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/Options.td (original)
+++ lld/trunk/ELF/Options.td Mon Jun 11 00:24:31 2018
@@ -480,3 +480,8 @@ def: F<"EB">;
 def: F<"EL">;
 def: JoinedOrSeparate<["-"], "G">;
 def: F<"Qy">;
+
+// Hidden option used for testing MIPS multi-GOT implementation.
+defm mips_got_size:
+  Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">,
+  Flags<[HelpHidden]>;

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Mon Jun 11 00:24:31 2018
@@ -85,27 +85,16 @@ static std::string getLocation(InputSect
 // pollute other `handleTlsRelocation` by MIPS `ifs` statements.
 // Mips has a custom MipsGotSection that handles the writing of GOT entries
 // without dynamic relocations.
-template <class ELFT>
 static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,
                                         InputSectionBase &C, uint64_t Offset,
                                         int64_t Addend, RelExpr Expr) {
   if (Expr == R_MIPS_TLSLD) {
-    if (InX::MipsGot->addTlsIndex() && Config->Pic)
-      InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::MipsGot,
-                             InX::MipsGot->getTlsIndexOff(), nullptr);
+    InX::MipsGot->addTlsIndex(*C.File);
     C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
     return 1;
   }
-
   if (Expr == R_MIPS_TLSGD) {
-    if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) {
-      uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym);
-      InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::MipsGot, Off,
-                             &Sym);
-      if (Sym.IsPreemptible)
-        InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::MipsGot,
-                               Off + Config->Wordsize, &Sym);
-    }
+    InX::MipsGot->addDynTlsEntry(*C.File, Sym);
     C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
     return 1;
   }
@@ -184,7 +173,7 @@ handleTlsRelocation(RelType Type, Symbol
   if (Config->EMachine == EM_ARM)
     return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
   if (Config->EMachine == EM_MIPS)
-    return handleMipsTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
+    return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
 
   if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
       Config->Shared) {
@@ -476,7 +465,6 @@ static void replaceWithDefined(Symbol &S
   Sym.PltIndex = Old.PltIndex;
   Sym.GotIndex = Old.GotIndex;
   Sym.VerdefIndex = Old.VerdefIndex;
-  Sym.IsInGlobalMipsGot = Old.IsInGlobalMipsGot;
   Sym.IsPreemptible = true;
   Sym.ExportDynamic = true;
   Sym.IsUsedInRegularObj = true;
@@ -816,7 +804,7 @@ static void processRelocAux(InputSection
       // a dynamic relocation.
       // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
       if (Config->EMachine == EM_MIPS)
-        InX::MipsGot->addEntry(Sym, Addend, Expr);
+        InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
       return;
     }
   }
@@ -1002,10 +990,7 @@ static void scanReloc(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
-      InX::MipsGot->addEntry(Sym, Addend, Expr);
-      if (Sym.isTls() && Sym.IsPreemptible)
-        InX::RelaDyn->addReloc(Target->TlsGotRel, InX::MipsGot,
-                               Sym.getGotOffset(), &Sym);
+      InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
     } else if (!Sym.isInGot()) {
       addGotEntry<ELFT>(Sym);
     }

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Mon Jun 11 00:24:31 2018
@@ -158,19 +158,13 @@ protected:
          uint8_t StOther, uint8_t Type)
       : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
         Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
-        IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
-        IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections),
-        NeedsTocRestore(false) {}
+        IsInIplt(false), IsInIgot(false), IsPreemptible(false),
+        Used(!Config->GcSections), NeedsTocRestore(false) {}
 
 public:
   // True the symbol should point to its PLT entry.
   // For SharedSymbol only.
   unsigned NeedsPltAddr : 1;
-  // True if this symbol has an entry in the global part of MIPS GOT.
-  unsigned IsInGlobalMipsGot : 1;
-
-  // True if this symbol is referenced by 32-bit GOT relocations.
-  unsigned Is32BitMipsGot : 1;
 
   // True if this symbol is in the Iplt sub-section of the Plt.
   unsigned IsInIplt : 1;

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Mon Jun 11 00:24:31 2018
@@ -29,6 +29,7 @@
 #include "lld/Common/Strings.h"
 #include "lld/Common/Threads.h"
 #include "lld/Common/Version.h"
+#include "llvm/ADT/SetOperations.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
 #include "llvm/Object/Decompressor.h"
@@ -636,180 +637,344 @@ void GotSection::writeTo(uint8_t *Buf) {
   relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
 }
 
+static uint64_t getMipsPageAddr(uint64_t Addr) {
+  return (Addr + 0x8000) & ~0xffff;
+}
+
+static uint64_t getMipsPageCount(uint64_t Size) {
+  return (Size + 0xfffe) / 0xffff + 1;
+}
+
 MipsGotSection::MipsGotSection()
     : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
                        ".got") {}
 
-void MipsGotSection::addEntry(Symbol &Sym, int64_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
+void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend,
+                              RelExpr Expr) {
+  FileGot &G = getGot(File);
   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.
-    PageIndexMap.insert({Sym.getOutputSection(), 0});
-    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 = TlsEntries.size();
-    TlsEntries.push_back(&Sym);
-    return;
-  }
-  auto AddEntry = [&](Symbol &S, uint64_t A, GotEntries &Items) {
-    if (S.isInGot() && !A)
-      return;
-    size_t NewIndex = Items.size();
-    if (!EntryIndexMap.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, GlobalEntries);
-    Sym.IsInGlobalMipsGot = true;
-  } else if (Expr == R_MIPS_GOT_OFF32) {
-    AddEntry(Sym, Addend, LocalEntries32);
-    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, LocalEntries);
-  }
+    if (const OutputSection *OS = Sym.getOutputSection())
+      G.PagesMap.insert({OS, {}});
+    else
+      G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0});
+  } else if (Sym.isTls())
+    G.Tls.insert({&Sym, 0});
+  else if (Sym.IsPreemptible && Expr == R_ABS)
+    G.Relocs.insert({&Sym, 0});
+  else if (Sym.IsPreemptible)
+    G.Global.insert({&Sym, 0});
+  else if (Expr == R_MIPS_GOT_OFF32)
+    G.Local32.insert({{&Sym, Addend}, 0});
+  else
+    G.Local16.insert({{&Sym, Addend}, 0});
 }
 
-bool MipsGotSection::addDynTlsEntry(Symbol &Sym) {
-  if (Sym.GlobalDynIndex != -1U)
-    return false;
-  Sym.GlobalDynIndex = TlsEntries.size();
-  // Global Dynamic TLS entries take two GOT slots.
-  TlsEntries.push_back(nullptr);
-  TlsEntries.push_back(&Sym);
-  return true;
+void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) {
+  getGot(File).DynTlsSymbols.insert({&Sym, 0});
 }
 
-// Reserves TLS entries for a TLS module ID and a TLS block offset.
-// In total it takes two GOT slots.
-bool MipsGotSection::addTlsIndex() {
-  if (TlsIndexOff != uint32_t(-1))
-    return false;
-  TlsIndexOff = TlsEntries.size() * Config->Wordsize;
-  TlsEntries.push_back(nullptr);
-  TlsEntries.push_back(nullptr);
-  return true;
+void MipsGotSection::addTlsIndex(InputFile &File) {
+  getGot(File).DynTlsSymbols.insert({nullptr, 0});
 }
 
-static uint64_t getMipsPageAddr(uint64_t Addr) {
-  return (Addr + 0x8000) & ~0xffff;
+size_t MipsGotSection::FileGot::getEntriesNum() const {
+  return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() +
+         Tls.size() + DynTlsSymbols.size() * 2;
 }
 
-static uint64_t getMipsPageCount(uint64_t Size) {
-  return (Size + 0xfffe) / 0xffff + 1;
+size_t MipsGotSection::FileGot::getPageEntriesNum() const {
+  size_t Num = 0;
+  for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap)
+    Num += P.second.Count;
+  return Num;
 }
 
-uint64_t MipsGotSection::getPageEntryOffset(const Symbol &B,
-                                            int64_t Addend) const {
-  const OutputSection *OutSec = B.getOutputSection();
-  uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
-  uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend));
-  uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
-  assert(Index < PageEntriesNum);
-  return (HeaderEntriesNum + Index) * Config->Wordsize;
+size_t MipsGotSection::FileGot::getIndexedEntriesNum() const {
+  size_t Count = getPageEntriesNum() + Local16.size() + Global.size();
+  // If there are relocation-only entries in the GOT, TLS entries
+  // are allocated after them. TLS entries should be addressable
+  // by 16-bit index so count both reloc-only and TLS entries.
+  if (!Tls.empty() || !DynTlsSymbols.empty())
+    Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2;
+  return Count;
 }
 
-uint64_t MipsGotSection::getSymEntryOffset(const Symbol &B,
-                                           int64_t Addend) const {
-  // Calculate offset of the GOT entries block: TLS, global, local.
-  uint64_t Index = HeaderEntriesNum + PageEntriesNum;
-  if (B.isTls())
-    Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size();
-  else if (B.IsInGlobalMipsGot)
-    Index += LocalEntries.size() + LocalEntries32.size();
-  else if (B.Is32BitMipsGot)
-    Index += LocalEntries.size();
-  // Calculate offset of the GOT entry in the block.
-  if (B.isInGot())
-    Index += B.GotIndex;
-  else {
-    auto It = EntryIndexMap.find({&B, Addend});
-    assert(It != EntryIndexMap.end());
-    Index += It->second;
+MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) {
+  if (!F.MipsGotIndex.hasValue()) {
+    Gots.emplace_back();
+    Gots.back().File = &F;
+    F.MipsGotIndex = Gots.size() - 1;
   }
-  return Index * Config->Wordsize;
+  return Gots[*F.MipsGotIndex];
 }
 
-uint64_t MipsGotSection::getTlsOffset() const {
-  return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize;
+uint64_t MipsGotSection::getPageEntryOffset(const InputFile &F,
+                                            const Symbol &Sym,
+                                            int64_t Addend) const {
+  const FileGot &G = Gots[*F.MipsGotIndex];
+  uint64_t Index = 0;
+  if (const OutputSection *OutSec = Sym.getOutputSection()) {
+    uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
+    uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend));
+    Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff;
+  } else {
+    Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))});
+  }
+  return Index * Config->Wordsize;
 }
 
-uint64_t MipsGotSection::getGlobalDynOffset(const Symbol &B) const {
-  return B.GlobalDynIndex * Config->Wordsize;
+uint64_t MipsGotSection::getSymEntryOffset(const InputFile &F, const Symbol &S,
+                                           int64_t Addend) const {
+  const FileGot &G = Gots[*F.MipsGotIndex];
+  Symbol *Sym = const_cast<Symbol *>(&S);
+  if (Sym->isTls())
+    return G.Tls.find(Sym)->second * Config->Wordsize;
+  if (Sym->IsPreemptible)
+    return G.Global.find(Sym)->second * Config->Wordsize;
+  return G.Local16.find({Sym, Addend})->second * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getTlsIndexOffset(const InputFile &F) const {
+  const FileGot &G = Gots[*F.MipsGotIndex];
+  return G.DynTlsSymbols.find(nullptr)->second * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getGlobalDynOffset(const InputFile &F,
+                                            const Symbol &S) const {
+  const FileGot &G = Gots[*F.MipsGotIndex];
+  Symbol *Sym = const_cast<Symbol *>(&S);
+  return G.DynTlsSymbols.find(Sym)->second * Config->Wordsize;
 }
 
 const Symbol *MipsGotSection::getFirstGlobalEntry() const {
-  return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first;
+  if (Gots.empty())
+    return nullptr;
+  const FileGot &PrimGot = Gots.front();
+  if (!PrimGot.Global.empty())
+    return PrimGot.Global.front().first;
+  if (!PrimGot.Relocs.empty())
+    return PrimGot.Relocs.front().first;
+  return nullptr;
 }
 
 unsigned MipsGotSection::getLocalEntriesNum() const {
-  return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() +
-         LocalEntries32.size();
+  if (Gots.empty())
+    return HeaderEntriesNum;
+  return HeaderEntriesNum + Gots.front().getPageEntriesNum() +
+         Gots.front().Local16.size();
+}
+
+bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) {
+  FileGot Tmp = Dst;
+  set_union(Tmp.PagesMap, Src.PagesMap);
+  set_union(Tmp.Local16, Src.Local16);
+  set_union(Tmp.Global, Src.Global);
+  set_union(Tmp.Relocs, Src.Relocs);
+  set_union(Tmp.Tls, Src.Tls);
+  set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols);
+
+  size_t Count = IsPrimary ? HeaderEntriesNum : 0;
+  Count += Tmp.getIndexedEntriesNum();
+
+  if (Count * Config->Wordsize > Config->MipsGotSize)
+    return false;
+
+  std::swap(Tmp, Dst);
+  return true;
 }
 
 void MipsGotSection::finalizeContents() { updateAllocSize(); }
 
 bool MipsGotSection::updateAllocSize() {
-  PageEntriesNum = 0;
-  for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) {
-    // For each output section referenced by GOT page relocations calculate
-    // and save into PageIndexMap 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. And take in account the case when the section intersects
-    // page boundaries.
-    P.second = PageEntriesNum;
-    PageEntriesNum += getMipsPageCount(P.first->Size);
-  }
-  Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
-         Config->Wordsize;
+  Size = HeaderEntriesNum * Config->Wordsize;
+  for (const FileGot &G : Gots)
+    Size += G.getEntriesNum() * Config->Wordsize;
   return false;
 }
 
+template <class ELFT> void MipsGotSection::build() {
+  if (Gots.empty())
+    return;
+
+  std::vector<FileGot> MergedGots(1);
+
+  // For each GOT move non-preemptible symbols from the `Global`
+  // to `Local16` list. Preemptible symbol might become non-preemptible
+  // one if, for example, it gets a related copy relocation.
+  for (FileGot &Got : Gots) {
+    for (auto &P: Got.Global)
+      if (!P.first->IsPreemptible)
+        Got.Local16.insert({{P.first, 0}, 0});
+    Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+      return !P.first->IsPreemptible;
+    });
+  }
+
+  // For each GOT remove "reloc-only" entry if there is "global"
+  // entry for the same symbol. And add local entries which indexed
+  // using 32-bit value at the end of 16-bit entries.
+  for (FileGot &Got : Gots) {
+    Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+      return Got.Global.count(P.first);
+    });
+    set_union(Got.Local16, Got.Local32);
+    Got.Local32.clear();
+  }
+
+  // Evaluate number of "reloc-only" entries in the resulting GOT.
+  // To do that put all unique "reloc-only" and "global" entries
+  // from all GOTs to the future primary GOT.
+  FileGot *PrimGot = &MergedGots.front();
+  for (FileGot &Got : Gots) {
+    set_union(PrimGot->Relocs, Got.Global);
+    set_union(PrimGot->Relocs, Got.Relocs);
+    Got.Relocs.clear();
+  }
+
+  // Evaluate number of "page" entries in each GOT.
+  for (FileGot &Got : Gots) {
+    for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+         Got.PagesMap) {
+      const OutputSection *OS = P.first;
+      uint64_t SecSize = 0;
+      for (BaseCommand *Cmd : OS->SectionCommands) {
+        if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
+          for (InputSection *IS : ISD->Sections) {
+            uint64_t Off = alignTo(SecSize, IS->Alignment);
+            SecSize = Off + IS->getSize();
+          }
+      }
+      P.second.Count = getMipsPageCount(SecSize);
+    }
+  }
+
+  // Merge GOTs. Try to join as much as possible GOTs but do not
+  // exceed maximum GOT size. In case of overflow create new GOT
+  // and continue merging.
+  for (FileGot &SrcGot : Gots) {
+    FileGot &DstGot = MergedGots.back();
+    InputFile *File = SrcGot.File;
+    if (!tryMergeGots(DstGot, SrcGot, &DstGot == PrimGot)) {
+      MergedGots.emplace_back();
+      std::swap(MergedGots.back(), SrcGot);
+    }
+    File->MipsGotIndex = MergedGots.size() - 1;
+  }
+  std::swap(Gots, MergedGots);
+
+  // Reduce number of "reloc-only" entries in the primary GOT
+  // by substracting "global" entries exist in the primary GOT.
+  PrimGot = &Gots.front();
+  PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+    return PrimGot->Global.count(P.first);
+  });
+
+  // Calculate indexes for each GOT entry.
+  size_t Index = HeaderEntriesNum;
+  for (FileGot &Got : Gots) {
+    Got.StartIndex = &Got == PrimGot ? 0 : Index;
+    for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+         Got.PagesMap) {
+      // For each output section referenced by GOT page relocations calculate
+      // and save into PagesMap 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. And take in account the case when the section intersects
+      // page boundaries.
+      P.second.FirstIndex = Index;
+      Index += P.second.Count;
+    }
+    for (auto &P: Got.Local16)
+      P.second = Index++;
+    for (auto &P: Got.Global)
+      P.second = Index++;
+    for (auto &P: Got.Relocs)
+      P.second = Index++;
+    for (auto &P: Got.Tls)
+      P.second = Index++;
+    for (auto &P: Got.DynTlsSymbols) {
+      P.second = Index;
+      Index += 2;
+    }
+  }
+
+  // Update Symbol::GotIndex field to use this
+  // value later in the `sortMipsSymbols` function.
+  for (auto &P : PrimGot->Global)
+    P.first->GotIndex = P.second;
+  for (auto &P : PrimGot->Relocs)
+    P.first->GotIndex = P.second;
+
+  // Create dynamic relocations.
+  for (FileGot &Got : Gots) {
+    // Create dynamic relocations for TLS entries.
+    for (std::pair<Symbol *, size_t> &P : Got.Tls) {
+      Symbol *S = P.first;
+      uint64_t Offset = P.second * Config->Wordsize;
+      if (S->IsPreemptible)
+        InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
+    }
+    for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) {
+      Symbol *S = P.first;
+      uint64_t Offset = P.second * Config->Wordsize;
+      if (S == nullptr) {
+        if (!Config->Pic)
+          continue;
+        InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+      } else {
+        if (!P.first->IsPreemptible)
+          continue;
+        InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+        Offset += Config->Wordsize;
+        InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
+      }
+    }
+
+    // Do not create dynamic relocations for non-TLS
+    // entries in the primary GOT.
+    if (&Got == PrimGot)
+      continue;
+
+    // Dynamic relocations for "global" entries.
+    for (const std::pair<Symbol *, size_t> &P : Got.Global) {
+      uint64_t Offset = P.second * Config->Wordsize;
+      InX::RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
+    }
+    if (!Config->Pic)
+      continue;
+    // Dynamic relocations for "local" entries in case of PIC.
+    for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+         Got.PagesMap) {
+      size_t PageCount = L.second.Count;
+      for (size_t PI = 0; PI < PageCount; ++PI) {
+        uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize;
+        InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
+                                int64_t(PI * 0x10000)});
+      }
+    }
+    for (const std::pair<GotEntry, size_t> &P : Got.Local16) {
+      uint64_t Offset = P.second * Config->Wordsize;
+      InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
+                              P.first.first, P.first.second});
+    }
+  }
+}
+
 bool MipsGotSection::empty() const {
   // We add the .got section to the result for dynamic MIPS target because
   // its address and properties are mentioned in the .dynamic section.
   return Config->Relocatable;
 }
 
-uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); }
+uint64_t MipsGotSection::getGp(const InputFile *F) const {
+  // For files without related GOT or files refer a primary GOT
+  // returns "common" _gp value. For secondary GOTs calculate
+  // individual _gp values.
+  if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0)
+    return ElfSym::MipsGp->getVA(0);
+  return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize +
+         0x7ff0;
+}
 
 void MipsGotSection::writeTo(uint8_t *Buf) {
   // Set the MSB of the second GOT slot. This is not required by any
@@ -827,49 +992,47 @@ void MipsGotSection::writeTo(uint8_t *Bu
   // keep doing this for now. We really need to revisit this to see
   // if we had to do this.
   writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
-  Buf += HeaderEntriesNum * Config->Wordsize;
-  // Write 'page address' entries to the local part of the GOT.
-  for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) {
-    size_t PageCount = getMipsPageCount(L.first->Size);
-    uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
-    for (size_t PI = 0; PI < PageCount; ++PI) {
-      uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize;
-      writeUint(Entry, FirstPageAddr + PI * 0x10000);
-    }
-  }
-  Buf += PageEntriesNum * Config->Wordsize;
-  auto AddEntry = [&](const GotEntry &SA) {
-    uint8_t *Entry = Buf;
-    Buf += Config->Wordsize;
-    const Symbol *Sym = SA.first;
-    uint64_t VA = Sym->getVA(SA.second);
-    if (Sym->StOther & STO_MIPS_MICROMIPS)
-      VA |= 1;
-    writeUint(Entry, VA);
-  };
-  std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry);
-  std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry);
-  std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry);
-  // Initialize TLS-related GOT entries. If the entry has a corresponding
-  // dynamic relocations, leave it initialized by zero. Write down adjusted
-  // TLS symbol's values otherwise. To calculate the adjustments use offsets
-  // for thread-local storage.
-  // https://www.linux-mips.org/wiki/NPTL
-  if (TlsIndexOff != -1U && !Config->Pic)
-    writeUint(Buf + TlsIndexOff, 1);
-  for (const Symbol *B : TlsEntries) {
-    if (!B || B->IsPreemptible)
-      continue;
-    uint64_t VA = B->getVA();
-    if (B->GotIndex != -1U) {
-      uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize;
-      writeUint(Entry, VA - 0x7000);
-    }
-    if (B->GlobalDynIndex != -1U) {
-      uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize;
-      writeUint(Entry, 1);
-      Entry += Config->Wordsize;
-      writeUint(Entry, VA - 0x8000);
+  for (const FileGot &G : Gots) {
+    auto Write = [&](size_t I, const Symbol *S, int64_t A) {
+      uint64_t VA = A;
+      if (S) {
+        VA = S->getVA(A);
+        if (S->StOther & STO_MIPS_MICROMIPS)
+          VA |= 1;
+      }
+      writeUint(Buf + I * Config->Wordsize, VA);
+    };
+    // Write 'page address' entries to the local part of the GOT.
+    for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+         G.PagesMap) {
+      size_t PageCount = L.second.Count;
+      uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+      for (size_t PI = 0; PI < PageCount; ++PI)
+        Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000);
+    }
+    // Local, global, TLS, reloc-only  entries.
+    // If TLS 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
+    for (const std::pair<GotEntry, size_t> &P : G.Local16)
+      Write(P.second, P.first.first, P.first.second);
+    // Write VA to the primary GOT only. For secondary GOTs that
+    // will be done by REL32 dynamic relocations.
+    if (&G == &Gots.front())
+      for (const std::pair<const Symbol *, size_t> &P : G.Global)
+        Write(P.second, P.first, 0);
+    for (const std::pair<Symbol *, size_t> &P : G.Relocs)
+      Write(P.second, P.first, 0);
+    for (const std::pair<Symbol *, size_t> &P : G.Tls)
+      Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000);
+    for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) {
+      if (P.first == nullptr && !Config->Pic)
+        Write(P.second, nullptr, 1);
+      else if (P.first && !P.first->IsPreemptible) {
+        Write(P.second, nullptr, 1);
+        Write(P.second + 1, P.first, -0x8000);
+      }
     }
   }
 }
@@ -1234,7 +1397,10 @@ uint64_t DynamicReloc::getOffset() const
 int64_t DynamicReloc::computeAddend() const {
   if (UseSymVA)
     return Sym->getVA(Addend);
-  return Addend;
+  if (!OutputSec)
+    return Addend;
+  // See the comment in the DynamicReloc ctor.
+  return getMipsPageAddr(OutputSec->Addr) + Addend;
 }
 
 uint32_t DynamicReloc::getSymIndex() const {
@@ -1288,17 +1454,6 @@ static void encodeDynamicReloc(typename
   if (Config->IsRela)
     P->r_addend = Rel.computeAddend();
   P->r_offset = Rel.getOffset();
-  if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot)
-    // The MIPS GOT section contains dynamic relocations that correspond to TLS
-    // entries. These entries are placed after the global and local sections of
-    // the GOT. At the point when we create these relocations, the size of the
-    // global and local sections is unknown, so the offset that we store in the
-    // TLS entry's DynamicReloc is relative to the start of the TLS section of
-    // the GOT, rather than being relative to the start of the GOT. This line of
-    // code adds the size of the global and local sections to the virtual
-    // address computed by getOffset() in order to adjust it into the TLS
-    // section.
-    P->r_offset += InX::MipsGot->getTlsOffset();
   P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
 }
 
@@ -1537,10 +1692,8 @@ static bool sortMipsSymbols(const Symbol
                             const SymbolTableEntry &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.Sym->IsInGlobalMipsGot;
-  bool RIsInLocalGot = !R.Sym->IsInGlobalMipsGot;
-  if (LIsInLocalGot || RIsInLocalGot)
-    return !RIsInLocalGot;
+  if (!L.Sym->isInGot() || !R.Sym->isInGot())
+    return !L.Sym->isInGot();
   return L.Sym->GotIndex < R.Sym->GotIndex;
 }
 
@@ -2746,6 +2899,11 @@ template void PltSection::addEntry<ELF32
 template void PltSection::addEntry<ELF64LE>(Symbol &Sym);
 template void PltSection::addEntry<ELF64BE>(Symbol &Sym);
 
+template void MipsGotSection::build<ELF32LE>();
+template void MipsGotSection::build<ELF32BE>();
+template void MipsGotSection::build<ELF64LE>();
+template void MipsGotSection::build<ELF64BE>();
+
 template class elf::MipsAbiFlagsSection<ELF32LE>;
 template class elf::MipsAbiFlagsSection<ELF32BE>;
 template class elf::MipsAbiFlagsSection<ELF64LE>;

Modified: lld/trunk/ELF/SyntheticSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.h?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.h (original)
+++ lld/trunk/ELF/SyntheticSections.h Mon Jun 11 00:24:31 2018
@@ -178,12 +178,21 @@ public:
   bool updateAllocSize() override;
   void finalizeContents() override;
   bool empty() const override;
-  void addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr);
-  bool addDynTlsEntry(Symbol &Sym);
-  bool addTlsIndex();
-  uint64_t getPageEntryOffset(const Symbol &B, int64_t Addend) const;
-  uint64_t getSymEntryOffset(const Symbol &B, int64_t Addend) const;
-  uint64_t getGlobalDynOffset(const Symbol &B) const;
+
+  // Join separate GOTs built for each input file to generate
+  // primary and optional multiple secondary GOTs.
+  template <class ELFT> void build();
+
+  void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr);
+  void addDynTlsEntry(InputFile &File, Symbol &Sym);
+  void addTlsIndex(InputFile &File);
+
+  uint64_t getPageEntryOffset(const InputFile &F, const Symbol &S,
+                              int64_t Addend) const;
+  uint64_t getSymEntryOffset(const InputFile &F, const Symbol &S,
+                             int64_t Addend) const;
+  uint64_t getGlobalDynOffset(const InputFile &F, const Symbol &S) const;
+  uint64_t getTlsIndexOffset(const InputFile &F) 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
@@ -195,13 +204,8 @@ public:
   // the number of reserved entries.
   unsigned getLocalEntriesNum() const;
 
-  // Returns offset of TLS part of the MIPS GOT table. This part goes
-  // after 'local' and 'global' entries.
-  uint64_t getTlsOffset() const;
-
-  uint32_t getTlsIndexOff() const { return TlsIndexOff; }
-
-  uint64_t getGp() const;
+  // Return _gp value for primary GOT (nullptr) or particular input file.
+  uint64_t getGp(const InputFile *F = nullptr) const;
 
 private:
   // MIPS GOT consists of three parts: local, global and tls. Each part
@@ -240,32 +244,110 @@ private:
   //   addressing, but MIPS ABI requires that these entries be present in GOT.
   // TLS entries:
   //   Entries created by TLS relocations.
+  //
+  // If the sum of local, global and tls entries is less than 64K only single
+  // got is enough. Otherwise, multi-got is created. Series of primary and
+  // multiple secondary GOTs have the following layout:
+  // - Primary GOT
+  //     Header
+  //     Local entries
+  //     Global entries
+  //     Relocation only entries
+  //     TLS entries
+  //
+  // - Secondary GOT
+  //     Local entries
+  //     Global entries
+  //     TLS entries
+  // ...
+  //
+  // All GOT entries required by relocations from a single input file entirely
+  // belong to either primary or one of secondary GOTs. To reference GOT entries
+  // each GOT has its own _gp value points to the "middle" of the GOT.
+  // In the code this value loaded to the register which is used for GOT access.
+  //
+  // MIPS 32 function's prologue:
+  //   lui     v0,0x0
+  //   0: R_MIPS_HI16  _gp_disp
+  //   addiu   v0,v0,0
+  //   4: R_MIPS_LO16  _gp_disp
+  //
+  // MIPS 64:
+  //   lui     at,0x0
+  //   14: R_MIPS_GPREL16  main
+  //
+  // Dynamic linker does not know anything about secondary GOTs and cannot
+  // use a regular MIPS mechanism for GOT entries initialization. So we have
+  // to use an approach accepted by other architectures and create dynamic
+  // relocations R_MIPS_REL32 to initialize global entries (and local in case
+  // of PIC code) in secondary GOTs. But ironically MIPS dynamic linker
+  // requires GOT entries and correspondingly ordered dynamic symbol table
+  // entries to deal with dynamic relocations. To handle this problem
+  // relocation-only section in the primary GOT contains entries for all
+  // symbols referenced in global parts of secondary GOTs. Although the sum
+  // of local and normal global entries of the primary got should be less
+  // than 64K, the size of the primary got (including relocation-only entries
+  // can be greater than 64K, because parts of the primary got that overflow
+  // the 64K limit are used only by the dynamic linker at dynamic link-time
+  // and not by 16-bit gp-relative addressing at run-time.
+  //
+  // For complete multi-GOT description see the following link
+  // https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT
 
   // Number of "Header" entries.
   static const unsigned HeaderEntriesNum = 2;
-  // Number of allocated "Page" entries.
-  uint32_t PageEntriesNum = 0;
-  // Map output sections referenced by MIPS GOT relocations
-  // to the first index of "Page" entries allocated for this section.
-  llvm::SmallMapVector<const OutputSection *, size_t, 16> PageIndexMap;
-
-  typedef std::pair<const Symbol *, uint64_t> GotEntry;
-  typedef std::vector<GotEntry> GotEntries;
-  // Map from Symbol-Addend pair to the GOT index.
-  llvm::DenseMap<GotEntry, size_t> EntryIndexMap;
-  // Local entries (16-bit access).
-  GotEntries LocalEntries;
-  // Local entries (32-bit access).
-  GotEntries LocalEntries32;
 
-  // Normal and reloc-only global entries.
-  GotEntries GlobalEntries;
+  uint64_t Size = 0;
 
-  // TLS entries.
-  std::vector<const Symbol *> TlsEntries;
+  size_t LocalEntriesNum = 0;
 
-  uint32_t TlsIndexOff = -1;
-  uint64_t Size = 0;
+  // Symbol and addend.
+  typedef std::pair<Symbol *, int64_t> GotEntry;
+
+  struct FileGot {
+    InputFile *File = nullptr;
+    size_t StartIndex = 0;
+
+    struct PageBlock {
+      size_t FirstIndex = 0;
+      size_t Count = 0;
+    };
+
+    // Map output sections referenced by MIPS GOT relocations
+    // to the description (index/count) "page" entries allocated
+    // for this section.
+    llvm::SmallMapVector<const OutputSection *, PageBlock, 16> PagesMap;
+    // Maps from Symbol+Addend pair or just Symbol to the GOT entry index.
+    llvm::MapVector<GotEntry, size_t> Local16;
+    llvm::MapVector<GotEntry, size_t> Local32;
+    llvm::MapVector<Symbol *, size_t> Global;
+    llvm::MapVector<Symbol *, size_t> Relocs;
+    llvm::MapVector<Symbol *, size_t> Tls;
+    // Set of symbols referenced by dynamic TLS relocations.
+    llvm::MapVector<Symbol *, size_t> DynTlsSymbols;
+
+    // Total number of all entries.
+    size_t getEntriesNum() const;
+    // Number of "page" entries.
+    size_t getPageEntriesNum() const;
+    // Number of entries require 16-bit index to access.
+    size_t getIndexedEntriesNum() const;
+
+    bool isOverflow() const;
+  };
+
+  // Container of GOT created for each input file.
+  // After building a final series of GOTs this container
+  // holds primary and secondary GOT's.
+  std::vector<FileGot> Gots;
+
+  // Return (and create if necessary) `FileGot`.
+  FileGot &getGot(InputFile &F);
+
+  // Try to merge two GOTs. In case of success the `Dst` contains
+  // result of merging and the function returns true. In case of
+  // ovwerflow the `Dst` is unchanged and the function returns false.
+  bool tryMergeGots(FileGot & Dst, FileGot & Src, bool IsPrimary);
 };
 
 class GotPltSection final : public SyntheticSection {
@@ -318,7 +400,15 @@ public:
   DynamicReloc(RelType Type, const InputSectionBase *InputSec,
                uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend)
       : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
-        UseSymVA(UseSymVA), Addend(Addend) {}
+        UseSymVA(UseSymVA), Addend(Addend), OutputSec(nullptr) {}
+  // This constructor records dynamic relocation settings used by MIPS
+  // multi-GOT implementation. It's to relocate addresses of 64kb pages
+  // lie inside the output section.
+  DynamicReloc(RelType Type, const InputSectionBase *InputSec,
+               uint64_t OffsetInSec, const OutputSection *OutputSec,
+               int64_t Addend)
+      : Type(Type), Sym(nullptr), InputSec(InputSec), OffsetInSec(OffsetInSec),
+        UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {}
 
   uint64_t getOffset() const;
   uint32_t getSymIndex() const;
@@ -341,6 +431,7 @@ private:
   // plus the original addend as the final relocation addend.
   bool UseSymVA;
   int64_t Addend;
+  const OutputSection *OutputSec;
 };
 
 template <class ELFT> class DynamicSection final : public SyntheticSection {

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Jun 11 00:24:31 2018
@@ -1611,6 +1611,9 @@ template <class ELFT> void Writer<ELFT>:
   if (errorCount())
     return;
 
+  if (InX::MipsGot)
+    InX::MipsGot->build<ELFT>();
+
   removeUnusedSyntheticSections();
 
   sortSections();

Added: lld/trunk/test/ELF/Inputs/mips-mgot-1.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/mips-mgot-1.s?rev=334390&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/mips-mgot-1.s (added)
+++ lld/trunk/test/ELF/Inputs/mips-mgot-1.s Mon Jun 11 00:24:31 2018
@@ -0,0 +1,10 @@
+  .text
+  .global foo1
+foo1:
+  addiu  $2, $2, %gottprel(tls0)  # tls got entry
+  addiu  $2, $2, %gottprel(tls1)  # tls got entry
+
+  .section .tdata,"awT",%progbits
+  .global tls1
+tls1:
+  .word 0

Added: lld/trunk/test/ELF/Inputs/mips-mgot-2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/mips-mgot-2.s?rev=334390&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/mips-mgot-2.s (added)
+++ lld/trunk/test/ELF/Inputs/mips-mgot-2.s Mon Jun 11 00:24:31 2018
@@ -0,0 +1,17 @@
+  .text
+  .global foo2
+foo2:
+  lw     $2, %got(.data)($gp)     # page entry
+  addi   $2, $2, %lo(.data)
+  lw     $2, %call16(foo0)($gp)   # global entry
+  lw     $2, %call16(foo2)($gp)   # global entry
+  addiu  $2, $2, %tlsgd(tls0)     # tls gd entry
+  addiu  $2, $2, %gottprel(tls0)  # tls got entry
+
+  .data
+  .space 0x20000
+
+  .section .tdata,"awT",%progbits
+  .global tls2
+tls2:
+  .word 0

Added: lld/trunk/test/ELF/mips-abs-got.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-abs-got.s?rev=334390&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-abs-got.s (added)
+++ lld/trunk/test/ELF/mips-abs-got.s Mon Jun 11 00:24:31 2018
@@ -0,0 +1,36 @@
+# REQUIRES: mips
+
+# Check GOT relocations against absolute symbols.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -o %t.o %s
+# RUN: echo "SECTIONS { \
+# RUN:          zero = 0; foo = 0x11004; bar = 0x22000; }" > %t.script
+# RUN: ld.lld --script %t.script -o %t.exe %t.o
+# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s
+
+# CHECK:      Static GOT {
+# CHECK:        Local entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Access: -32736
+# CHECK-NEXT:       Initial: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Access: -32728
+# CHECK-NEXT:       Initial: 0x10000
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Access: -32720
+# CHECK-NEXT:       Initial: 0x30000
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT: }
+
+  .text
+  nop
+  .reloc 0, R_MIPS_GOT_PAGE, 0
+  ld      $v0, %got_page(zero)($gp)
+  ld      $v0, %got_page(foo)($gp)
+  ld      $v0, %got_page(bar+0x10008)($gp)

Modified: lld/trunk/test/ELF/mips-dynamic.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-dynamic.s?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-dynamic.s (original)
+++ lld/trunk/test/ELF/mips-dynamic.s Mon Jun 11 00:24:31 2018
@@ -99,8 +99,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-got-script.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-got-script.s?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-got-script.s (original)
+++ lld/trunk/test/ELF/mips-got-script.s Mon Jun 11 00:24:31 2018
@@ -7,8 +7,8 @@
 
 # REQUIRES: mips
 
-# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 5
-#                                    ^-- 2 * header + 3 local entries
+# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 4
+#                                    ^-- 2 * header + 2 local entries
 # CHECK:      Local entries [
 # CHECK-NEXT:   Entry {
 # CHECK-NEXT:     Address:
@@ -22,12 +22,6 @@
 # CHECK-NEXT:     Initial: 0x10000
 #                          ^-- loc2
 # CHECK-NEXT:   }
-# CHECK-NEXT:   Entry {
-# CHECK-NEXT:     Address:
-# CHECK-NEXT:     Access: -32736
-# CHECK-NEXT:     Initial: 0x20000
-#                          ^-- redundant
-# CHECK-NEXT:   }
 # CHECK-NEXT: ]
 
   .text

Modified: lld/trunk/test/ELF/mips-got-weak.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-got-weak.s?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-got-weak.s (original)
+++ lld/trunk/test/ELF/mips-got-weak.s Mon Jun 11 00:24:31 2018
@@ -3,15 +3,15 @@
 # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
 # RUN: ld.lld %t.o -shared -o %t1.so
 # RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t1.so \
-# RUN:   | FileCheck -check-prefix=NOSYM %s
+# RUN:   | FileCheck -check-prefixes=CHECK,NOSYM %s
 # RUN: ld.lld %t.o -shared -Bsymbolic -o %t2.so
 # RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t2.so \
-# RUN:   | FileCheck -check-prefix=SYM %s
+# RUN:   | FileCheck -check-prefixes=CHECK,SYM %s
 
 # REQUIRES: mips
 
-# NOSYM:      Relocations [
-# NOSYM-NEXT: ]
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
 
 # NOSYM:        Symbol {
 # NOSYM:          Name: foo
@@ -22,17 +22,19 @@
 # NOSYM-NEXT:     Other: 0
 # NOSYM-NEXT:     Section: .data
 # NOSYM-NEXT:   }
-# NOSYM-NEXT:   Symbol {
-# NOSYM-NEXT:     Name: bar
-# NOSYM-NEXT:     Value: 0x0
-# NOSYM-NEXT:     Size: 0
-# NOSYM-NEXT:     Binding: Weak
-# NOSYM-NEXT:     Type: None
-# NOSYM-NEXT:     Other: 0
-# NOSYM-NEXT:     Section: Undefined
-# NOSYM-NEXT:   }
-# NOSYM-NEXT:   Symbol {
-# NOSYM-NEXT:     Name: sym
+
+# CHECK:        Symbol {
+# CHECK:          Name: bar
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Weak
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+
+# NOSYM:        Symbol {
+# NOSYM:          Name: sym
 # NOSYM-NEXT:     Value: 0x20004
 # NOSYM-NEXT:     Size: 0
 # NOSYM-NEXT:     Binding: Global
@@ -40,30 +42,48 @@
 # NOSYM-NEXT:     Other: 0
 # NOSYM-NEXT:     Section: .data
 # NOSYM-NEXT:   }
-# NOSYM-NEXT: ]
 
-# NOSYM:      0x70000011 MIPS_SYMTABNO        4
-# NOSYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO     2
-# NOSYM-NEXT: 0x70000013 MIPS_GOTSYM          0x1
-
-# NOSYM:      Primary GOT {
-# NOSYM-NEXT:   Canonical gp value:
-# NOSYM-NEXT:   Reserved entries [
-# NOSYM-NEXT:     Entry {
-# NOSYM-NEXT:       Address:
-# NOSYM-NEXT:       Access: -32752
-# NOSYM-NEXT:       Initial: 0x0
-# NOSYM-NEXT:       Purpose: Lazy resolver
-# NOSYM-NEXT:     }
-# NOSYM-NEXT:     Entry {
-# NOSYM-NEXT:       Address:
-# NOSYM-NEXT:       Access: -32748
-# NOSYM-NEXT:       Initial: 0x80000000
-# NOSYM-NEXT:       Purpose: Module pointer (GNU extension)
-# NOSYM-NEXT:     }
-# NOSYM-NEXT:   ]
-# NOSYM-NEXT:   Local entries [
+# CHECK:      0x70000011 MIPS_SYMTABNO        4
+
+# SYM:        0x7000000A MIPS_LOCAL_GOTNO     4
+# SYM:        0x70000013 MIPS_GOTSYM          0x3
+
+# NOSYM:      0x7000000A MIPS_LOCAL_GOTNO     2
+# NOSYM:      0x70000013 MIPS_GOTSYM          0x1
+
+# CHECK:      Primary GOT {
+# CHECK-NEXT:   Canonical gp value:
+# CHECK-NEXT:   Reserved entries [
+# CHECK:        ]
+
+# SYM:         Local entries [
+# SYM-NEXT:       Entry {
+# SYM-NEXT:         Address:
+# SYM-NEXT:         Access: -32744
+# SYM-NEXT:         Initial: 0x20000
+# SYM-NEXT:       }
+# SYM-NEXT:       Entry {
+# SYM-NEXT:         Address:
+# SYM-NEXT:         Access: -32740
+# SYM-NEXT:         Initial: 0x20004
+# SYM-NEXT:       }
+# SYM-NEXT:     ]
+
+# NOSYM:        Local entries [
 # NOSYM-NEXT:   ]
+
+# SYM-NEXT:     Global entries [
+# SYM-NEXT:       Entry {
+# SYM-NEXT:         Address:
+# SYM-NEXT:         Access: -32736
+# SYM-NEXT:         Initial: 0x0
+# SYM-NEXT:         Value: 0x0
+# SYM-NEXT:         Type: None
+# SYM-NEXT:         Section: Undefined
+# SYM-NEXT:         Name: bar
+# SYM-NEXT:       }
+# SYM-NEXT:     ]
+
 # NOSYM-NEXT:   Global entries [
 # NOSYM-NEXT:     Entry {
 # NOSYM-NEXT:       Address:
@@ -93,68 +113,9 @@
 # NOSYM-NEXT:       Name: sym
 # NOSYM-NEXT:     }
 # NOSYM-NEXT:   ]
-# NOSYM-NEXT:   Number of TLS and multi-GOT entries: 0
-# NOSYM-NEXT: }
-
-# SYM:      Relocations [
-# SYM-NEXT: ]
 
-# SYM:        Symbol {
-# SYM:          Name: bar
-# SYM-NEXT:     Value: 0x0
-# SYM-NEXT:     Size: 0
-# SYM-NEXT:     Binding: Weak
-# SYM-NEXT:     Type: None
-# SYM-NEXT:     Other: 0
-# SYM-NEXT:     Section: Undefined
-# SYM-NEXT:   }
-# SYM-NEXT: ]
-
-# SYM:      0x70000011 MIPS_SYMTABNO        4
-# SYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO     4
-# SYM-NEXT: 0x70000013 MIPS_GOTSYM          0x3
-
-# SYM:      Primary GOT {
-# SYM-NEXT:   Canonical gp value:
-# SYM-NEXT:   Reserved entries [
-# SYM-NEXT:     Entry {
-# SYM-NEXT:       Address:
-# SYM-NEXT:       Access: -32752
-# SYM-NEXT:       Initial: 0x0
-# SYM-NEXT:       Purpose: Lazy resolver
-# SYM-NEXT:     }
-# SYM-NEXT:     Entry {
-# SYM-NEXT:       Address:
-# SYM-NEXT:       Access: -32748
-# SYM-NEXT:       Initial: 0x80000000
-# SYM-NEXT:       Purpose: Module pointer (GNU extension)
-# SYM-NEXT:     }
-# SYM-NEXT:   ]
-# SYM-NEXT:   Local entries [
-# SYM-NEXT:     Entry {
-# SYM-NEXT:       Address:
-# SYM-NEXT:       Access: -32744
-# SYM-NEXT:       Initial: 0x20000
-# SYM-NEXT:     }
-# SYM-NEXT:     Entry {
-# SYM-NEXT:       Address:
-# SYM-NEXT:       Access: -32740
-# SYM-NEXT:       Initial: 0x20004
-# SYM-NEXT:     }
-# SYM-NEXT:   ]
-# SYM-NEXT:   Global entries [
-# SYM-NEXT:     Entry {
-# SYM-NEXT:       Address:
-# SYM-NEXT:       Access: -32736
-# SYM-NEXT:       Initial: 0x0
-# SYM-NEXT:       Value: 0x0
-# SYM-NEXT:       Type: None
-# SYM-NEXT:       Section: Undefined
-# SYM-NEXT:       Name: bar
-# SYM-NEXT:     }
-# SYM-NEXT:   ]
-# SYM-NEXT:   Number of TLS and multi-GOT entries: 0
-# SYM-NEXT: }
+# CHECK:        Number of TLS and multi-GOT entries: 0
+# CHECK-NEXT: }
 
   .text
   .global  sym

Added: lld/trunk/test/ELF/mips-mgot.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-mgot.s?rev=334390&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-mgot.s (added)
+++ lld/trunk/test/ELF/mips-mgot.s Mon Jun 11 00:24:31 2018
@@ -0,0 +1,129 @@
+# Check MIPS multi-GOT layout.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t0.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %p/Inputs/mips-mgot-1.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %p/Inputs/mips-mgot-2.s -o %t2.o
+# RUN: ld.lld -shared -mips-got-size 52 %t0.o %t1.o %t2.o -o %t.so
+# RUN: llvm-objdump -s -section=.got -t %t.so | FileCheck %s
+# RUN: llvm-readobj -r -dt -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      Contents of section .got:
+# CHECK-NEXT:  60000 00000000 80000000 00010000 00010030
+# CHECK-NEXT:  60010 00020000 00030000 00040000 00050000
+# CHECK-NEXT:  60020 00060000 00070000 00000000 00000000
+# CHECK-NEXT:  60030 00000004 00000000 00000000 00000000
+# CHECK-NEXT:  60040 00000000 00020000 00030000 00040000
+# CHECK-NEXT:  60050 00050000 00060000 00070000 00000000
+# CHECK-NEXT:  60060 00000000 00000000 00000000 00000000
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00000000 l       .tdata          00000000 loc0
+# CHECK: 00010000         .text           00000000 foo0
+# CHECK: 00000000 g       .tdata          00000000 tls0
+# CHECK: 00010020         .text           00000000 foo1
+# CHECK: 00000004 g       .tdata          00000000 tls1
+# CHECK: 00010030         .text           00000000 foo2
+# CHECK: 00000008 g       .tdata          00000000 tls2
+
+# GOT:      Relocations [
+# GOT-NEXT:   Section (7) .rel.dyn {
+# GOT-NEXT:     0x60010 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60014 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60018 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x6001C R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60020 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60024 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60044 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60048 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x6004C R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60050 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60054 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60058 R_MIPS_REL32 - 0x0
+# GOT-NEXT:     0x60028 R_MIPS_REL32 foo0 0x0
+# GOT-NEXT:     0x6005C R_MIPS_REL32 foo0 0x0
+# GOT-NEXT:     0x60060 R_MIPS_REL32 foo2 0x0
+# GOT-NEXT:     0x6003C R_MIPS_TLS_DTPMOD32 - 0x0
+# GOT-NEXT:     0x60030 R_MIPS_TLS_TPREL32 tls1 0x0
+# GOT-NEXT:     0x6002C R_MIPS_TLS_TPREL32 tls0 0x0
+# GOT-NEXT:     0x60034 R_MIPS_TLS_DTPMOD32 tls0 0x0
+# GOT-NEXT:     0x60038 R_MIPS_TLS_DTPREL32 tls0 0x0
+# GOT-NEXT:     0x60064 R_MIPS_TLS_TPREL32 tls0 0x0
+# GOT-NEXT:     0x60068 R_MIPS_TLS_DTPMOD32 tls0 0x0
+# GOT-NEXT:     0x6006C R_MIPS_TLS_DTPREL32 tls0 0x0
+# GOT-NEXT:   }
+# GOT-NEXT: ]
+
+# GOT:      DynamicSymbols [
+# GOT:        Symbol {
+# GOT:          Name: foo0
+# GOT-NEXT:     Value: 0x10000
+# GOT:        }
+# GOT-NEXT:   Symbol {
+# GOT-NEXT:     Name: foo2
+# GOT-NEXT:     Value: 0x10030
+# GOT:        }
+# GOT-NEXT: ]
+
+# GOT:      Primary GOT {
+# GOT-NEXT:   Canonical gp value: 0x67FF0
+# GOT-NEXT:   Reserved entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32752
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Purpose: Lazy resolver
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32748
+# GOT-NEXT:       Initial: 0x80000000
+# GOT-NEXT:       Purpose: Module pointer (GNU extension)
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Local entries [
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x10000
+# GOT-NEXT:       Value: 0x10000
+# GOT-NEXT:       Type: None
+# GOT-NEXT:       Section: .text
+# GOT-NEXT:       Name: foo0
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32740
+# GOT-NEXT:       Initial: 0x10030
+# GOT-NEXT:       Value: 0x10030
+# GOT-NEXT:       Type: None
+# GOT-NEXT:       Section: .text
+# GOT-NEXT:       Name: foo2
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 24
+# GOT-NEXT: }
+
+  .text
+  .global foo0
+foo0:
+  lw     $2, %got(.data)($gp)     # page entry
+  addi   $2, $2, %lo(.data)
+  lw     $2, %call16(foo0)($gp)   # global entry
+  addiu  $2, $2, %tlsgd(tls0)     # tls gd entry
+  addiu  $2, $2, %gottprel(tls0)  # tls got entry
+  addiu  $2, $2, %tlsldm(loc0)    # tls ld entry
+
+  .data
+  .space 0x20000
+
+  .section .tdata,"awT",%progbits
+  .global tls0
+tls0:
+loc0:
+  .word 0

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=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-plt-copy.s (original)
+++ lld/trunk/test/ELF/mips-plt-copy.s Mon Jun 11 00:24:31 2018
@@ -12,12 +12,12 @@
 
 # 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-DAG:      0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
+# CHECK-DAG:      0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Section ({{.*}}) .rel.plt {
-# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0
-# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0
+# CHECK-DAG:      0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0
+# CHECK-DAG:      0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0
 # CHECK-NEXT:   }
 # CHECK-NEXT: ]
 

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=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-sto-plt.s (original)
+++ lld/trunk/test/ELF/mips-sto-plt.s Mon Jun 11 00:24:31 2018
@@ -10,23 +10,23 @@
 # REQUIRES: mips
 
 # CHECK:      Symbol {
-# CHECK:        Name: foo0@
-# CHECK-NEXT:   Value: 0x0
+# CHECK:        Name: foo1@
+# CHECK-NEXT:   Value: 0x[[FOO1:[0-9A-F]+]]
 # 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: }
 
@@ -48,7 +48,7 @@
 # CHECK-NEXT:     Entry {
 # CHECK-NEXT:       Address:
 # CHECK-NEXT:       Initial:
-# CHECK-NEXT:       Value: 0x20050
+# CHECK-NEXT:       Value: 0x[[FOO1]]
 # CHECK-NEXT:       Type: Function
 # CHECK-NEXT:       Section: Undefined
 # CHECK-NEXT:       Name: foo1

Modified: lld/trunk/test/ELF/mips-tls-64.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-tls-64.s?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-tls-64.s (original)
+++ lld/trunk/test/ELF/mips-tls-64.s Mon Jun 11 00:24:31 2018
@@ -16,18 +16,18 @@
 # REQUIRES: mips
 
 # DIS:      __start:
-# DIS-NEXT:    20000:   24 62 80 20   addiu   $2, $3, -32736
-# DIS-NEXT:    20004:   24 62 80 30   addiu   $2, $3, -32720
-# DIS-NEXT:    20008:   24 62 80 38   addiu   $2, $3, -32712
-# DIS-NEXT:    2000c:   24 62 80 48   addiu   $2, $3, -32696
-# DIS-NEXT:    20010:   24 62 80 58   addiu   $2, $3, -32680
+# DIS-NEXT:    20000:   24 62 80 30   addiu   $2, $3, -32720
+# DIS-NEXT:    20004:   24 62 80 20   addiu   $2, $3, -32736
+# DIS-NEXT:    20008:   24 62 80 40   addiu   $2, $3, -32704
+# DIS-NEXT:    2000c:   24 62 80 50   addiu   $2, $3, -32688
+# DIS-NEXT:    20010:   24 62 80 28   addiu   $2, $3, -32728
 
 # DIS:      Contents of section .got:
 # DIS-NEXT:  30010 00000000 00000000 80000000 00000000
-# DIS-NEXT:  30020 00000000 00000000 00000000 00000000
-# DIS-NEXT:  30030 00000000 00000000 00000000 00000001
-# DIS-NEXT:  30040 00000000 00000000 00000000 00000001
-# DIS-NEXT:  30050 ffffffff ffff8004 ffffffff ffff9004
+# DIS-NEXT:  30020 00000000 00000000 ffffffff ffff9004
+# DIS-NEXT:  30030 00000000 00000000 00000000 00000000
+# DIS-NEXT:  30040 00000000 00000001 00000000 00000000
+# DIS-NEXT:  30050 00000000 00000001 ffffffff ffff8004
 
 # DIS: 0000000000000000 l       .tdata          00000000 loc
 # DIS: 0000000000000004 g       .tdata          00000000 bar
@@ -35,9 +35,9 @@
 
 # CHECK:      Relocations [
 # CHECK-NEXT:   Section (7) .rel.dyn {
-# CHECK-NEXT:     0x30020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# CHECK-NEXT:     0x30028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# CHECK-NEXT:     0x30030 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT:     0x30020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT:     0x30030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT:     0x30038 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
 # CHECK-NEXT:   }
 # CHECK-NEXT: ]
 # CHECK-NEXT: Primary GOT {
@@ -49,31 +49,31 @@
 # CHECK-NEXT:   Global entries [
 # CHECK-NEXT:   ]
 # CHECK-NEXT:   Number of TLS and multi-GOT entries: 8
-#               ^-- -32736 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 foo
-#               ^-- -32728                     R_MIPS_TLS_DTPREL64 foo
-#               ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  foo
-#               ^-- -32712 R_MIPS_TLS_LDM      1 loc
-#               ^-- -32704                     0 loc
-#               ^-- -32696 R_MIPS_TLS_GD       1 bar
-#               ^-- -32688                     VA - 0x8000 bar
-#               ^-- -32680 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+#               ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  foo
+#               ^-- -32728 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+#               ^-- -32720 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 foo
+#               ^-- -32712                     R_MIPS_TLS_DTPREL64 foo
+#               ^-- -32704 R_MIPS_TLS_LDM      1 loc
+#               ^-- -32696                     0 loc
+#               ^-- -32688 R_MIPS_TLS_GD       1 bar
+#               ^-- -32680                     VA - 0x8000 bar
 
 # DIS-SO:      Contents of section .got:
 # DIS-SO-NEXT:  20000 00000000 00000000 80000000 00000000
-# DIS-SO-NEXT:  20010 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT:  20010 00000000 00000000 00000000 00000004
 # DIS-SO-NEXT:  20020 00000000 00000000 00000000 00000000
 # DIS-SO-NEXT:  20030 00000000 00000000 00000000 00000000
 # DIS-SO-NEXT:  20040 00000000 00000000 00000000 00000000
 
 # SO:      Relocations [
 # SO-NEXT:   Section (7) .rel.dyn {
-# SO-NEXT:     0x20028 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
-# SO-NEXT:     0x20038 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
-# SO-NEXT:     0x20040 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
-# SO-NEXT:     0x20048 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
-# SO-NEXT:     0x20010 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# SO-NEXT:     0x20018 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# SO-NEXT:     0x20020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:     0x20030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# SO-NEXT:     0x20010 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:     0x20020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:     0x20028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:     0x20018 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT:     0x20040 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT:     0x20048 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
 # SO-NEXT:   }
 # SO-NEXT: ]
 # SO-NEXT: Primary GOT {
@@ -85,14 +85,14 @@
 # SO-NEXT:   Global entries [
 # SO-NEXT:   ]
 # SO-NEXT:   Number of TLS and multi-GOT entries: 8
-#            ^-- -32736 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 foo
-#            ^-- -32728                     R_MIPS_TLS_DTPREL64 foo
-#            ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  foo
-#            ^-- -32712 R_MIPS_TLS_LDM      R_MIPS_TLS_DTPMOD64 loc
-#            ^-- -32704                     0 loc
-#            ^-- -32696 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 bar
-#            ^-- -32688                     R_MIPS_TLS_DTPREL64 bar
-#            ^-- -32680 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  bar
+#            ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  foo
+#            ^-- -32728 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  bar
+#            ^-- -32720 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 foo
+#            ^-- -32712                     R_MIPS_TLS_DTPREL64 foo
+#            ^-- -32704 R_MIPS_TLS_LDM      R_MIPS_TLS_DTPMOD64 loc
+#            ^-- -32696                     0 loc
+#            ^-- -32688 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 bar
+#            ^-- -32680                     R_MIPS_TLS_DTPREL64 bar
 
   .text
   .global  __start

Modified: lld/trunk/test/ELF/mips-tls-static.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-tls-static.s?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-tls-static.s (original)
+++ lld/trunk/test/ELF/mips-tls-static.s Mon Jun 11 00:24:31 2018
@@ -10,8 +10,8 @@
 # CHECK:      Contents of section .data:
 # CHECK-NEXT:  30000 0002000c ffff8004 ffff9004
 # CHECK:      Contents of section .got:
-# CHECK-NEXT:  30010 00000000 80000000 00000001 ffff8000
-# CHECK-NEXT:  30020 00000001 00000000 ffff9000
+# CHECK-NEXT:  30010 00000000 80000000 ffff9000 00000001
+# CHECK-NEXT:  30020 ffff8000 00000001 00000000
 #
 # CHECK: SYMBOL TABLE:
 # CHECK: 0002000c         .text           00000000 __tls_get_addr

Modified: lld/trunk/test/ELF/mips-tls.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-tls.s?rev=334390&r1=334389&r2=334390&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-tls.s (original)
+++ lld/trunk/test/ELF/mips-tls.s Mon Jun 11 00:24:31 2018
@@ -16,16 +16,16 @@
 # REQUIRES: mips
 
 # DIS:      __start:
-# DIS-NEXT:    20000:   24 62 80 18   addiu   $2, $3, -32744
-# DIS-NEXT:    20004:   24 62 80 20   addiu   $2, $3, -32736
-# DIS-NEXT:    20008:   24 62 80 24   addiu   $2, $3, -32732
-# DIS-NEXT:    2000c:   24 62 80 2c   addiu   $2, $3, -32724
-# DIS-NEXT:    20010:   24 62 80 34   addiu   $2, $3, -32716
+# DIS-NEXT:    20000:   24 62 80 20   addiu   $2, $3, -32736
+# DIS-NEXT:    20004:   24 62 80 18   addiu   $2, $3, -32744
+# DIS-NEXT:    20008:   24 62 80 28   addiu   $2, $3, -32728
+# DIS-NEXT:    2000c:   24 62 80 30   addiu   $2, $3, -32720
+# DIS-NEXT:    20010:   24 62 80 1c   addiu   $2, $3, -32740
 
 # DIS:      Contents of section .got:
-# DIS-NEXT:  30010 00000000 80000000 00000000 00000000
-# DIS-NEXT:  30020 00000000 00000001 00000000 00000001
-# DIS-NEXT:  30030 ffff8004 ffff9004
+# DIS-NEXT:  30010 00000000 80000000 00000000 ffff9004
+# DIS-NEXT:  30020 00000000 00000000 00000001 00000000
+# DIS-NEXT:  30030 00000001 ffff8004
 
 # DIS: 00000000 l       .tdata          00000000 loc
 # DIS: 00000004 g       .tdata          00000000 bar
@@ -33,9 +33,9 @@
 
 # CHECK:      Relocations [
 # CHECK-NEXT:   Section (7) .rel.dyn {
-# CHECK-NEXT:     0x30018 R_MIPS_TLS_DTPMOD32 foo 0x0
-# CHECK-NEXT:     0x3001C R_MIPS_TLS_DTPREL32 foo 0x0
-# CHECK-NEXT:     0x30020 R_MIPS_TLS_TPREL32 foo 0x0
+# CHECK-NEXT:     0x30018 R_MIPS_TLS_TPREL32 foo 0x0
+# CHECK-NEXT:     0x30020 R_MIPS_TLS_DTPMOD32 foo 0x0
+# CHECK-NEXT:     0x30024 R_MIPS_TLS_DTPREL32 foo 0x0
 # CHECK-NEXT:   }
 # CHECK-NEXT: ]
 # CHECK-NEXT: Primary GOT {
@@ -47,29 +47,29 @@
 # CHECK-NEXT:   Global entries [
 # CHECK-NEXT:   ]
 # CHECK-NEXT:   Number of TLS and multi-GOT entries: 8
-#               ^-- -32744 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 foo
-#               ^-- -32740                     R_MIPS_TLS_DTPREL32 foo
-#               ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  foo
-#               ^-- -32732 R_MIPS_TLS_LDM      1 loc
-#               ^-- -32728                     0 loc
-#               ^-- -32724 R_MIPS_TLS_GD       1 bar
-#               ^-- -32720                     VA - 0x8000 bar
-#               ^-- -32716 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+#               ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  foo
+#               ^-- -32740 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+#               ^-- -32736 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 foo
+#               ^-- -32732                     R_MIPS_TLS_DTPREL32 foo
+#               ^-- -32728 R_MIPS_TLS_LDM      1 loc
+#               ^-- -32724                     0 loc
+#               ^-- -32720 R_MIPS_TLS_GD       1 bar
+#               ^-- -32716                     VA - 0x8000 bar
 
 # DIS-SO:      Contents of section .got:
-# DIS-SO-NEXT:  20000 00000000 80000000 00000000 00000000
+# DIS-SO-NEXT:  20000 00000000 80000000 00000000 00000004
 # DIS-SO-NEXT:  20010 00000000 00000000 00000000 00000000
 # DIS-SO-NEXT:  20020 00000000 00000000
 
 # SO:      Relocations [
 # SO-NEXT:   Section (7) .rel.dyn {
-# SO-NEXT:     0x20014 R_MIPS_TLS_DTPMOD32 - 0x0
-# SO-NEXT:     0x2001C R_MIPS_TLS_DTPMOD32 bar 0x0
-# SO-NEXT:     0x20020 R_MIPS_TLS_DTPREL32 bar 0x0
-# SO-NEXT:     0x20024 R_MIPS_TLS_TPREL32 bar 0x0
-# SO-NEXT:     0x20008 R_MIPS_TLS_DTPMOD32 foo 0x0
-# SO-NEXT:     0x2000C R_MIPS_TLS_DTPREL32 foo 0x0
-# SO-NEXT:     0x20010 R_MIPS_TLS_TPREL32 foo 0x0
+# SO-NEXT:     0x20018 R_MIPS_TLS_DTPMOD32 - 0x0
+# SO-NEXT:     0x20008 R_MIPS_TLS_TPREL32 foo 0x0
+# SO-NEXT:     0x20010 R_MIPS_TLS_DTPMOD32 foo 0x0
+# SO-NEXT:     0x20014 R_MIPS_TLS_DTPREL32 foo 0x0
+# SO-NEXT:     0x2000C R_MIPS_TLS_TPREL32 bar 0x0
+# SO-NEXT:     0x20020 R_MIPS_TLS_DTPMOD32 bar 0x0
+# SO-NEXT:     0x20024 R_MIPS_TLS_DTPREL32 bar 0x0
 # SO-NEXT:   }
 # SO-NEXT: ]
 # SO-NEXT: Primary GOT {
@@ -81,14 +81,14 @@
 # SO-NEXT:   Global entries [
 # SO-NEXT:   ]
 # SO-NEXT:   Number of TLS and multi-GOT entries: 8
-#            ^-- -32744 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 foo
-#            ^-- -32740 R_MIPS_TLS_DTPREL32 foo
-#            ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  foo
-#            ^-- -32732 R_MIPS_TLS_LDM      R_MIPS_TLS_DTPMOD32 loc
-#            ^-- -32728 0 loc
-#            ^-- -32724 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 bar
-#            ^-- -32720 R_MIPS_TLS_DTPREL32 bar
-#            ^-- -32716 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  bar
+#            ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  foo
+#            ^-- -32740 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  bar
+#            ^-- -32736 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 foo
+#            ^-- -32732 R_MIPS_TLS_DTPREL32 foo
+#            ^-- -32728 R_MIPS_TLS_LDM      R_MIPS_TLS_DTPMOD32 loc
+#            ^-- -32724 0 loc
+#            ^-- -32720 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 bar
+#            ^-- -32716 R_MIPS_TLS_DTPREL32 bar
 
   .text
   .global  __start




More information about the llvm-commits mailing list