[ELF][X86] Allow R_386_TLS_LDO_32 and R_X86_64_DTPOFF{32,64} to preemptable local...
authorFangrui Song <maskray@google.com>
Mon, 22 Apr 2019 03:10:40 +0000 (03:10 +0000)
committerFangrui Song <maskray@google.com>
Mon, 22 Apr 2019 03:10:40 +0000 (03:10 +0000)
commitbc4b159bb1121ed9e1c00df35a4f5dd5712de8de
tree591072d2a422da89a52897c0241aeb7ba0095ff3
parent1233c15be59160eb48bec08327db012bc3f2aedf
[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
lld/ELF/Arch/X86.cpp
lld/ELF/Arch/X86_64.cpp
lld/ELF/InputSection.cpp
lld/ELF/Relocations.cpp
lld/ELF/Relocations.h
lld/test/ELF/i386-tls-ld-preemptable.s [new file with mode: 0644]
lld/test/ELF/x86-64-tls-ld-preemptable.s [new file with mode: 0644]