Skip to content

Commit

Permalink
[PPC64] Add TLS local dynamic to local exec relaxation
Browse files Browse the repository at this point in the history
This patch adds the target call back relaxTlsLdToLe to support TLS relaxation
from local dynamic to local exec model.

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

llvm-svn: 336559
  • Loading branch information
syzaara committed Jul 9, 2018
1 parent a627253 commit 75c348a
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 8 deletions.
50 changes: 50 additions & 0 deletions lld/ELF/Arch/PPC64.cpp
Expand Up @@ -55,6 +55,7 @@ class PPC64 final : public TargetInfo {
RelExpr Expr) const override;
void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
} // namespace

Expand Down Expand Up @@ -165,6 +166,52 @@ void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
}


void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement.
// The local dynamic code sequence for a global `x` will look like:
// Instruction Relocation Symbol
// addis r3, r2, x@got@tlsld@ha R_PPC64_GOT_TLSLD16_HA x
// addi r3, r3, x@got@tlsld@l R_PPC64_GOT_TLSLD16_LO x
// bl __tls_get_addr(x@tlsgd) R_PPC64_TLSLD x
// R_PPC64_REL24 __tls_get_addr
// nop None None

// Relaxing to local exec entails converting:
// addis r3, r2, x@got@tlsld@ha into nop
// addi r3, r3, x@got@tlsld@l into addis r3, r13, 0
// bl __tls_get_addr(x@tlsgd) into nop
// nop into addi r3, r3, 4096

uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
switch (Type) {
case R_PPC64_GOT_TLSLD16_HA:
write32(Loc - EndianOffset, 0x60000000); // nop
break;
case R_PPC64_GOT_TLSLD16_LO:
write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13, 0
break;
case R_PPC64_TLSLD:
write32(Loc, 0x60000000); // nop
write32(Loc + 4, 0x38631000); // addi r3, r3, 4096
break;
case R_PPC64_DTPREL16:
case R_PPC64_DTPREL16_HA:
case R_PPC64_DTPREL16_HI:
case R_PPC64_DTPREL16_DS:
case R_PPC64_DTPREL16_LO:
case R_PPC64_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_GOT_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_DS:
case R_PPC64_GOT_DTPREL16_HI:
relocateOne(Loc, Type, Val);
break;
default:
llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
}
}

RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
Expand Down Expand Up @@ -230,6 +277,7 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
case R_PPC64_TLSGD:
return R_TLSDESC_CALL;
case R_PPC64_TLSLD:
return R_TLSLD_HINT;
case R_PPC64_TLS:
return R_HINT;
default:
Expand Down Expand Up @@ -431,6 +479,8 @@ RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const {
if (Expr == R_RELAX_TLS_GD_TO_IE)
return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
if (Expr == R_RELAX_TLS_LD_TO_LE)
return R_RELAX_TLS_LD_TO_LE_ABS;
return Expr;
}

Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/InputSection.cpp
Expand Up @@ -483,6 +483,7 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
case R_INVALID:
return 0;
case R_ABS:
case R_RELAX_TLS_LD_TO_LE_ABS:
case R_RELAX_GOT_PC_NOPIC:
return Sym.getVA(A);
case R_ADDEND:
Expand Down Expand Up @@ -516,6 +517,7 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
case R_HINT:
case R_NONE:
case R_TLSDESC_CALL:
case R_TLSLD_HINT:
llvm_unreachable("cannot relocate hint relocs");
case R_MIPS_GOTREL:
return Sym.getVA(A) - InX::MipsGot->getGp(File);
Expand Down Expand Up @@ -767,6 +769,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
Target->relaxTlsIeToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_LD_TO_LE:
case R_RELAX_TLS_LD_TO_LE_ABS:
Target->relaxTlsLdToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_GD_TO_LE:
Expand Down
21 changes: 13 additions & 8 deletions lld/ELF/Relocations.cpp
Expand Up @@ -188,13 +188,17 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
return 1;
}

if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC>(Expr)) {
if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC,
R_TLSLD_HINT>(Expr)) {
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
C.Relocations.push_back(
{R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
return 2;
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
Offset, Addend, &Sym});
return Target->TlsGdRelaxSkip;
}
if (Expr == R_TLSLD_HINT)
return 1;
if (InX::Got->addTlsIndex())
InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got,
InX::Got->getTlsIndexOff(), nullptr);
Expand All @@ -203,9 +207,10 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
}

