[elf2] Implement R_X86_64_TPOFF32.

This does not support TPOFF32 relocations to local symbols as the address calculations are separate. Support for this will be a separate patch.

llvm-svn: 251998
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index e3e3fef..5007ba0 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -644,6 +644,9 @@
   case SymbolBody::DefinedRegularKind: {
     const auto &DR = cast<DefinedRegular<ELFT>>(S);
     InputSectionBase<ELFT> &SC = DR.Section;
+    if (DR.Sym.getType() == STT_TLS)
+      return SC.OutSec->getVA() + SC.getOffset(DR.Sym) -
+             Out<ELFT>::TlsInitImageVA;
     return SC.OutSec->getVA() + SC.getOffset(DR.Sym);
   }
   case SymbolBody::DefinedCommonKind:
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 5a23c86..df17336 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -353,6 +353,7 @@
 // globally accessible. Writer initializes them, so don't use them
 // until Writer is initialized.
 template <class ELFT> struct Out {
+  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
   static DynamicSection<ELFT> *Dynamic;
   static GnuHashTableSection<ELFT> *GnuHashTab;
   static GotPltSection<ELFT> *GotPlt;
@@ -370,6 +371,7 @@
   static StringTableSection<ELFT> *StrTab;
   static SymbolTableSection<ELFT> *DynSymTab;
   static SymbolTableSection<ELFT> *SymTab;
+  static uintX_t TlsInitImageVA;
 };
 
 template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
@@ -389,6 +391,7 @@
 template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab;
 template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab;
 template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab;
+template <class ELFT> typename Out<ELFT>::uintX_t Out<ELFT>::TlsInitImageVA;
 }
 }
 #endif
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 0ebcf82..7adc5c6 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -339,6 +339,9 @@
       error("R_X86_64_32S out of range");
     write32le(Loc, SA);
     break;
+  case R_X86_64_TPOFF32:
+    write32le(Loc, SA);
+    break;
   default:
     error("unrecognized reloc " + Twine(Type));
   }
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 4f8f623..fe87d92 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -716,8 +716,10 @@
     }
 
     if ((Sec->getFlags() & SHF_ALLOC) && (Sec->getFlags() & SHF_TLS)) {
-      if (!TlsPhdr.p_vaddr)
+      if (!TlsPhdr.p_vaddr) {
         setPhdr(&TlsPhdr, PT_TLS, PF_R, FileOff, VA, 0, Sec->getAlign());
+        Out<ELFT>::TlsInitImageVA = VA;
+      }
       if (Sec->getType() != SHT_NOBITS)
         VA = RoundUpToAlignment(VA, Sec->getAlign());
       uintX_t TVA = RoundUpToAlignment(VA + ThreadBSSOffset, Sec->getAlign());
diff --git a/lld/test/elf2/tls.s b/lld/test/elf2/tls.s
index 5b5fc4f..6b3cad1 100644
--- a/lld/test/elf2/tls.s
+++ b/lld/test/elf2/tls.s
@@ -1,21 +1,34 @@
 // REQUIRES: x86
 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
 // RUN: ld.lld2 %t -o %tout
-// RUN: llvm-readobj -sections -program-headers %tout | FileCheck %s
+// RUN: llvm-readobj -symbols -sections -program-headers %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
 
 .global _start
 _start:
+  movl %fs:a@tpoff, %eax
+  movl %fs:b@tpoff, %eax
+  movl %fs:c@tpoff, %eax
+  movl %fs:d@tpoff, %eax
 
+  .global a
 	.section	.tbss,"awT",@nobits
+a:
 	.long	0
 
+  .global b
 	.section	.tdata,"awT",@progbits
+b:
 	.long	1
 
+  .global c
 	.section	.thread_bss,"awT",@nobits
+c:
 	.long	0
 
+  .global d
 	.section	.thread_data,"awT",@progbits
+d:
 	.long	2
 
 // CHECK:          Name: .tdata
@@ -77,9 +90,9 @@
 // CHECK-NEXT:       SHF_WRITE
 // CHECK-NEXT:     ]
 
-// 0x1100C = TBSS_ADDR + 4
+// 0x1200C = TBSS_ADDR + 4
 
-// CHECK-NEXT:     Address: 0x1100C
+// CHECK-NEXT:     Address: 0x1200C
 // CHECK-NEXT:     Offset:
 // CHECK-NEXT:     Size: 4
 // CHECK-NEXT:     Link:
@@ -88,11 +101,49 @@
 // CHECK-NEXT:     EntrySize:
 // CHECK-NEXT:   }
 
+// CHECK:      Symbols [
+// CHECK:          Name: a
+// CHECK-NEXT:     Value: 0x8
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .tbss
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: b
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .tdata
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: c
+// CHECK-NEXT:     Value: 0xC
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .thread_bss
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: d
+// CHECK-NEXT:     Value: 0x4
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .thread_data
+// CHECK-NEXT:   }
+
 // Check that the TLS NOBITS sections weren't added to the R/W PT_LOAD's size.
 
 // CHECK:      ProgramHeaders [
 // CHECK:          Type: PT_LOAD
 // CHECK:          Type: PT_LOAD
+// CHECK:          Type: PT_LOAD
 // CHECK:          FileSize: 8
 // CHECK-NEXT:     MemSize: 8
 // CHECK-NEXT:     Flags [
@@ -110,3 +161,10 @@
 // CHECK-NEXT:     ]
 // CHECK-NEXT:     Alignment:
 // CHECK-NEXT:   }
+
+// DIS:      Disassembly of section .text:
+// DIS-NEXT: _start:
+// DIS-NEXT:    11000: {{.+}} movl    %fs:8, %eax
+// DIS-NEXT:    11008: {{.+}} movl    %fs:0, %eax
+// DIS-NEXT:    11010: {{.+}} movl    %fs:12, %eax
+// DIS-NEXT:    11018: {{.+}} movl    %fs:4, %eax