PowerPC64le PLT reference counting

A fix for ELFv2 ABI garbage-collection.

	* elf64-ppc.c (ppc64_elf_gc_sweep_hook): Support ELFv2 PLT
	reference counting.
This commit is contained in:
Alan Modra 2017-04-05 12:47:41 +09:30
parent 4ac40124ee
commit 8dea77f025
2 changed files with 35 additions and 11 deletions

View File

@ -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> 2017-04-02 Jon Turney <jon.turney@dronecode.org.uk>
(_bfd_XXi_swap_aouthdr_out): For clarity, use defines rather than (_bfd_XXi_swap_aouthdr_out): For clarity, use defines rather than

View File

@ -6595,7 +6595,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
unsigned long r_symndx; unsigned long r_symndx;
enum elf_ppc64_reloc_type r_type; enum elf_ppc64_reloc_type r_type;
struct elf_link_hash_entry *h = NULL; struct elf_link_hash_entry *h = NULL;
struct plt_entry **plt_list; struct plt_entry **plt_list = NULL;
unsigned char tls_type = 0; unsigned char tls_type = 0;
r_symndx = ELF64_R_SYM (rel->r_info); 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) if (ent->got.refcount > 0)
ent->got.refcount -= 1; ent->got.refcount -= 1;
} }
if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
plt_list = &h->plt.plist;
break; break;
case R_PPC64_PLT16_HA: 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_BRNTAKEN:
case R_PPC64_REL14_BRTAKEN: case R_PPC64_REL14_BRTAKEN:
case R_PPC64_REL24: case R_PPC64_REL24:
plt_list = NULL;
if (h != NULL) if (h != NULL)
plt_list = &h->plt.plist; plt_list = &h->plt.plist;
else if (local_got_ents != NULL) 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) if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
plt_list = local_plt + r_symndx; plt_list = local_plt + r_symndx;
} }
if (plt_list) break;
{
struct plt_entry *ent;
for (ent = *plt_list; ent != NULL; ent = ent->next) case R_PPC64_ADDR64:
if (ent->addend == rel->r_addend) case R_PPC64_ADDR16:
break; case R_PPC64_ADDR16_DS:
if (ent != NULL && ent->plt.refcount > 0) case R_PPC64_ADDR16_HA:
ent->plt.refcount -= 1; 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; break;
default: default:
break; 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; return TRUE;
} }