[ELF][MIPS] Fix initialization of TLS-related GOT entries
authorSimon Atanasyan <simon@atanasyan.com>
Thu, 8 Sep 2016 09:07:19 +0000 (09:07 +0000)
committerSimon Atanasyan <simon@atanasyan.com>
Thu, 8 Sep 2016 09:07:19 +0000 (09:07 +0000)
This patch allows static linking of TLS code. To do that it fixes
GOT entries initialization.

If TLS-related GOT entry created for a preemptible symbol i.e. has
a corresponding dynamic relocation, leave the entry initialized by zero.
Write down adjusted TLS symbol's values otherwise. For the adjustments
calculation use offsets for thread-local storage.

https://www.linux-mips.org/wiki/NPTL

llvm-svn: 280914

lld/ELF/OutputSections.cpp
lld/ELF/OutputSections.h
lld/ELF/Relocations.cpp
lld/test/ELF/mips-tls-64.s
lld/test/ELF/mips-tls-static.s
lld/test/ELF/mips-tls.s

index f245120..278e5c5 100644 (file)
@@ -261,7 +261,7 @@ template <class ELFT> void GotSection<ELFT>::finalize() {
   this->Header.sh_size = EntriesNum * sizeof(uintX_t);
 }
 
-template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *&Buf) {
+template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *Buf) {
   // Set the MSB of the second GOT slot. This is not required by any
   // MIPS ABI documentation, though.
   //
@@ -293,11 +293,38 @@ template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *&Buf) {
   };
   std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
   std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
+  // Initialize TLS-related GOT entries. If the entry has a corresponding
+  // dynamic relocations, leave it initialized by zero. Write down adjusted
+  // TLS symbol's values otherwise. To calculate the adjustments use offsets
+  // for thread-local storage.
+  // https://www.linux-mips.org/wiki/NPTL
+  if (TlsIndexOff != -1U && !Config->Pic)
+    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf + TlsIndexOff,
+                                                            1);
+  for (const SymbolBody *B : Entries) {
+    if (!B || B->isPreemptible())
+      continue;
+    uintX_t VA = B->getVA<ELFT>();
+    if (B->GotIndex != -1U) {
+      uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
+      write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry,
+                                                              VA - 0x7000);
+    }
+    if (B->GlobalDynIndex != -1U) {
+      uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
+      write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, 1);
+      Entry += sizeof(uintX_t);
+      write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry,
+                                                              VA - 0x8000);
+    }
+  }
 }
 
 template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
-  if (Config->EMachine == EM_MIPS)
+  if (Config->EMachine == EM_MIPS) {
     writeMipsGot(Buf);
+    return;
+  }
   for (const SymbolBody *B : Entries) {
     uint8_t *Entry = Buf;
     Buf += sizeof(uintX_t);
index a5833a6..5fee870 100644 (file)
@@ -181,7 +181,7 @@ private:
   MipsGotEntries MipsGlobal;
 
   // Write MIPS-specific parts of the GOT.
-  void writeMipsGot(uint8_t *&Buf);
+  void writeMipsGot(uint8_t *Buf);
 };
 
 template <class ELFT>
index 0244f02..af72aaa 100644 (file)
@@ -93,7 +93,7 @@ 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())
+    if (Out<ELFT>::Got->addTlsIndex() && Config->Pic)
       Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
                                     Out<ELFT>::Got->getTlsIndexOff(), false,
                                     nullptr, 0});
@@ -101,7 +101,7 @@ handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
     return 1;
   }
   if (Target->isTlsGlobalDynamicRel(Type)) {
-    if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+    if (Out<ELFT>::Got->addDynTlsEntry(Body) && Body.isPreemptible()) {
       typedef typename ELFT::uint uintX_t;
       uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
       Out<ELFT>::RelaDyn->addReloc(
@@ -666,9 +666,9 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
         // 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())
+        if (Body.isTls() && Body.isPreemptible())
           AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
-                  !Preemptible, &Body, 0});
+                  false, &Body, 0});
         continue;
       }
 
index 9c05e94..808fa4c 100644 (file)
 # 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:         %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=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
 
