[lld] r335651 - [PPC64] Thread-local storage general-dynamic to initial-exec relaxation.

Sean Fertile via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 26 12:38:19 PDT 2018


Author: sfertile
Date: Tue Jun 26 12:38:18 2018
New Revision: 335651

URL: http://llvm.org/viewvc/llvm-project?rev=335651&view=rev
Log:
[PPC64] Thread-local storage general-dynamic to initial-exec relaxation.

Patch adds support for relaxing the general-dynamic tls sequence to
initial-exec.

the relaxation performs the following transformation:
addis r3, r2, x at got@tlsgd at ha --> addis r3, r2, x at got@tprel at ha
addi r3, r3, x at got@tlsgd at l   --> ld r3, x at got@tprel at l(r3)
bl __tls_get_addr(x at tlsgd)   --> nop
nop                          --> add r3, r3, r13

and instead of emitting a DTPMOD64/DTPREL64 pair for x, we emit a single
R_PPC64_TPREL64.

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

Added:
    lld/trunk/test/ELF/ppc64-gd-to-ie.s
Modified:
    lld/trunk/ELF/Arch/PPC64.cpp
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Relocations.h

Modified: lld/trunk/ELF/Arch/PPC64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/PPC64.cpp?rev=335651&r1=335650&r2=335651&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/PPC64.cpp (original)
+++ lld/trunk/ELF/Arch/PPC64.cpp Tue Jun 26 12:38:18 2018
@@ -51,6 +51,9 @@ public:
   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
 
@@ -214,6 +217,7 @@ RelExpr PPC64::getRelExpr(RelType Type,
   case R_PPC64_DTPREL64:
     return R_ABS;
   case R_PPC64_TLSGD:
+    return R_TLSDESC_CALL;
   case R_PPC64_TLSLD:
   case R_PPC64_TLS:
     return R_HINT;
@@ -405,6 +409,55 @@ bool PPC64::needsThunk(RelExpr Expr, Rel
   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;
+}
+
+// Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement.
+// The general dynamic code sequence for a global `x` uses 4 instructions.
+// Instruction                    Relocation                Symbol
+// addis r3, r2, x at got@tlsgd at ha   R_PPC64_GOT_TLSGD16_HA      x
+// addi  r3, r3, x at got@tlsgd at l    R_PPC64_GOT_TLSGD16_LO      x
+// bl __tls_get_addr(x at tlsgd)     R_PPC64_TLSGD               x
+//                                R_PPC64_REL24               __tls_get_addr
+// nop                            None                       None
+//
+// Relaxing to initial-exec entails:
+// 1) Convert the addis/addi pair that builds the address of the tls_index
+//    struct for 'x' to an addis/ld pair that loads an offset from a got-entry.
+// 2) Convert the call to __tls_get_addr to a nop.
+// 3) Convert the nop following the call to an add of the loaded offset to the
+//    thread pointer.
+// Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is
+// used as the relaxation hint for both steps 2 and 3.
+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 rT, r2, sym at got@tlsgd at ha to
+    //                      addis rT, r2, sym at got@tprel at ha.
+    relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val);
+    return;
+  case R_PPC64_GOT_TLSGD16_LO: {
+    // Relax from addi  r3, rA, sym at got@tlsgd at l to
+    //            ld r3, sym at got@tprel at l(rA)
+    uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+    uint32_t InputRegister = (read32(Loc - EndianOffset) & (0x1f << 16));
+    write32(Loc - EndianOffset, 0xE8600000 | InputRegister);
+    relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val);
+    return;
+  }
+  case R_PPC64_TLSGD:
+    write32(Loc, 0x60000000);     // bl __tls_get_addr(sym at tlsgd) --> nop
+    write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
+    return;
+  default:
+    llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
+  }
+}
+
 TargetInfo *elf::getPPC64TargetInfo() {
   static PPC64 Target;
   return &Target;

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=335651&r1=335650&r2=335651&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Tue Jun 26 12:38:18 2018
@@ -504,6 +504,7 @@ static uint64_t getRelocTargetVA(const I
   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:
@@ -773,11 +774,18 @@ void InputSectionBase::relocateAlloc(uin
       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) {

Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=335651&r1=335650&r2=335651&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Tue Jun 26 12:38:18 2018
@@ -67,6 +67,7 @@ enum RelExpr {
   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,

Added: lld/trunk/test/ELF/ppc64-gd-to-ie.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-gd-to-ie.s?rev=335651&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc64-gd-to-ie.s (added)
+++ lld/trunk/test/ELF/ppc64-gd-to-ie.s Tue Jun 26 12:38:18 2018
@@ -0,0 +1,104 @@
+# 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, at function
+_start:
+.Lfunc_gep0:
+        addis 2, 12, .TOC.-.Lfunc_gep0 at ha
+        addi 2, 2, .TOC.-.Lfunc_gep0 at l
+.Lfunc_lep0:
+        .localentry     _start, .Lfunc_lep0-.Lfunc_gep0
+        mflr 0
+        std 0, 16(1)
+        stdu 1, -32(1)
+        addis 3, 2, a at got@tlsgd at ha
+        addi 3, 3, a at got@tlsgd at l
+        bl __tls_get_addr(a at tlsgd)
+        nop
+        lwa 3, 0(3)
+        addi 1, 1, 32
+        ld 0, 16(1)
+        mtlr 0
+        blr
+
+
+        .globl other_reg
+        .p2align        4
+        .type   other_reg, at function
+other_reg:
+.Lfunc_gep1:
+        addis 2, 12, .TOC.-.Lfunc_gep1 at ha
+        addi 2, 2, .TOC.-.Lfunc_gep1 at l
+.Lfunc_lep1:
+        .localentry     other_reg, .Lfunc_lep1-.Lfunc_gep1
+        mflr 0
+        std 0, 16(1)
+        stdu 1, -32(1)
+        addis 5, 2, a at got@tlsgd at ha
+        addi 3, 5, a at got@tlsgd at l
+        bl __tls_get_addr(a at tlsgd)
+        nop
+        lwa 4, 0(3)
+        addis 30, 2, b at got@tlsgd at ha
+        addi 3, 30, b at got@tlsgd at l
+        bl __tls_get_addr(b at tlsgd)
+        nop
+        lwa 3, 0(3)
+        add 3, 4, 3
+        addi 1, 1, 32
+        ld 0, 16(1)
+        mtlr 0
+        blr
+
+        .globl __tls_get_addr
+        .type __tls_get_addr, at function
+__tls_get_addr:
+
+
+# CheckGot: .got          00000018 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
+
+# Dis-LABEL: other_reg
+# Dis:         addis 5, 2, 0
+# Dis-NEXT:    ld 3, -32760(5)
+# Dis-NEXT:    nop
+# Dis-NEXT:    add 3, 3, 13
+# Dis:         addis 30, 2, 0
+# Dis:         ld 3, -32752(30)
+# Dis-NEXT:    nop
+# Dis-NEXT:    add 3, 3, 13
+
+# Verify that the only dynamic relocations we emit are TPREL ones rather then
+# the DTPMOD64/DTPREL64 pair for general-dynamic.
+# OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 2 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
+# OutputRelocs-NEXT:  {{[0-9a-f]+}}    {{[0-9a-f]+}}   R_PPC64_TPREL64        {{[0-9a-f]+}} b + 0




More information about the llvm-commits mailing list