From 903b777ddeb4c11a7de12cab59124e777614edec Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 19 Aug 2019 17:34:03 +0930 Subject: [PATCH] PowerPC64 ha/lo insn checks These are done in ppc64_elf_edit_toc, which now also garbage collects unused GOT entries. The checks for legitimate instructions weren't being done for the GOT relocs, unless the file also happened to have a toc section. * elf64-ppc.c (struct ppc64_elf_obj_tdata): Rename has_gotrel to has_optrel. (struct _ppc64_elf_section_data): Likewise. (ppc64_elf_check_relocs): Set has_optrel for more relocs. (ppc64_elf_edit_toc): Do ha/lo insn checks in GOT loop rather than TOC loop. Check PLT16 insns too. --- bfd/ChangeLog | 9 +++ bfd/elf64-ppc.c | 172 ++++++++++++++++++++++++++++++++------------------------ 2 files changed, 109 insertions(+), 72 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 962fc1f..4c94113 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2019-08-19 Alan Modra + + * elf64-ppc.c (struct ppc64_elf_obj_tdata): Rename has_gotrel + to has_optrel. + (struct _ppc64_elf_section_data): Likewise. + (ppc64_elf_check_relocs): Set has_optrel for more relocs. + (ppc64_elf_edit_toc): Do ha/lo insn checks in GOT loop rather + than TOC loop. Check PLT16 insns too. + 2019-08-16 H.J. Lu PR ld/24905 diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index abbdfed..60918d9 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1780,8 +1780,9 @@ struct ppc64_elf_obj_tdata instruction not one we handle. */ unsigned int unexpected_toc_insn : 1; - /* Set if got relocs that can be optimised are present in this file. */ - unsigned int has_gotrel : 1; + /* Set if PLT/GOT/TOC relocs that can be optimised are present in + this file. */ + unsigned int has_optrel : 1; }; #define ppc64_elf_tdata(bfd) \ @@ -1982,8 +1983,9 @@ struct _ppc64_elf_section_data /* Flag set when PLTCALL relocs are detected. */ unsigned int has_pltcall:1; - /* Flag set when section has GOT relocations that can be optimised. */ - unsigned int has_gotrel:1; + /* Flag set when section has PLT/GOT/TOC relocations that can be + optimised. */ + unsigned int has_optrel:1; }; #define ppc64_elf_section_data(sec) \ @@ -4573,6 +4575,34 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, sym_addend = 0; break; } + + switch (r_type) + { + case R_PPC64_PLT16_HA: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT16_HA: + case R_PPC64_TOC16_HA: + case R_PPC64_PLT16_LO: + case R_PPC64_PLT16_LO_DS: + case R_PPC64_GOT_TLSLD16_LO: + case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT16_LO: + case R_PPC64_GOT16_LO_DS: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_LO_DS: + case R_PPC64_GOT_PCREL34: + ppc64_elf_tdata (abfd)->has_optrel = 1; + ppc64_elf_section_data (sec)->has_optrel = 1; + break; + default: + break; + } + if (h != NULL) { if (h->type == STT_GNU_IFUNC) @@ -4650,17 +4680,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, sec->has_tls_reloc = 1; goto dogot; + case R_PPC64_GOT16: + case R_PPC64_GOT16_LO: + case R_PPC64_GOT16_HI: case R_PPC64_GOT16_HA: + case R_PPC64_GOT16_DS: case R_PPC64_GOT16_LO_DS: case R_PPC64_GOT_PCREL34: - ppc64_elf_tdata (abfd)->has_gotrel = 1; - ppc64_elf_section_data (sec)->has_gotrel = 1; - /* Fall through. */ - - case R_PPC64_GOT16_DS: - case R_PPC64_GOT16: - case R_PPC64_GOT16_HI: - case R_PPC64_GOT16_LO: dogot: /* This symbol requires a global offset table entry. */ sec->has_toc_reloc = 1; @@ -8604,67 +8630,10 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; bfd_vma val; - enum {no_check, check_lo, check_ha} insn_check; r_type = ELF64_R_TYPE (rel->r_info); switch (r_type) { - default: - insn_check = no_check; - break; - - case R_PPC64_GOT_TLSLD16_HA: - case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TPREL16_HA: - case R_PPC64_GOT_DTPREL16_HA: - case R_PPC64_GOT16_HA: - case R_PPC64_TOC16_HA: - insn_check = check_ha; - break; - - case R_PPC64_GOT_TLSLD16_LO: - case R_PPC64_GOT_TLSGD16_LO: - case R_PPC64_GOT_TPREL16_LO_DS: - case R_PPC64_GOT_DTPREL16_LO_DS: - case R_PPC64_GOT16_LO: - case R_PPC64_GOT16_LO_DS: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_LO_DS: - insn_check = check_lo; - break; - } - - if (insn_check != no_check) - { - bfd_vma off = rel->r_offset & ~3; - unsigned char buf[4]; - unsigned int insn; - - if (!bfd_get_section_contents (ibfd, sec, buf, off, 4)) - { - free (used); - goto error_ret; - } - insn = bfd_get_32 (ibfd, buf); - if (insn_check == check_lo - ? !ok_lo_toc_insn (insn, r_type) - : ((insn & ((0x3f << 26) | 0x1f << 16)) - != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) - { - char str[12]; - - ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1; - sprintf (str, "%#08x", insn); - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: toc optimization is not supported for" - " %s instruction\n"), - ibfd, sec, rel->r_offset & ~3, str); - } - } - - switch (r_type) - { case R_PPC64_TOC16: case R_PPC64_TOC16_LO: case R_PPC64_TOC16_HI: @@ -9014,11 +8983,13 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if (!is_ppc64_elf (ibfd)) continue; - if (!ppc64_elf_tdata (ibfd)->has_gotrel) + if (!ppc64_elf_tdata (ibfd)->has_optrel) continue; sec = ppc64_elf_tdata (ibfd)->got; - got = sec->output_section->vma + sec->output_offset + 0x8000; + got = 0; + if (sec != NULL) + got = sec->output_section->vma + sec->output_offset + 0x8000; local_syms = NULL; symtab_hdr = &elf_symtab_hdr (ibfd); @@ -9026,7 +8997,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) for (sec = ibfd->sections; sec != NULL; sec = sec->next) { if (sec->reloc_count == 0 - || !ppc64_elf_section_data (sec)->has_gotrel + || !ppc64_elf_section_data (sec)->has_optrel || discarded_section (sec)) continue; @@ -9056,10 +9027,67 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) bfd_vma sym_addend, val, pc; unsigned char buf[8]; unsigned int insn; + enum {no_check, check_lo, check_ha} insn_check; r_type = ELF64_R_TYPE (rel->r_info); switch (r_type) { + default: + insn_check = no_check; + break; + + case R_PPC64_PLT16_HA: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT16_HA: + case R_PPC64_TOC16_HA: + insn_check = check_ha; + break; + + case R_PPC64_PLT16_LO: + case R_PPC64_PLT16_LO_DS: + case R_PPC64_GOT_TLSLD16_LO: + case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT16_LO: + case R_PPC64_GOT16_LO_DS: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_LO_DS: + insn_check = check_lo; + break; + } + + if (insn_check != no_check) + { + bfd_vma off = rel->r_offset & ~3; + + if (!bfd_get_section_contents (ibfd, sec, buf, off, 4)) + goto got_error_ret; + + insn = bfd_get_32 (ibfd, buf); + if (insn_check == check_lo + ? !ok_lo_toc_insn (insn, r_type) + : ((insn & ((0x3f << 26) | 0x1f << 16)) + != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) + { + char str[12]; + + ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1; + sprintf (str, "%#08x", insn); + info->callbacks->einfo + /* xgettext:c-format */ + (_("%H: got/toc optimization is not supported for" + " %s instruction\n"), + ibfd, sec, rel->r_offset & ~3, str); + continue; + } + } + + switch (r_type) + { /* Note that we don't delete GOT entries for R_PPC64_GOT16_DS since we'd need a lot more analysis. For starters, the preliminary layout is -- 2.7.4