diff options
author | Alan Modra <amodra@gmail.com> | 2020-08-24 16:32:57 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2020-08-24 21:15:06 +0930 |
commit | 252dcdf432c67f6baafb766ed068c64db1eb2bad (patch) | |
tree | f065483aba2070e20ef18b2c5cb711b82bb6041c /bfd | |
parent | f16c3d4f137ae02fab0982782b2e1c2b2afc8583 (diff) | |
download | gdb-252dcdf432c67f6baafb766ed068c64db1eb2bad.zip gdb-252dcdf432c67f6baafb766ed068c64db1eb2bad.tar.gz gdb-252dcdf432c67f6baafb766ed068c64db1eb2bad.tar.bz2 |
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.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 14 | ||||
-rw-r--r-- | bfd/elf32-ppc.c | 98 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 64 |
3 files changed, 122 insertions, 54 deletions
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 <amodra@gmail.com> + + * 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 <danglin@gcc.gnu.org> 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; |