aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog14
-rw-r--r--bfd/bfd-in2.h7
-rw-r--r--bfd/elf64-ppc.c237
-rw-r--r--bfd/libbfd.h7
-rw-r--r--bfd/reloc.c14
-rw-r--r--gas/ChangeLog8
-rw-r--r--gas/config/tc-ppc.c44
-rw-r--r--include/ChangeLog7
-rw-r--r--include/elf/ppc64.h10
-rw-r--r--ld/ChangeLog10
-rw-r--r--ld/testsuite/ld-powerpc/powerpc.exp3
-rw-r--r--ld/testsuite/ld-powerpc/tlsgd.d31
-rw-r--r--ld/testsuite/ld-powerpc/tlsgd.s52
-rw-r--r--ld/testsuite/ld-powerpc/tlsie.d54
-rw-r--r--ld/testsuite/ld-powerpc/tlsie.s77
-rw-r--r--ld/testsuite/ld-powerpc/tlsld.d36
-rw-r--r--ld/testsuite/ld-powerpc/tlsld.s58
17 files changed, 634 insertions, 35 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index a9dce78..62e4beb 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+2019-07-19 Alan Modra <amodra@gmail.com>
+
+ * reloc.c (BFD_RELOC_PPC64_TPREL34, BFD_RELOC_PPC64_DTPREL34),
+ (BFD_RELOC_PPC64_GOT_TLSGD34, BFD_RELOC_PPC64_GOT_TLSLD34),
+ (BFD_RELOC_PPC64_GOT_TPREL34, BFD_RELOC_PPC64_GOT_DTPREL34),
+ (BFD_RELOC_PPC64_TLS_PCREL): New pcrel tls relocs.
+ * elf64-ppc.c (ppc64_elf_howto_raw): Add howtos for pcrel tls relocs.
+ (ppc64_elf_reloc_type_lookup): Translate pcrel tls relocs.
+ (must_be_dyn_reloc, dec_dynrel_count): Add R_PPC64_TPREL64.
+ (ppc64_elf_check_relocs): Support pcrel tls relocs.
+ (ppc64_elf_tls_optimize, ppc64_elf_relocate_section): Likewise.
+ * bfd-in2.h: Regenerate.
+ * libbfd.h: Regenerate.
+
2019-07-18 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ppc64_elf_relocate_section): Don't bother selecting
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 05e3219..8374390 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3563,6 +3563,13 @@ instruction. */
BFD_RELOC_PPC64_DTPREL16_HIGHERA,
BFD_RELOC_PPC64_DTPREL16_HIGHEST,
BFD_RELOC_PPC64_DTPREL16_HIGHESTA,
+ BFD_RELOC_PPC64_TPREL34,
+ BFD_RELOC_PPC64_DTPREL34,
+ BFD_RELOC_PPC64_GOT_TLSGD34,
+ BFD_RELOC_PPC64_GOT_TLSLD34,
+ BFD_RELOC_PPC64_GOT_TPREL34,
+ BFD_RELOC_PPC64_GOT_DTPREL34,
+ BFD_RELOC_PPC64_TLS_PCREL,
/* IBM 370/390 relocations */
BFD_RELOC_I370_D12,
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index df4a12c..abbdfed 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -920,6 +920,24 @@ static reloc_howto_type ppc64_elf_howto_raw[] =
HOW (R_PPC64_PLT_PCREL34_NOTOC, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
ppc64_elf_unhandled_reloc),
+ HOW (R_PPC64_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_GOT_TLSGD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_GOT_TLSLD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_GOT_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_GOT_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
HOW (R_PPC64_ADDR16_HIGHER34, 1, 16, 0xffff, 34, FALSE, dont,
bfd_elf_generic_reloc),
@@ -1119,6 +1137,7 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
break;
case BFD_RELOC_PPC64_PLTGOT16_LO_DS: r = R_PPC64_PLTGOT16_LO_DS;
break;
+ case BFD_RELOC_PPC64_TLS_PCREL:
case BFD_RELOC_PPC_TLS: r = R_PPC64_TLS;
break;
case BFD_RELOC_PPC_TLSGD: r = R_PPC64_TLSGD;
@@ -1253,6 +1272,18 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
break;
case BFD_RELOC_PPC64_PLT_PCREL34: r = R_PPC64_PLT_PCREL34;
break;
+ case BFD_RELOC_PPC64_TPREL34: r = R_PPC64_TPREL34;
+ break;
+ case BFD_RELOC_PPC64_DTPREL34: r = R_PPC64_DTPREL34;
+ break;
+ case BFD_RELOC_PPC64_GOT_TLSGD34: r = R_PPC64_GOT_TLSGD34;
+ break;
+ case BFD_RELOC_PPC64_GOT_TLSLD34: r = R_PPC64_GOT_TLSLD34;
+ break;
+ case BFD_RELOC_PPC64_GOT_TPREL34: r = R_PPC64_GOT_TPREL34;
+ break;
+ case BFD_RELOC_PPC64_GOT_DTPREL34: r = R_PPC64_GOT_DTPREL34;
+ break;
case BFD_RELOC_PPC64_ADDR16_HIGHER34: r = R_PPC64_ADDR16_HIGHER34;
break;
case BFD_RELOC_PPC64_ADDR16_HIGHERA34: r = R_PPC64_ADDR16_HIGHERA34;
@@ -2727,6 +2758,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
case R_PPC64_TPREL64:
+ case R_PPC64_TPREL34:
/* These relocations are relative but in a shared library the
linker doesn't know the thread pointer base. */
return bfd_link_dll (info);
@@ -4514,6 +4546,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_D34_HI30:
case R_PPC64_D34_HA30:
case R_PPC64_D28:
+ case R_PPC64_TPREL34:
+ case R_PPC64_DTPREL34:
htab->powerxx_stubs = 1;
/* Fall through. */
default:
@@ -4528,6 +4562,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_PCREL34:
case R_PPC64_GOT_PCREL34:
+ case R_PPC64_GOT_TLSGD34:
+ case R_PPC64_GOT_TLSLD34:
+ case R_PPC64_GOT_TPREL34:
+ case R_PPC64_GOT_DTPREL34:
case R_PPC64_PLT_PCREL34:
case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_PCREL28:
@@ -4580,6 +4618,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSLD34:
tls_type = TLS_TLS | TLS_LD;
goto dogottls;
@@ -4587,6 +4626,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT_TLSGD16_LO:
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSGD34:
tls_type = TLS_TLS | TLS_GD;
goto dogottls;
@@ -4594,6 +4634,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_TPREL34:
if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
tls_type = TLS_TLS | TLS_TPREL;
@@ -4603,6 +4644,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_HI:
case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL34:
tls_type = TLS_TLS | TLS_DTPREL;
dogottls:
sec->has_tls_reloc = 1;
@@ -4949,6 +4991,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_TPREL16_HIGHERA:
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
+ case R_PPC64_TPREL34:
if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
goto dodyn;
@@ -6769,6 +6812,7 @@ dec_dynrel_count (bfd_vma r_info,
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
case R_PPC64_TPREL64:
+ case R_PPC64_TPREL34:
case R_PPC64_DTPMOD64:
case R_PPC64_DTPREL64:
case R_PPC64_ADDR64:
@@ -7733,6 +7777,12 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
value += sym_sec->output_offset;
value += sym_sec->output_section->vma;
value -= htab->elf.tls_sec->vma + TP_OFFSET;
+ /* Note that even though the prefix insns
+ allow a 1<<33 offset we use the same test
+ as for addis;addi. There may be a mix of
+ pcrel and non-pcrel code and the decision
+ to optimise is per symbol, not per TLS
+ sequence. */
ok_tprel = value + 0x80008000ULL < 1ULL << 32;
}
}
@@ -7764,6 +7814,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
{
case R_PPC64_GOT_TLSLD16:
case R_PPC64_GOT_TLSLD16_LO:
+ case R_PPC64_GOT_TLSLD34:
expecting_tls_get_addr = 1;
found_tls_get_addr_arg = 1;
/* Fall through. */
@@ -7784,6 +7835,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TLSGD34:
expecting_tls_get_addr = 1;
found_tls_get_addr_arg = 1;
/* Fall through. */
@@ -7800,6 +7852,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
tls_type = TLS_TLS | TLS_GD;
break;
+ case R_PPC64_GOT_TPREL34:
case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_HI:
@@ -14436,29 +14489,72 @@ ppc64_elf_relocate_section (bfd *output_bfd,
}
break;
+ case R_PPC64_GOT_TPREL34:
+ if ((tls_mask & TLS_TLS) != 0
+ && (tls_mask & TLS_TPREL) == 0)
+ {
+ /* pld ra,sym@got@tprel@pcrel -> paddi ra,r13,sym@tprel */
+ pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ pinsn <<= 32;
+ pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+ pinsn += ((2ULL << 56) + (-1ULL << 52)
+ + (14ULL << 26) - (57ULL << 26) + (13ULL << 16));
+ bfd_put_32 (input_bfd, pinsn >> 32,
+ contents + rel->r_offset);
+ bfd_put_32 (input_bfd, pinsn & 0xffffffff,
+ contents + rel->r_offset + 4);
+ r_type = R_PPC64_TPREL34;
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ }
+ break;
+
case R_PPC64_TLS:
if ((tls_mask & TLS_TLS) != 0
&& (tls_mask & TLS_TPREL) == 0)
{
- insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
insn = _bfd_elf_ppc_at_tls_transform (insn, 13);
if (insn == 0)
- abort ();
- bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
- /* Was PPC64_TLS which sits on insn boundary, now
- PPC64_TPREL16_LO which is at low-order half-word. */
- rel->r_offset += d_offset;
- r_type = R_PPC64_TPREL16_LO;
- if (toc_symndx != 0)
+ break;
+ if ((rel->r_offset & 3) == 0)
{
- rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
- rel->r_addend = toc_addend;
- /* We changed the symbol. Start over in order to
- get h, sym, sec etc. right. */
- goto again;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ /* Was PPC64_TLS which sits on insn boundary, now
+ PPC64_TPREL16_LO which is at low-order half-word. */
+ rel->r_offset += d_offset;
+ r_type = R_PPC64_TPREL16_LO;
+ if (toc_symndx != 0)
+ {
+ rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+ rel->r_addend = toc_addend;
+ /* We changed the symbol. Start over in order to
+ get h, sym, sec etc. right. */
+ goto again;
+ }
+ else
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ }
+ else if ((rel->r_offset & 3) == 1)
+ {
+ /* For pcrel IE to LE we already have the full
+ offset and thus don't need an addi here. A nop
+ or mr will do. */
+ if ((insn & (0x3f << 26)) == 14 << 26)
+ {
+ /* Extract regs from addi rt,ra,si. */
+ unsigned int rt = (insn >> 21) & 0x1f;
+ unsigned int ra = (insn >> 16) & 0x1f;
+ if (rt == ra)
+ insn = NOP;
+ else
+ {
+ /* Build or ra,rs,rb with rb==rs, ie. mr ra,rs. */
+ insn = (rt << 16) | (ra << 21) | (ra << 11);
+ insn |= (31u << 26) | (444u << 1);
+ }
+ }
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset - 1);
}
- else
- rel->r_info = ELF64_R_INFO (r_symndx, r_type);
}
break;
@@ -14584,6 +14680,51 @@ ppc64_elf_relocate_section (bfd *output_bfd,
}
break;
+ case R_PPC64_GOT_TLSGD34:
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+ {
+ pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ pinsn <<= 32;
+ pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+ if ((tls_mask & TLS_GDIE) != 0)
+ {
+ /* IE, pla -> pld */
+ pinsn += (-2ULL << 56) + (57ULL << 26) - (14ULL << 26);
+ r_type = R_PPC64_GOT_TPREL34;
+ }
+ else
+ {
+ /* LE, pla pcrel -> paddi r13 */
+ pinsn += (-1ULL << 52) + (13ULL << 16);
+ r_type = R_PPC64_TPREL34;
+ }
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ bfd_put_32 (input_bfd, pinsn >> 32,
+ contents + rel->r_offset);
+ bfd_put_32 (input_bfd, pinsn & 0xffffffff,
+ contents + rel->r_offset + 4);
+ }
+ break;
+
+ case R_PPC64_GOT_TLSLD34:
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
+ {
+ pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ pinsn <<= 32;
+ pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+ pinsn += (-1ULL << 52) + (13ULL << 16);
+ bfd_put_32 (input_bfd, pinsn >> 32,
+ contents + rel->r_offset);
+ bfd_put_32 (input_bfd, pinsn & 0xffffffff,
+ contents + rel->r_offset + 4);
+ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+ r_symndx = STN_UNDEF;
+ r_type = R_PPC64_TPREL34;
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ goto again;
+ }
+ break;
+
case R_PPC64_TLSGD:
if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
&& rel + 1 < relend)
@@ -14619,16 +14760,27 @@ ppc64_elf_relocate_section (bfd *output_bfd,
r_symndx = toc_symndx;
rel->r_addend = toc_addend;
}
- r_type = R_PPC64_TPREL16_LO;
- rel->r_offset = offset + d_offset;
- insn2 = 0x38630000; /* addi 3,3,0 */
+ if (r_type1 == R_PPC64_REL24_NOTOC
+ || r_type1 == R_PPC64_PLTCALL_NOTOC)
+ {
+ r_type = R_PPC64_NONE;
+ insn2 = NOP;
+ }
+ else
+ {
+ rel->r_offset = offset + d_offset;
+ r_type = R_PPC64_TPREL16_LO;
+ insn2 = 0x38630000; /* addi 3,3,0 */
+ }
}
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
/* Zap the reloc on the _tls_get_addr call too. */
BFD_ASSERT (offset == rel[1].r_offset);
rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
bfd_put_32 (input_bfd, insn2, contents + offset);
- if ((tls_mask & TLS_GDIE) == 0 && toc_symndx != 0)
+ if ((tls_mask & TLS_GDIE) == 0
+ && toc_symndx != 0
+ && r_type != R_PPC64_NONE)
goto again;
}
break;
@@ -14654,18 +14806,27 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
bfd_put_32 (output_bfd, NOP, contents + offset + 4);
- rel->r_offset = offset + d_offset;
- r_symndx = STN_UNDEF;
- r_type = R_PPC64_TPREL16_LO;
+ if (r_type1 == R_PPC64_REL24_NOTOC
+ || r_type1 == R_PPC64_PLTCALL_NOTOC)
+ {
+ r_type = R_PPC64_NONE;
+ insn2 = NOP;
+ }
+ else
+ {
+ rel->r_offset = offset + d_offset;
+ r_symndx = STN_UNDEF;
+ r_type = R_PPC64_TPREL16_LO;
+ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+ insn2 = 0x38630000; /* addi 3,3,0 */
+ }
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
- rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-
/* Zap the reloc on the _tls_get_addr call too. */
BFD_ASSERT (offset == rel[1].r_offset);
rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
- insn2 = 0x38630000; /* addi 3,3,0 */
bfd_put_32 (input_bfd, insn2, contents + offset);
- goto again;
+ if (r_type != R_PPC64_NONE)
+ goto again;
}
break;
@@ -15267,6 +15428,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_TLSGD16_LO:
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSGD34:
tls_type = TLS_TLS | TLS_GD;
goto dogot;
@@ -15274,6 +15436,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSLD34:
tls_type = TLS_TLS | TLS_LD;
goto dogot;
@@ -15281,6 +15444,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_TPREL34:
tls_type = TLS_TLS | TLS_TPREL;
goto dogot;
@@ -15288,6 +15452,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_HI:
case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL34:
tls_type = TLS_TLS | TLS_DTPREL;
goto dogot;
@@ -15309,7 +15474,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
struct got_entry *ent;
bfd_vma sym_addend = orig_rel.r_addend;
- if (r_type == R_PPC64_GOT_PCREL34)
+ if (r_type == R_PPC64_GOT_PCREL34
+ || r_type == R_PPC64_GOT_TLSGD34
+ || r_type == R_PPC64_GOT_TLSLD34
+ || r_type == R_PPC64_GOT_TPREL34
+ || r_type == R_PPC64_GOT_DTPREL34)
sym_addend = 0;
if (tls_type == (TLS_TLS | TLS_LD)
@@ -15491,7 +15660,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
abort ();
relocation = got->output_section->vma + got->output_offset + off;
- if (r_type != R_PPC64_GOT_PCREL34)
+ if (!(r_type == R_PPC64_GOT_PCREL34
+ || r_type == R_PPC64_GOT_TLSGD34
+ || r_type == R_PPC64_GOT_TLSLD34
+ || r_type == R_PPC64_GOT_TPREL34
+ || r_type == R_PPC64_GOT_DTPREL34))
addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
}
break;
@@ -15644,6 +15817,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_TPREL16_HIGHERA:
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
+ case R_PPC64_TPREL34:
if (h != NULL
&& h->elf.root.type == bfd_link_hash_undefweak
&& h->elf.dynindx == -1)
@@ -15679,6 +15853,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_DTPREL16_HIGHERA:
case R_PPC64_DTPREL16_HIGHEST:
case R_PPC64_DTPREL16_HIGHESTA:
+ case R_PPC64_DTPREL34:
if (htab->elf.tls_sec != NULL)
addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
break;
@@ -16301,6 +16476,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_D34_HA30:
case R_PPC64_PCREL34:
case R_PPC64_GOT_PCREL34:
+ case R_PPC64_TPREL34:
+ case R_PPC64_DTPREL34:
+ case R_PPC64_GOT_TLSGD34:
+ case R_PPC64_GOT_TLSLD34:
+ case R_PPC64_GOT_TPREL34:
+ case R_PPC64_GOT_DTPREL34:
case R_PPC64_PLT_PCREL34:
case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_D28:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index ff6e0ea..fd45595 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1539,6 +1539,13 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_PPC64_DTPREL16_HIGHERA",
"BFD_RELOC_PPC64_DTPREL16_HIGHEST",
"BFD_RELOC_PPC64_DTPREL16_HIGHESTA",
+ "BFD_RELOC_PPC64_TPREL34",
+ "BFD_RELOC_PPC64_DTPREL34",
+ "BFD_RELOC_PPC64_GOT_TLSGD34",
+ "BFD_RELOC_PPC64_GOT_TLSLD34",
+ "BFD_RELOC_PPC64_GOT_TPREL34",
+ "BFD_RELOC_PPC64_GOT_DTPREL34",
+ "BFD_RELOC_PPC64_TLS_PCREL",
"BFD_RELOC_I370_D12",
"BFD_RELOC_CTOR",
"BFD_RELOC_ARM_PCREL_BRANCH",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 266e775..9ca68ca 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -3007,6 +3007,20 @@ ENUMX
BFD_RELOC_PPC64_DTPREL16_HIGHEST
ENUMX
BFD_RELOC_PPC64_DTPREL16_HIGHESTA
+ENUMX
+ BFD_RELOC_PPC64_TPREL34
+ENUMX
+ BFD_RELOC_PPC64_DTPREL34
+ENUMX
+ BFD_RELOC_PPC64_GOT_TLSGD34
+ENUMX
+ BFD_RELOC_PPC64_GOT_TLSLD34
+ENUMX
+ BFD_RELOC_PPC64_GOT_TPREL34
+ENUMX
+ BFD_RELOC_PPC64_GOT_DTPREL34
+ENUMX
+ BFD_RELOC_PPC64_TLS_PCREL
ENUMDOC
PowerPC and PowerPC64 thread-local storage relocations.
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 6e457d9..b445ba3 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,11 @@
+2019-07-19 Alan Modra <amodra@gmail.com>
+
+ * config/tc-ppc.c (ppc_elf_suffix): Map "tls@pcrel", "got@tlsgd@pcrel",
+ "got@tlsld@pcrel", "got@tprel@pcrel", and "got@dtprel@pcrel".
+ (fixup_size, md_assemble): Handle pcrel tls relocs.
+ (ppc_force_relocation, ppc_fix_adjustable): Likewise.
+ (md_apply_fix, tc_gen_reloc): Likewise.
+
2019-07-17 Jose E. Marchesi <jose.marchesi@oracle.com>
* config/tc-bpf.c: Make .lcomm to get a third argument with the
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 5f8d120..7d6459a 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -2224,6 +2224,11 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
MAP64 ("pcrel", BFD_RELOC_PPC64_PCREL34),
MAP64 ("got@pcrel", BFD_RELOC_PPC64_GOT_PCREL34),
MAP64 ("plt@pcrel", BFD_RELOC_PPC64_PLT_PCREL34),
+ MAP64 ("tls@pcrel", BFD_RELOC_PPC64_TLS_PCREL),
+ MAP64 ("got@tlsgd@pcrel", BFD_RELOC_PPC64_GOT_TLSGD34),
+ MAP64 ("got@tlsld@pcrel", BFD_RELOC_PPC64_GOT_TLSLD34),
+ MAP64 ("got@tprel@pcrel", BFD_RELOC_PPC64_GOT_TPREL34),
+ MAP64 ("got@dtprel@pcrel", BFD_RELOC_PPC64_GOT_DTPREL34),
MAP64 ("higher34", BFD_RELOC_PPC64_ADDR16_HIGHER34),
MAP64 ("highera34", BFD_RELOC_PPC64_ADDR16_HIGHERA34),
MAP64 ("highest34", BFD_RELOC_PPC64_ADDR16_HIGHEST34),
@@ -3155,6 +3160,7 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
case BFD_RELOC_PPC_VLE_SDAREL_HI16D:
case BFD_RELOC_PPC_VLE_SDAREL_LO16A:
case BFD_RELOC_PPC_VLE_SDAREL_LO16D:
+ case BFD_RELOC_PPC64_TLS_PCREL:
case BFD_RELOC_RVA:
size = 4;
break;
@@ -3196,6 +3202,8 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
case BFD_RELOC_PPC64_D34_LO:
case BFD_RELOC_PPC64_D34_HI30:
case BFD_RELOC_PPC64_D34_HA30:
+ case BFD_RELOC_PPC64_TPREL34:
+ case BFD_RELOC_PPC64_DTPREL34:
case BFD_RELOC_PPC64_TOC:
size = 8;
break;
@@ -3203,6 +3211,10 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
case BFD_RELOC_64_PCREL:
case BFD_RELOC_64_PLT_PCREL:
case BFD_RELOC_PPC64_GOT_PCREL34:
+ case BFD_RELOC_PPC64_GOT_TLSGD34:
+ case BFD_RELOC_PPC64_GOT_TLSLD34:
+ case BFD_RELOC_PPC64_GOT_TPREL34:
+ case BFD_RELOC_PPC64_GOT_DTPREL34:
case BFD_RELOC_PPC64_PCREL28:
case BFD_RELOC_PPC64_PCREL34:
case BFD_RELOC_PPC64_PLT_PCREL34:
@@ -3744,6 +3756,7 @@ md_assemble (char *str)
break;
case BFD_RELOC_PPC_TLS:
+ case BFD_RELOC_PPC64_TLS_PCREL:
if (!_bfd_elf_ppc_at_tls_transform (opcode->opcode, 0))
as_bad (_("@tls may not be used with \"%s\" operands"),
opcode->name);
@@ -3756,13 +3769,19 @@ md_assemble (char *str)
break;
/* We'll only use the 32 (or 64) bit form of these relocations
- in constants. Instructions get the 16 bit form. */
+ in constants. Instructions get the 16 or 34 bit form. */
case BFD_RELOC_PPC_DTPREL:
- reloc = BFD_RELOC_PPC_DTPREL16;
+ if (operand->bitm == 0x3ffffffffULL)
+ reloc = BFD_RELOC_PPC64_DTPREL34;
+ else
+ reloc = BFD_RELOC_PPC_DTPREL16;
break;
case BFD_RELOC_PPC_TPREL:
- reloc = BFD_RELOC_PPC_TPREL16;
+ if (operand->bitm == 0x3ffffffffULL)
+ reloc = BFD_RELOC_PPC64_TPREL34;
+ else
+ reloc = BFD_RELOC_PPC_TPREL16;
break;
case BFD_RELOC_PPC64_PCREL34:
@@ -3774,6 +3793,10 @@ md_assemble (char *str)
/* Fall through. */
case BFD_RELOC_PPC64_GOT_PCREL34:
case BFD_RELOC_PPC64_PLT_PCREL34:
+ case BFD_RELOC_PPC64_GOT_TLSGD34:
+ case BFD_RELOC_PPC64_GOT_TLSLD34:
+ case BFD_RELOC_PPC64_GOT_TPREL34:
+ case BFD_RELOC_PPC64_GOT_DTPREL34:
if (operand->bitm != 0x3ffffffffULL
|| (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
as_warn (_("%s unsupported on this instruction"), "@pcrel");
@@ -7003,7 +7026,7 @@ ppc_force_relocation (fixS *fix)
}
if (fix->fx_r_type >= BFD_RELOC_PPC_TLS
- && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
+ && fix->fx_r_type <= BFD_RELOC_PPC64_TLS_PCREL)
return 1;
return generic_force_reloc (fix);
@@ -7071,7 +7094,7 @@ ppc_fix_adjustable (fixS *fix)
&& fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
&& fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
&& !(fix->fx_r_type >= BFD_RELOC_PPC_TLS
- && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA));
+ && fix->fx_r_type <= BFD_RELOC_PPC64_TLS_PCREL));
}
#endif
@@ -7503,6 +7526,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
+ case BFD_RELOC_PPC64_TPREL34:
+ case BFD_RELOC_PPC64_DTPREL34:
+ case BFD_RELOC_PPC64_GOT_TLSGD34:
+ case BFD_RELOC_PPC64_GOT_TLSLD34:
+ case BFD_RELOC_PPC64_GOT_TPREL34:
+ case BFD_RELOC_PPC64_GOT_DTPREL34:
gas_assert (fixP->fx_addsy != NULL);
S_SET_THREAD_LOCAL (fixP->fx_addsy);
fieldval = 0;
@@ -7573,6 +7602,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
case BFD_RELOC_PPC_TLS:
case BFD_RELOC_PPC_TLSGD:
case BFD_RELOC_PPC_TLSLD:
+ case BFD_RELOC_PPC64_TLS_PCREL:
fieldval = 0;
break;
#endif
@@ -7826,6 +7856,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
case BFD_RELOC_PPC64_TPREL16_HIGHERA:
case BFD_RELOC_PPC64_TPREL16_HIGHEST:
case BFD_RELOC_PPC64_TPREL16_HIGHESTA:
+ case BFD_RELOC_PPC64_TLS_PCREL:
fixP->fx_done = 0;
break;
#endif
@@ -7918,6 +7949,9 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ /* BFD_RELOC_PPC64_TLS_PCREL generates R_PPC64_TLS with an odd r_offset. */
+ if (fixp->fx_r_type == BFD_RELOC_PPC64_TLS_PCREL)
+ reloc->address++;
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
if (reloc->howto == (reloc_howto_type *) NULL)
{
diff --git a/include/ChangeLog b/include/ChangeLog
index 07e0c5c..bb5abb1 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,10 @@
+2019-07-19 Alan Modra <amodra@gmail.com>
+
+ * elf/ppc64.h (R_PPC64_TPREL34, R_PPC64_DTPREL34),
+ (R_PPC64_GOT_TLSGD34, R_PPC64_GOT_TLSLD34),
+ (R_PPC64_GOT_TPREL34, R_PPC64_GOT_DTPREL34): Define.
+ (IS_PPC64_TLS_RELOC): Include new tls relocs.
+
2019-07-18 Nick Alcock <nick.alcock@oracle.com>
* ctf-api.h (ECTF_NOTFUNC): Fix description.
diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h
index e90c7fd..226c989 100644
--- a/include/elf/ppc64.h
+++ b/include/elf/ppc64.h
@@ -181,6 +181,12 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type)
RELOC_NUMBER (R_PPC64_REL16_HIGHESTA34, 143)
RELOC_NUMBER (R_PPC64_D28, 144)
RELOC_NUMBER (R_PPC64_PCREL28, 145)
+ RELOC_NUMBER (R_PPC64_TPREL34, 146)
+ RELOC_NUMBER (R_PPC64_DTPREL34, 147)
+ RELOC_NUMBER (R_PPC64_GOT_TLSGD34, 148)
+ RELOC_NUMBER (R_PPC64_GOT_TLSLD34, 149)
+ RELOC_NUMBER (R_PPC64_GOT_TPREL34, 150)
+ RELOC_NUMBER (R_PPC64_GOT_DTPREL34, 151)
#ifndef RELOC_MACROS_GEN_FUNC
/* Relocation only used internally by gas or ld. If you need to use
@@ -218,8 +224,8 @@ END_RELOC_NUMBERS (R_PPC64_max)
#define IS_PPC64_TLS_RELOC(R) \
(((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) \
- || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA))
-
+ || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA) \
+ || ((R) >= R_PPC64_TPREL34 && (R) <= R_PPC64_GOT_DTPREL34))
/* e_flags bits specifying ABI.
1 for original function descriptor using ABI,
diff --git a/ld/ChangeLog b/ld/ChangeLog
index c031b0e..9fcc55c 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,5 +1,15 @@
2019-07-19 Alan Modra <amodra@gmail.com>
+ * testsuite/ld-powerpc/tlsgd.d,
+ * testsuite/ld-powerpc/tlsgd.s,
+ * testsuite/ld-powerpc/tlsie.d,
+ * testsuite/ld-powerpc/tlsie.s,
+ * testsuite/ld-powerpc/tlsld.d,
+ * testsuite/ld-powerpc/tlsld.s: New tests.
+ * testsuite/ld-powerpc/powerpc.exp: Run them.
+
+2019-07-19 Alan Modra <amodra@gmail.com>
+
* testsuite/ld-powerpc/tlsldopt.d: Rename from tlsld.d.
* testsuite/ld-powerpc/tlsldopt.s: Rename from tlsld.s.
* testsuite/ld-powerpc/tlsldopt32.d: Rename from tlsld32.d.
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index 508d48e..87a7462 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -343,6 +343,9 @@ if [ supports_ppc64 ] then {
run_dump_test "pr23937"
run_dump_test "callstub-1"
run_dump_test "callstub-2"
+ run_dump_test "tlsgd"
+ run_dump_test "tlsld"
+ run_dump_test "tlsie"
}
run_dump_test "tlsldopt32"
diff --git a/ld/testsuite/ld-powerpc/tlsgd.d b/ld/testsuite/ld-powerpc/tlsgd.d
new file mode 100644
index 0000000..42c9b5f
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tlsgd.d
@@ -0,0 +1,31 @@
+#source: tlsgd.s
+#as: -a64 -mfuture
+#ld: -melf64ppc
+#objdump: -dr -Mfuture
+
+.*: file format .*
+
+Disassembly of section \.text:
+
+.*:
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 90 08|08 90 6d 38) addi r3,r13,-28664
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 90 10|10 90 6d 38) addi r3,r13,-28656
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (06 03 ff ff|ff ff 03 06) paddi r3,r13,-28648
+.*: (38 6d 90 18|18 90 6d 38)
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 90 20|20 90 6d 38) addi r3,r13,-28640
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 90 20|20 90 6d 38) addi r3,r13,-28640
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (06 03 ff ff|ff ff 03 06) paddi r3,r13,-28640
+.*: (38 6d 90 20|20 90 6d 38)
+.*: (60 00 00 00|00 00 00 60) nop
diff --git a/ld/testsuite/ld-powerpc/tlsgd.s b/ld/testsuite/ld-powerpc/tlsgd.s
new file mode 100644
index 0000000..304bd60
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tlsgd.s
@@ -0,0 +1,52 @@
+ .section ".tbss","awT",@nobits
+ .p2align 3
+pad: .space 8
+ .global a
+a: .space 8
+ .global b
+b: .space 8
+ .global c
+c: .space 8
+ .global d
+d: .space 8
+
+ .text
+ .globl _start
+_start:
+#Small model OpenPower
+ addi 3,2,.La@toc
+ bl __tls_get_addr(.La@tlsgd)
+ nop
+ .section .toc,"aw",@progbits
+ .p2align 3
+.La:
+ .quad a@dtpmod
+ .quad a@dtprel
+ .text
+
+#Medium mode ELF
+ addis 3,2,b@got@tlsgd@ha
+ addi 3,3,b@got@tlsgd@l
+ bl __tls_get_addr(b@tlsgd)
+ nop
+
+#PCrel
+ pla 3,c@got@tlsgd@pcrel
+ bl __tls_get_addr@notoc(c@tlsgd)
+
+#All of the above using the same symbol
+ addis 3,2,.Ld@toc@ha
+ addi 3,3,.Ld@toc@l
+ bl __tls_get_addr(.Ld@tlsgd)
+ nop
+ .section .toc,"aw",@progbits
+.Ld:
+ .quad d@dtpmod
+ .quad d@dtprel
+ .text
+ addis 3,2,d@got@tlsgd@ha
+ addi 3,3,d@got@tlsgd@l
+ bl __tls_get_addr(d@tlsgd)
+ nop
+ pla 3,d@got@tlsgd@pcrel
+ bl __tls_get_addr@notoc(d@tlsgd)
diff --git a/ld/testsuite/ld-powerpc/tlsie.d b/ld/testsuite/ld-powerpc/tlsie.d
new file mode 100644
index 0000000..79613bd
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tlsie.d
@@ -0,0 +1,54 @@
+#source: tlsie.s
+#as: -a64 -mfuture
+#ld: -melf64ppc
+#objdump: -dr -Mfuture
+
+.*: file format .*
+
+Disassembly of section \.text:
+
+.*:
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (39 4d 90 08|08 90 4d 39) addi r10,r13,-28664
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 90 10|10 90 6d 38) addi r3,r13,-28656
+.*: (06 03 ff ff|ff ff 03 06) paddi r4,r13,-28648
+.*: (38 8d 90 18|18 90 8d 38)
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (39 4d 90 20|20 90 4d 39) addi r10,r13,-28640
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 90 20|20 90 6d 38) addi r3,r13,-28640
+.*: (06 03 ff ff|ff ff 03 06) paddi r30,r13,-28640
+.*: (3b cd 90 20|20 90 cd 3b)
+.*: (7f c3 f3 78|78 f3 c3 7f) mr r3,r30
+.*: (80 9e 00 00|00 00 9e 80) lwz r4,0\(r30\)
+.*: (84 9e 00 00|00 00 9e 84) lwzu r4,0\(r30\)
+.*: (88 be 00 00|00 00 be 88) lbz r5,0\(r30\)
+.*: (8c be 00 00|00 00 be 8c) lbzu r5,0\(r30\)
+.*: (90 de 00 00|00 00 de 90) stw r6,0\(r30\)
+.*: (94 de 00 00|00 00 de 94) stwu r6,0\(r30\)
+.*: (98 fe 00 00|00 00 fe 98) stb r7,0\(r30\)
+.*: (9c fe 00 00|00 00 fe 9c) stbu r7,0\(r30\)
+.*: (a1 1e 00 00|00 00 1e a1) lhz r8,0\(r30\)
+.*: (a5 1e 00 00|00 00 1e a5) lhzu r8,0\(r30\)
+.*: (a9 3e 00 00|00 00 3e a9) lha r9,0\(r30\)
+.*: (ad 3e 00 00|00 00 3e ad) lhau r9,0\(r30\)
+.*: (b1 5e 00 00|00 00 5e b1) sth r10,0\(r30\)
+.*: (b5 5e 00 00|00 00 5e b5) sthu r10,0\(r30\)
+.*: (c1 7e 00 00|00 00 7e c1) lfs f11,0\(r30\)
+.*: (c5 7e 00 00|00 00 7e c5) lfsu f11,0\(r30\)
+.*: (c9 9e 00 00|00 00 9e c9) lfd f12,0\(r30\)
+.*: (cd 9e 00 00|00 00 9e cd) lfdu f12,0\(r30\)
+.*: (d1 be 00 00|00 00 be d1) stfs f13,0\(r30\)
+.*: (d5 be 00 00|00 00 be d5) stfsu f13,0\(r30\)
+.*: (d9 de 00 00|00 00 de d9) stfd f14,0\(r30\)
+.*: (dd de 00 00|00 00 de dd) stfdu f14,0\(r30\)
+.*: (e9 fe 00 00|00 00 fe e9) ld r15,0\(r30\)
+.*: (e9 fe 00 01|01 00 fe e9) ldu r15,0\(r30\)
+.*: (fa 1e 00 00|00 00 1e fa) std r16,0\(r30\)
+.*: (fa 1e 00 01|01 00 1e fa) stdu r16,0\(r30\)
+.*: (ea 3e 00 02|02 00 3e ea) lwa r17,0\(r30\)
diff --git a/ld/testsuite/ld-powerpc/tlsie.s b/ld/testsuite/ld-powerpc/tlsie.s
new file mode 100644
index 0000000..384e7ce
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tlsie.s
@@ -0,0 +1,77 @@
+ .section ".tbss","awT",@nobits
+ .p2align 3
+pad: .space 8
+ .global a
+a: .space 8
+ .global b
+b: .space 8
+ .global c
+c: .space 8
+ .global d
+d: .space 8
+
+ .text
+ .globl _start
+_start:
+#Small model OpenPower
+ ld 9,.La@toc(2)
+ add 10,9,.La@tls
+ .section .toc,"aw",@progbits
+.La:
+ .quad a@tprel
+ .text
+
+#Medium model ELF
+ addi 9,2,b@got@tprel@ha
+ ld 10,b@got@tprel@l(9)
+ add 3,10,b@tls
+
+#PCrel
+ pld 4,c@got@tprel@pcrel
+ add 4,4,c@tls@pcrel
+
+#All of the above using the same symbol
+ addis 9,2,.Ld@toc@ha
+ ld 9,.Ld@toc@l(9)
+ add 10,9,.Ld@tls
+ .section .toc,"aw",@progbits
+.Ld:
+ .quad d@tprel
+ .text
+ addi 9,2,d@got@tprel@ha
+ ld 31,d@got@tprel@l(9)
+ add 3,31,d@tls
+ pld 30,d@got@tprel@pcrel
+ add 3,30,d@tls@pcrel
+#Note that after optimisation r31 and r30 above have a different value to
+#what they would have without optimisation. r31 may not even be written.
+#Here are all the other insns that gas/ld accept as the final insn of an
+#IE sequence. The r30 value below will be different after optimisation
+#for the non-update forms.
+ lwzx 4,30,d@tls@pcrel
+ lwzux 4,30,d@tls@pcrel
+ lbzx 5,30,d@tls@pcrel
+ lbzux 5,30,d@tls@pcrel
+ stwx 6,30,d@tls@pcrel
+ stwux 6,30,d@tls@pcrel
+ stbx 7,30,d@tls@pcrel
+ stbux 7,30,d@tls@pcrel
+ lhzx 8,30,d@tls@pcrel
+ lhzux 8,30,d@tls@pcrel
+ lhax 9,30,d@tls@pcrel
+ lhaux 9,30,d@tls@pcrel
+ sthx 10,30,d@tls@pcrel
+ sthux 10,30,d@tls@pcrel
+ lfsx 11,30,d@tls@pcrel
+ lfsux 11,30,d@tls@pcrel
+ lfdx 12,30,d@tls@pcrel
+ lfdux 12,30,d@tls@pcrel
+ stfsx 13,30,d@tls@pcrel
+ stfsux 13,30,d@tls@pcrel
+ stfdx 14,30,d@tls@pcrel
+ stfdux 14,30,d@tls@pcrel
+ ldx 15,30,d@tls@pcrel
+ ldux 15,30,d@tls@pcrel
+ stdx 16,30,d@tls@pcrel
+ stdux 16,30,d@tls@pcrel
+ lwax 17,30,d@tls@pcrel
diff --git a/ld/testsuite/ld-powerpc/tlsld.d b/ld/testsuite/ld-powerpc/tlsld.d
new file mode 100644
index 0000000..740b15b
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tlsld.d
@@ -0,0 +1,36 @@
+#source: tlsld.s
+#as: -a64 -mfuture
+#ld: -melf64ppc
+#objdump: -dr -Mfuture
+
+.*: file format .*
+
+Disassembly of section \.text:
+
+.*:
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 10 00|00 10 6d 38) addi r3,r13,4096
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 10 00|00 10 6d 38) addi r3,r13,4096
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (06 00 00 00|00 00 00 06) paddi r3,r13,4096
+.*: (38 6d 10 00|00 10 6d 38)
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (06 03 ff ff|ff ff 03 06) paddi r9,r3,-32728
+.*: (39 23 80 28|28 80 23 39)
+.*: (04 10 00 01|01 00 10 04) pld r10,65784
+.*: (e5 40 00 f8|f8 00 40 e5)
+.*: (7d 4a 1a 14|14 1a 4a 7d) add r10,r10,r3
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 10 00|00 10 6d 38) addi r3,r13,4096
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (38 6d 10 00|00 10 6d 38) addi r3,r13,4096
+.*: (60 00 00 00|00 00 00 60) nop
+.*: (06 00 00 00|00 00 00 06) paddi r3,r13,4096
+.*: (38 6d 10 00|00 10 6d 38)
+.*: (60 00 00 00|00 00 00 60) nop
diff --git a/ld/testsuite/ld-powerpc/tlsld.s b/ld/testsuite/ld-powerpc/tlsld.s
new file mode 100644
index 0000000..4ab2630
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tlsld.s
@@ -0,0 +1,58 @@
+ .section ".tbss","awT",@nobits
+ .p2align 3
+pad: .space 8
+ .global a
+a: .space 8
+ .global b
+b: .space 8
+ .global c
+c: .space 8
+ .global d
+d: .space 8
+z2: .space 8
+z3: .space 8
+
+ .text
+ .globl _start
+_start:
+#Small model OpenPower
+ addi 3,2,.La@toc
+ bl __tls_get_addr(.La@tlsld)
+ nop
+ .section .toc,"aw",@progbits
+ .p2align 3
+.La:
+ .quad a@dtpmod
+ .quad 0
+ .text
+
+#Medium mode ELF
+ addis 3,2,b@got@tlsld@ha
+ addi 3,3,b@got@tlsld@l
+ bl __tls_get_addr(b@tlsld)
+ nop
+
+#PCrel, with dtprel access to vars
+ pla 3,c@got@tlsld@pcrel
+ bl __tls_get_addr@notoc(c@tlsld)
+ paddi 9,3,z2@dtprel
+ pld 10,z3@got@dtprel@pcrel
+ add 10,10,3
+
+#All of the above using the same symbol
+ addis 3,2,.Ld@toc@ha
+ addi 3,3,.Ld@toc@l
+ bl __tls_get_addr(.Ld@tlsld)
+ nop
+ .section .toc,"aw",@progbits
+ .p2align 3
+.Ld:
+ .quad d@dtpmod
+ .quad 0
+ .text
+ addis 3,2,d@got@tlsld@ha
+ addi 3,3,d@got@tlsld@l
+ bl __tls_get_addr(d@tlsld)
+ nop
+ pla 3,d@got@tlsld@pcrel
+ bl __tls_get_addr@notoc(d@tlsld)