Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -207,7 +207,7 @@ } else if (Target->relocNeedsGot(Type, *Body)) { SymVA = Out::Got->getEntryAddr(*Body); if (Body->isTls()) - Type = Target->getTlsGotReloc(Type); + Type = Target->getTlsGotReloc(Type, true); } else if (!Target->needsCopyRel(Type, *Body) && isa>(*Body)) { continue; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -104,6 +104,7 @@ template typename GotSection::uintX_t GotSection::getEntryAddr(const SymbolBody &B) const { + assert(B.GotIndex != (uint32_t)-1); return this->getVA() + B.GotIndex * sizeof(uintX_t); } @@ -224,7 +225,7 @@ if (Target->isTlsOptimized(Type, Body)) { P->setSymbolAndType(Body->DynamicSymbolTableIndex, - Target->getTlsGotReloc(), Config->Mips64EL); + Target->getTlsGotReloc(Type), Config->Mips64EL); P->r_offset = Out::Got->getEntryAddr(*Body); return true; } @@ -276,7 +277,8 @@ else if (LazyReloc) Reloc = Target->getPltReloc(); else if (NeedsGot) - Reloc = Body->isTls() ? Target->getTlsGotReloc() : Target->getGotReloc(); + Reloc = + Body->isTls() ? Target->getTlsGotReloc(Type) : Target->getGotReloc(); else if (NeedsCopy) Reloc = Target->getCopyReloc(); else Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -46,7 +46,7 @@ return false; } virtual unsigned getPltRefReloc(unsigned Type) const; - virtual unsigned getTlsGotReloc(unsigned Type = -1) const { + virtual unsigned getTlsGotReloc(unsigned Type, bool Static = false) const { return TlsGotReloc; } virtual void writeGotHeaderEntries(uint8_t *Buf) const; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -87,7 +87,7 @@ X86TargetInfo(); void writeGotPltHeaderEntries(uint8_t *Buf) const override; unsigned getDynReloc(unsigned Type) const override; - unsigned getTlsGotReloc(unsigned Type) const override; + unsigned getTlsGotReloc(unsigned Type, bool Static) const override; bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override; void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, @@ -299,9 +299,11 @@ return Type; } -unsigned X86TargetInfo::getTlsGotReloc(unsigned Type) const { - if (Type == R_386_TLS_IE) +unsigned X86TargetInfo::getTlsGotReloc(unsigned Type, bool Static) const { + if (Static && Type == R_386_TLS_IE) return Type; + if (Type == R_386_TLS_IE_32) + return R_386_TLS_TPOFF32; return TlsGotReloc; } @@ -309,7 +311,7 @@ if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32 || Type == R_386_TLS_GOTIE) return Config->Shared; - if (Type == R_386_TLS_IE) + if (Type == R_386_TLS_IE || Type == R_386_TLS_IE_32) return canBePreempted(&S, true); return Type == R_386_TLS_GD; } @@ -364,7 +366,8 @@ bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { if (S.isTls() && Type == R_386_TLS_GD) return Target->isTlsOptimized(Type, &S) && canBePreempted(&S, true); - if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE) + if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE || + Type == R_386_TLS_IE_32) return !isTlsOptimized(Type, &S); return Type == R_386_GOT32 || relocNeedsPlt(Type, S); } @@ -402,7 +405,8 @@ break; case R_386_TLS_GD: case R_386_TLS_LDM: - case R_386_TLS_TPOFF: { + case R_386_TLS_TPOFF: + case R_386_TLS_TPOFF32: { uint64_t V = SA - Out::Got->getVA() - Out::Got->getNumEntries() * 4; checkInt<32>(V, Type); @@ -427,9 +431,10 @@ bool X86TargetInfo::isTlsOptimized(unsigned Type, const SymbolBody *S) const { if (Config->Shared || (S && !S->isTls())) return false; + if (Type == R_386_TLS_IE || Type == R_386_TLS_IE_32) + return !canBePreempted(S, true); return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM || Type == R_386_TLS_GD || - (Type == R_386_TLS_IE && !canBePreempted(S, true)) || (Type == R_386_TLS_GOTIE && !canBePreempted(S, true)); } @@ -451,6 +456,7 @@ return 1; case R_386_TLS_GOTIE: case R_386_TLS_IE: + case R_386_TLS_IE_32: relocateTlsIeToLe(Type, Loc, BufEnd, P, SA); return 0; case R_386_TLS_LDM: @@ -556,13 +562,16 @@ // "MOVL foo@GOTTPOFF(%RIP), %REG" is transformed to "MOVL $foo, %REG". // "ADDL foo@GOTNTPOFF(%RIP), %REG" is transformed to "LEAL foo(%REG), %REG" // Note: gold converts to ADDL instead of LEAL. + // In the same way R_386_TLS_IE_32 relocation is optimized to + // R_386_TLS_LE_32 here. *Inst = IsMov ? 0xc7 : 0x8d; if (IsMov) *Op = 0xc0 | ((*Op >> 3) & 7); else *Op = 0x80 | Reg | (Reg << 3); } - relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA); + uint32_t Reloc = (Type == R_386_TLS_IE_32) ? R_386_TLS_LE_32 : R_386_TLS_LE; + relocateOne(Loc, BufEnd, Reloc, P, SA); } X86_64TargetInfo::X86_64TargetInfo() { Index: test/ELF/tls-opt-ie32le-i686.s =================================================================== --- test/ELF/tls-opt-ie32le-i686.s +++ test/ELF/tls-opt-ie32le-i686.s @@ -0,0 +1,83 @@ +// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %tso +// RUN: llvm-readobj -s -r %tso | FileCheck --check-prefix=DSO %s +// RUN: llvm-objdump -d %tso | FileCheck --check-prefix=DISASMDSO %s +// RUN: ld.lld %t.o -o %t +// RUN: llvm-readobj -s -r %t | FileCheck --check-prefix=EXE %s +// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMEXE %s + +// DSO: Section { +// DSO: Index: 8 +// DSO: Name: .got +// DSO-NEXT: Type: SHT_PROGBITS +// DSO-NEXT: Flags [ +// DSO-NEXT: SHF_ALLOC +// DSO-NEXT: SHF_WRITE +// DSO-NEXT: ] +// DSO-NEXT: Address: 0x2048 +// DSO-NEXT: Offset: 0x2048 +// DSO-NEXT: Size: 8 +// DSO-NEXT: Link: 0 +// DSO-NEXT: Info: 0 +// DSO-NEXT: AddressAlignment: 4 +// DSO-NEXT: EntrySize: 0 +// DSO-NEXT: } +// DSO: Relocations [ +// DSO-NEXT: Section ({{.*}}) .rel.dyn { +// DSO-NEXT: 0x2048 R_386_TLS_TPOFF32 tls0 0x0 +// DSO-NEXT: 0x204C R_386_TLS_TPOFF32 tls1 0x0 +// DSO-NEXT: } +// DSO-NEXT: ] + +// DISASMDSO: Disassembly of section .text: +// DISASMDSO-NEXT: _start: +// DISASMDSO-NEXT: 1000: 65 a1 00 00 00 00 movl %gs:0, %eax +// DISASMDSO-NEXT: 1006: 03 83 f8 ff ff ff addl -8(%ebx), %eax +// DISASMDSO-NEXT: 100c: 65 a1 00 00 00 00 movl %gs:0, %eax +// DISASMDSO-NEXT: 1012: 8b 83 f8 ff ff ff movl -8(%ebx), %eax +// DISASMDSO-NEXT: 1018: 65 a1 00 00 00 00 movl %gs:0, %eax +// DISASMDSO-NEXT: 101e: 03 83 fc ff ff ff addl -4(%ebx), %eax +// DISASMDSO-NEXT: 1024: 65 a1 00 00 00 00 movl %gs:0, %eax +// DISASMDSO-NEXT: 102a: 8b 83 fc ff ff ff movl -4(%ebx), %eax + +// EXE: Section { +// EXE-NOT: Name: .got + +// DISASMEXE: Disassembly of section .text: +// DISASMEXE-NEXT: _start: +// DISASMEXE-NEXT: 11000: 65 a1 00 00 00 00 movl %gs:0, %eax +// DISASMEXE-NEXT: 11006: 8d 80 08 00 00 00 leal 8(%eax), %eax +// DISASMEXE-NEXT: 1100c: 65 a1 00 00 00 00 movl %gs:0, %eax +// DISASMEXE-NEXT: 11012: c7 c0 08 00 00 00 movl $8, %eax +// DISASMEXE-NEXT: 11018: 65 a1 00 00 00 00 movl %gs:0, %eax +// DISASMEXE-NEXT: 1101e: 8d 80 04 00 00 00 leal 4(%eax), %eax +// DISASMEXE-NEXT: 11024: 65 a1 00 00 00 00 movl %gs:0, %eax +// DISASMEXE-NEXT: 1102a: c7 c0 04 00 00 00 movl $4, %eax + +.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: +movl %gs:0,%eax +addl tls0@gottpoff(%ebx),%eax +movl %gs:0,%eax +movl tls0@gottpoff(%ebx),%eax + +movl %gs:0,%eax +addl tls1@gottpoff(%ebx),%eax +movl %gs:0,%eax +movl tls1@gottpoff(%ebx),%eax