[lld] r362722 - [PPC32] Support GD/LD/IE/LE TLS models and their relaxations

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 6 10:03:10 PDT 2019


Author: maskray
Date: Thu Jun  6 10:03:10 2019
New Revision: 362722

URL: http://llvm.org/viewvc/llvm-project?rev=362722&view=rev
Log:
[PPC32] Support GD/LD/IE/LE TLS models and their relaxations

Reviewed By: ruiu

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

Added:
    lld/trunk/test/ELF/ppc32-tls-gd.s
    lld/trunk/test/ELF/ppc32-tls-ie.s
    lld/trunk/test/ELF/ppc32-tls-ld.s
    lld/trunk/test/ELF/ppc32-tls-le.s
Modified:
    lld/trunk/ELF/Arch/PPC.cpp
    lld/trunk/ELF/Arch/PPC64.cpp
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Target.h

Modified: lld/trunk/ELF/Arch/PPC.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/PPC.cpp?rev=362722&r1=362721&r2=362722&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/PPC.cpp (original)
+++ lld/trunk/ELF/Arch/PPC.cpp Thu Jun  6 10:03:10 2019
@@ -39,12 +39,27 @@ public:
   RelExpr getRelExpr(RelType Type, const Symbol &S,
                      const uint8_t *Loc) const override;
   void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+  RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
+                          RelExpr Expr) const override;
+  int getTlsGdRelaxSkip(RelType Type) 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;
+  void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
 };
 } // namespace
 
 static uint16_t lo(uint32_t V) { return V; }
 static uint16_t ha(uint32_t V) { return (V + 0x8000) >> 16; }
 
