From 8dea77f0254d6a76d71092c922e9409ef1b67df4 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 5 Apr 2017 12:47:41 +0930 Subject: [PATCH] PowerPC64le PLT reference counting A fix for ELFv2 ABI garbage-collection. * elf64-ppc.c (ppc64_elf_gc_sweep_hook): Support ELFv2 PLT reference counting. --- bfd/ChangeLog | 5 +++++ bfd/elf64-ppc.c | 41 ++++++++++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 4703b21f8ee..0e4ad30158e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,8 @@ +2017-04-05 Alan Modra + + * elf64-ppc.c (ppc64_elf_gc_sweep_hook): Support ELFv2 PLT + reference counting. + 2017-04-02 Jon Turney (_bfd_XXi_swap_aouthdr_out): For clarity, use defines rather than diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index ae3903289a9..386db9a0dfe 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -6595,7 +6595,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, unsigned long r_symndx; enum elf_ppc64_reloc_type r_type; struct elf_link_hash_entry *h = NULL; - struct plt_entry **plt_list; + struct plt_entry **plt_list = NULL; unsigned char tls_type = 0; r_symndx = ELF64_R_SYM (rel->r_info); @@ -6674,6 +6674,8 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, if (ent->got.refcount > 0) ent->got.refcount -= 1; } + if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1) + plt_list = &h->plt.plist; break; case R_PPC64_PLT16_HA: @@ -6685,7 +6687,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_PPC64_REL14_BRNTAKEN: case R_PPC64_REL14_BRTAKEN: case R_PPC64_REL24: - plt_list = NULL; if (h != NULL) plt_list = &h->plt.plist; else if (local_got_ents != NULL) @@ -6697,21 +6698,39 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) plt_list = local_plt + r_symndx; } - if (plt_list) - { - struct plt_entry *ent; + break; - for (ent = *plt_list; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend) - break; - if (ent != NULL && ent->plt.refcount > 0) - ent->plt.refcount -= 1; - } + case R_PPC64_ADDR64: + case R_PPC64_ADDR16: + case R_PPC64_ADDR16_DS: + case R_PPC64_ADDR16_HA: + case R_PPC64_ADDR16_HI: + case R_PPC64_ADDR16_HIGH: + case R_PPC64_ADDR16_HIGHA: + case R_PPC64_ADDR16_HIGHER: + case R_PPC64_ADDR16_HIGHERA: + case R_PPC64_ADDR16_HIGHEST: + case R_PPC64_ADDR16_HIGHESTA: + case R_PPC64_ADDR16_LO: + case R_PPC64_ADDR16_LO_DS: + if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1 + && rel->r_addend == 0) + plt_list = &h->plt.plist; break; default: break; } + if (plt_list != NULL) + { + struct plt_entry *ent; + + for (ent = *plt_list; ent != NULL; ent = ent->next) + if (ent->addend == rel->r_addend) + break; + if (ent != NULL && ent->plt.refcount > 0) + ent->plt.refcount -= 1; + } } return TRUE; } -- 2.30.2