diff options
| author | Fangrui Song <maskray@google.com> | 2019-04-22 03:10:40 +0000 |
|---|---|---|
| committer | Fangrui Song <maskray@google.com> | 2019-04-22 03:10:40 +0000 |
| commit | bc4b159bb1121ed9e1c00df35a4f5dd5712de8de (patch) | |
| tree | 591072d2a422da89a52897c0241aeb7ba0095ff3 | |
| parent | 1233c15be59160eb48bec08327db012bc3f2aedf (diff) | |
| download | bcm5719-llvm-bc4b159bb1121ed9e1c00df35a4f5dd5712de8de.tar.gz bcm5719-llvm-bc4b159bb1121ed9e1c00df35a4f5dd5712de8de.zip | |
[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
llvm-svn: 358870
| -rw-r--r-- | lld/ELF/Arch/X86.cpp | 3 | ||||
| -rw-r--r-- | lld/ELF/Arch/X86_64.cpp | 3 | ||||
| -rw-r--r-- | lld/ELF/InputSection.cpp | 4 | ||||
| -rw-r--r-- | lld/ELF/Relocations.cpp | 13 | ||||
| -rw-r--r-- | lld/ELF/Relocations.h | 1 | ||||
| -rw-r--r-- | lld/test/ELF/i386-tls-ld-preemptable.s | 18 | ||||
| -rw-r--r-- | lld/test/ELF/x86-64-tls-ld-preemptable.s | 20 |
7 files changed, 53 insertions, 9 deletions
diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp index 7001eb47194..468ca20f540 100644 --- a/lld/ELF/Arch/X86.cpp +++ b/lld/ELF/Arch/X86.cpp @@ -84,8 +84,9 @@ RelExpr X86::getRelExpr(RelType Type, const Symbol &S, 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: diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp index 668b408639b..4ac945467d9 100644 --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -82,9 +82,10 @@ RelExpr X86_64::getRelExpr(RelType Type, const Symbol &S, 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: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index a32015f4b14..060374ad6d4 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -616,6 +616,8 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A, 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(uint8_t *Buf, ArrayRef<RelTy> Rels) { 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) + "'"; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 14d3c1d2f35..d5c36b667f7 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -248,7 +248,8 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, } // 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 diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index 48ed3621a93..240dc68ab70 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -31,6 +31,7 @@ using RelType = uint32_t; enum RelExpr { R_ABS, R_ADDEND, + R_DTPREL, R_GOT, R_GOT_OFF, R_GOT_PC, diff --git a/lld/test/ELF/i386-tls-ld-preemptable.s b/lld/test/ELF/i386-tls-ld-preemptable.s new file mode 100644 index 00000000000..8f9d91a965b --- /dev/null +++ b/lld/test/ELF/i386-tls-ld-preemptable.s @@ -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@TLSLDM(%ebx), %eax + calll __tls_get_addr@PLT + movl i@DTPOFF(%eax), %eax # R_386_TLS_LDO_32 + +.section .tbss,"awT",@nobits +.globl i +i: + .long 0 + .size i, 4 diff --git a/lld/test/ELF/x86-64-tls-ld-preemptable.s b/lld/test/ELF/x86-64-tls-ld-preemptable.s new file mode 100644 index 00000000000..50f9b244776 --- /dev/null +++ b/lld/test/ELF/x86-64-tls-ld-preemptable.s @@ -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@TLSLD(%rip), %rdi + callq __tls_get_addr@PLT + leaq i@DTPOFF(%rax), %rax # R_X86_64_DTPOFF32 + movabsq i@DTPOFF, %rax # R_X86_64_DTPOFF64 + +.section .tbss,"awT",@nobits +.globl i +i: + .long 0 + .size i, 4 |

