aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAndreas Krebbel <krebbel@linux.vnet.ibm.com>2015-10-16 21:49:43 +0200
committerAndreas Krebbel <krebbel@linux.vnet.ibm.com>2015-10-22 10:13:22 +0200
commitd8ee9e44cc9a986b063a6ea6c91d39217cce65a1 (patch)
treea6614df4e66089c8bf79a78c4272c33dcf3026a2 /bfd
parent01a53584798606cf6329e8a86134cb9b47d1de11 (diff)
downloadgdb-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/ChangeLog6
-rw-r--r--bfd/elf32-s390.c42
-rw-r--r--bfd/elf64-s390.c42
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