Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -91,6 +91,14 @@ uint32_t SymIndex = RI.getSymbol(Config->Mips64EL); uint32_t Type = RI.getType(Config->Mips64EL); + if (Type == Target->getTlsLocalDynamicReloc()) { + Target->relocateOne( + Buf + RI.r_offset, BufEnd, Type, BaseAddr + RI.r_offset, + Out::Got->getVA() + Out::LocalModuleTlsIndexOffset + + getAddend(RI)); + continue; + } + // Handle relocations for local symbols -- they never get // resolved so we don't allocate a SymbolBody. const Elf_Shdr *SymTab = File.getSymbolTable(); Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -118,6 +118,7 @@ } void writeTo(uint8_t *Buf) override; void addEntry(SymbolBody *Sym); + uint32_t addLocalModuleTlsIndex(); bool empty() const { return Entries.empty(); } uintX_t getEntryAddr(const SymbolBody &B) const; @@ -372,6 +373,7 @@ static SymbolTableSection *DynSymTab; static SymbolTableSection *SymTab; static uintX_t TlsInitImageVA; + static uint32_t LocalModuleTlsIndexOffset; }; template DynamicSection *Out::Dynamic; @@ -392,6 +394,7 @@ template SymbolTableSection *Out::DynSymTab; template SymbolTableSection *Out::SymTab; template typename Out::uintX_t Out::TlsInitImageVA; +template uint32_t Out::LocalModuleTlsIndexOffset = -1; } // namespace elf2 } // namespace lld Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -80,6 +80,12 @@ Entries.push_back(Sym); } +template uint32_t GotSection::addLocalModuleTlsIndex() { + Entries.push_back(nullptr); + Entries.push_back(nullptr); + return (Entries.size() - 2) * sizeof(uintX_t); +} + template typename GotSection::uintX_t GotSection::getEntryAddr(const SymbolBody &B) const { @@ -90,6 +96,8 @@ for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); + if (!B) + continue; if (canBePreempted(B, false)) continue; // The dynamic linker will take care of it. uintX_t VA = getSymVA(*B); @@ -163,6 +171,15 @@ Body = Body->repl(); uint32_t Type = RI.getType(Config->Mips64EL); + + if (Type == Target->getTlsLocalDynamicReloc()) { + P->setSymbolAndType(0, Target->getTlsModuleIndexReloc(), + Config->Mips64EL); + P->r_offset = + Out::Got->getVA() + Out::LocalModuleTlsIndexOffset; + continue; + } + bool NeedsCopy = Body && Target->relocNeedsCopy(Type, *Body); bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body); bool CanBePreempted = canBePreempted(Body, NeedsGot); Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -28,6 +28,8 @@ unsigned getPltReloc() const { return PltReloc; } unsigned getGotRefReloc() const { return GotRefReloc; } unsigned getRelativeReloc() const { return RelativeReloc; } + unsigned getTlsLocalDynamicReloc() const { return TlsLocalDynamicReloc; } + unsigned getTlsModuleIndexReloc() const { return TlsModuleIndexReloc; } unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; } unsigned getPltEntrySize() const { return PltEntrySize; } bool supportsLazyRelocations() const { return LazyRelocations; } @@ -64,6 +66,8 @@ unsigned GotReloc; unsigned PltReloc; unsigned RelativeReloc; + unsigned TlsLocalDynamicReloc{}; + unsigned TlsModuleIndexReloc{}; unsigned PltEntrySize = 8; unsigned PltZeroEntrySize = 0; bool LazyRelocations = false; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -211,6 +211,8 @@ GotRefReloc = R_X86_64_PC32; PltReloc = R_X86_64_JUMP_SLOT; RelativeReloc = R_X86_64_RELATIVE; + TlsLocalDynamicReloc = R_X86_64_TLSLD; + TlsModuleIndexReloc = R_X86_64_DTPMOD64; LazyRelocations = true; PltEntrySize = 16; PltZeroEntrySize = 16; @@ -326,6 +328,7 @@ case R_X86_64_PC32: case R_X86_64_GOTPCREL: case R_X86_64_PLT32: + case R_X86_64_TLSLD: write32le(Loc, SA - P); break; case R_X86_64_64: Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -191,6 +191,15 @@ SymbolBody *Body = File.getSymbolBody(SymIndex); uint32_t Type = RI.getType(Config->Mips64EL); + if (Type == Target->getTlsLocalDynamicReloc()) { + if (Out::LocalModuleTlsIndexOffset == -1) { + Out::LocalModuleTlsIndexOffset = + Out::Got->addLocalModuleTlsIndex(); + Out::RelaDyn->addReloc({C, RI}); + } + continue; + } + // Set "used" bit for --as-needed. if (Body && Body->isUndefined() && !Body->isWeak()) if (auto *S = dyn_cast>(Body->repl())) Index: test/elf2/tls-dynamic.s =================================================================== --- /dev/null +++ test/elf2/tls-dynamic.s @@ -0,0 +1,41 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +// RUN: ld.lld2 -shared %t -o %tout +// RUN: llvm-readobj -sections -relocations %tout | FileCheck %s +// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS + + .text + .globl _start +_start: + leaq a@tlsld(%rip), %rdi + callq __tls_get_addr@PLT + + .global a + .section .tbss,"awT",@nobits + .align 4 +a: + .long 0 + +// Get the address of the got, and check that it has two entries. + +// CHECK: Sections [ +// CHECK: Name: .got +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_WRITE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x20D0 +// CHECK-NEXT: Offset: +// CHECK-NEXT: Size: 16 + +// CHECK: Relocations [ +// CHECK: Section ({{.+}}) .rela.dyn { +// CHECK-NEXT: 0x20D0 R_X86_64_DTPMOD64 - 0x0 +// CHECK-NEXT: } + +// 4297 = (0x20D0 + -4) - (0x1000 + 3) // PC relative offset to got entry. + +// DIS: Disassembly of section .text: +// DIS-NEXT: _start: +// DIS-NEXT: 1000: {{.+}} leaq 4297(%rip), %rdi