Index: ELF/Arch/PPC64.cpp =================================================================== --- ELF/Arch/PPC64.cpp +++ ELF/Arch/PPC64.cpp @@ -51,6 +51,9 @@ void writeGotHeader(uint8_t *Buf) const override; bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const override; + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace @@ -213,6 +216,7 @@ case R_PPC64_DTPREL16_LO_DS: return R_ABS; case R_PPC64_TLSGD: + return R_TLSGD_HINT; case R_PPC64_TLSLD: case R_PPC64_TLS: return R_HINT; @@ -401,6 +405,34 @@ // a call stub. return Type == R_PPC64_REL24 && S.isInPlt(); } +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; + } + return Expr; +} + +void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { + case R_PPC64_GOT_TLSGD16_HA: + // This is relaxed from addis r3, r2, sym@got@tlsgd@ha to + // addis r3, r2, sym@got@tprel@ha. + write16(Loc, applyPPCHa(Val - PPC64TocOffset)); + return; + case R_PPC64_GOT_TLSGD16_LO: + // ld r3, sym@got@tprel@l(r3) + write32(Loc - ((Config->EKind == ELF64BEKind) ? 2U : 0U), + 0xE8630000 | applyPPCLo(Val - PPC64TocOffset)); + return; + case R_PPC64_TLSGD: + write32(Loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop + write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13 + return; + default: + llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); + } +} TargetInfo *elf::getPPC64TargetInfo() { static PPC64 Target; Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -504,6 +504,7 @@ case R_RELAX_TLS_GD_TO_IE_END: return Sym.getGotOffset() + A - InX::Got->getSize(); case R_GOT_OFF: + case R_RELAX_TLS_GD_TO_IE_GOT_OFF: return Sym.getGotOffset() + A; case R_GOT_PAGE_PC: case R_RELAX_TLS_GD_TO_IE_PAGE_PC: @@ -514,6 +515,7 @@ case R_HINT: case R_NONE: case R_TLSDESC_CALL: + case R_TLSGD_HINT: llvm_unreachable("cannot relocate hint relocs"); case R_MIPS_GOTREL: return Sym.getVA(A) - InX::MipsGot->getGp(File); @@ -773,11 +775,18 @@ break; case R_RELAX_TLS_GD_TO_IE: case R_RELAX_TLS_GD_TO_IE_ABS: + case R_RELAX_TLS_GD_TO_IE_GOT_OFF: case R_RELAX_TLS_GD_TO_IE_PAGE_PC: case R_RELAX_TLS_GD_TO_IE_END: Target->relaxTlsGdToIe(BufLoc, Type, TargetVA); break; case R_PPC_CALL: + // If this is a call to __tls_get_addr, it may be part of a TLS + // sequence that has been relaxed and turned into a nop. In this + // case, we don't want to handle it as a call. + if (read32(BufLoc) == 0x60000000) // nop + break; + // Patch a nop (0x60000000) to a ld. if (Rel.Sym->NeedsTocRestore) { if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) { Index: ELF/Relocations.h =================================================================== --- ELF/Relocations.h +++ ELF/Relocations.h @@ -67,6 +67,7 @@ R_RELAX_TLS_GD_TO_IE, R_RELAX_TLS_GD_TO_IE_ABS, R_RELAX_TLS_GD_TO_IE_END, + R_RELAX_TLS_GD_TO_IE_GOT_OFF, R_RELAX_TLS_GD_TO_IE_PAGE_PC, R_RELAX_TLS_GD_TO_LE, R_RELAX_TLS_GD_TO_LE_NEG, @@ -79,6 +80,7 @@ R_TLSDESC_PAGE, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, + R_TLSGD_HINT, R_TLSGD_PC, R_TLSLD_GOT_FROM_END, R_TLSLD_GOT, Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -210,8 +210,12 @@ } if (isRelExprOneOf(Expr)) { + R_TLSGD_GOT_FROM_END, R_TLSGD_HINT, R_TLSGD_PC>(Expr)) { if (Config->Shared) { + // Relxation hint, since we are not relaxing from GD it can be skipped. + if (Expr == R_TLSGD_HINT) + return 1; + if (InX::Got->addDynTlsEntry(Sym)) { uint64_t Off = InX::Got->getGlobalDynOffset(Sym); InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, Off, &Sym); Index: test/ELF/ppc64-gd-to-ie.s =================================================================== --- /dev/null +++ test/ELF/ppc64-gd-to-ie.s @@ -0,0 +1,65 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o +# RUN: ld.lld -shared %t2.o -o %t3.so +# RUN: ld.lld %t.o %t3.so -o %t +# RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s +# 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-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o +# RUN: ld.lld -shared %t2.o -o %t3.so +# RUN: ld.lld %t.o %t3.so -o %t +# RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s +# 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 + .p2align 4 + .type _start,@function +_start: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + addis 3, 2, a@got@tlsgd@ha + addi 3, 3, a@got@tlsgd@l + bl __tls_get_addr(a@tlsgd) + nop + lwa 3, 0(3) + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + + + .globl __tls_get_addr + .type __tls_get_addr,@function +__tls_get_addr: + + +# CheckGot: .got 00000010 00000000100200c0 DATA +# .got is at 0x100200c0 so the toc-base is 100280c0. +# `a` is at .got[1], we expect the offsets to be: +# Ha(a) = ((0x100200c8 - 0x100280c0) + 0x8000) >> 16 = 0 +# Lo(a) = (0x100200c8 - 0x100280c0) = -32760 + +# Dis-LABEL: _start +# Dis: addis 3, 2, 0 +# Dis-NEXT: ld 3, -32760(3) +# Dis-NEXT: nop +# Dis-NEXT: add 3, 3, 13 + +# Verify that the only dynamic relocation we emit is a TPREL one rather then the +# DTPMOD64/DTPREL64 pair for general-dynamic. +# OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 1 entries: +# OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# OutputRelocs-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_TPREL64 {{[0-9a-f]+}} a + 0