[lld] r358870 - [ELF][X86] Allow R_386_TLS_LDO_32 and R_X86_64_DTPOFF{32, 64} to preemptable local-dynamic symbols

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 21 20:10:40 PDT 2019


Author: maskray
Date: Sun Apr 21 20:10:40 2019
New Revision: 358870

URL: http://llvm.org/viewvc/llvm-project?rev=358870&view=rev
Log:
[ELF][X86] Allow R_386_TLS_LDO_32 and R_X86_64_DTPOFF{32,64} to preemptable local-dynamic symbols

Summary:
Fixes PR35242. A simplified reproduce:

    thread_local int i; int f() { return i; }

% {g++,clang++} -fPIC -shared -ftls-model=local-dynamic -fuse-ld=lld a.cc
ld.lld: error: can't create dynamic relocation R_X86_64_DTPOFF32 against symbol: i in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output

In isStaticLinkTimeConstant(), Syn.IsPreemptible is true, so it is not
seen as a constant. The error is then issued in processRelocAux().

A symbol of the local-dynamic TLS model cannot be preempted but it can
preempt symbols of the global-dynamic TLS model in other DSOs.
So it makes some sense that the variable is not static.

This patch fixes the linking error by changing getRelExpr() on
R_386_TLS_LDO_32 and R_X86_64_DTPOFF{32,64} from R_ABS to R_DTPREL.
R_PPC64_DTPREL_* and R_MIPS_TLS_DTPREL_* need similar fixes, but they are not handled in this patch.

As a bonus, we use `if (Expr == R_ABS && !Config->Shared)` to find
ld-to-le opportunities. R_ABS is overloaded here for such STT_TLS symbols.
A dedicated R_DTPREL is clearer.

Differential Revision: https://reviews.llvm.org/D60945

Added:
    lld/trunk/test/ELF/i386-tls-ld-preemptable.s
    lld/trunk/test/ELF/x86-64-tls-ld-preemptable.s
Modified:
    lld/trunk/ELF/Arch/X86.cpp
    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.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/X86.cpp?rev=358870&r1=358869&r2=358870&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/X86.cpp (original)
+++ lld/trunk/ELF/Arch/X86.cpp Sun Apr 21 20:10:40 2019
@@ -84,8 +84,9 @@ RelExpr X86::getRelExpr(RelType Type, co
   case R_386_8:
   case R_386_16:
   case R_386_32:
-  case R_386_TLS_LDO_32:
     return R_ABS;
+  case R_386_TLS_LDO_32:
+    return R_DTPREL;
   case R_386_TLS_GD:
     return R_TLSGD_GOTPLT;
   case R_386_TLS_LDM:

Modified: lld/trunk/ELF/Arch/X86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/X86_64.cpp?rev=358870&r1=358869&r2=358870&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/X86_64.cpp (original)
+++ lld/trunk/ELF/Arch/X86_64.cpp Sun Apr 21 20:10:40 2019
@@ -82,9 +82,10 @@ RelExpr X86_64::getRelExpr(RelType Type,
   case R_X86_64_32:
   case R_X86_64_32S:
   case R_X86_64_64:
+    return R_ABS;
   case R_X86_64_DTPOFF32:
   case R_X86_64_DTPOFF64:
-    return R_ABS;
+    return R_DTPREL;
   case R_X86_64_TPOFF32:
     return R_TLS;
   case R_X86_64_TLSLD:

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=358870&r1=358869&r2=358870&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Sun Apr 21 20:10:40 2019
@@ -616,6 +616,8 @@ static uint64_t getRelocTargetVA(const I
   case R_RELAX_TLS_LD_TO_LE_ABS:
   case R_RELAX_GOT_PC_NOPIC:
     return Sym.getVA(A);
+  case R_DTPREL:
+    return Sym.getVA(A);
   case R_ADDEND:
     return A;
   case R_ARM_SBREL:
@@ -806,7 +808,7 @@ void InputSection::relocateNonAlloc(uint
     if (Expr == R_NONE)
       continue;
 
-    if (Expr != R_ABS) {
+    if (Expr != R_ABS && Expr != R_DTPREL) {
       std::string Msg = getLocation<ELFT>(Offset) +
                         ": has non-ABS relocation " + toString(Type) +
                         " against symbol '" + toString(Sym) + "'";

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=358870&r1=358869&r2=358870&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Sun Apr 21 20:10:40 2019
@@ -248,7 +248,8 @@ handleTlsRelocation(RelType Type, Symbol
   }
 
   // Local-Dynamic relocs can be relaxed to Local-Exec.
-  if (Expr == R_ABS && !Config->Shared) {
+  // TODO Delete R_ABS after all R_*_DTPREL_* relocations migrate to R_DTPREL.
+  if ((Expr == R_ABS || Expr == R_DTPREL) && !Config->Shared) {
     C.Relocations.push_back(
         {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
          Offset, Addend, &Sym});
@@ -398,13 +399,13 @@ static bool isRelExpr(RelExpr Expr) {
 static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
                                      InputSectionBase &S, uint64_t RelOff) {
   // These expressions always compute a constant
-  if (oneof<R_GOTPLT, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF,
+  if (oneof<R_DTPREL, R_GOTPLT, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF,
             R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF,
             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_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE,
-            R_HINT, R_TLSLD_HINT, R_TLSIE_HINT>(E))
+            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_TLSDESC_CALL, 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=358870&r1=358869&r2=358870&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Sun Apr 21 20:10:40 2019
@@ -31,6 +31,7 @@ using RelType = uint32_t;
 enum RelExpr {
   R_ABS,
   R_ADDEND,
+  R_DTPREL,
   R_GOT,
   R_GOT_OFF,
   R_GOT_PC,

Added: lld/trunk/test/ELF/i386-tls-ld-preemptable.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/i386-tls-ld-preemptable.s?rev=358870&view=auto
==============================================================================
--- lld/trunk/test/ELF/i386-tls-ld-preemptable.s (added)
+++ lld/trunk/test/ELF/i386-tls-ld-preemptable.s Sun Apr 21 20:10:40 2019
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s
+
+# CHECK: 100b:       movl    (%eax), %eax
+
+# We used to error on R_386_TLS_LDO_32 to preemptable symbols.
+# i is STB_GLOBAL and preemptable.
+  leal i at TLSLDM(%ebx), %eax
+  calll __tls_get_addr at PLT
+  movl i at DTPOFF(%eax), %eax # R_386_TLS_LDO_32
+
+.section .tbss,"awT", at nobits
+.globl i
+i:
+  .long 0
+  .size i, 4

Added: lld/trunk/test/ELF/x86-64-tls-ld-preemptable.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/x86-64-tls-ld-preemptable.s?rev=358870&view=auto
==============================================================================
--- lld/trunk/test/ELF/x86-64-tls-ld-preemptable.s (added)
+++ lld/trunk/test/ELF/x86-64-tls-ld-preemptable.s Sun Apr 21 20:10:40 2019
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s
+
+# CHECK:      100c:       leaq    (%rax), %rax
+# CHECK-NEXT: 1013:       movabsq 0, %rax
+
+# We used to error on R_X86_64_DTPOFF{32,64} to preemptable symbols.
+# i is STB_GLOBAL and preemptable.
+  leaq i at TLSLD(%rip), %rdi
+  callq __tls_get_addr at PLT
+  leaq i at DTPOFF(%rax), %rax # R_X86_64_DTPOFF32
+  movabsq i at DTPOFF, %rax # R_X86_64_DTPOFF64
+
+.section .tbss,"awT", at nobits
+.globl i
+i:
+  .long 0
+  .size i, 4




More information about the llvm-commits mailing list