diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 12 | ||||
-rw-r--r-- | bfd/elf32-ppc.c | 40 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 34 |
3 files changed, 84 insertions, 2 deletions
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 <amodra@gmail.com> + * 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 <amodra@gmail.com> + * 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: |