Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -123,6 +123,7 @@ bool empty() const { return Entries.empty(); } uintX_t getEntryAddr(const SymbolBody &B) const; uintX_t getGlobalDynAddr(const SymbolBody &B) const; + uintX_t getNumEntries() const { return Entries.size(); } // 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 Index: lld/trunk/ELF/Target.cpp =================================================================== --- lld/trunk/ELF/Target.cpp +++ lld/trunk/ELF/Target.cpp @@ -224,6 +224,11 @@ PCRelReloc = R_386_PC32; GotReloc = R_386_GLOB_DAT; PltReloc = R_386_JUMP_SLOT; + TlsGotReloc = R_386_TLS_TPOFF; + TlsGlobalDynamicReloc = R_386_TLS_GD; + TlsLocalDynamicReloc = R_386_TLS_LDM; + TlsModuleIndexReloc = R_386_TLS_DTPMOD32; + TlsOffsetReloc = R_386_TLS_DTPOFF32; LazyRelocations = true; PltEntrySize = 16; PltZeroEntrySize = 16; @@ -247,7 +252,8 @@ } bool X86TargetInfo::isTlsDynReloc(unsigned Type) const { - if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32) + if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32 || + Type == R_386_TLS_GOTIE) return Config->Shared; return false; } @@ -300,7 +306,8 @@ } bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - return Type == R_386_GOT32 || relocNeedsPlt(Type, S); + return Type == R_386_TLS_GOTIE || Type == R_386_GOT32 || + relocNeedsPlt(Type, S); } bool X86TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { @@ -323,6 +330,18 @@ case R_386_PC32: add32le(Loc, SA - P); break; + case R_386_TLS_GD: + case R_386_TLS_LDM: + case R_386_TLS_TPOFF: { + uint64_t V = SA - Out::Got->getVA() - + Out::Got->getNumEntries() * 4; + checkInt<32>(V, Type); + write32le(Loc, V); + break; + } + case R_386_TLS_LDO_32: + write32le(Loc, SA); + break; case R_386_TLS_LE: write32le(Loc, SA - Out::TlsPhdr->p_memsz); break; Index: lld/trunk/test/ELF/tls-dynamic-i686.s =================================================================== --- lld/trunk/test/ELF/tls-dynamic-i686.s +++ lld/trunk/test/ELF/tls-dynamic-i686.s @@ -0,0 +1,92 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t +// RUN: ld.lld -shared %t -o %tout +// RUN: llvm-readobj -sections -relocations %tout | FileCheck %s +// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS + +.type tls0,@object +.section .tbss,"awT",@nobits +.globl tls0 +.align 4 +tls0: + .long 0 + .size tls0, 4 + +.type tls1,@object +.globl tls1 +.align 4 +tls1: + .long 0 + .size tls1, 4 + +.section .text +.globl _start +_start: +leal tls0@tlsgd(,%ebx,1),%eax +call __tls_get_addr@plt + +leal tls1@tlsgd(,%ebx,1),%eax +call __tls_get_addr@plt + +leal tls0@tlsldm(%ebx),%eax +call __tls_get_addr@plt +leal tls0@dtpoff(%eax),%edx + +leal tls1@tlsldm(%ebx),%eax +call __tls_get_addr@plt +leal tls1@dtpoff(%eax),%edx + +movl %gs:0,%eax +addl tls0@gotntpoff(%ebx),%eax + +movl %gs:0,%eax +addl tls1@gotntpoff(%ebx),%eax + +// CHECK: Index: 10 +// CHECK-NEXT: Name: .got +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_WRITE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x2068 +// CHECK-NEXT: Offset: 0x2068 +// CHECK-NEXT: Size: 32 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 4 +// CHECK-NEXT: EntrySize: 0 + +// CHECK: Relocations [ +// CHECK: Section ({{.+}}) .rel.dyn { +// CHECK-NEXT: 0x2068 R_386_TLS_DTPMOD32 tls0 0x0 +// CHECK-NEXT: 0x206C R_386_TLS_DTPOFF32 tls0 0x0 +// CHECK-NEXT: 0x2070 R_386_TLS_DTPMOD32 tls1 0x0 +// CHECK-NEXT: 0x2074 R_386_TLS_DTPOFF32 tls1 0x0 +// CHECK-NEXT: 0x2078 R_386_TLS_DTPMOD32 - 0x0 +// CHECK-NEXT: 0x2080 R_386_TLS_TPOFF tls0 0x0 +// CHECK-NEXT: 0x2084 R_386_TLS_TPOFF tls1 0x0 +// CHECK-NEXT: } + +// DIS: Disassembly of section .text: +// DIS-NEXT: _start: +// General dynamic model: +// -32 and -24 are first and second GOT entries offsets. +// Each one is a pair of records. +// DIS-NEXT: 1000: 8d 04 1d e0 ff ff ff leal -32(,%ebx), %eax +// DIS-NEXT: 1007: e8 64 00 00 00 calll 100 +// DIS-NEXT: 100c: 8d 04 1d e8 ff ff ff leal -24(,%ebx), %eax +// DIS-NEXT: 1013: e8 58 00 00 00 calll 88 +// Local dynamic model: +// -16 is a local module tls index offset. +// DIS-NEXT: 1018: 8d 83 f0 ff ff ff leal -16(%ebx), %eax +// DIS-NEXT: 101e: e8 4d 00 00 00 calll 77 +// DIS-NEXT: 1023: 8d 90 00 00 00 00 leal (%eax), %edx +// DIS-NEXT: 1029: 8d 83 f0 ff ff ff leal -16(%ebx), %eax +// DIS-NEXT: 102f: e8 3c 00 00 00 calll 60 +// DIS-NEXT: 1034: 8d 90 04 00 00 00 leal 4(%eax), %edx +// Initial exec model: +// DIS-NEXT: 103a: 65 a1 00 00 00 00 movl %gs:0, %eax +// DIS-NEXT: 1040: 03 83 f8 ff ff ff addl -8(%ebx), %eax +// DIS-NEXT: 1046: 65 a1 00 00 00 00 movl %gs:0, %eax +// DIS-NEXT: 104c: 03 83 fc ff ff ff addl -4(%ebx), %eax