Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -133,7 +133,7 @@ if (Target->isTlsGlobalDynamicReloc(Type) && !Target->isTlsOptimized(Type, &Body)) { Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, - Out::Got->getEntryAddr(Body) + + Out::Got->getGlobalDynAddr(Body) + getAddend(RI)); continue; } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -122,6 +122,8 @@ uint32_t addLocalModuleTlsIndex(); bool empty() const { return Entries.empty(); } uintX_t getEntryAddr(const SymbolBody &B) const; + uintX_t getGlobalDynAddr(const SymbolBody &B) const; + uintX_t getEntriesNum() 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: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -81,7 +81,7 @@ } template void GotSection::addDynTlsEntry(SymbolBody *Sym) { - Sym->GotIndex = Target->getGotHeaderEntriesNum() + Entries.size(); + Sym->GlobDynIndex = Target->getGotHeaderEntriesNum() + Entries.size(); // Global Dynamic TLS entries take two GOT slots. Entries.push_back(Sym); Entries.push_back(nullptr); @@ -100,6 +100,12 @@ } template +typename GotSection::uintX_t +GotSection::getGlobalDynAddr(const SymbolBody &B) const { + return this->getVA() + B.GlobDynIndex * sizeof(uintX_t); +} + +template const SymbolBody *GotSection::getMipsFirstGlobalEntry() const { return Entries.empty() ? nullptr : Entries.front(); } @@ -225,11 +231,12 @@ if (Body && Target->isTlsGlobalDynamicReloc(Type)) { P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Target->getTlsModuleIndexReloc(), Config->Mips64EL); - P->r_offset = Out::Got->getEntryAddr(*Body); + P->r_offset = Out::Got->getGlobalDynAddr(*Body); auto *PNext = reinterpret_cast(Buf); PNext->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Target->getTlsOffsetReloc(), Config->Mips64EL); - PNext->r_offset = Out::Got->getEntryAddr(*Body) + sizeof(uintX_t); + PNext->r_offset = + Out::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t); continue; } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -90,9 +90,11 @@ } void setDynamicSymbolTableIndex(unsigned V) { DynamicSymbolTableIndex = V; } + uint32_t GlobDynIndex = -1; uint32_t GotIndex = -1; uint32_t GotPltIndex = -1; uint32_t PltIndex = -1; + bool hasGlobDyn() const { return GlobDynIndex != -1U; } bool isInGot() const { return GotIndex != -1U; } bool isInGotPlt() const { return GotPltIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -229,6 +229,11 @@ GotReloc = R_386_GLOB_DAT; GotRefReloc = R_386_GOT32; 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; @@ -252,7 +257,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; } @@ -305,7 +311,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 { @@ -333,6 +340,17 @@ case R_386_TLS_LE_32: write32le(Loc, Out::TlsPhdr->p_memsz - SA); break; + case R_386_TLS_GD: + case R_386_TLS_LDM: + case R_386_TLS_TPOFF: { + uint64_t Offset = SA - Out::Got->getVA() - + Out::Got->getEntriesNum() * 4; + checkInt<32>(Offset, Type); + write32le(Loc, Offset); + } break; + case R_386_TLS_LDO_32: + write32le(Loc, SA); + break; default: error("unrecognized reloc " + Twine(Type)); } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -224,7 +224,7 @@ if (Body && Body->isTLS() && Target->isTlsGlobalDynamicReloc(Type)) { if (Target->isTlsOptimized(Type, Body)) continue; - if (Body->isInGot()) + if (Body->hasGlobDyn()) continue; Out::Got->addDynTlsEntry(Body); Out::RelaDyn->addReloc({&C, &RI}); Index: test/ELF/tls-dynamic-i686.s =================================================================== --- test/ELF/tls-dynamic-i686.s +++ 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