+static uint32_t readFromHalf16(const uint8_t *Loc) {
+  return read32(Loc - (Config->EKind == ELF32BEKind ? 2 : 0));
+}
+
+static void writeFromHalf16(uint8_t *Loc, uint32_t Insn) {
+  write32(Loc - (Config->EKind == ELF32BEKind ? 2 : 0), Insn);
+}
+
 void elf::writePPC32GlinkSection(uint8_t *Buf, size_t NumEntries) {
   // On PPC Secure PLT ABI, bl foo at plt jumps to a call stub, which loads an
   // absolute address from a specific .plt slot (usually called .got.plt on
@@ -128,6 +143,10 @@ PPC::PPC() {
 
   NeedsThunks = true;
 
+  TlsModuleIndexRel = R_PPC_DTPMOD32;
+  TlsOffsetRel = R_PPC_DTPREL32;
+  TlsGotRel = R_PPC_TPREL32;
+
   DefaultMaxPageSize = 65536;
   DefaultImageBase = 0x10000000;
 
@@ -169,6 +188,12 @@ bool PPC::inBranchRange(RelType Type, ui
 RelExpr PPC::getRelExpr(RelType Type, const Symbol &S,
                         const uint8_t *Loc) const {
   switch (Type) {
+  case R_PPC_DTPREL16:
+  case R_PPC_DTPREL16_HA:
+  case R_PPC_DTPREL16_HI:
+  case R_PPC_DTPREL16_LO:
+  case R_PPC_DTPREL32:
+    return R_DTPREL;
   case R_PPC_REL14:
   case R_PPC_REL32:
   case R_PPC_LOCAL24PC:
@@ -182,28 +207,84 @@ RelExpr PPC::getRelExpr(RelType Type, co
     return R_PLT_PC;
   case R_PPC_PLTREL24:
     return R_PPC32_PLTREL;
+  case R_PPC_GOT_TLSGD16:
+    return R_TLSGD_GOT;
+  case R_PPC_GOT_TLSLD16:
+    return R_TLSLD_GOT;
+  case R_PPC_GOT_TPREL16:
+    return R_GOT_OFF;
+  case R_PPC_TLS:
+    return R_TLSIE_HINT;
+  case R_PPC_TLSGD:
+    return R_TLSDESC_CALL;
+  case R_PPC_TLSLD:
+    return R_TLSLD_HINT;
+  case R_PPC_TPREL16:
+  case R_PPC_TPREL16_HA:
+  case R_PPC_TPREL16_LO:
+  case R_PPC_TPREL16_HI:
+    return R_TLS;
   default:
     return R_ABS;
   }
 }
 
-void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+static std::pair<RelType, uint64_t> fromDTPREL(RelType Type, uint64_t Val) {
+  uint64_t DTPBiasedVal = Val - 0x8000;
   switch (Type) {
+  case R_PPC_DTPREL16:
+    return {R_PPC64_ADDR16, DTPBiasedVal};
+  case R_PPC_DTPREL16_HA:
+    return {R_PPC_ADDR16_HA, DTPBiasedVal};
+  case R_PPC_DTPREL16_HI:
+    return {R_PPC_ADDR16_HI, DTPBiasedVal};
+  case R_PPC_DTPREL16_LO:
+    return {R_PPC_ADDR16_LO, DTPBiasedVal};
+  case R_PPC_DTPREL32:
+    return {R_PPC_ADDR32, DTPBiasedVal};
+  default:
+    return {Type, Val};
+  }
+}
+
+void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+  RelType NewType;
+  std::tie(NewType, Val) = fromDTPREL(Type, Val);
+  switch (NewType) {
   case R_PPC_ADDR16:
   case R_PPC_GOT16:
+  case R_PPC_GOT_TLSGD16:
+  case R_PPC_GOT_TLSLD16:
+  case R_PPC_GOT_TPREL16:
+  case R_PPC_TPREL16:
     checkInt(Loc, Val, 16, Type);
     write16(Loc, Val);
     break;
   case R_PPC_ADDR16_HA:
+  case R_PPC_DTPREL16_HA:
+  case R_PPC_GOT_TLSGD16_HA:
+  case R_PPC_GOT_TLSLD16_HA:
+  case R_PPC_GOT_TPREL16_HA:
   case R_PPC_REL16_HA:
+  case R_PPC_TPREL16_HA:
     write16(Loc, ha(Val));
     break;
   case R_PPC_ADDR16_HI:
+  case R_PPC_DTPREL16_HI:
+  case R_PPC_GOT_TLSGD16_HI:
+  case R_PPC_GOT_TLSLD16_HI:
+  case R_PPC_GOT_TPREL16_HI:
   case R_PPC_REL16_HI:
+  case R_PPC_TPREL16_HI:
     write16(Loc, Val >> 16);
     break;
   case R_PPC_ADDR16_LO:
+  case R_PPC_DTPREL16_LO:
+  case R_PPC_GOT_TLSGD16_LO:
+  case R_PPC_GOT_TLSLD16_LO:
+  case R_PPC_GOT_TPREL16_LO:
   case R_PPC_REL16_LO:
+  case R_PPC_TPREL16_LO:
     write16(Loc, Val);
     break;
   case R_PPC_ADDR32:
@@ -232,6 +313,109 @@ void PPC::relocateOne(uint8_t *Loc, RelT
   }
 }
 
+RelExpr PPC::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;
+}
+
+int PPC::getTlsGdRelaxSkip(RelType Type) const {
+  // A __tls_get_addr call instruction is marked with 2 relocations:
+  //
+  //   R_PPC_TLSGD / R_PPC_TLSLD: marker relocation
+  //   R_PPC_REL24: __tls_get_addr
+  //
+  // After the relaxation we no longer call __tls_get_addr and should skip both
+  // relocations to not create a false dependence on __tls_get_addr being
+  // defined.
+  if (Type == R_PPC_TLSGD || Type == R_PPC_TLSLD)
+    return 2;
+  return 1;
+}
+
+void PPC::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+  switch (Type) {
+  case R_PPC_GOT_TLSGD16: {
+    // addi rT, rA, x at got@tlsgd --> lwz rT, x at got@tprel(rA)
+    uint32_t Insn = readFromHalf16(Loc);
+    writeFromHalf16(Loc, 0x80000000 | (Insn & 0x03ff0000));
+    relocateOne(Loc, R_PPC_GOT_TPREL16, Val);
+    break;
+  }
+  case R_PPC_TLSGD:
+    // bl __tls_get_addr(x at tldgd) --> add r3, r3, r2
+    write32(Loc, 0x7c631214);
+    break;
+  default:
+    llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
+  }
+}
+
+void PPC::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+  switch (Type) {
+  case R_PPC_GOT_TLSGD16:
+    // addi r3, r31, x at got@tlsgd --> addis r3, r2, x at tprel@ha
+    writeFromHalf16(Loc, 0x3c620000 | ha(Val));
+    break;
+  case R_PPC_TLSGD:
+    // bl __tls_get_addr(x at tldgd) --> add r3, r3, x at tprel@l
+    write32(Loc, 0x38630000 | lo(Val));
+    break;
+  default:
+    llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+  }
+}
+
+void PPC::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+  switch (Type) {
+  case R_PPC_GOT_TLSLD16:
+    // addi r3, rA, x at got@tlsgd --> addis r3, r2, 0
+    writeFromHalf16(Loc, 0x3c620000);
+    break;
+  case R_PPC_TLSLD:
+    // r3+x at dtprel computes r3+x-0x8000, while we want it to compute r3+x at tprel
+    // = r3+x-0x7000, so add 4096 to r3.
+    // bl __tls_get_addr(x at tlsld) --> addi r3, r3, 4096
+    write32(Loc, 0x38631000);
+    break;
+  case R_PPC_DTPREL16:
+  case R_PPC_DTPREL16_HA:
+  case R_PPC_DTPREL16_HI:
+  case R_PPC_DTPREL16_LO:
+    relocateOne(Loc, Type, Val);
+    break;
+  default:
+    llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
+  }
+}
+
+void PPC::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+  switch (Type) {
+  case R_PPC_GOT_TPREL16: {
+    // lwz rT, x at got@tprel(rA) --> addis rT, r2, x at tprel@ha
+    uint32_t RT = readFromHalf16(Loc) & 0x03e00000;
+    writeFromHalf16(Loc, 0x3c020000 | RT | ha(Val));
+    break;
+  }
+  case R_PPC_TLS: {
+    uint32_t Insn = read32(Loc);
+    if (Insn >> 26 != 31)
+      error("unrecognized instruction for IE to LE R_PPC_TLS");
+    // addi rT, rT, x at tls --> addi rT, rT, x at tprel@l
+    uint32_t DFormOp = getPPCDFormOp((read32(Loc) & 0x000007fe) >> 1);
+    if (DFormOp == 0)
+      error("unrecognized instruction for IE to LE R_PPC_TLS");
+    write32(Loc, (DFormOp << 26) | (Insn & 0x03ff0000) | lo(Val));
+    break;
+  }
+  default:
+    llvm_unreachable("unsupported relocation for TLS IE to LE relaxation");
+  }
+}
+
 TargetInfo *elf::getPPCTargetInfo() {
   static PPC Target;
   return &Target;

Modified: lld/trunk/ELF/Arch/PPC64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/PPC64.cpp?rev=362722&r1=362721&r2=362722&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/PPC64.cpp (original)
+++ lld/trunk/ELF/Arch/PPC64.cpp Thu Jun  6 10:03:10 2019
@@ -452,7 +452,7 @@ void PPC64::relaxTlsLdToLe(uint8_t *Loc,
   }
 }
 
