Skip to content

Commit

Permalink
[ELF] Fix getRelocTargetVA formulae of R_TLS and R_NEG_TLS
Browse files Browse the repository at this point in the history
For R_TLS:
1) Delete Sym.isTls() . The assembler ensures the symbol is STT_TLS.
   If not (the input is broken), we would crash (dereferencing null Out::TlsPhdr).
2) Change Sym.isUndefWeak() to Sym.isUndefined(), otherwise with --noinhibit-exec
   we would still evaluate the symbol and crash.
3) Return A if the symbol is undefined. This is PR40570.
   The case is probably unrealistic but returning A matches R_ABS and the
   behavior of several dynamic loaders.

R_NEG_TLS is obsoleted Sun TLS we don't fully support, but
R_RELAX_TLS_GD_TO_LE_NEG is still used by GD->LE relaxation (subl $var@tpoff,%eax).

They should add the addend. Unfortunately I can't test it as compilers don't seem to generate non-zero implicit addends.

Reviewed By: ruiu

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

llvm-svn: 361146
  • Loading branch information
MaskRay authored and MrSidims committed May 24, 2019
1 parent c4314af commit 97d1104
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 8 deletions.
17 changes: 9 additions & 8 deletions lld/ELF/InputSection.cpp
Expand Up @@ -738,17 +738,18 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
case R_RELAX_TLS_IE_TO_LE:
case R_RELAX_TLS_LD_TO_LE:
case R_TLS:
// A weak undefined TLS symbol resolves to the base of the TLS
// block, i.e. gets a value of zero. If we pass --gc-sections to
// lld and .tbss is not referenced, it gets reclaimed and we don't
// create a TLS program header. Therefore, we resolve this
// statically to zero.
if (Sym.isTls() && Sym.isUndefWeak())
return 0;
// It is not very clear what to return if the symbol is undefined. With
// --noinhibit-exec, even a non-weak undefined reference may reach here.
// Just return A, which matches R_ABS, and the behavior of some dynamic
// loaders.
if (Sym.isUndefined())
return A;
return Sym.getVA(A) + getTlsTpOffset();
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
return -(Sym.getVA(A) + getTlsTpOffset());
if (Sym.isUndefined())
return A;
return -Sym.getVA(0) - getTlsTpOffset() + A;
case R_SIZE:
return Sym.getSize() + A;
case R_TLSDESC:
Expand Down
16 changes: 16 additions & 0 deletions lld/test/ELF/i386-tls-le-undef.s
@@ -0,0 +1,16 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o
# RUN: ld.lld --noinhibit-exec %t.o -o %t 2>&1
# RUN: llvm-objdump -d %t | FileCheck %s

## Undefined TLS symbols resolve to 0.
## In --noinhibit-exec mode, a non-weak undefined symbol is not an error.

# CHECK: subl $0, %eax
# CHECK: subl $0, %eax

.weak weak_undef
movl %gs:0, %eax
subl $weak_undef@tpoff,%eax
movl %gs:0, %eax
subl $undef@tpoff,%eax
15 changes: 15 additions & 0 deletions lld/test/ELF/x86-64-tls-le-undef.s
@@ -0,0 +1,15 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
# RUN: ld.lld --noinhibit-exec %t.o -o %t 2>&1
# RUN: llvm-objdump -d %t | FileCheck %s

## Undefined TLS symbols resolve to 0.
## In --noinhibit-exec mode, a non-weak undefined symbol is not an error.

# CHECK: leaq 16(%rax), %rdx
# CHECK-NEXT: leaq 32(%rax), %rdx

.weak weak
movq %fs:0, %rax
leaq weak@tpoff+16(%rax), %rdx
leaq global@tpoff+32(%rax), %rdx

0 comments on commit 97d1104

Please sign in to comment.