[lld] r361911 - [ELF] Implement General Dynamic style TLSDESC for x86-64
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Tue May 28 19:03:57 PDT 2019
Author: maskray
Date: Tue May 28 19:03:56 2019
New Revision: 361911
URL: http://llvm.org/viewvc/llvm-project?rev=361911&view=rev
Log:
[ELF] Implement General Dynamic style TLSDESC for x86-64
This handles two initial relocation types R_X86_64_GOTPC32_TLSDESC and
R_X86_64_TLSDESC_CALL, as well as the GD->LE and GD->IE relaxations.
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62513
Added:
lld/trunk/test/ELF/invalid/x86-64-tlsdesc-gd.s
lld/trunk/test/ELF/x86-64-tlsdesc-gd.s
Modified:
lld/trunk/ELF/Arch/X86_64.cpp
lld/trunk/ELF/InputSection.cpp
lld/trunk/ELF/Relocations.cpp
lld/trunk/ELF/Relocations.h
Modified: lld/trunk/ELF/Arch/X86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/X86_64.cpp?rev=361911&r1=361910&r2=361911&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/X86_64.cpp (original)
+++ lld/trunk/ELF/Arch/X86_64.cpp Tue May 28 19:03:56 2019
@@ -55,6 +55,7 @@ X86_64::X86_64() {
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 @@ RelExpr X86_64::getRelExpr(RelType Type,
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 @@ RelExpr X86_64::getRelExpr(RelType Type,
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,82 @@ RelType X86_64::getDynRel(RelType Type)
}
void X86_64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
- // Convert
- // .byte 0x66
- // leaq x at tlsgd(%rip), %rdi
- // .word 0x6666
- // rex64
- // call __tls_get_addr at plt
- // to
- // mov %fs:0x0,%rax
- // lea x at 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 at 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);
+ if (Type == R_X86_64_TLSGD) {
+ // Convert
+ // .byte 0x66
+ // leaq x at tlsgd(%rip), %rdi
+ // .word 0x6666
+ // rex64
+ // call __tls_get_addr at plt
+ // to the following two instructions.
+ 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 at 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);
+ } else {
+ // Convert
+ // lea x at tlsgd(%rip), %rax
+ // call *(%rax)
+ // to the following two instructions.
+ 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 at tlsdesc(%rip), %rax");
+ return;
+ }
+ // movq $x at 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 at tlsgd(%rip), %rdi
- // .word 0x6666
- // rex64
- // call __tls_get_addr at plt
- // to
- // mov %fs:0x0,%rax
- // addq x at 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 at tpoff,%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);
+ if (Type == R_X86_64_TLSGD) {
+ // Convert
+ // .byte 0x66
+ // leaq x at tlsgd(%rip), %rdi
+ // .word 0x6666
+ // rex64
+ // call __tls_get_addr at plt
+ // to the following two instructions.
+ 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 at 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);
+ } else {
+ // Convert
+ // lea x at tlsgd(%rip), %rax
+ // call *(%rax)
+ // to the following two instructions.
+ 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 at tlsdesc(%rip), %rax");
+ return;
+ }
+ // movq x at 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 +373,7 @@ void X86_64::relocateOne(uint8_t *Loc, R
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:
Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=361911&r1=361910&r2=361911&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Tue May 28 19:03:56 2019
@@ -755,6 +755,8 @@ static uint64_t getRelocTargetVA(const I
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);
Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=361911&r1=361910&r2=361911&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Tue May 28 19:03:56 2019
@@ -217,7 +217,8 @@ handleTlsRelocation(RelType Type, Symbol
if (Config->EMachine == EM_MIPS)
return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
- if (oneof<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
+ if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC>(
+ Expr) &&
Config->Shared) {
if (In.Got->addDynTlsEntry(Sym)) {
uint64_t Off = In.Got->getGlobalDynOffset(Sym);
@@ -273,8 +274,8 @@ handleTlsRelocation(RelType Type, Symbol
return 1;
}
- if (oneof<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT,
- R_TLSGD_GOTPLT, R_TLSGD_PC>(Expr)) {
+ if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
+ R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
if (In.Got->addDynTlsEntry(Sym)) {
uint64_t Off = In.Got->getGlobalDynOffset(Sym);
@@ -403,8 +404,8 @@ static bool isStaticLinkTimeConstant(Rel
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
Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=361911&r1=361910&r2=361911&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Tue May 28 19:03:56 2019
@@ -61,6 +61,7 @@ enum RelExpr {
R_TLS,
R_TLSDESC,
R_TLSDESC_CALL,
+ R_TLSDESC_PC,
R_TLSGD_GOT,
R_TLSGD_GOTPLT,
R_TLSGD_PC,
Added: lld/trunk/test/ELF/invalid/x86-64-tlsdesc-gd.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/invalid/x86-64-tlsdesc-gd.s?rev=361911&view=auto
==============================================================================
--- lld/trunk/test/ELF/invalid/x86-64-tlsdesc-gd.s (added)
+++ lld/trunk/test/ELF/invalid/x86-64-tlsdesc-gd.s Tue May 28 19:03:56 2019
@@ -0,0 +1,15 @@
+# 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 at tlsdesc(%rip), %rax
+
+leaq a at tlsdesc(%rip), %rdx
+call *a at tlscall(%rdx)
+movl %fs:(%rax), %eax
Added: lld/trunk/test/ELF/x86-64-tlsdesc-gd.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/x86-64-tlsdesc-gd.s?rev=361911&view=auto
==============================================================================
--- lld/trunk/test/ELF/x86-64-tlsdesc-gd.s (added)
+++ lld/trunk/test/ELF/x86-64-tlsdesc-gd.s Tue May 28 19:03:56 2019
@@ -0,0 +1,69 @@
+# 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 at tlsdesc(%rip), %rax
+call *a at tlscall(%rax)
+movl %fs:(%rax), %eax
+
+leaq b at tlsdesc(%rip), %rax
+call *b at tlscall(%rax)
+movl %fs:(%rax), %eax
+
+.section .tbss
+.globl a
+.zero 8
+a:
+.zero 4
More information about the llvm-commits
mailing list