From 9a23f96e919ba91587d077b1d399246dde4002dd Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 30 Aug 2017 20:35:35 +0930 Subject: 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. --- bfd/ChangeLog | 12 ++++++++++++ bfd/elf32-ppc.c | 40 +++++++++++++++++++++++++++++++++++++++- bfd/elf64-ppc.c | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 84 insertions(+), 2 deletions(-) (limited to 'bfd') diff --git a/bfd/ChangeLog b/bfd/ChangeLog index ec74d9d..205b016 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,17 @@ 2017-08-30 Alan Modra + * 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. + +2017-08-30 Alan Modra + * elf64-ppc.c (ppc64_elf_relocate_section): When optimizing __tls_get_addr call sequences to LE, don't move the addi down to the nop. Replace the bl with addi and leave the nop alone. 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: diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 5b96a04..cf7c178 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -4120,6 +4120,9 @@ struct ppc_link_hash_table unsigned int second_toc_pass:1; unsigned int do_toc_opt:1; + /* Set if tls optimization is enabled. */ + unsigned int do_tls_opt:1; + /* Set on error. */ unsigned int stub_error:1; @@ -8925,6 +8928,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (toc_ref != NULL) free (toc_ref); + htab->do_tls_opt = 1; return TRUE; } @@ -15152,6 +15156,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* Multi-instruction sequences that access the TOC can be optimized, eg. addis ra,r2,0; addi rb,ra,x; to nop; addi rb,r2,x; */ + howto = ppc64_elf_howto_table[(int) r_type]; switch (r_type) { default: @@ -15213,10 +15218,37 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_put_32 (input_bfd, insn, p); } break; + + case R_PPC64_TPREL16_HA: + if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) + { + bfd_byte *p = contents + (rel->r_offset & ~3); + insn = bfd_get_32 (input_bfd, p); + if ((insn & ((0x3f << 26) | 0x1f << 16)) + != ((15u << 26) | (13 << 16)) /* addis rt,13,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_PPC64_TPREL16_LO: + case R_PPC64_TPREL16_LO_DS: + if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) + { + bfd_byte *p = contents + (rel->r_offset & ~3); + insn = bfd_get_32 (input_bfd, p); + insn &= ~(0x1f << 16); + insn |= 13 << 16; + bfd_put_32 (input_bfd, insn, p); + } + break; } /* Do any further special processing. */ - howto = ppc64_elf_howto_table[(int) r_type]; switch (r_type) { default: -- cgit v1.1