+# RUN: ld.lld -shared %t.o %t.so -o %t-out.so
+# RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s
+# RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %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:    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:      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-NEXT:  30008 00000000 00000000 80000000 00000000
+# DIS-NEXT:  30018 00000000 00000000 00000000 00000000
+# DIS-NEXT:  30028 00000000 00000000 00000000 00000001
+# DIS-NEXT:  30038 00000000 00000000 00000000 00000001
+# DIS-NEXT:  30048 ffffffff ffff8004 ffffffff ffff9004
 
 # DIS: 0000000000030000 l       .tdata          00000000 .tdata
 # DIS: 0000000000030000 l       .tdata          00000000 loc
-# DIS: 0000000000000004 g       .tdata          00000000 foo
+# DIS: 0000000000000004 g       .tdata          00000000 bar
+# DIS: 0000000000000000 g       *UND*           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:     0x30018 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT:     0x30020 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT:     0x30028 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
 # 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:        ]
 # 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
+# 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
+
+# DIS-SO:      Contents of section .got:
+# DIS-SO-NEXT:  20008 00000000 00000000 80000000 00000000
+# DIS-SO-NEXT:  20018 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT:  20028 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT:  20038 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT:  20048 00000000 00000000 00000000 00000000
+
+# SO:      Relocations [
+# SO-NEXT:   Section (7) .rela.dyn {
+# SO-NEXT:     0x20030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 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:     0x20050 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT:     0x20018 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:     0x20020 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:     0x20028 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:   }
+# SO-NEXT: ]
+# SO-NEXT: Primary GOT {
+# SO-NEXT:   Canonical gp value: 0x27FF8
+# SO-NEXT:   Reserved entries [
+# SO:        ]
+# SO-NEXT:   Local entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Global entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Number of TLS and multi-GOT entries: 8
+#            ^-- 0x20018 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 foo
+#            ^-- 0x20020                     R_MIPS_TLS_DTPREL64 foo
+#            ^-- 0x20028 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  foo
+#            ^-- 0x20030 R_MIPS_TLS_LDM      R_MIPS_TLS_DTPMOD64 loc
+#            ^-- 0x20038                     0 loc
+#            ^-- 0x20040 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 bar
+#            ^-- 0x20048                     R_MIPS_TLS_DTPREL64 bar
+#            ^-- 0x20050 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  bar
 
   .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
+  addiu $2, $3, %tlsldm(loc)    # R_MIPS_TLS_LDM
+  addiu $2, $3, %tlsgd(bar)     # R_MIPS_TLS_GD
+  addiu $2, $3, %gottprel(bar)  # R_MIPS_TLS_GOTTPREL
 
  .section .tdata,"awT",%progbits
- .global foo
+ .global bar
 loc:
  .word 0
-foo:
+bar:
  .word 0
index a641a8e..6f0fa55 100644 (file)
@@ -7,17 +7,22 @@
 
 # REQUIRES: mips
 
+# CHECK:      Contents of section .got:
+# CHECK-NEXT:  30008 00000000 80000000 00000001 ffff8000
+# CHECK-NEXT:  30018 00000001 00000000 ffff9000
 # CHECK:      Contents of section .data:
-# CHECK-NEXT:  40000 00020004 ffff8004 ffff9004
+# CHECK-NEXT:  40000 0002000c ffff8004 ffff9004
 #
 # CHECK: SYMBOL TABLE:
-# CHECK: 00020004         .text           00000000 __tls_get_addr
+# CHECK: 0002000c         .text           00000000 __tls_get_addr
 # CHECK: 00000000 g       .tdata          00000000 tls1
 
   .text
   .global __start
 __start:
-  nop
+  addiu $2, $3, %tlsgd(tls1)      # R_MIPS_TLS_GD
+  addiu $2, $3, %tlsldm(tls2)     # R_MIPS_TLS_LDM
+  addiu $2, $3, %gottprel(tls1)   # R_MIPS_TLS_GOTTPREL
 
   .global __tls_get_addr
 __tls_get_addr:
@@ -33,4 +38,5 @@ loc:
  .global tls1
 tls1:
  .word __tls_get_addr
