[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