diff options
author | Andreas Krebbel <krebbel@linux.vnet.ibm.com> | 2015-10-16 21:49:43 +0200 |
---|---|---|
committer | Andreas Krebbel <krebbel@linux.vnet.ibm.com> | 2015-10-22 10:13:22 +0200 |
commit | d8ee9e44cc9a986b063a6ea6c91d39217cce65a1 (patch) | |
tree | a6614df4e66089c8bf79a78c4272c33dcf3026a2 /bfd | |
parent | 01a53584798606cf6329e8a86134cb9b47d1de11 (diff) | |
download | gdb-d8ee9e44cc9a986b063a6ea6c91d39217cce65a1.zip gdb-d8ee9e44cc9a986b063a6ea6c91d39217cce65a1.tar.gz gdb-d8ee9e44cc9a986b063a6ea6c91d39217cce65a1.tar.bz2 |
S/390: ifunc: Fix function pointers to hidden ifunc symbols.
bfd/ChangeLog:
* elf32-s390.c (elf_s390_adjust_dynamic_symbol): Set the PLT
reference counters for local IFUNC calls.
* elf64-s390.c (elf_s390_adjust_dynamic_symbol): Likewise.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 6 | ||||
-rw-r--r-- | bfd/elf32-s390.c | 42 | ||||
-rw-r--r-- | bfd/elf64-s390.c | 42 |
3 files changed, 88 insertions, 2 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 86a8ce8..b7f42cd 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,11 @@ 2015-10-22 Andreas Krebbel <krebbel@linux.vnet.ibm.com> + * elf32-s390.c (elf_s390_adjust_dynamic_symbol): Set the PLT + reference counters for local IFUNC calls. + * elf64-s390.c (elf_s390_adjust_dynamic_symbol): Likewise. + +2015-10-22 Andreas Krebbel <krebbel@linux.vnet.ibm.com> + * elf32-s390.c (elf_s390_check_relocs): Fallthrough to the PLT slot allocating code for GOTOFF relocs on ifunc symbols. (elf_s390_gc_sweep_hook): Decrement plt refcount for GOTOFF relocs diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c index fcdade0..d154fb7 100644 --- a/bfd/elf32-s390.c +++ b/bfd/elf32-s390.c @@ -1658,7 +1658,47 @@ elf_s390_adjust_dynamic_symbol (struct bfd_link_info *info, /* STT_GNU_IFUNC symbol must go through PLT. */ if (s390_is_ifunc_symbol_p (h)) - return TRUE; + { + /* All local STT_GNU_IFUNC references must be treated as local + calls via local PLT. */ + if (h->ref_regular && SYMBOL_CALLS_LOCAL (info, h)) + { + bfd_size_type pc_count = 0, count = 0; + struct elf_dyn_relocs **pp; + struct elf_s390_link_hash_entry *eh; + struct elf_dyn_relocs *p; + + eh = (struct elf_s390_link_hash_entry *) h; + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + pc_count += p->pc_count; + p->count -= p->pc_count; + p->pc_count = 0; + count += p->count; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + + if (pc_count || count) + { + h->needs_plt = 1; + h->non_got_ref = 1; + if (h->plt.refcount <= 0) + h->plt.refcount = 1; + else + h->plt.refcount += 1; + } + } + + if (h->plt.refcount <= 0) + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + return TRUE; + } /* If this is a function, put it in the procedure linkage table. We will fill in the contents of the procedure linkage table later diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c index 588892f..2b62271 100644 --- a/bfd/elf64-s390.c +++ b/bfd/elf64-s390.c @@ -1592,7 +1592,47 @@ elf_s390_adjust_dynamic_symbol (struct bfd_link_info *info, /* STT_GNU_IFUNC symbol must go through PLT. */ if (s390_is_ifunc_symbol_p (h)) - return TRUE; + { + /* All local STT_GNU_IFUNC references must be treated as local + calls via local PLT. */ + if (h->ref_regular && SYMBOL_CALLS_LOCAL (info, h)) + { + bfd_size_type pc_count = 0, count = 0; + struct elf_dyn_relocs **pp; + struct elf_s390_link_hash_entry *eh; + struct elf_dyn_relocs *p; + + eh = (struct elf_s390_link_hash_entry *) h; + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + pc_count += p->pc_count; + p->count -= p->pc_count; + p->pc_count = 0; + count += p->count; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + + if (pc_count || count) + { + h->needs_plt = 1; + h->non_got_ref = 1; + if (h->plt.refcount <= 0) + h->plt.refcount = 1; + else + h->plt.refcount += 1; + } + } + + if (h->plt.refcount <= 0) + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + return TRUE; + } /* If this is a function, put it in the procedure linkage table. We will fill in the contents of the procedure linkage table later |