aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2020-08-24 16:32:57 +0930
committerAlan Modra <amodra@gmail.com>2020-08-24 21:15:06 +0930
commit252dcdf432c67f6baafb766ed068c64db1eb2bad (patch)
treef065483aba2070e20ef18b2c5cb711b82bb6041c /bfd
parentf16c3d4f137ae02fab0982782b2e1c2b2afc8583 (diff)
downloadgdb-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/ChangeLog14
-rw-r--r--bfd/elf32-ppc.c98
-rw-r--r--bfd/elf64-ppc.c64
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;