diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2014-12-04 14:19:41 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2014-12-04 16:55:39 -0800 |
commit | 3972882e52d7199000bb5dfc753a86aa296a567a (patch) | |
tree | f12cdd28c4f0d470e3db7b5cb17c82824d5631e6 /bfd/elf-ifunc.c | |
parent | 82cf9cb2653b39c426f330854c64028eab4cb65d (diff) | |
download | gdb-3972882e52d7199000bb5dfc753a86aa296a567a.zip gdb-3972882e52d7199000bb5dfc753a86aa296a567a.tar.gz 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.c | 125 |
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; +} |