// Local-Dynamic relocs can be relaxed to Local-Exec.
if (isRelExprOneOf<R_ABS, R_TLSLD_GOT_FROM_END, R_TLSLD_PC>(Expr) &&
!Config->Shared) {
C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
if (Expr == R_ABS && !Config->Shared) {
C.Relocations.push_back(
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
Offset, Addend, &Sym});
return 1;
}

Expand Down Expand Up @@ -357,8 +362,8 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END,
R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(
E))
R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
R_TLSLD_HINT>(E))
return true;

// These never do, except if the entire file is position dependent or if
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Relocations.h
Expand Up @@ -73,6 +73,7 @@ enum RelExpr {
R_RELAX_TLS_GD_TO_LE_NEG,
R_RELAX_TLS_IE_TO_LE,
R_RELAX_TLS_LD_TO_LE,
R_RELAX_TLS_LD_TO_LE_ABS,
R_SIZE,
R_TLS,
R_TLSDESC,
Expand All @@ -84,6 +85,7 @@ enum RelExpr {
R_TLSLD_GOT,
R_TLSLD_GOT_FROM_END,
R_TLSLD_GOT_OFF,
R_TLSLD_HINT,
R_TLSLD_PC,
};

Expand Down
84 changes: 84 additions & 0 deletions lld/test/ELF/ppc64-tls-ld-le.s
@@ -0,0 +1,84 @@
// REQUIRES: ppc

// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
// RUN: ld.lld %t.o -o %t
// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s

// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
// RUN: ld.lld %t.o -o %t
// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s

.text
.abiversion 2
.globl _start # -- Begin function _start
.p2align 4
.type _start,@function
_start: # @_start
.Lfunc_begin0:
.Lfunc_gep0:
addis 2, 12, .TOC.-.Lfunc_gep0@ha
addi 2, 2, .TOC.-.Lfunc_gep0@l
.Lfunc_lep0:
.localentry _start, .Lfunc_lep0-.Lfunc_gep0
# %bb.0: # %entry
mflr 0
std 31, -8(1)
std 0, 16(1)
stdu 1, -64(1)
mr 31, 1
std 30, 48(31) # 8-byte Folded Spill
li 3, 0
stw 3, 44(31)
addis 3, 2, a@got@tlsld@ha
addi 3, 3, a@got@tlsld@l
bl __tls_get_addr(a@tlsld)
nop
addis 3, 3, a@dtprel@ha
addi 3, 3, a@dtprel@l
lwz 30, 0(3)
extsw 3, 30
ld 30, 48(31) # 8-byte Folded Reload
addi 1, 1, 64
ld 0, 16(1)
ld 31, -8(1)
mtlr 0
blr
.long 0
.quad 0
.Lfunc_end0:
.size _start, .Lfunc_end0-.Lfunc_begin0
# -- End function
.globl __tls_get_addr
.type __tls_get_addr,@function
__tls_get_addr:
.type a,@object # @a
.section .tdata,"awT",@progbits
.p2align 2
a:
.long 2 # 0x2
.size a, 4

// Verify that the input has local-dynamic tls relocation types
// InputRelocs: Relocation section '.rela.text'
// InputRelocs: R_PPC64_GOT_TLSLD16_HA {{0+}} a + 0
// InputRelocs: R_PPC64_GOT_TLSLD16_LO {{0+}} a + 0
// InputRelocs: R_PPC64_TLSLD {{0+}} a + 0

// Verify that the local-dynamic sequence is relaxed to local exec.
// Dis: _start:
// Dis: nop
// Dis: addis 3, 13, 0
// Dis: nop
// Dis: addi 3, 3, 4096

// #ha(a@dtprel) --> (0x0 -0x8000 + 0x8000) >> 16 = 0
// #lo(a@dtprel) --> (0x0 -0x8000) = -0x8000 = -32768
// Dis: addis 3, 3, 0
// Dis: addi 3, 3, -32768

// Verify that no local-dynamic relocations exist for the dynamic linker.
// OutputRelocs-NOT: R_PPC64_DTPMOD64

0 comments on commit 75c348a

Please sign in to comment.