aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2017-04-05 12:47:41 +0930
committerAlan Modra <amodra@gmail.com>2017-04-05 21:59:44 +0930
commit8dea77f0254d6a76d71092c922e9409ef1b67df4 (patch)
tree322f8de080668b489b7caa2f4ac75485c7ce680d
parent4ac40124eef08045bf99ad9f4fcc277961953109 (diff)
downloadgdb-8dea77f0254d6a76d71092c922e9409ef1b67df4.zip
gdb-8dea77f0254d6a76d71092c922e9409ef1b67df4.tar.gz
gdb-8dea77f0254d6a76d71092c922e9409ef1b67df4.tar.bz2
PowerPC64le PLT reference counting
A fix for ELFv2 ABI garbage-collection. * elf64-ppc.c (ppc64_elf_gc_sweep_hook): Support ELFv2 PLT reference counting.
-rw-r--r--bfd/ChangeLog5
-rw-r--r--bfd/elf64-ppc.c41
2 files changed, 35 insertions, 11 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 4703b21..0e4ad30 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,8 @@
+2017-04-05 Alan Modra <amodra@gmail.com>
+
+ * elf64-ppc.c (ppc64_elf_gc_sweep_hook): Support ELFv2 PLT
+ reference counting.
+
2017-04-02 Jon Turney <jon.turney@dronecode.org.uk>
(_bfd_XXi_swap_aouthdr_out): For clarity, use defines rather than
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index ae39032..386db9a 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;
}