[ELF][MIPS] Fix initialization of TLS-related GOT entries

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
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index f245120..278e5c5 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -261,7 +261,7 @@
   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 @@
   };
   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);