PowerPC ifunc with local symbols
This fixes some cases where the linker would incorrectly error on plt relocs to local ifunc symbols. I've also tidied plt and ifunc handling for ppc64, where check_relocs was allowing for the possibility of plt calls via addr14/addr24 relocs but relocate_section was not. * elf32-ppc.c (ppc_elf_check_relocs): Don't error on local ifunc plt call. Wrap long lines. (ppc_elf_relocate_section): Wrap long lines. * elf64-ppc.c (ppc64_elf_check_relocs): Don't error on local ifunc plt calls. Move __tls_get_addr checks later. Don't create plt for addr14/addr24 relocs. (ppc64_elf_gc_sweep_hook): Adjust to suit check_relocs changes. (ppc64_elf_relocate_section): Correct local ifunc handling for PLT64, PLT32 and PLT16 relocs.
This commit is contained in:
parent
c20f6f63ed
commit
cbf9597294
|
@ -1,3 +1,15 @@
|
||||||
|
2015-12-07 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
* elf32-ppc.c (ppc_elf_check_relocs): Don't error on local ifunc
|
||||||
|
plt call. Wrap long lines.
|
||||||
|
(ppc_elf_relocate_section): Wrap long lines.
|
||||||
|
* elf64-ppc.c (ppc64_elf_check_relocs): Don't error on local ifunc
|
||||||
|
plt calls. Move __tls_get_addr checks later. Don't create plt
|
||||||
|
for addr14/addr24 relocs.
|
||||||
|
(ppc64_elf_gc_sweep_hook): Adjust to suit check_relocs changes.
|
||||||
|
(ppc64_elf_relocate_section): Correct local ifunc handling for
|
||||||
|
PLT64, PLT32 and PLT16 relocs.
|
||||||
|
|
||||||
2015-12-07 Alan Modra <amodra@gmail.com>
|
2015-12-07 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
PR19323
|
PR19323
|
||||||
|
|
|
@ -3948,6 +3948,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||||
enum elf_ppc_reloc_type r_type;
|
enum elf_ppc_reloc_type r_type;
|
||||||
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
||||||
int tls_type;
|
int tls_type;
|
||||||
|
struct plt_entry **ifunc;
|
||||||
|
|
||||||
r_symndx = ELF32_R_SYM (rel->r_info);
|
r_symndx = ELF32_R_SYM (rel->r_info);
|
||||||
if (r_symndx < symtab_hdr->sh_info)
|
if (r_symndx < symtab_hdr->sh_info)
|
||||||
|
@ -3980,6 +3981,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||||
|
|
||||||
tls_type = 0;
|
tls_type = 0;
|
||||||
r_type = ELF32_R_TYPE (rel->r_info);
|
r_type = ELF32_R_TYPE (rel->r_info);
|
||||||
|
ifunc = NULL;
|
||||||
if (h == NULL && !htab->is_vxworks)
|
if (h == NULL && !htab->is_vxworks)
|
||||||
{
|
{
|
||||||
Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
|
Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
|
||||||
|
@ -3989,8 +3991,6 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||||
|
|
||||||
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
|
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
|
||||||
{
|
{
|
||||||
struct plt_entry **ifunc;
|
|
||||||
|
|
||||||
/* Set PLT_IFUNC flag for this sym, no GOT entry yet. */
|
/* Set PLT_IFUNC flag for this sym, no GOT entry yet. */
|
||||||
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
|
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
|
||||||
PLT_IFUNC);
|
PLT_IFUNC);
|
||||||
|
@ -4224,21 +4224,20 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf (stderr, "Reloc requires a PLT entry\n");
|
fprintf (stderr, "Reloc requires a PLT entry\n");
|
||||||
#endif
|
#endif
|
||||||
/* This symbol requires a procedure linkage table entry. We
|
/* This symbol requires a procedure linkage table entry. */
|
||||||
actually build the entry in finish_dynamic_symbol,
|
|
||||||
because this might be a case of linking PIC code without
|
|
||||||
linking in any dynamic objects, in which case we don't
|
|
||||||
need to generate a procedure linkage table after all. */
|
|
||||||
|
|
||||||
if (h == NULL)
|
if (h == NULL)
|
||||||
{
|
{
|
||||||
/* It does not make sense to have a procedure linkage
|
if (ifunc == NULL)
|
||||||
table entry for a local symbol. */
|
{
|
||||||
info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"),
|
/* It does not make sense to have a procedure linkage
|
||||||
abfd, sec, rel->r_offset,
|
table entry for a non-ifunc local symbol. */
|
||||||
ppc_elf_howto_table[r_type]->name);
|
info->callbacks->einfo
|
||||||
bfd_set_error (bfd_error_bad_value);
|
(_("%P: %H: %s reloc against local symbol\n"),
|
||||||
return FALSE;
|
abfd, sec, rel->r_offset,
|
||||||
|
ppc_elf_howto_table[r_type]->name);
|
||||||
|
bfd_set_error (bfd_error_bad_value);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4316,9 +4315,10 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||||
{
|
{
|
||||||
if (bfd_link_pic (info))
|
if (bfd_link_pic (info))
|
||||||
{
|
{
|
||||||
info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
|
info->callbacks->einfo
|
||||||
abfd, sec, rel->r_offset,
|
(_("%P: %H: @local call to ifunc %s\n"),
|
||||||
h->root.root.string);
|
abfd, sec, rel->r_offset,
|
||||||
|
h->root.root.string);
|
||||||
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -8968,8 +8968,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||||
case R_PPC_PLTREL24:
|
case R_PPC_PLTREL24:
|
||||||
if (h != NULL && ifunc == NULL)
|
if (h != NULL && ifunc == NULL)
|
||||||
{
|
{
|
||||||
struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
|
struct plt_entry *ent;
|
||||||
bfd_link_pic (info) ? addend : 0);
|
|
||||||
|
ent = find_plt_ent (&h->plt.plist, got2,
|
||||||
|
bfd_link_pic (info) ? addend : 0);
|
||||||
if (ent == NULL
|
if (ent == NULL
|
||||||
|| htab->plt == NULL)
|
|| htab->plt == NULL)
|
||||||
{
|
{
|
||||||
|
|
198
bfd/elf64-ppc.c
198
bfd/elf64-ppc.c
|
@ -5340,7 +5340,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
enum elf_ppc64_reloc_type r_type;
|
enum elf_ppc64_reloc_type r_type;
|
||||||
int tls_type;
|
int tls_type;
|
||||||
struct _ppc64_elf_section_data *ppc64_sec;
|
struct _ppc64_elf_section_data *ppc64_sec;
|
||||||
struct plt_entry **ifunc;
|
struct plt_entry **ifunc, **plt_list;
|
||||||
|
|
||||||
r_symndx = ELF64_R_SYM (rel->r_info);
|
r_symndx = ELF64_R_SYM (rel->r_info);
|
||||||
if (r_symndx < symtab_hdr->sh_info)
|
if (r_symndx < symtab_hdr->sh_info)
|
||||||
|
@ -5383,28 +5383,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r_type = ELF64_R_TYPE (rel->r_info);
|
r_type = ELF64_R_TYPE (rel->r_info);
|
||||||
if (is_branch_reloc (r_type))
|
|
||||||
{
|
|
||||||
if (h != NULL && (h == tga || h == dottga))
|
|
||||||
{
|
|
||||||
if (rel != relocs
|
|
||||||
&& (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
|
|
||||||
|| ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
|
|
||||||
/* We have a new-style __tls_get_addr call with a marker
|
|
||||||
reloc. */
|
|
||||||
;
|
|
||||||
else
|
|
||||||
/* Mark this section as having an old-style call. */
|
|
||||||
sec->has_tls_get_addr_call = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* STT_GNU_IFUNC symbols must have a PLT entry. */
|
|
||||||
if (ifunc != NULL
|
|
||||||
&& !update_plt_info (abfd, ifunc, rel->r_addend))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (r_type)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
case R_PPC64_TLSGD:
|
case R_PPC64_TLSGD:
|
||||||
|
@ -5516,27 +5496,29 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
case R_PPC64_PLT16_LO:
|
case R_PPC64_PLT16_LO:
|
||||||
case R_PPC64_PLT32:
|
case R_PPC64_PLT32:
|
||||||
case R_PPC64_PLT64:
|
case R_PPC64_PLT64:
|
||||||
/* This symbol requires a procedure linkage table entry. We
|
/* This symbol requires a procedure linkage table entry. */
|
||||||
actually build the entry in adjust_dynamic_symbol,
|
plt_list = ifunc;
|
||||||
because this might be a case of linking PIC code without
|
if (h != NULL)
|
||||||
linking in any dynamic objects, in which case we don't
|
|
||||||
need to generate a procedure linkage table after all. */
|
|
||||||
if (h == NULL)
|
|
||||||
{
|
{
|
||||||
/* It does not make sense to have a procedure linkage
|
|
||||||
table entry for a local symbol. */
|
|
||||||
bfd_set_error (bfd_error_bad_value);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
|
|
||||||
return FALSE;
|
|
||||||
h->needs_plt = 1;
|
h->needs_plt = 1;
|
||||||
if (h->root.root.string[0] == '.'
|
if (h->root.root.string[0] == '.'
|
||||||
&& h->root.root.string[1] != '\0')
|
&& h->root.root.string[1] != '\0')
|
||||||
((struct ppc_link_hash_entry *) h)->is_func = 1;
|
((struct ppc_link_hash_entry *) h)->is_func = 1;
|
||||||
|
plt_list = &h->plt.plist;
|
||||||
}
|
}
|
||||||
|
if (plt_list == NULL)
|
||||||
|
{
|
||||||
|
/* It does not make sense to have a procedure linkage
|
||||||
|
table entry for a non-ifunc local symbol. */
|
||||||
|
info->callbacks->einfo
|
||||||
|
(_("%P: %H: %s reloc against local symbol\n"),
|
||||||
|
abfd, sec, rel->r_offset,
|
||||||
|
ppc64_elf_howto_table[r_type]->name);
|
||||||
|
bfd_set_error (bfd_error_bad_value);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!update_plt_info (abfd, plt_list, rel->r_addend))
|
||||||
|
return FALSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* The following relocations don't need to propagate the
|
/* The following relocations don't need to propagate the
|
||||||
|
@ -5649,21 +5631,43 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
/* Fall through. */
|
/* Fall through. */
|
||||||
|
|
||||||
case R_PPC64_REL24:
|
case R_PPC64_REL24:
|
||||||
if (h != NULL && ifunc == NULL)
|
plt_list = ifunc;
|
||||||
|
if (h != NULL)
|
||||||
{
|
{
|
||||||
/* We may need a .plt entry if the function this reloc
|
|
||||||
refers to is in a shared lib. */
|
|
||||||
if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
|
|
||||||
return FALSE;
|
|
||||||
h->needs_plt = 1;
|
h->needs_plt = 1;
|
||||||
if (h->root.root.string[0] == '.'
|
if (h->root.root.string[0] == '.'
|
||||||
&& h->root.root.string[1] != '\0')
|
&& h->root.root.string[1] != '\0')
|
||||||
((struct ppc_link_hash_entry *) h)->is_func = 1;
|
((struct ppc_link_hash_entry *) h)->is_func = 1;
|
||||||
|
|
||||||
if (h == tga || h == dottga)
|
if (h == tga || h == dottga)
|
||||||
sec->has_tls_reloc = 1;
|
{
|
||||||
|
sec->has_tls_reloc = 1;
|
||||||
|
if (rel != relocs
|
||||||
|
&& (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
|
||||||
|
|| ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
|
||||||
|
/* We have a new-style __tls_get_addr call with
|
||||||
|
a marker reloc. */
|
||||||
|
;
|
||||||
|
else
|
||||||
|
/* Mark this section as having an old-style call. */
|
||||||
|
sec->has_tls_get_addr_call = 1;
|
||||||
|
}
|
||||||
|
plt_list = &h->plt.plist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We may need a .plt entry if the function this reloc
|
||||||
|
refers to is in a shared lib. */
|
||||||
|
if (plt_list
|
||||||
|
&& !update_plt_info (abfd, plt_list, rel->r_addend))
|
||||||
|
return FALSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case R_PPC64_ADDR14:
|
||||||
|
case R_PPC64_ADDR14_BRNTAKEN:
|
||||||
|
case R_PPC64_ADDR14_BRTAKEN:
|
||||||
|
case R_PPC64_ADDR24:
|
||||||
|
goto dodyn;
|
||||||
|
|
||||||
case R_PPC64_TPREL64:
|
case R_PPC64_TPREL64:
|
||||||
tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
|
tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
|
||||||
if (bfd_link_pic (info))
|
if (bfd_link_pic (info))
|
||||||
|
@ -5806,10 +5810,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
case R_PPC64_REL30:
|
case R_PPC64_REL30:
|
||||||
case R_PPC64_REL32:
|
case R_PPC64_REL32:
|
||||||
case R_PPC64_REL64:
|
case R_PPC64_REL64:
|
||||||
case R_PPC64_ADDR14:
|
|
||||||
case R_PPC64_ADDR14_BRNTAKEN:
|
|
||||||
case R_PPC64_ADDR14_BRTAKEN:
|
|
||||||
case R_PPC64_ADDR24:
|
|
||||||
case R_PPC64_ADDR32:
|
case R_PPC64_ADDR32:
|
||||||
case R_PPC64_UADDR16:
|
case R_PPC64_UADDR16:
|
||||||
case R_PPC64_UADDR32:
|
case R_PPC64_UADDR32:
|
||||||
|
@ -6505,6 +6505,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;
|
||||||
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);
|
||||||
|
@ -6528,38 +6529,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_branch_reloc (r_type))
|
|
||||||
{
|
|
||||||
struct plt_entry **ifunc = NULL;
|
|
||||||
if (h != NULL)
|
|
||||||
{
|
|
||||||
if (h->type == STT_GNU_IFUNC)
|
|
||||||
ifunc = &h->plt.plist;
|
|
||||||
}
|
|
||||||
else if (local_got_ents != NULL)
|
|
||||||
{
|
|
||||||
struct plt_entry **local_plt = (struct plt_entry **)
|
|
||||||
(local_got_ents + symtab_hdr->sh_info);
|
|
||||||
unsigned char *local_got_tls_masks = (unsigned char *)
|
|
||||||
(local_plt + symtab_hdr->sh_info);
|
|
||||||
if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
|
|
||||||
ifunc = local_plt + r_symndx;
|
|
||||||
}
|
|
||||||
if (ifunc != NULL)
|
|
||||||
{
|
|
||||||
struct plt_entry *ent;
|
|
||||||
|
|
||||||
for (ent = *ifunc; ent != NULL; ent = ent->next)
|
|
||||||
if (ent->addend == rel->r_addend)
|
|
||||||
break;
|
|
||||||
if (ent == NULL)
|
|
||||||
abort ();
|
|
||||||
if (ent->plt.refcount > 0)
|
|
||||||
ent->plt.refcount -= 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (r_type)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
case R_PPC64_GOT_TLSLD16:
|
case R_PPC64_GOT_TLSLD16:
|
||||||
|
@ -6626,11 +6595,23 @@ 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;
|
||||||
|
else if (local_got_ents != NULL)
|
||||||
|
{
|
||||||
|
struct plt_entry **local_plt = (struct plt_entry **)
|
||||||
|
(local_got_ents + symtab_hdr->sh_info);
|
||||||
|
unsigned char *local_got_tls_masks = (unsigned char *)
|
||||||
|
(local_plt + symtab_hdr->sh_info);
|
||||||
|
if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
|
||||||
|
plt_list = local_plt + r_symndx;
|
||||||
|
}
|
||||||
|
if (plt_list)
|
||||||
{
|
{
|
||||||
struct plt_entry *ent;
|
struct plt_entry *ent;
|
||||||
|
|
||||||
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
|
for (ent = *plt_list; ent != NULL; ent = ent->next)
|
||||||
if (ent->addend == rel->r_addend)
|
if (ent->addend == rel->r_addend)
|
||||||
break;
|
break;
|
||||||
if (ent != NULL && ent->plt.refcount > 0)
|
if (ent != NULL && ent->plt.refcount > 0)
|
||||||
|
@ -14485,30 +14466,43 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
||||||
case R_PPC64_PLT64:
|
case R_PPC64_PLT64:
|
||||||
/* Relocation is to the entry for this symbol in the
|
/* Relocation is to the entry for this symbol in the
|
||||||
procedure linkage table. */
|
procedure linkage table. */
|
||||||
|
{
|
||||||
|
struct plt_entry **plt_list = NULL;
|
||||||
|
if (h != NULL)
|
||||||
|
plt_list = &h->elf.plt.plist;
|
||||||
|
else if (local_got_ents != NULL)
|
||||||
|
{
|
||||||
|
struct plt_entry **local_plt = (struct plt_entry **)
|
||||||
|
(local_got_ents + symtab_hdr->sh_info);
|
||||||
|
unsigned char *local_got_tls_masks = (unsigned char *)
|
||||||
|
(local_plt + symtab_hdr->sh_info);
|
||||||
|
if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
|
||||||
|
plt_list = local_plt + r_symndx;
|
||||||
|
}
|
||||||
|
if (plt_list)
|
||||||
|
{
|
||||||
|
struct plt_entry *ent;
|
||||||
|
|
||||||
/* Resolve a PLT reloc against a local symbol directly,
|
for (ent = *plt_list; ent != NULL; ent = ent->next)
|
||||||
without using the procedure linkage table. */
|
if (ent->plt.offset != (bfd_vma) -1
|
||||||
if (h == NULL)
|
&& ent->addend == orig_rel.r_addend)
|
||||||
break;
|
{
|
||||||
|
asection *plt;
|
||||||
|
|
||||||
/* It's possible that we didn't make a PLT entry for this
|
plt = htab->elf.splt;
|
||||||
symbol. This happens when statically linking PIC code,
|
if (!htab->elf.dynamic_sections_created
|
||||||
or when using -Bsymbolic. Go find a match if there is a
|
|| h == NULL
|
||||||
PLT entry. */
|
|| h->elf.dynindx == -1)
|
||||||
if (htab->elf.splt != NULL)
|
plt = htab->elf.iplt;
|
||||||
{
|
relocation = (plt->output_section->vma
|
||||||
struct plt_entry *ent;
|
+ plt->output_offset
|
||||||
for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
|
+ ent->plt.offset);
|
||||||
if (ent->plt.offset != (bfd_vma) -1
|
addend = 0;
|
||||||
&& ent->addend == orig_rel.r_addend)
|
unresolved_reloc = FALSE;
|
||||||
{
|
break;
|
||||||
relocation = (htab->elf.splt->output_section->vma
|
}
|
||||||
+ htab->elf.splt->output_offset
|
}
|
||||||
+ ent->plt.offset);
|
}
|
||||||
unresolved_reloc = FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_PPC64_TOC:
|
case R_PPC64_TOC:
|
||||||
|
|
Loading…
Reference in New Issue