[lld] r273569 - [ELF][MIPS] Support MIPS TLS relocations

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 23 08:26:31 PDT 2016


Author: atanasyan
Date: Thu Jun 23 10:26:31 2016
New Revision: 273569

URL: http://llvm.org/viewvc/llvm-project?rev=273569&view=rev
Log:
[ELF][MIPS] Support MIPS TLS relocations

The patch adds one more partition to the MIPS GOT. This time it is for
TLS related GOT entries. Such entries are located after 'local' and 'global'
ones. We cannot get a final offset for these entries at the time of
creation because we do not know size of 'local' and 'global' partitions.
So we have to adjust the offset later using `getMipsTlsOffset()` method.

All MIPS TLS relocations which need GOT entries operates MIPS style GOT
offset - 'offset from the GOT's beginning' - MipsGPOffset constant. That
is why I add new types of relocation expressions.

One more difference from othe ABIs is that the MIPS ABI does not support
any TLS relocation relaxations. I decided to make a separate function
`handleMipsTlsRelocation` and put MIPS TLS relocation handling code
there. It is similar to `handleTlsRelocation` routine and duplicates its
code. But it allows to make the code cleaner and prevent pollution of
the `handleTlsRelocation` by MIPS 'if' statements.

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

Added:
    lld/trunk/test/ELF/Inputs/mips-tls.s
    lld/trunk/test/ELF/mips-tls-64.s
    lld/trunk/test/ELF/mips-tls.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/Target.cpp

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=273569&r1=273568&r2=273569&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Thu Jun 23 10:26:31 2016
@@ -220,6 +220,12 @@ getSymVA(uint32_t Type, typename ELFT::u
     // 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_MIPS_TLSGD:
+    return Out<ELFT>::Got->getGlobalDynOffset(Body) +
+           Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+  case R_MIPS_TLSLD:
+    return Out<ELFT>::Got->getTlsIndexOff() +
+           Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
   case R_PPC_OPD: {
     uint64_t SymVA = Body.getVA<ELFT>(A);
     // If we have an undefined weak symbol, we might get here with a symbol

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=273569&r1=273568&r2=273569&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Jun 23 10:26:31 2016
@@ -135,6 +135,14 @@ void GotSection<ELFT>::addMipsEntry(Symb
     MipsOutSections.insert(OutSec);
     return;
   }
+  if (Sym.isTls()) {
+    // GOT entries created for MIPS TLS relocations behave like
+    // almost GOT entries from other ABIs. They go to the end
+    // of the global offset table.
+    Sym.GotIndex = Entries.size();
+    Entries.push_back(&Sym);
+    return;
+  }
   auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) {
     if (S.isInGot() && !A)
       return;
@@ -192,7 +200,9 @@ 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)
+  if (B.isTls())
+    Off += MipsLocal.size() + MipsGlobal.size() + B.GotIndex;
+  else if (B.IsInGlobalMipsGot)
     Off += MipsLocal.size() + B.GotIndex;
   else if (B.isInGot())
     Off += B.GotIndex;
@@ -205,6 +215,12 @@ GotSection<ELFT>::getMipsGotOffset(const
 }
 
 template <class ELFT>
+typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() {
+  return (MipsPageEntries + MipsLocal.size() + MipsGlobal.size()) *
+         sizeof(uintX_t);
+}
+
+template <class ELFT>
 typename GotSection<ELFT>::uintX_t
 GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
   return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
@@ -355,6 +371,11 @@ template <class ELFT> void RelocationSec
     if (Config->Rela)
       P->r_addend = Rel.getAddend();
     P->r_offset = Rel.getOffset();
+    if (Config->EMachine == EM_MIPS && Rel.getOutputSec() == Out<ELFT>::Got)
+      // Dynamic relocation against MIPS GOT section make deal TLS entries
+      // allocated in the end of the GOT. We need to adjust the offset to take
+      // in account 'local' and 'global' GOT entries.
+      P->r_offset += Out<ELFT>::Got->getMipsTlsOffset();
     P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
   }
 

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=273569&r1=273568&r2=273569&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Jun 23 10:26:31 2016
@@ -134,6 +134,10 @@ public:
   // the number of reserved entries. This method is MIPS-specific.
   unsigned getMipsLocalEntriesNum() const;
 
+  // Returns offset of TLS part of the MIPS GOT table. This part goes
+  // after 'local' and 'global' entries.
+  uintX_t getMipsTlsOffset();
+
   uintX_t getTlsIndexVA() { return Base::getVA() + TlsIndexOff; }
   uint32_t getTlsIndexOff() { return TlsIndexOff; }
 
