Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -147,6 +147,8 @@ } else if (!Target->relocNeedsCopy(Type, Body) && isa>(Body)) { continue; + } else if (Target->requireTlsDynReloc(Type)) { + continue; } Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + getAddend(RI)); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -241,7 +241,8 @@ Config->Mips64EL); else P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), - NeedsCopy ? Target->getCopyReloc() : Type, + NeedsCopy ? Target->getCopyReloc() + : Target->replaceDynReloc(Type), Config->Mips64EL); } else { P->setSymbolAndType(0, Target->getRelativeReloc(), Config->Mips64EL); Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -30,7 +30,6 @@ 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; } @@ -44,6 +43,8 @@ bool supportsLazyRelocations() const { return LazyRelocations; } unsigned getGotHeaderEntriesNum() const { return GotHeaderEntriesNum; } unsigned getGotPltHeaderEntriesNum() const { return GotPltHeaderEntriesNum; } + virtual unsigned replaceDynReloc(unsigned Type) const { return Type; } + virtual bool requireTlsDynReloc(unsigned Type) const { return false; } virtual unsigned getPltRefReloc(unsigned Type) const; virtual void writeGotHeaderEntries(uint8_t *Buf) const; virtual void writeGotPltHeaderEntries(uint8_t *Buf) const; @@ -84,7 +85,6 @@ unsigned TlsGlobalDynamicReloc = 0; unsigned TlsModuleIndexReloc; unsigned TlsOffsetReloc; - unsigned TlsPcRelGotReloc = 0; unsigned PltEntrySize = 8; unsigned PltZeroEntrySize = 0; unsigned GotHeaderEntriesNum = 0; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -46,6 +46,8 @@ class X86TargetInfo final : public TargetInfo { public: X86TargetInfo(); + unsigned replaceDynReloc(unsigned Type) const override; + bool requireTlsDynReloc(unsigned Type) const override; void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr) const override; @@ -62,6 +64,7 @@ public: X86_64TargetInfo(); unsigned getPltRefReloc(unsigned Type) const override; + bool requireTlsDynReloc(unsigned Type) const override; void writeGotPltHeaderEntries(uint8_t *Buf) const override; void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, @@ -170,6 +173,20 @@ PltReloc = R_386_JUMP_SLOT; } +unsigned X86TargetInfo::replaceDynReloc(unsigned Type) const { + if (Type == R_386_TLS_LE) + return R_386_TLS_TPOFF; + if (Type == R_386_TLS_LE_32) + return R_386_TLS_TPOFF32; + return Type; +} + +bool X86TargetInfo::requireTlsDynReloc(unsigned Type) const { + if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32) + return Config->Shared; + return false; +} + void X86TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} void X86TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr) const {} @@ -207,6 +224,12 @@ case R_386_32: add32le(Loc, SA); break; + case R_386_TLS_LE: + write32le(Loc, SA - Out::TlsPhdr->p_memsz); + break; + case R_386_TLS_LE_32: + write32le(Loc, Out::TlsPhdr->p_memsz - SA); + break; default: error("unrecognized reloc " + Twine(Type)); } @@ -224,7 +247,6 @@ 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; @@ -280,6 +302,10 @@ relocNeedsPlt(Type, S); } +bool X86_64TargetInfo::requireTlsDynReloc(unsigned Type) const { + return Type == R_X86_64_GOTTPOFF; +} + unsigned X86_64TargetInfo::getPltRefReloc(unsigned Type) const { if (Type == R_X86_64_PLT32) return R_X86_64_PC32; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -226,7 +226,7 @@ continue; } - if ((Body && Body->isTLS()) && Type != Target->getTlsPcRelGotReloc()) + if ((Body && Body->isTLS()) && !Target->requireTlsDynReloc(Type)) continue; bool NeedsGot = false; Index: test/ELF/tls-i686.s =================================================================== --- test/ELF/tls-i686.s +++ test/ELF/tls-i686.s @@ -0,0 +1,69 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t +// RUN: ld.lld %t -o %tout +// RUN: ld.lld %t -shared -o %tsharedout +// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS +// RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=RELOC +// RUN: llvm-objdump -d %tsharedout | FileCheck %s --check-prefix=DISSHARED +// RUN: llvm-readobj -r %tsharedout | FileCheck %s --check-prefix=RELOCSHARED + +.section ".tdata", "awT", @progbits +.globl var +.globl var1 +var: +.long 0 +var1: +.long 1 + +.text +.global _start +_start: + movl $var@tpoff, %edx + movl %gs:0, %ecx + subl %edx, %eax + movl $var1@tpoff, %edx + movl %gs:0, %ecx + subl %edx, %eax + + movl %gs:0, %ecx + leal var@ntpoff(%ecx), %eax + movl %gs:0, %ecx + leal var1@ntpoff(%ecx), %eax + +// DIS: Disassembly of section .text: +// DIS-NEXT: _start: +// DIS-NEXT: 11000: ba 08 00 00 00 movl $8, %edx +// DIS-NEXT: 11005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 1100c: 29 d0 subl %edx, %eax +// DIS-NEXT: 1100e: ba 04 00 00 00 movl $4, %edx +// DIS-NEXT: 11013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 1101a: 29 d0 subl %edx, %eax +// DIS-NEXT: 1101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 11023: 8d 81 f8 ff ff ff leal -8(%ecx), %eax +// DIS-NEXT: 11029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 11030: 8d 81 fc ff ff ff leal -4(%ecx), %eax + +// RELOC: Relocations [ +// RELOC-NEXT: ] + +// DISSHARED: Disassembly of section .text: +// DISSHARED-NEXT: _start: +// DISSHARED-NEXT: 1000: ba 00 00 00 00 movl $0, %edx +// DISSHARED-NEXT: 1005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 100c: 29 d0 subl %edx, %eax +// DISSHARED-NEXT: 100e: ba 00 00 00 00 movl $0, %edx +// DISSHARED-NEXT: 1013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 101a: 29 d0 subl %edx, %eax +// DISSHARED-NEXT: 101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 1023: 8d 81 00 00 00 00 leal (%ecx), %eax +// DISSHARED-NEXT: 1029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 1030: 8d 81 00 00 00 00 leal (%ecx), %eax + +// RELOCSHARED: Relocations [ +// RELOCSHARED-NEXT: Section (4) .rel.dyn { +// RELOCSHARED-NEXT: 0x1001 R_386_TLS_TPOFF32 var 0x0 +// RELOCSHARED-NEXT: 0x100F R_386_TLS_TPOFF32 var1 0x0 +// RELOCSHARED-NEXT: 0x1025 R_386_TLS_TPOFF var 0x0 +// RELOCSHARED-NEXT: 0x1032 R_386_TLS_TPOFF var1 0x0 +// RELOCSHARED-NEXT: } +// RELOCSHARED-NEXT: ]