Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -90,14 +90,23 @@ for (const RelType &RI : Rels) { uint32_t SymIndex = RI.getSymbol(Config->Mips64EL); uint32_t Type = RI.getType(Config->Mips64EL); + uint8_t *BufLoc = Buf + RI.r_offset; + uintX_t AddrLoc = BaseAddr + RI.r_offset; + + if (Type == Target->getTlsLocalDynamicReloc()) { + Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, + 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(); if (SymIndex < SymTab->sh_info) { uintX_t SymVA = getLocalRelTarget(File, RI); - Target->relocateOne(Buf + RI.r_offset, BufEnd, Type, - BaseAddr + RI.r_offset, SymVA); + Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA); continue; } @@ -116,7 +125,7 @@ isa>(Body)) { continue; } - Target->relocateOne(Buf + RI.r_offset, BufEnd, Type, BaseAddr + RI.r_offset, + Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + getAddend(RI)); } } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -116,6 +116,7 @@ void finalize() override; 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; @@ -371,6 +372,7 @@ static SymbolTableSection *DynSymTab; static SymbolTableSection *SymTab; static Elf_Phdr *TlsPhdr; + static uint32_t LocalModuleTlsIndexOffset; }; template DynamicSection *Out::Dynamic; @@ -391,6 +393,7 @@ template SymbolTableSection *Out::DynSymTab; template SymbolTableSection *Out::SymTab; template typename Out::Elf_Phdr *Out::TlsPhdr; +template uint32_t Out::LocalModuleTlsIndexOffset = -1; } // namespace elf2 } // namespace lld Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -82,6 +82,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 { @@ -99,6 +105,8 @@ for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); + if (!B) + continue; // MIPS has special rules to fill up GOT entries. // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: @@ -177,6 +185,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 @@ -29,6 +29,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; } @@ -67,6 +69,8 @@ unsigned GotReloc; unsigned PltReloc; unsigned RelativeReloc; + unsigned TlsLocalDynamicReloc{}; + unsigned TlsModuleIndexReloc{}; unsigned PltEntrySize = 8; unsigned PltZeroEntrySize = 0; unsigned GotHeaderEntriesNum = 0; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -213,6 +213,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; @@ -328,6 +330,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 == uint32_t(-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,48 @@ +// 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 + + leaq a@tlsld(%rip), %rdi + callq __tls_get_addr@PLT + leaq b@tlsld(%rip), %rdi + callq __tls_get_addr@PLT + + .global a + .section .tbss,"awT",@nobits + .align 4 +a: + .long 0 + + .global b + .section .tbss,"awT",@nobits + .align 4 +b: + .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: .text: +// DIS-NEXT: 1000: {{.+}} leaq 4297(%rip), %rdi +// DIS-NEXT: 1007: {{.+}} callq +// DIS-NEXT: 100c: {{.+}} leaq 4285(%rip), %rdi