@@ -215,6 +219,7 @@ public:
   uintX_t getOffset() const;
   uintX_t getAddend() const;
   uint32_t getSymIndex() const;
+  const OutputSectionBase<ELFT> *getOutputSec() const { return OutputSec; }
 
   uint32_t Type;
 

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=273569&r1=273568&r2=273569&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Thu Jun 23 10:26:31 2016
@@ -60,7 +60,8 @@ namespace elf {
 
 static bool refersToGotEntry(RelExpr Expr) {
   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_MIPS_GOT_OFF || Expr == R_MIPS_TLSGD ||
+         Expr == R_MIPS_TLSLD || 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;
 }
@@ -81,6 +82,39 @@ static bool isPreemptible(const SymbolBo
   return Body.isPreemptible();
 }
 
+// This function is similar to the `handleTlsRelocation`. MIPS does not support
+// any relaxations for TLS relocations so by factoring out MIPS handling into
+// the separate function we can simplify the code and does not pollute
+// `handleTlsRelocation` by MIPS `ifs` statements.
+template <class ELFT>
+static unsigned
+handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
+                        InputSectionBase<ELFT> &C, typename ELFT::uint Offset,
+                        typename ELFT::uint Addend, RelExpr Expr) {
+  if (Expr == R_MIPS_TLSLD) {
+    if (Out<ELFT>::Got->addTlsIndex())
+      Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
+                                    Out<ELFT>::Got->getTlsIndexOff(), false,
+                                    nullptr, 0});
+    C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+    return 1;
+  }
+  if (Target->isTlsGlobalDynamicRel(Type)) {
+    if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+      typedef typename ELFT::uint uintX_t;
+      uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+      Out<ELFT>::RelaDyn->addReloc(
+          {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
+      Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
+                                    Off + (uintX_t)sizeof(uintX_t), false,
+                                    &Body, 0});
+    }
+    C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+    return 1;
+  }
+  return 0;
+}
+
 // Returns the number of relocations processed.
 template <class ELFT>
 static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
@@ -95,6 +129,9 @@ static unsigned handleTlsRelocation(uint
 
   typedef typename ELFT::uint uintX_t;
 
+  if (Config->EMachine == EM_MIPS)
+    return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
+
   if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) &&
       Config->Shared) {
     if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
@@ -254,9 +291,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_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)
+      E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_MIPS_TLSGD ||
+      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
@@ -603,6 +640,9 @@ static void scanRelocs(InputSectionBase<
         // for detailed description:
         // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
         Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+        if (Body.isTls())
+          AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
+                  !Preemptible, &Body, 0});
         continue;
       }
 

Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=273569&r1=273568&r2=273569&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Thu Jun 23 10:26:31 2016
@@ -30,6 +30,8 @@ enum RelExpr {
   R_HINT,
   R_MIPS_GOT_LOCAL_PAGE,
   R_MIPS_GOT_OFF,
+  R_MIPS_TLSGD,
+  R_MIPS_TLSLD,
   R_NEG_TLS,
   R_PAGE_PC,
   R_PC,

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=273569&r1=273568&r2=273569&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Thu Jun 23 10:26:31 2016
@@ -190,6 +190,8 @@ public:
   RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
   uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
   uint32_t getDynRel(uint32_t Type) const override;
+  bool isTlsLocalDynamicRel(uint32_t Type) const override;
+  bool isTlsGlobalDynamicRel(uint32_t Type) const override;
   void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
   void writePltHeader(uint8_t *Buf) const override;
   void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
@@ -1706,10 +1708,17 @@ template <class ELFT> MipsTargetInfo<ELF
   ThunkSize = 16;
   CopyRel = R_MIPS_COPY;
   PltRel = R_MIPS_JUMP_SLOT;
-  if (ELFT::Is64Bits)
+  if (ELFT::Is64Bits) {
     RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
-  else
+    TlsGotRel = R_MIPS_TLS_TPREL64;
+    TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64;
+    TlsOffsetRel = R_MIPS_TLS_DTPREL64;
+  } else {
     RelativeRel = R_MIPS_REL32;
+    TlsGotRel = R_MIPS_TLS_TPREL32;
+    TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32;
+    TlsOffsetRel = R_MIPS_TLS_DTPREL32;
+  }
 }
 
 template <class ELFT>
@@ -1752,9 +1761,14 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr
   // fallthrough
   case R_MIPS_CALL16:
   case R_MIPS_GOT_DISP:
