From 252dcdf432c67f6baafb766ed068c64db1eb2bad Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 24 Aug 2020 16:32:57 +0930 Subject: PowerPC TPREL_HA/LO optimisation ppc64 ld optimises sequences like the following addis 3,13,wot@tprel@ha lwz 3,wot@tprel@l(3) to nop lwz 3,wot@tprel(13) when "wot" is located near enough to the thread pointer. However, the ABI doesn't require that R_PPC64_TPREL16_HA always be on an addis rt,13,imm instruction, and while ld checked for that on the high-part instruction it didn't disable the optimisation on the low-part instruction. This patch fixes that problem, disabling the tprel optimisation globally if high-part instructions don't pass sanity checks. The optimisation is also enabled for ppc32, where before ld.bfd had the code in the wrong place and ld.gold had it in a block only enabled for ppc64. bfd/ * elf32-ppc.c (ppc_elf_check_relocs): Set has_tls_reloc for high part tprel16 relocs. (ppc_elf_tls_optimize): Sanity check high part tprel16 relocs. Clear do_tls_opt on odd instructions. (ppc_elf_relocate_section): Move TPREL16_HA/LO optimisation later. Don't sanity check them here. * elf64-ppc.c (ppc64_elf_check_relocs): Set has_tls_reloc for high part tprel16 relocs. (ppc64_elf_tls_optimize): Sanity check high part tprel16 relocs. Clear do_tls_opt on odd instructions. (ppc64_elf_relocate_section): Don't sanity check TPREL16_HA. ld/ * testsuite/ld-powerpc/tls32.d: Update for TPREL_HA/LO optimisation. * testsuite/ld-powerpc/tlsexe32.d: Likewise. * testsuite/ld-powerpc/tlsldopt32.d: Likewise. * testsuite/ld-powerpc/tlsmark32.d: Likewise. * testsuite/ld-powerpc/tlsopt4_32.d: Likewise. * testsuite/ld-powerpc/tprel.s, * testsuite/ld-powerpc/tprel.d, * testsuite/ld-powerpc/tprel32.d: New tests. * testsuite/ld-powerpc/tprelbad.s, * testsuite/ld-powerpc/tprelbad.d: New test. * testsuite/ld-powerpc/powerpc.exp: Run them. gold/ * powerpc.cc (Target_powerpc): Add tprel_opt_ and accessors. (Target_powerpc::Scan::local): Sanity check tprel high relocs. (Target_powerpc::Scan::global): Likewise. (Target_powerpc::Relocate::relocate): Control tprel optimisation with tprel_opt_ and enable for 32-bit. --- bfd/ChangeLog | 14 +++++++++ bfd/elf32-ppc.c | 98 ++++++++++++++++++++++++++++++++++++--------------------- bfd/elf64-ppc.c | 64 ++++++++++++++++++++++++++----------- 3 files changed, 122 insertions(+), 54 deletions(-) (limited to 'bfd') diff --git a/bfd/ChangeLog b/bfd/ChangeLog index eb4d882..08e9763 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2020-08-24 Alan Modra + + * elf32-ppc.c (ppc_elf_check_relocs): Set has_tls_reloc for + high part tprel16 relocs. + (ppc_elf_tls_optimize): Sanity check high part tprel16 relocs. + Clear do_tls_opt on odd instructions. + (ppc_elf_relocate_section): Move TPREL16_HA/LO optimisation later. + Don't sanity check them here. + * elf64-ppc.c (ppc64_elf_check_relocs): Set has_tls_reloc for + high part tprel16 relocs. + (ppc64_elf_tls_optimize): Sanity check high part tprel16 relocs. + Clear do_tls_opt on odd instructions. + (ppc64_elf_relocate_section): Don't sanity check TPREL16_HA. + 2020-08-23 John David Anglin PR binutils/26357 diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 8d34b9b..43c0e18 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -3301,12 +3301,14 @@ ppc_elf_check_relocs (bfd *abfd, return FALSE; break; + case R_PPC_TPREL16_HI: + case R_PPC_TPREL16_HA: + sec->has_tls_reloc = 1; + /* Fall through. */ /* We shouldn't really be seeing TPREL32. */ case R_PPC_TPREL32: case R_PPC_TPREL16: case R_PPC_TPREL16_LO: - case R_PPC_TPREL16_HI: - case R_PPC_TPREL16_HA: if (bfd_link_dll (info)) info->flags |= DF_STATIC_TLS; goto dodyn; @@ -4416,6 +4418,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, if (htab == NULL) return FALSE; + htab->do_tls_opt = 1; + /* Make two passes through the relocs. First time check that tls relocs involved in setting up a tls_get_addr call are indeed followed by such a call. If they are not, don't do any tls @@ -4581,6 +4585,37 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, tls_clear = 0; break; + case R_PPC_TPREL16_HA: + if (pass == 0) + { + unsigned char buf[4]; + unsigned int insn; + bfd_vma off = rel->r_offset & ~3; + if (!bfd_get_section_contents (ibfd, sec, buf, + off, 4)) + { + if (elf_section_data (sec)->relocs != relstart) + free (relstart); + return FALSE; + } + insn = bfd_get_32 (ibfd, buf); + /* addis rt,2,imm */ + if ((insn & ((0x3fu << 26) | 0x1f << 16)) + != ((15u << 26) | (2 << 16))) + { + /* xgettext:c-format */ + info->callbacks->minfo + (_("%H: warning: %s unexpected insn %#x.\n"), + ibfd, sec, off, "R_PPC_TPREL16_HA", insn); + htab->do_tls_opt = 0; + } + } + continue; + + case R_PPC_TPREL16_HI: + htab->do_tls_opt = 0; + continue; + default: continue; } @@ -4675,7 +4710,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, free (relstart); } } - htab->do_tls_opt = 1; return TRUE; } @@ -7552,39 +7586,6 @@ ppc_elf_relocate_section (bfd *output_bfd, 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 & ((0x3fu << 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) { @@ -8754,6 +8755,31 @@ ppc_elf_relocate_section (bfd *output_bfd, default: break; + case R_PPC_TPREL16_HA: + if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) + { + bfd_byte *p = contents + (rel->r_offset & ~3); + 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; + } + + switch (r_type) + { + default: + break; + case R_PPC_PLTCALL: if (unresolved_reloc) { diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 5cbf9ac..02f0f18 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -5073,19 +5073,21 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -2; goto dodyn; - case R_PPC64_TPREL16: - case R_PPC64_TPREL16_LO: case R_PPC64_TPREL16_HI: case R_PPC64_TPREL16_HA: - case R_PPC64_TPREL16_DS: - case R_PPC64_TPREL16_LO_DS: case R_PPC64_TPREL16_HIGH: case R_PPC64_TPREL16_HIGHA: case R_PPC64_TPREL16_HIGHER: case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: + sec->has_tls_reloc = 1; + /* Fall through. */ case R_PPC64_TPREL34: + case R_PPC64_TPREL16: + case R_PPC64_TPREL16_DS: + case R_PPC64_TPREL16_LO: + case R_PPC64_TPREL16_LO_DS: if (bfd_link_dll (info)) info->flags |= DF_STATIC_TLS; goto dodyn; @@ -7936,6 +7938,8 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (htab == NULL) return FALSE; + htab->do_tls_opt = 1; + /* Make two passes over the relocs. On the first pass, mark toc entries involved with tls relocs, and check that tls relocs involved in setting up a tls_get_addr call are indeed followed by @@ -8240,6 +8244,42 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) } break; + case R_PPC64_TPREL16_HA: + if (pass == 0) + { + unsigned char buf[4]; + unsigned int insn; + bfd_vma off = rel->r_offset & ~3; + if (!bfd_get_section_contents (ibfd, sec, buf, + off, 4)) + goto err_free_rel; + insn = bfd_get_32 (ibfd, buf); + /* addis rt,13,imm */ + if ((insn & ((0x3fu << 26) | 0x1f << 16)) + != ((15u << 26) | (13 << 16))) + { + /* xgettext:c-format */ + info->callbacks->minfo + (_("%H: warning: %s unexpected insn %#x.\n"), + ibfd, sec, off, "R_PPC64_TPREL16_HA", insn); + htab->do_tls_opt = 0; + } + } + continue; + + case R_PPC64_TPREL16_HI: + case R_PPC64_TPREL16_HIGH: + case R_PPC64_TPREL16_HIGHA: + case R_PPC64_TPREL16_HIGHER: + case R_PPC64_TPREL16_HIGHERA: + case R_PPC64_TPREL16_HIGHEST: + case R_PPC64_TPREL16_HIGHESTA: + /* These can all be used in sequences along with + TPREL16_LO or TPREL16_LO_DS in ways we aren't + able to verify easily. */ + htab->do_tls_opt = 0; + continue; + default: continue; } @@ -8406,7 +8446,6 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) } free (toc_ref); - htab->do_tls_opt = 1; return TRUE; } @@ -16913,19 +16952,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, 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 & ((0x3fu << 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, - ppc64_elf_howto_table[r_type]->name, insn); - else - { - bfd_put_32 (input_bfd, NOP, p); - goto copy_reloc; - } + bfd_put_32 (input_bfd, NOP, p); + goto copy_reloc; } break; -- cgit v1.1