Index: lld/trunk/ELF/Arch/PPC64.cpp =================================================================== --- lld/trunk/ELF/Arch/PPC64.cpp +++ lld/trunk/ELF/Arch/PPC64.cpp @@ -55,6 +55,7 @@ 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::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 @@ 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 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; } Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -483,6 +483,7 @@ 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 @@ 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 @@ 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: Index: lld/trunk/ELF/Relocations.h =================================================================== --- lld/trunk/ELF/Relocations.h +++ lld/trunk/ELF/Relocations.h @@ -73,6 +73,7 @@ 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 @@ R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_GOT_OFF, + R_TLSLD_HINT, R_TLSLD_PC, }; Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -188,13 +188,17 @@ 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 @@ } // 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 @@ 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 Index: lld/trunk/test/ELF/ppc64-tls-ld-le.s =================================================================== --- lld/trunk/test/ELF/ppc64-tls-ld-le.s +++ lld/trunk/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