From 75c348a0974a6906bee27160dcc07c727129c6a7 Mon Sep 17 00:00:00 2001 From: Zaara Syeda Date: Mon, 9 Jul 2018 16:35:51 +0000 Subject: [PATCH] [PPC64] Add TLS local dynamic to local exec relaxation 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 --- lld/ELF/Arch/PPC64.cpp | 50 +++++++++++++++++++++++++ lld/ELF/InputSection.cpp | 3 ++ lld/ELF/Relocations.cpp | 21 +++++++---- lld/ELF/Relocations.h | 2 + lld/test/ELF/ppc64-tls-ld-le.s | 84 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 lld/test/ELF/ppc64-tls-ld-le.s diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp index 7331758..fa3bf6c 100644 --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -55,6 +55,7 @@ public: 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 @@ -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) { @@ -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: @@ -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; } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index e0fae50..89b2929 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -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: @@ -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); @@ -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: diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index f32b684..639fd70 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -188,13 +188,17 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, return 1; } - if (isRelExprOneOf(Expr)) { + if (isRelExprOneOf(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); @@ -203,9 +207,10 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, } // Local-Dynamic relocs can be relaxed to Local-Exec. - if (isRelExprOneOf(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; } @@ -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 diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index 91fb603..a412511 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -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, @@ -84,6 +85,7 @@ enum RelExpr { R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_GOT_OFF, + R_TLSLD_HINT, R_TLSLD_PC, }; diff --git a/lld/test/ELF/ppc64-tls-ld-le.s b/lld/test/ELF/ppc64-tls-ld-le.s new file mode 100644 index 0000000..d42d7b9 --- /dev/null +++ b/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 -- 2.7.4