diff options
author | Alan Modra <amodra@gmail.com> | 2017-08-30 20:35:35 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2017-08-30 20:43:31 +0930 |
commit | 9a23f96e919ba91587d077b1d399246dde4002dd (patch) | |
tree | 1eb693e16708eef776aece4643cda8dfde86301c /bfd | |
parent | b9f04fe0dfe64bc6224e7bb96378607f17da7446 (diff) | |
download | gdb-9a23f96e919ba91587d077b1d399246dde4002dd.zip gdb-9a23f96e919ba91587d077b1d399246dde4002dd.tar.gz 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')
-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: |