+tls2:
  .word 0
index 9635558..fa02324 100644 (file)
 # 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
 
+# RUN: ld.lld -shared %t.o %t.so -o %t-out.so
+# RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s
+# RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %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:    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:      Contents of section .got:
-# DIS_NEXT:  30004 00000000 80000000 00020000 00000000
-# DIS_NEXT:  30014 00000000 00000000 00000000 00000000
+# DIS-NEXT:  30008 00000000 80000000 00000000 00000000
+# DIS-NEXT:  30018 00000000 00000001 00000000 00000001
+# DIS-NEXT:  30028 ffff8004 ffff9004
 
 # DIS: 00030000 l       .tdata          00000000 .tdata
 # DIS: 00030000 l       .tdata          00000000 loc
+# DIS: 00000004 g       .tdata          00000000 bar
 # 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:     0x30018 R_MIPS_TLS_TPREL32 foo 0x0
 # CHECK-NEXT:   }
 # CHECK-NEXT: ]
 # CHECK-NEXT: Primary GOT {
-# CHECK-NEXT:   Canonical gp value: 0x37FF4
+# CHECK-NEXT:   Canonical gp value: 0x37FF8
 # 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:        ]
 # 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
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 8
+#               ^-- 0x30010 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 foo
+#               ^-- 0x30014                     R_MIPS_TLS_DTPREL32 foo
+#               ^-- 0x30018 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  foo
+#               ^-- 0x3001C R_MIPS_TLS_LDM      1 loc
+#               ^-- 0x30020                     0 loc
+#               ^-- 0x30024 R_MIPS_TLS_GD       1 bar
+#               ^-- 0x30028                     VA - 0x8000 bar
+#               ^-- 0x3002C R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+
+# DIS-SO:      Contents of section .got:
+# DIS-SO-NEXT:  20008 00000000 80000000 00000000 00000000
+# DIS-SO-NEXT:  20018 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT:  20028 00000000 00000000
+
+# SO:      Relocations [
+# SO-NEXT:   Section (7) .rel.dyn {
+# SO-NEXT:     0x2001C R_MIPS_TLS_DTPMOD32 - 0x0
+# SO-NEXT:     0x20024 R_MIPS_TLS_DTPMOD32 bar 0x0
+# SO-NEXT:     0x20028 R_MIPS_TLS_DTPREL32 bar 0x0
+# SO-NEXT:     0x2002C R_MIPS_TLS_TPREL32 bar 0x0
+# SO-NEXT:     0x20010 R_MIPS_TLS_DTPMOD32 foo 0x0
+# SO-NEXT:     0x20014 R_MIPS_TLS_DTPREL32 foo 0x0
+# SO-NEXT:     0x20018 R_MIPS_TLS_TPREL32 foo 0x0
+# SO-NEXT:   }
+# SO-NEXT: ]
+# SO-NEXT: Primary GOT {
+# SO-NEXT:   Canonical gp value: 0x27FF8
+# SO-NEXT:   Reserved entries [
+# SO:        ]
+# SO-NEXT:   Local entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Global entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Number of TLS and multi-GOT entries: 8
+#            ^-- 0x20010 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 foo
+#            ^-- 0x20014                     R_MIPS_TLS_DTPREL32 foo
+#            ^-- 0x20018 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  foo
+#            ^-- 0x2001C R_MIPS_TLS_LDM      R_MIPS_TLS_DTPMOD32 loc
+#            ^-- 0x20020                     0 loc
+#            ^-- 0x20024 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 bar
+#            ^-- 0x20028                     R_MIPS_TLS_DTPREL32 bar
+#            ^-- 0x2002C R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  bar
 
   .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
+  addiu $2, $3, %tlsldm(loc)    # R_MIPS_TLS_LDM
+  addiu $2, $3, %tlsgd(bar)     # R_MIPS_TLS_GD
+  addiu $2, $3, %gottprel(bar)  # R_MIPS_TLS_GOTTPREL
 
  .section .tdata,"awT",%progbits
+ .global bar
 loc:
  .word 0
+bar:
+ .word 0