-static unsigned getDFormOp(unsigned SecondaryOp) {
+unsigned elf::getPPCDFormOp(unsigned SecondaryOp) {
   switch (SecondaryOp) {
   case LBZX:
     return LBZ;
@@ -473,7 +473,6 @@ static unsigned getDFormOp(unsigned Seco
   case ADD:
     return ADDI;
   default:
-    error("unrecognized instruction for IE to LE R_PPC64_TLS");
     return 0;
   }
 }
@@ -515,7 +514,9 @@ void PPC64::relaxTlsIeToLe(uint8_t *Loc,
     if (PrimaryOp != 31)
       error("unrecognized instruction for IE to LE R_PPC64_TLS");
     uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30
-    uint32_t DFormOp = getDFormOp(SecondaryOp);
+    uint32_t DFormOp = getPPCDFormOp(SecondaryOp);
+    if (DFormOp == 0)
+      error("unrecognized instruction for IE to LE R_PPC64_TLS");
     write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF)));
     relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val);
     break;

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=362722&r1=362721&r2=362722&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Thu Jun  6 10:03:10 2019
@@ -611,6 +611,7 @@ static int64_t getTlsTpOffset(const Symb
   case EM_X86_64:
     // Variant 2. The TLS segment is located just before the thread pointer.
     return S.getVA(0) - alignTo(Out::TlsPhdr->p_memsz, Out::TlsPhdr->p_align);
+  case EM_PPC:
   case EM_PPC64:
     // The thread pointer points to a fixed offset from the start of the
     // executable's TLS segment. An offset of 0x7000 allows a signed 16-bit

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=362722&r1=362721&r2=362722&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Thu Jun  6 10:03:10 2019
@@ -166,6 +166,7 @@ void writePPC32GlinkSection(uint8_t *Buf
 
 bool tryRelaxPPC64TocIndirection(RelType Type, const Relocation &Rel,
                                  uint8_t *BufLoc);
+unsigned getPPCDFormOp(unsigned SecondaryOp);
 
 // In the PowerPC64 Elf V2 abi a function can have 2 entry points.  The first
 // is a global entry point (GEP) which typically is used to initialize the TOC

Added: lld/trunk/test/ELF/ppc32-tls-gd.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc32-tls-gd.s?rev=362722&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc32-tls-gd.s (added)
+++ lld/trunk/test/ELF/ppc32-tls-gd.s Thu Jun  6 10:03:10 2019
@@ -0,0 +1,98 @@
+# REQUIES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
+# RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o
+# RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so
+# RUN: echo '.globl __tls_get_addr; __tls_get_addr:' | llvm-mc -filetype=obj -triple=powerpc - -o %tga.o
+
+# RUN: ld.lld -shared %t.o %t1.o -o %t.so
+# RUN: llvm-readobj -d %t.so | FileCheck --check-prefix=GD-DYN %s
+# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=GD-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD %s
+
+# RUN: ld.lld %t.o %t1.o %tga.o -o %t
+# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
+
+# RUN: ld.lld %t.o %t1.so -o %t
+# RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s
+
+## DT_PPC_GOT represents the address of _GLOBAL_OFFSET_TABLE_.
+# GD-DYN: PPC_GOT 0x20078
+
+# GD-REL:      .rela.dyn {
+# GD-REL-NEXT:   0x20078 R_PPC_DTPMOD32 a 0x0
+# GD-REL-NEXT:   0x2007C R_PPC_DTPREL32 a 0x0
+# GD-REL-NEXT:   0x20080 R_PPC_DTPMOD32 b 0x0
+# GD-REL-NEXT:   0x20084 R_PPC_DTPREL32 b 0x0
+# GD-REL-NEXT:   0x20088 R_PPC_DTPMOD32 c 0x0
+# GD-REL-NEXT:   0x2008C R_PPC_DTPREL32 c 0x0
+# GD-REL-NEXT: }
+
+## &DTPMOD(a) - _GLOBAL_OFFSET_TABLE_ = 0x20078 - 0x20078 = 0
+# GD:      addi 3, 31, 0
+# GD-NEXT: bl .+32
+# GD-NEXT: lwz 3, 0(3)
+
+## &DTPMOD(b) - _GLOBAL_OFFSET_TABLE_ = 0x20080 - 0x20078 = 8
+# GD-NEXT: addi 3, 31, 8
+# GD-NEXT: bl .+20
+# GD-NEXT: lwz 3, 0(3)
+
+## &DTPMOD(c) - _GLOBAL_OFFSET_TABLE_ = 0x20088 - 0x20078 = 16
+# GD-NEXT: addi 3, 9, 16
+# GD-NEXT: bl .+8
+# GD-NEXT: lwz 3, 0(3)
+
+# NOREL: no relocations
+
+## a at tprel = 8-0x7000 = -28664
+# LE:      addis 3, 2, 0
+# LE-NEXT: addi 3, 3, -28664
+# LE-NEXT: lwz 3, 0(3)
+## b at tprel = 12-0x7000 = -28660
+# LE-NEXT: addis 3, 2, 0
+# LE-NEXT: addi 3, 3, -28660
+# LE-NEXT: lwz 3, 0(3)
+## c at tprel = 16-0x7000 = -28656
+# LE-NEXT: addis 3, 2, 0
+# LE-NEXT: addi 3, 3, -28656
+# LE-NEXT: lwz 3, 0(3)
+
+# IE-REL:      .rela.dyn {
+# IE-REL-NEXT:   0x10020068 R_PPC_TPREL32 b 0x0
+# IE-REL-NEXT:   0x1002006C R_PPC_TPREL32 c 0x0
+# IE-REL-NEXT: }
+
+## a is relaxed to use LE.
+## a at tprel = st_value(a)-0x8000 = -28664
+# IE:      addis 3, 2, 0
+# IE-NEXT: addi 3, 3, -28664
+# IE-NEXT: lwz 3, 0(3)
+## &.got[0] - _GLOBAL_OFFSET_TABLE_ = 0
+# IE-NEXT: lwz 3, 0(31)
+# IE-NEXT: add 3, 3, 2
+# IE-NEXT: lwz 3, 0(3)
+## &.got[1] - _GLOBAL_OFFSET_TABLE_ = 4
+# IE-NEXT: lwz 3, 4(9)
+# IE-NEXT: add 3, 3, 2
+# IE-NEXT: lwz 3, 0(3)
+
+addi 3, 31, a at got@tlsgd
+bl __tls_get_addr(a at tlsgd)
+lwz 3, 0(3)
+
+addi 3, 31, b at got@tlsgd
+bl __tls_get_addr(b at tlsgd)
+lwz 3, 0(3)
+
+## -fpic may use a different register (e.g. r9).
+addi 3, 9, c at got@tlsgd
+bl __tls_get_addr(c at tlsgd)
+lwz 3, 0(3)
+
+.section .tbss
+.globl a
+.zero 8
+a:
+.zero 4

Added: lld/trunk/test/ELF/ppc32-tls-ie.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc32-tls-ie.s?rev=362722&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc32-tls-ie.s (added)
+++ lld/trunk/test/ELF/ppc32-tls-ie.s Thu Jun  6 10:03:10 2019
@@ -0,0 +1,67 @@
+# REQUIES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
+
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=IE-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=IE %s
+
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
+
+## A non-preemptable symbol (b) has 0 st_shndx.
+# IE-REL:      .rela.dyn {
+# IE-REL-NEXT:   0x2005C R_PPC_TPREL32 - 0xC
+# IE-REL-NEXT:   0x20058 R_PPC_TPREL32 a 0x0
+# IE-REL-NEXT: }
+
+## &.got[0] - _GLOBAL_OFFSET_TABLE_ = 0
+# IE:      lwz 10, 0(9)
+# IE-NEXT: add 10, 10, 2
+## &.got[1] - _GLOBAL_OFFSET_TABLE_ = 4
+# IE-NEXT: lwz 8, 4(7)
+# IE-NEXT: lbzx 10, 8, 2
+
+# NOREL: no relocations
+
+## a at tprel = st_value(a)-0x7000 = -28664
+## b at tprel = st_value(b)-0x7000 = -28660
+# LE:      addis 10, 2, 0
+# LE-NEXT: addi 10, 10, -28664
+# LE-NEXT: addis 8, 2, 0
+# LE-NEXT: lbz 10, -28660(8)
+
+lwz 10, a at got@tprel(9)
+add 10, 10, a at tls
+
+lwz 8, c at got@tprel(7)
+lbzx 10, 8, c at tls
+
+## In IE, these instructions (op rT, rA, x at tls) are not changed.
+# IE-NEXT: lhzx 12, 2, 2
+# IE-NEXT: lwzx 13, 3, 2
+# IE-NEXT: stbx 14, 4, 2
+# IE-NEXT: sthx 15, 5, 2
+# IE-NEXT: stwx 16, 6, 2
+
+## In LE, these X-Form instructions are changed to their corresponding D-Form.
+# LE-NEXT: lhz 12, -28660(2)
+# LE-NEXT: lwz 13, -28660(3)
+# LE-NEXT: stb 14, -28660(4)
+# LE-NEXT: sth 15, -28660(5)
+# LE-NEXT: stw 16, -28660(6)
+
+lhzx 12, 2, s at tls
+lwzx 13, 3, i at tls
+stbx 14, 4, c at tls
+sthx 15, 5, s at tls
+stwx 16, 6, i at tls
+
+.section .tbss
+.globl a
+.zero 8
+a:
+.zero 4
+c:
+s:
+i:

Added: lld/trunk/test/ELF/ppc32-tls-ld.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc32-tls-ld.s?rev=362722&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc32-tls-ld.s (added)
+++ lld/trunk/test/ELF/ppc32-tls-ld.s Thu Jun  6 10:03:10 2019
@@ -0,0 +1,82 @@
+# REQUIRES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
+# RUN: echo '.globl __tls_get_addr; __tls_get_addr:' | llvm-mc -filetype=obj -triple=powerpc - -o %tga.o
+
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=LD-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=LD %s
+
+# RUN: ld.lld %t.o %tga.o -o %t
+# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
+
+# LD-REL:      .rela.dyn {
+# LD-REL-NEXT:   0x20078 R_PPC_DTPMOD32 - 0x0
+# LD-REL-NEXT: }
+
+## .got - _GLOBAL_OFFSET_TABLE_ = 0
+# LD:      addi 3, 30, 0
+# LD-NEXT: bl .+40
+## a at dtprel = st_value(a)-0x8000 = 65540-0x8000 = 65536*1-32764
+## b at dtprel = st_value(a)-0x8000 = 131080-0x8000 = 65536*2-32760
+# LD-NEXT: addis 9, 3, 1
+# LD-NEXT: addis 10, 3, 2
+# LD-NEXT: addi 9, 9, -32764
+# LD-NEXT: addi 10, 10, -32760
+## small at dtprel = st_value(small)-0x8000 = 4-0x8000 = -32764
+# LD-NEXT: addi 9, 3, -32764
+
+## Check that b at got@tlsld does not allocate another GOT entry.
+## It shares In.Got->TlsIndexOff allocated when processing a at got@tlsld.
+## .got - _GLOBAL_OFFSET_TABLE_ = 0
+# LD-NEXT: addi 3, 9, 0
+# LD-NEXT: bl .+12
+## b at dtprel = st_value(a)-0x8000 = 131080-0x8000 = 65536*2-32760
+# LD-NEXT: addis 29, 3, 2
+# LD-NEXT: addi 29, 29, -32760
+
+## When producing an executable, the LD code sequence can be relaxed to LE.
+## It is the same as GD->LE.
+## tpoff(_TLS_MODULE_BASE_) = 0, tpoff(a) = -8, tpoff(b) = -4
+
+# NOREL: no relocations
+
+## Set r3 to r2+4096
+# LE:      addis 3, 2, 0
+# LE-NEXT: addi 3, 3, 4096
+## a at tprel = 65540-0x7000 = 65536*1-32764
+## b at tprel = 131080-0x7000 = 65536*2-32760
+# LE-NEXT: addis 9, 3, 1
+# LE-NEXT: addis 10, 3, 2
+# LE-NEXT: addi 9, 9, -32764
+# LE-NEXT: addi 10, 10, -32760
+## small at tprel = 4-0x7000 = -32764
+# LE-NEXT: addi 9, 3, -32764
+
+## Set r3 to r2+4096
+# LE-NEXT: addis 3, 2, 0
+# LE-NEXT: addi 3, 3, 4096
+## b at tprel = 131080-0x7000 = 65536*2-32760
+# LE-NEXT: addis 29, 3, 2
+# LE-NEXT: addi 29, 29, -32760
+
+addi 3, 30, a at got@tlsld
+bl __tls_get_addr(a at tlsld)
+addis 9, 3, a at dtprel@ha
+addis 10, 3, b at dtprel@ha
+addi 9, 9, a at dtprel@l
+addi 10, 10, b at dtprel@l
+addi 9, 3, small at dtprel
+
+addi 3, 9, b at got@tlsld
+bl __tls_get_addr(b at tlsld)
+addis 29, 3, b at dtprel@ha
+addi 29, 29, b at dtprel@l
+
+.section .tbss
+.zero 4
+small:
+.zero 65536
+a:
+.zero 65540
+b:

Added: lld/trunk/test/ELF/ppc32-tls-le.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc32-tls-le.s?rev=362722&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc32-tls-le.s (added)
+++ lld/trunk/test/ELF/ppc32-tls-le.s Thu Jun  6 10:03:10 2019
@@ -0,0 +1,24 @@
+# REQUIES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
+
+## a at tprel = st_value(a)-0x7000 = -28664
+## b at tprel = st_value(b)-0x7000 = -28660
+# LE:      addis 9, 2, 0
+# LE-NEXT: addi 9, 9, -28664
+# LE-NEXT: addis 10, 2, 0
+# LE-NEXT: lwz 9, -28660(10)
+
+addis 9, 2, a at tprel@ha
+addi 9, 9, a at tprel@l
+
+addis 10, 2, b at tprel@ha
+lwz 9,b at tprel@l(10)
+
+.section .tbss
+.globl a
+.zero 8
+a:
+.zero 4
+b:




More information about the llvm-commits mailing list