Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -140,7 +140,7 @@ Type = Target->getPLTRefReloc(Type); } else if (Target->relocNeedsGot(Type, Body)) { SymVA = Out::Got->getEntryAddr(Body); - Type = Target->getGotRefReloc(); + Type = Body.isTLS() ? Target->getTlsGotReloc() : Target->getGotRefReloc(); } else if (Target->relocPointsToGot(Type)) { SymVA = Out::Got->getVA(); Type = Target->getPCRelReloc(); Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -118,6 +118,7 @@ void finalize() override; void writeTo(uint8_t *Buf) override; void addEntry(SymbolBody *Sym); + void addDynTlsEntry(SymbolBody *Sym); uint32_t addLocalModuleTlsIndex(); bool empty() const { return Entries.empty(); } uintX_t getEntryAddr(const SymbolBody &B) const; Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -80,9 +80,13 @@ template void GotSection::addEntry(SymbolBody *Sym) { Sym->GotIndex = Target->getGotHeaderEntriesNum() + Entries.size(); Entries.push_back(Sym); +} + +template void GotSection::addDynTlsEntry(SymbolBody *Sym) { + Sym->GotIndex = Target->getGotHeaderEntriesNum() + Entries.size(); // Global Dynamic TLS entries take two GOT slots. - if (Sym->isTLS()) - Entries.push_back(nullptr); + Entries.push_back(Sym); + Entries.push_back(nullptr); } template uint32_t GotSection::addLocalModuleTlsIndex() { @@ -231,10 +235,11 @@ Target->relocNeedsPlt(Type, *Body); if (CanBePreempted) { + unsigned GotReloc = + Body->isTLS() ? Target->getTlsGotReloc() : Target->getGotReloc(); if (NeedsGot) P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), - LazyReloc ? Target->getPltReloc() - : Target->getGotReloc(), + LazyReloc ? Target->getPltReloc() : GotReloc, Config->Mips64EL); else P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Index: lld/trunk/ELF/Target.h =================================================================== --- lld/trunk/ELF/Target.h +++ lld/trunk/ELF/Target.h @@ -29,6 +29,8 @@ unsigned getPltReloc() const { return PltReloc; } unsigned getGotRefReloc() const { return GotRefReloc; } unsigned getRelativeReloc() const { return RelativeReloc; } + unsigned getTlsGotReloc() const { return TlsGotReloc; } + unsigned getTlsPcRelGotReloc() const { return TlsPcRelGotReloc; } bool isTlsLocalDynamicReloc(unsigned Type) const { return Type == TlsLocalDynamicReloc; } @@ -75,10 +77,12 @@ unsigned GotReloc; unsigned PltReloc; unsigned RelativeReloc; + unsigned TlsGotReloc = 0; unsigned TlsLocalDynamicReloc = 0; unsigned TlsGlobalDynamicReloc = 0; unsigned TlsModuleIndexReloc; unsigned TlsOffsetReloc; + unsigned TlsPcRelGotReloc = 0; unsigned PltEntrySize = 8; unsigned PltZeroEntrySize = 0; unsigned GotHeaderEntriesNum = 0; Index: lld/trunk/ELF/Target.cpp =================================================================== --- lld/trunk/ELF/Target.cpp +++ lld/trunk/ELF/Target.cpp @@ -215,10 +215,12 @@ GotRefReloc = R_X86_64_PC32; PltReloc = R_X86_64_JUMP_SLOT; RelativeReloc = R_X86_64_RELATIVE; + TlsGotReloc = R_X86_64_TPOFF64; TlsLocalDynamicReloc = R_X86_64_TLSLD; TlsGlobalDynamicReloc = R_X86_64_TLSGD; TlsModuleIndexReloc = R_X86_64_DTPMOD64; TlsOffsetReloc = R_X86_64_DTPOFF64; + TlsPcRelGotReloc = R_X86_64_GOTTPOFF; LazyRelocations = true; PltEntrySize = 16; PltZeroEntrySize = 16; @@ -266,7 +268,8 @@ } bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S); + return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_GOTPCREL || + relocNeedsPlt(Type, S); } unsigned X86_64TargetInfo::getPLTRefReloc(unsigned Type) const { @@ -338,6 +341,7 @@ case R_X86_64_PLT32: case R_X86_64_TLSLD: case R_X86_64_TLSGD: + case R_X86_64_TPOFF64: write32le(Loc, SA - P); break; case R_X86_64_64: Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -216,18 +216,19 @@ if (Body) Body = Body->repl(); - if (Body && Body->isTLS()) { - if (!Target->isTlsGlobalDynamicReloc(Type)) - continue; + if (Body && Body->isTLS() && Target->isTlsGlobalDynamicReloc(Type)) { if (Body->isInGot()) continue; - Out::Got->addEntry(Body); + Out::Got->addDynTlsEntry(Body); Out::RelaDyn->addReloc({&C, &RI}); Out::RelaDyn->addReloc({nullptr, nullptr}); Body->setUsedInDynamicReloc(); continue; } + if ((Body && Body->isTLS()) && Type != Target->getTlsPcRelGotReloc()) + continue; + bool NeedsGot = false; bool NeedsPlt = false; if (Body) { Index: lld/trunk/test/elf2/Inputs/tls-got.s =================================================================== --- lld/trunk/test/elf2/Inputs/tls-got.s +++ lld/trunk/test/elf2/Inputs/tls-got.s @@ -0,0 +1,14 @@ +.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 Index: lld/trunk/test/elf2/tls-got.s =================================================================== --- lld/trunk/test/elf2/tls-got.s +++ lld/trunk/test/elf2/tls-got.s @@ -0,0 +1,58 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-got.s -o %t2.o +// RUN: ld.lld2 -shared %t2.o -o %t2.so +// RUN: ld.lld2 -e main %t1.o %t2.so -o %t3 +// RUN: llvm-readobj -s -r %t3 | FileCheck %s +// RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=DISASM %s + +// CHECK: Section { +// CHECK: Index: 8 +// 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: [[ADDR:.*]] +// CHECK-NEXT: Offset: 0x20A0 +// CHECK-NEXT: Size: 16 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 8 +// CHECK-NEXT: EntrySize: 0 +// CHECK-NEXT: } + +// CHECK: Relocations [ +// CHECK-NEXT: Section (4) .rela.dyn { +// CHECK-NEXT: [[ADDR]] R_X86_64_TPOFF64 tls1 0x0 +// CHECK-NEXT: 0x120A8 R_X86_64_TPOFF64 tls0 0x0 +// CHECK-NEXT: } +// CHECK-NEXT: ] + +//0x11000 + 4249 + 7 = 0x120A0 +//0x1100A + 4247 + 7 = 0x120A8 +//0x11014 + 4237 + 7 = 0x120A8 +//DISASM: Disassembly of section .text: +//DISASM-NEXT: main: +//DISASM-NEXT: 11000: 48 8b 05 99 10 00 00 movq 4249(%rip), %rax +//DISASM-NEXT: 11007: 64 8b 00 movl %fs:(%rax), %eax +//DISASM-NEXT: 1100a: 48 8b 05 97 10 00 00 movq 4247(%rip), %rax +//DISASM-NEXT: 11011: 64 8b 00 movl %fs:(%rax), %eax +//DISASM-NEXT: 11014: 48 8b 05 8d 10 00 00 movq 4237(%rip), %rax +//DISASM-NEXT: 1101b: 64 8b 00 movl %fs:(%rax), %eax +//DISASM-NEXT: 1101e: c3 retq + +.section .tdata,"awT",@progbits + +.text + .globl main + .align 16, 0x90 + .type main,@function +main: + movq tls1@GOTTPOFF(%rip), %rax + movl %fs:0(%rax), %eax + movq tls0@GOTTPOFF(%rip), %rax + movl %fs:0(%rax), %eax + movq tls0@GOTTPOFF(%rip), %rax + movl %fs:0(%rax), %eax + ret