Index: ELF/Arch/X86_64.cpp =================================================================== --- ELF/Arch/X86_64.cpp +++ ELF/Arch/X86_64.cpp @@ -55,6 +55,7 @@ PltRel = R_X86_64_JUMP_SLOT; RelativeRel = R_X86_64_RELATIVE; IRelativeRel = R_X86_64_IRELATIVE; + TlsDescRel = R_X86_64_TLSDESC; TlsGotRel = R_X86_64_TPOFF64; TlsModuleIndexRel = R_X86_64_DTPMOD64; TlsOffsetRel = R_X86_64_DTPOFF64; @@ -88,6 +89,8 @@ return R_DTPREL; case R_X86_64_TPOFF32: return R_TLS; + case R_X86_64_TLSDESC_CALL: + return R_TLSDESC_CALL; case R_X86_64_TLSLD: return R_TLSLD_PC; case R_X86_64_TLSGD: @@ -105,6 +108,8 @@ case R_X86_64_GOT32: case R_X86_64_GOT64: return R_GOTPLT; + case R_X86_64_GOTPC32_TLSDESC: + return R_TLSDESC_PC; case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: @@ -173,45 +178,78 @@ } void X86_64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { - // Convert - // .byte 0x66 - // leaq x@tlsgd(%rip), %rdi - // .word 0x6666 - // rex64 - // call __tls_get_addr@plt - // to - // mov %fs:0x0,%rax - // lea x@tpoff,%rax - const uint8_t Inst[] = { - 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax - 0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax - }; - memcpy(Loc - 4, Inst, sizeof(Inst)); + if (Type == R_X86_64_TLSGD) { + // Convert + // .byte 0x66 + // leaq x@tlsgd(%rip), %rdi + // .word 0x6666 + // rex64 + // call __tls_get_addr@plt + // to + const uint8_t Inst[] = { + 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, + 0x00, 0x00, // mov %fs:0x0,%rax + 0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax + }; + memcpy(Loc - 4, Inst, sizeof(Inst)); - // The original code used a pc relative relocation and so we have to - // compensate for the -4 in had in the addend. - write32le(Loc + 8, Val + 4); + // The original code used a pc relative relocation and so we have to + // compensate for the -4 in had in the addend. + write32le(Loc + 8, Val + 4); + } else { + // Convert + // lea x@tlsgd(%rip), %rax + // call *(%rax) + // to + assert(Type == R_X86_64_GOTPC32_TLSDESC); + if (memcmp(Loc - 3, "\x48\x8d\x05", 3)) { + error(getErrorLocation(Loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " + "in callq *x@tlsdesc(%rip), %rax"); + return; + } + // movq $x@tpoff(%rip),%rax + Loc[-2] = 0xc7; + Loc[-1] = 0xc0; + write32le(Loc, Val + 4); + // xchg ax,ax + Loc[4] = 0x66; + Loc[5] = 0x90; + } } void X86_64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { - // Convert - // .byte 0x66 - // leaq x@tlsgd(%rip), %rdi - // .word 0x6666 - // rex64 - // call __tls_get_addr@plt - // to - // mov %fs:0x0,%rax - // addq x@tpoff,%rax - const uint8_t Inst[] = { - 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax - 0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@tpoff,%rax - }; - memcpy(Loc - 4, Inst, sizeof(Inst)); + if (Type == R_X86_64_TLSGD) { + // Convert + // .byte 0x66 + // leaq x@tlsgd(%rip), %rdi + // .word 0x6666 + // rex64 + // call __tls_get_addr@plt + // to + const uint8_t Inst[] = { + 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, + 0x00, 0x00, // mov %fs:0x0,%rax + 0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@gottpoff(%rip),%rax + }; + memcpy(Loc - 4, Inst, sizeof(Inst)); - // Both code sequences are PC relatives, but since we are moving the constant - // forward by 8 bytes we have to subtract the value by 8. - write32le(Loc + 8, Val - 8); + // Both code sequences are PC relatives, but since we are moving the + // constant forward by 8 bytes we have to subtract the value by 8. + write32le(Loc + 8, Val - 8); + } else { + assert(Type == R_X86_64_GOTPC32_TLSDESC); + if (memcmp(Loc - 3, "\x48\x8d\x05", 3)) { + error(getErrorLocation(Loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " + "in callq *x@tlsdesc(%rip), %rax"); + return; + } + // movq x@gottpoff(%rip),%rax + Loc[-2] = 0x8b; + write32le(Loc, Val); + // xchg ax,ax + Loc[4] = 0x66; + Loc[5] = 0x90; + } } // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to @@ -331,6 +369,7 @@ case R_X86_64_TPOFF32: case R_X86_64_GOT32: case R_X86_64_GOTPC32: + case R_X86_64_GOTPC32_TLSDESC: case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -755,6 +755,8 @@ return Sym.getSize() + A; case R_TLSDESC: return In.Got->getGlobalDynAddr(Sym) + A; + case R_TLSDESC_PC: + return In.Got->getGlobalDynAddr(Sym) + A - P; case R_AARCH64_TLSDESC_PAGE: return getAArch64Page(In.Got->getGlobalDynAddr(Sym) + A) - getAArch64Page(P); Index: ELF/Relocations.h =================================================================== --- ELF/Relocations.h +++ ELF/Relocations.h @@ -61,6 +61,7 @@ R_TLS, R_TLSDESC, R_TLSDESC_CALL, + R_TLSDESC_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -217,7 +217,8 @@ if (Config->EMachine == EM_MIPS) return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); - if (oneof(Expr) && + if (oneof( + Expr) && Config->Shared) { if (In.Got->addDynTlsEntry(Sym)) { uint64_t Off = In.Got->getGlobalDynOffset(Sym); @@ -273,8 +274,8 @@ return 1; } - if (oneof(Expr)) { + if (oneof(Expr)) { if (Config->Shared) { if (In.Got->addDynTlsEntry(Sym)) { uint64_t Off = In.Got->getGlobalDynOffset(Sym); @@ -403,8 +404,8 @@ R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC_CALL_PLT, - R_PPC64_RELAX_TOC, R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT, R_TLSLD_HINT, - R_TLSIE_HINT>(E)) + R_PPC64_RELAX_TOC, R_TLSDESC_CALL, R_TLSDESC_PC, + R_AARCH64_TLSDESC_PAGE, R_HINT, R_TLSLD_HINT, R_TLSIE_HINT>(E)) return true; // These never do, except if the entire file is position dependent or if Index: test/ELF/invalid/x86-64-tlsdesc-gd.s =================================================================== --- /dev/null +++ test/ELF/invalid/x86-64-tlsdesc-gd.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: echo '.tbss; .globl a; a:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o +# RUN: ld.lld -shared %t1.o -o %t1.so + +## GD to LE relaxation. +# RUN: not ld.lld %t.o %t1.o -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s +## GD to IE relaxation. +# RUN: not ld.lld %t.o %t1.so -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s + +# CHECK: error: [[INPUT]]:(.text+0x0): R_X86_64_GOTPC32_TLSDESC must be used in callq *x@tlsdesc(%rip), %rax + +## FIXME llvm-mc currently marks a as NOTYPE. +.type a, STT_TLS + +leaq a@tlsdesc(%rip), %rdx +call *a@tlscall(%rdx) +movl %fs:(%rax), %eax Index: test/ELF/x86-64-tlsdesc-gd.s =================================================================== --- /dev/null +++ test/ELF/x86-64-tlsdesc-gd.s @@ -0,0 +1,72 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: echo '.tbss; .globl b; b:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o +# RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so + +# RUN: ld.lld -shared %t.o %t1.o -o %t.so +# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=GD-REL %s +# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD %s + +# RUN: ld.lld %t.o %t1.o -o %t +# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s + +# RUN: ld.lld %t.o %t1.so -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE-REL %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s + +# GD-REL: .rela.dyn { +# GD-REL-NEXT: 0x20A0 R_X86_64_TLSDESC a 0x0 +# GD-REL-NEXT: 0x20B0 R_X86_64_TLSDESC b 0x0 +# GD-REL-NEXT: } + +# 0x20a0-0x1007 = 4249 +# GD: leaq 4249(%rip), %rax +# GD-NEXT: 1007: callq *(%rax) +# GD-NEXT: movl %fs:(%rax), %eax + +# 0x20b0-0x1013 = 4253 +# GD-NEXT: leaq 4253(%rip), %rax +# GD-NEXT: 1013: callq *(%rax) +# GD-NEXT: movl %fs:(%rax), %eax + +# NOREL: no relocations + +## offset(a) = -4 +# LE: movq $-4, %rax +# LE-NEXT: nop +# LE-NEXT: movl %fs:(%rax), %eax +## offset(b) = 0 +# LE: movq $0, %rax +# LE-NEXT: nop +# LE-NEXT: movl %fs:(%rax), %eax + +# IE-REL: .rela.dyn { +# IE-REL-NEXT: 0x2020C0 R_X86_64_TPOFF64 b 0x0 +# IE-REL-NEXT: } + +## a is relaxed to use LE. +# IE: movq $-4, %rax +# IE-NEXT: nop +# IE-NEXT: movl %fs:(%rax), %eax +## 0x2020C0 - 0x201013 = 4269 +# IE-NEXT: movq 4269(%rip), %rax +# IE-NEXT: 201013: nop +# IE-NEXT: movl %fs:(%rax), %eax + +leaq a@tlsdesc(%rip), %rax +call *a@tlscall(%rax) +movl %fs:(%rax), %eax + +leaq b@tlsdesc(%rip), %rax +call *b@tlscall(%rax) +movl %fs:(%rax), %eax + +## FIXME llvm-mc currently marks b as NOTYPE. +.type b, STT_TLS + +.section .tbss +.globl a +.zero 8 +a: +.zero 4