+  case R_MIPS_TLS_GOTTPREL:
     return R_MIPS_GOT_OFF;
   case R_MIPS_GOT_PAGE:
     return R_MIPS_GOT_LOCAL_PAGE;
+  case R_MIPS_TLS_GD:
+    return R_MIPS_TLSGD;
+  case R_MIPS_TLS_LDM:
+    return R_MIPS_TLSLD;
   }
 }
 
@@ -1768,6 +1782,16 @@ uint32_t MipsTargetInfo<ELFT>::getDynRel
 }
 
 template <class ELFT>
+bool MipsTargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
+  return Type == R_MIPS_TLS_LDM;
+}
+
+template <class ELFT>
+bool MipsTargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
+  return Type == R_MIPS_TLS_GD;
+}
+
+template <class ELFT>
 void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
   write32<ELFT::TargetEndianness>(Buf, Out<ELFT>::Plt->getVA());
 }
@@ -1961,6 +1985,8 @@ void MipsTargetInfo<ELFT>::relocateOne(u
   case R_MIPS_GOT_PAGE:
   case R_MIPS_GOT16:
   case R_MIPS_GPREL16:
+  case R_MIPS_TLS_GD:
+  case R_MIPS_TLS_LDM:
     checkInt<16>(Val, Type);
   // fallthrough
   case R_MIPS_CALL16:
@@ -1968,6 +1994,7 @@ void MipsTargetInfo<ELFT>::relocateOne(u
   case R_MIPS_LO16:
   case R_MIPS_PCLO16:
   case R_MIPS_TLS_DTPREL_LO16:
+  case R_MIPS_TLS_GOTTPREL:
   case R_MIPS_TLS_TPREL_LO16:
     writeMipsLo16<E>(Loc, Val);
     break;

Added: lld/trunk/test/ELF/Inputs/mips-tls.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/mips-tls.s?rev=273569&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/mips-tls.s (added)
+++ lld/trunk/test/ELF/Inputs/mips-tls.s Thu Jun 23 10:26:31 2016
@@ -0,0 +1,5 @@
+ .globl   foo
+ .section .tdata,"awT",%progbits
+ .type    foo, %object
+foo:
+ .word 0

Added: lld/trunk/test/ELF/mips-tls-64.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-tls-64.s?rev=273569&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-tls-64.s (added)
+++ lld/trunk/test/ELF/mips-tls-64.s Thu Jun 23 10:26:31 2016
@@ -0,0 +1,86 @@
+# Check MIPS TLS 64-bit relocations handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %p/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld -shared %t.so.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# DIS:      __start:
+# DIS-NEXT:    20000:   24 62 80 28   addiu   $2, $3, -32728
+# DIS-NEXT:    20004:   24 62 80 38   addiu   $2, $3, -32712
+# DIS-NEXT:    20008:   8f 82 80 20   lw      $2, -32736($gp)
+# DIS-NEXT:    2000c:   24 62 80 48   addiu   $2, $3, -32696
+
+# DIS:      Contents of section .got:
+# DIS_NEXT:  30008 00000000 00000000 80000000 00000000
+# DIS_NEXT:  30018 00000000 00020000 00000000 00000000
+# DIS_NEXT:  30028 00000000 00000004 00000000 00000000
+# DIS_NEXT:  30038 00000000 00000000 00000000 00000004
+
+# DIS: 0000000000030000 l       .tdata          00000000 .tdata
+# DIS: 0000000000030000 l       .tdata          00000000 loc
+# DIS: 0000000000000004 g       .tdata          00000000 foo
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rela.dyn {
+# CHECK-NEXT:     0x30020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# CHECK-NEXT:     0x30028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# CHECK-NEXT:     0x30030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# CHECK-NEXT:     0x30040 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE - 0x4
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Primary GOT {
+# CHECK-NEXT:   Canonical gp value: 0x37FF8
+# CHECK-NEXT:   Reserved entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30008
+# CHECK-NEXT:       Access: -32752
+# CHECK-NEXT:       Initial: 0x0
+# CHECK-NEXT:       Purpose: Lazy resolver
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30010
+# CHECK-NEXT:       Access: -32744
+# CHECK-NEXT:       Initial: 0x80000000
+# CHECK-NEXT:       Purpose: Module pointer (GNU extension)
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30018
+# CHECK-NEXT:       Access: -32736
+# CHECK-NEXT:       Initial: 0x0
+# CHECK-NEXT:       Value: 0x0
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo0
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 5
+#               ^-- 0x30020 / -32728 - R_MIPS_TLS_GD  - R_MIPS_TLS_DTPMOD32 foo
+#               ^-- 0x30028 / -32720                  - R_MIPS_TLS_DTPREL32 foo
+#               ^-- 0x30030 / -32712 - R_MIPS_TLS_LDM - R_MIPS_TLS_DTPMOD32 loc
+#               ^-- 0x30038 / -32704
+#               ^-- 0x30040 / -32696 - R_MIPS_TLS_GOTTPREL - R_MIPS_TLS_TPREL32
+
+  .text
+  .global  __start
+__start:
+  addiu $2, $3, %tlsgd(foo)     # R_MIPS_TLS_GD
+  addiu $2, $3, %tlsldm(loc)    # R_MIPS_TLS_LDM
+  lw    $2, %got(foo0)($gp)
+  addiu $2, $3, %gottprel(foo)  # R_MIPS_TLS_GOTTPREL
+
+ .section .tdata,"awT",%progbits
+ .global foo
+loc:
+ .word 0
+foo:
+ .word 0

Added: lld/trunk/test/ELF/mips-tls.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-tls.s?rev=273569&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-tls.s (added)
+++ lld/trunk/test/ELF/mips-tls.s Thu Jun 23 10:26:31 2016
@@ -0,0 +1,77 @@
+# Check MIPS TLS relocations handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %p/Inputs/mips-tls.s -o %t.so.o
+# RUN: ld.lld -shared %t.so.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# DIS:      __start:
+# DIS-NEXT:    20000:   24 62 80 1c   addiu   $2, $3, -32740
+# DIS-NEXT:    20004:   24 62 80 24   addiu   $2, $3, -32732
+# DIS-NEXT:    20008:   8f 82 80 18   lw      $2, -32744($gp)
+# DIS-NEXT:    2000c:   24 62 80 2c   addiu   $2, $3, -32724
+
+# DIS:      Contents of section .got:
+# DIS_NEXT:  30004 00000000 80000000 00020000 00000000
+# DIS_NEXT:  30014 00000000 00000000 00000000 00000000
+
+# DIS: 00030000 l       .tdata          00000000 .tdata
+# DIS: 00030000 l       .tdata          00000000 loc
+# DIS: 00000000 g       *UND*           00000000 foo
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rel.dyn {
+# CHECK-NEXT:     0x30018 R_MIPS_TLS_DTPMOD32 - 0x0
+# CHECK-NEXT:     0x30010 R_MIPS_TLS_DTPMOD32 foo 0x0
+# CHECK-NEXT:     0x30014 R_MIPS_TLS_DTPREL32 foo 0x0
+# CHECK-NEXT:     0x30020 R_MIPS_TLS_TPREL32 foo 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Primary GOT {
+# CHECK-NEXT:   Canonical gp value: 0x37FF4
+# CHECK-NEXT:   Reserved entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30004
+# CHECK-NEXT:       Access: -32752
+# CHECK-NEXT:       Initial: 0x0
+# CHECK-NEXT:       Purpose: Lazy resolver
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x30008
+# CHECK-NEXT:       Access: -32748
+# CHECK-NEXT:       Initial: 0x80000000
+# CHECK-NEXT:       Purpose: Module pointer (GNU extension)
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x3000C
+# CHECK-NEXT:       Access: -32744
+# CHECK-NEXT:       Initial: 0x20000
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 5
+#               ^-- 0x30010 / -32740 - R_MIPS_TLS_GD  - R_MIPS_TLS_DTPMOD32 foo
+#               ^-- 0x30018 / -32736                  - R_MIPS_TLS_DTPREL32 foo
+#               ^-- 0x3001C / -32732 - R_MIPS_TLS_LDM - R_MIPS_TLS_DTPMOD32 loc
+#               ^-- 0x30020 / -32728
+#               ^-- 0x30024 / -32724 - R_MIPS_TLS_GOTTPREL - R_MIPS_TLS_TPREL32
+
+  .text
+  .global  __start
+__start:
+  addiu $2, $3, %tlsgd(foo)     # R_MIPS_TLS_GD
+  addiu $2, $3, %tlsldm(loc)    # R_MIPS_TLS_LDM
+  lw    $2, %got(__start)($gp)
+  addiu $2, $3, %gottprel(foo)  # R_MIPS_TLS_GOTTPREL
+
+ .section .tdata,"awT",%progbits
+loc:
+ .word 0




More information about the llvm-commits mailing list