aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2017-08-30 20:35:35 +0930
committerAlan Modra <amodra@gmail.com>2017-08-30 20:43:31 +0930
commit9a23f96e919ba91587d077b1d399246dde4002dd (patch)
tree1eb693e16708eef776aece4643cda8dfde86301c /bfd/elf32-ppc.c
parentb9f04fe0dfe64bc6224e7bb96378607f17da7446 (diff)
downloadfsf-binutils-gdb-9a23f96e919ba91587d077b1d399246dde4002dd.zip
fsf-binutils-gdb-9a23f96e919ba91587d077b1d399246dde4002dd.tar.gz
fsf-binutils-gdb-9a23f96e919ba91587d077b1d399246dde4002dd.tar.bz2
PowerPC TPREL16_HA/LO reloc optimization
In the TLS GD/LD to LE optimization, ld replaces a sequence like addi 3,2,x@got@tlsgd R_PPC64_GOT_TLSGD16 x bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x R_PPC64_REL24 __tls_get_addr nop with addis 3,13,x@tprel@ha R_PPC64_TPREL16_HA x addi 3,3,x@tprel@l R_PPC64_TPREL16_LO x nop When the tprel offset is small, this can be further optimized to nop addi 3,13,x@tprel nop bfd/ * elf64-ppc.c (struct ppc_link_hash_table): Add do_tls_opt. (ppc64_elf_tls_optimize): Set it. (ppc64_elf_relocate_section): Nop addis on TPREL16_HA, and convert insn on TPREL16_LO and TPREL16_LO_DS relocs to use r13 when addis would add zero. * elf32-ppc.c (struct ppc_elf_link_hash_table): Add do_tls_opt. (ppc_elf_tls_optimize): Set it. (ppc_elf_relocate_section): Nop addis on TPREL16_HA, and convert insn on TPREL16_LO relocs to use r2 when addis would add zero. gold/ * powerpc.cc (Target_powerpc::Relocate::relocate): Nop addis on TPREL16_HA, and convert insn on TPREL16_LO and TPREL16_LO_DS relocs to use r2/r13 when addis would add zero. ld/ * testsuite/ld-powerpc/tls.s: Add calls with tls markers. * testsuite/ld-powerpc/tls32.s: Likewise. * testsuite/ld-powerpc/powerpc.exp: Run tls marker tests. * testsuite/ld-powerpc/tls.d: Adjust for TPREL16_HA/LO optimization. * testsuite/ld-powerpc/tlsexe.d: Likewise. * testsuite/ld-powerpc/tlsexetoc.d: Likewise. * testsuite/ld-powerpc/tlsld.d: Likewise. * testsuite/ld-powerpc/tlsmark.d: Likewise. * testsuite/ld-powerpc/tlsopt4.d: Likewise. * testsuite/ld-powerpc/tlstoc.d: Likewise.
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r--bfd/elf32-ppc.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index a5d8193..2bdba9f 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -3345,6 +3345,9 @@ struct ppc_elf_link_hash_table
unsigned int local_ifunc_resolver:1;
unsigned int maybe_local_ifunc_resolver:1;
+ /* Set if tls optimization is enabled. */
+ unsigned int do_tls_opt:1;
+
/* The size of PLT entries. */
int plt_entry_size;
/* The distance between adjacent PLT slots. */
@@ -5631,6 +5634,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
symtab_hdr->contents = (unsigned char *) locsyms;
}
}
+ htab->do_tls_opt = 1;
return TRUE;
}
@@ -8426,10 +8430,44 @@ ppc_elf_relocate_section (bfd *output_bfd,
}
addend = rel->r_addend;
- tls_type = 0;
howto = NULL;
if (r_type < R_PPC_max)
howto = ppc_elf_howto_table[r_type];
+
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_PPC_TPREL16_HA:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ if ((insn & ((0x3f << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
+ /* xgettext:c-format */
+ info->callbacks->minfo
+ (_("%H: warning: %s unexpected insn %#x.\n"),
+ input_bfd, input_section, rel->r_offset, howto->name, insn);
+ else
+ bfd_put_32 (input_bfd, NOP, p);
+ }
+ break;
+
+ case R_PPC_TPREL16_LO:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ insn &= ~(0x1f << 16);
+ insn |= 2 << 16;
+ bfd_put_32 (input_bfd, insn, p);
+ }
+ break;
+ }
+
+ tls_type = 0;
switch (r_type)
{
default: