aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf-ifunc.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2014-12-04 14:19:41 -0800
committerH.J. Lu <hjl.tools@gmail.com>2014-12-04 16:55:39 -0800
commit3972882e52d7199000bb5dfc753a86aa296a567a (patch)
treef12cdd28c4f0d470e3db7b5cb17c82824d5631e6 /bfd/elf-ifunc.c
parent82cf9cb2653b39c426f330854c64028eab4cb65d (diff)
downloadfsf-binutils-gdb-3972882e52d7199000bb5dfc753a86aa296a567a.zip
fsf-binutils-gdb-3972882e52d7199000bb5dfc753a86aa296a567a.tar.gz
fsf-binutils-gdb-3972882e52d7199000bb5dfc753a86aa296a567a.tar.bz2
Add _bfd_elf_ifunc_get_synthetic_symtab
In i386 and x86-64 binaries with ifunc, relocations against .got.plt section may not be in the same order as entries in PLT section. This patch adds _bfd_elf_ifunc_get_synthetic_symtab. It takes a function pointer which returns an array of PLT entry symbol values. It calls the function pointer to get the PLT entry symbol value array indexed by relocation index, instead of calling plt_sym_val on each relocation index. PR binutils/17677 * elf-bfd.h (_bfd_elf_ifunc_get_synthetic_symtab): New prototype. * elf-ifunc.c (_bfd_elf_ifunc_get_synthetic_symtab): New function. * elf32-i386.c (elf_i386_plt_sym_val): Removed. (elf_backend_plt_sym_val): Likewise. (elf_i386_get_plt_sym_val): New. (elf_i386_get_synthetic_symtab): Likewise. (bfd_elf32_get_synthetic_symtab): Likewise. * elf64-x86-64.c (elf_x86_64_plt_sym_val): Removed. (elf_x86_64_plt_sym_val_offset_plt_bnd): Likewise. (elf_backend_plt_sym_val): Likewise. (elf_x86_64_get_plt_sym_val): New. (elf_x86_64_get_synthetic_symtab): Use _bfd_elf_ifunc_get_synthetic_symtab. (bfd_elf64_get_synthetic_symtab): Don't undefine for NaCl.
Diffstat (limited to 'bfd/elf-ifunc.c')
-rw-r--r--bfd/elf-ifunc.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/bfd/elf-ifunc.c b/bfd/elf-ifunc.c
index dd8992b..f5ab47f 100644
--- a/bfd/elf-ifunc.c
+++ b/bfd/elf-ifunc.c
@@ -273,3 +273,128 @@ keep:
return TRUE;
}
+
+/* Similar to _bfd_elf_get_synthetic_symtab, optimized for unsorted PLT
+ entries. PLT is the PLT section. PLT_SYM_VAL is a function pointer
+ which returns an array of PLT entry symbol values. */
+
+long
+_bfd_elf_ifunc_get_synthetic_symtab
+ (bfd *abfd, long symcount ATTRIBUTE_UNUSED,
+ asymbol **syms ATTRIBUTE_UNUSED, long dynsymcount, asymbol **dynsyms,
+ asymbol **ret, asection *plt,
+ bfd_vma *(*get_plt_sym_val) (bfd *, asymbol **, asection *, asection *))
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ asection *relplt;
+ asymbol *s;
+ const char *relplt_name;
+ bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+ arelent *p;
+ long count, i, n;
+ size_t size;
+ Elf_Internal_Shdr *hdr;
+ char *names;
+ bfd_vma *plt_sym_val;
+
+ *ret = NULL;
+
+ if (plt == NULL)
+ return 0;
+
+ if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
+ return 0;
+
+ if (dynsymcount <= 0)
+ return 0;
+
+ relplt_name = bed->relplt_name;
+ if (relplt_name == NULL)
+ relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt";
+ relplt = bfd_get_section_by_name (abfd, relplt_name);
+ if (relplt == NULL)
+ return 0;
+
+ hdr = &elf_section_data (relplt)->this_hdr;
+ if (hdr->sh_link != elf_dynsymtab (abfd)
+ || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA))
+ return 0;
+
+ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+ if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+ return -1;
+
+ count = relplt->size / hdr->sh_entsize;
+ size = count * sizeof (asymbol);
+ p = relplt->relocation;
+ for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
+ {
+ size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+ if (p->addend != 0)
+ {
+#ifdef BFD64
+ size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64);
+#else
+ size += sizeof ("+0x") - 1 + 8;
+#endif
+ }
+ }
+
+ plt_sym_val = get_plt_sym_val (abfd, dynsyms, plt, relplt);
+ if (plt_sym_val == NULL)
+ return -1;
+
+ s = *ret = (asymbol *) bfd_malloc (size);
+ if (s == NULL)
+ {
+ free (plt_sym_val);
+ return -1;
+ }
+
+ names = (char *) (s + count);
+ p = relplt->relocation;
+ n = 0;
+ for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
+ {
+ size_t len;
+ bfd_vma addr;
+
+ addr = plt_sym_val[i];
+ if (addr == (bfd_vma) -1)
+ continue;
+
+ *s = **p->sym_ptr_ptr;
+ /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since
+ we are defining a symbol, ensure one of them is set. */
+ if ((s->flags & BSF_LOCAL) == 0)
+ s->flags |= BSF_GLOBAL;
+ s->flags |= BSF_SYNTHETIC;
+ s->section = plt;
+ s->value = addr - plt->vma;
+ s->name = names;
+ s->udata.p = NULL;
+ len = strlen ((*p->sym_ptr_ptr)->name);
+ memcpy (names, (*p->sym_ptr_ptr)->name, len);
+ names += len;
+ if (p->addend != 0)
+ {
+ char buf[30], *a;
+
+ memcpy (names, "+0x", sizeof ("+0x") - 1);
+ names += sizeof ("+0x") - 1;
+ bfd_sprintf_vma (abfd, buf, p->addend);
+ for (a = buf; *a == '0'; ++a)
+ ;
+ len = strlen (a);
+ memcpy (names, a, len);
+ names += len;
+ }
+ memcpy (names, "@plt", sizeof ("@plt"));
+ names += sizeof ("@plt");
+ ++s, ++n;
+ }
+
+ free (plt_sym_val);
+
+ return n;
+}