From 3972882e52d7199000bb5dfc753a86aa296a567a Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 4 Dec 2014 14:19:41 -0800 Subject: [PATCH] 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. --- bfd/ChangeLog | 19 ++++ bfd/elf-bfd.h | 3 + bfd/elf-ifunc.c | 125 ++++++++++++++++++++++++ bfd/elf32-i386.c | 101 +++++++++++++------ bfd/elf64-x86-64.c | 235 ++++++++++++++------------------------------- 5 files changed, 292 insertions(+), 191 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 5144eb69017..9185b8b40e3 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2014-12-04 H.J. Lu + + 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. + 2014-12-04 Alan Modra PR 17666 diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 43686584e53..3e54ab13dac 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2376,6 +2376,9 @@ extern bfd_boolean _bfd_elf_create_ifunc_sections extern bfd_boolean _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *, struct elf_link_hash_entry *, struct elf_dyn_relocs **, unsigned int, unsigned int, unsigned int); +extern long _bfd_elf_ifunc_get_synthetic_symtab + (bfd *, long, asymbol **, long, asymbol **, asymbol **, asection *, + bfd_vma *(*) (bfd *, asymbol **, asection *, asection *)); extern void elf_append_rela (bfd *, asection *, Elf_Internal_Rela *); extern void elf_append_rel (bfd *, asection *, Elf_Internal_Rela *); diff --git a/bfd/elf-ifunc.c b/bfd/elf-ifunc.c index dd8992bf874..f5ab47f3f73 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; +} diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index dcf37b14a86..2bd7f43ade7 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -5146,46 +5146,87 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, return TRUE; } -/* Return address in section PLT for the Ith GOTPLT relocation, for - relocation REL or (bfd_vma) -1 if it should not be included. */ +/* Return an array of PLT entry symbol values. */ -static bfd_vma -elf_i386_plt_sym_val (bfd_vma i, const asection *plt, const arelent *rel) +static bfd_vma * +elf_i386_get_plt_sym_val (bfd *abfd, asymbol **dynsyms, asection *plt, + asection *relplt) { - bfd *abfd; - const struct elf_i386_backend_data *bed; + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + arelent *p; + long count, i; + bfd_vma *plt_sym_val; bfd_vma plt_offset; + bfd_byte *plt_contents; + const struct elf_i386_backend_data *bed + = get_elf_i386_backend_data (abfd); + Elf_Internal_Shdr *hdr; + + /* Get the .plt section contents. */ + plt_contents = (bfd_byte *) bfd_malloc (plt->size); + if (plt_contents == NULL) + return NULL; + if (!bfd_get_section_contents (abfd, (asection *) plt, + plt_contents, 0, plt->size)) + { +bad_return: + free (plt_contents); + return NULL; + } - /* Only match R_386_JUMP_SLOT and R_386_IRELATIVE. */ - if (rel->howto->type != R_386_JUMP_SLOT - && rel->howto->type != R_386_IRELATIVE) - return (bfd_vma) -1; + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + goto bad_return; - abfd = plt->owner; - bed = get_elf_i386_backend_data (abfd); - plt_offset = bed->plt->plt_entry_size; + hdr = &elf_section_data (relplt)->this_hdr; + count = relplt->size / hdr->sh_entsize; + + plt_sym_val = (bfd_vma *) bfd_malloc (sizeof (bfd_vma) * count); + if (plt_sym_val == NULL) + goto bad_return; - if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU) - return plt->vma + (i + 1) * plt_offset; + for (i = 0; i < count; i++, p++) + plt_sym_val[i] = -1; - while (plt_offset < plt->size) + plt_offset = bed->plt->plt_entry_size; + p = relplt->relocation; + for (i = 0; i < count; i++, p++) { - bfd_vma reloc_offset; - bfd_byte reloc_offset_raw[4]; - - if (!bfd_get_section_contents (abfd, (asection *) plt, - reloc_offset_raw, - plt_offset + bed->plt->plt_reloc_offset, - sizeof (reloc_offset_raw))) - return (bfd_vma) -1; - - reloc_offset = H_GET_32 (abfd, reloc_offset_raw); - if (reloc_offset == i * sizeof (Elf32_External_Rel)) - return plt->vma + plt_offset; + long reloc_index; + + if (p->howto->type != R_386_JUMP_SLOT + && p->howto->type != R_386_IRELATIVE) + continue; + + reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset + + bed->plt->plt_reloc_offset)); + reloc_index /= sizeof (Elf32_External_Rel); + if (reloc_index >= count) + abort (); + plt_sym_val[reloc_index] = plt->vma + plt_offset; plt_offset += bed->plt->plt_entry_size; } - abort (); + free (plt_contents); + + return plt_sym_val; +} + +/* Similar to _bfd_elf_get_synthetic_symtab. */ + +static long +elf_i386_get_synthetic_symtab (bfd *abfd, + long symcount, + asymbol **syms, + long dynsymcount, + asymbol **dynsyms, + asymbol **ret) +{ + asection *plt = bfd_get_section_by_name (abfd, ".plt"); + return _bfd_elf_ifunc_get_synthetic_symtab (abfd, symcount, syms, + dynsymcount, dynsyms, ret, + plt, + elf_i386_get_plt_sym_val); } /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ @@ -5247,6 +5288,7 @@ elf_i386_add_symbol_hook (bfd * abfd, #define bfd_elf32_bfd_link_hash_table_create elf_i386_link_hash_table_create #define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup #define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup +#define bfd_elf32_get_synthetic_symtab elf_i386_get_synthetic_symtab #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol #define elf_backend_relocs_compatible _bfd_elf_relocs_compatible @@ -5266,7 +5308,6 @@ elf_i386_add_symbol_hook (bfd * abfd, #define elf_backend_always_size_sections elf_i386_always_size_sections #define elf_backend_omit_section_dynsym \ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_plt_sym_val elf_i386_plt_sym_val #define elf_backend_hash_symbol elf_i386_hash_symbol #define elf_backend_add_symbol_hook elf_i386_add_symbol_hook diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 566502f23ba..710e7ea8b8e 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -5483,85 +5483,94 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, return TRUE; } -/* Return address in section PLT for the Ith GOTPLT relocation, for - relocation REL or (bfd_vma) -1 if it should not be included. */ +/* Return an array of PLT entry symbol values. */ -static bfd_vma -elf_x86_64_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel) +static bfd_vma * +elf_x86_64_get_plt_sym_val (bfd *abfd, asymbol **dynsyms, asection *plt, + asection *relplt) { - bfd *abfd; - const struct elf_x86_64_backend_data *bed; + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + arelent *p; + long count, i; + bfd_vma *plt_sym_val; bfd_vma plt_offset; + bfd_byte *plt_contents; + const struct elf_x86_64_backend_data *bed; + Elf_Internal_Shdr *hdr; + asection *plt_bnd; - /* Only match R_X86_64_JUMP_SLOT and R_X86_64_IRELATIVE. */ - if (rel->howto->type != R_X86_64_JUMP_SLOT - && rel->howto->type != R_X86_64_IRELATIVE) - return (bfd_vma) -1; - - abfd = plt->owner; - bed = get_elf_x86_64_backend_data (abfd); - plt_offset = bed->plt_entry_size; - - if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU) - return plt->vma + (i + 1) * plt_offset; + /* Get the .plt section contents. PLT passed down may point to the + .plt.bnd section. Make sure that PLT always points to the .plt + section. */ + plt_bnd = bfd_get_section_by_name (abfd, ".plt.bnd"); + if (plt_bnd) + { + if (plt != plt_bnd) + abort (); + plt = bfd_get_section_by_name (abfd, ".plt"); + if (plt == NULL) + abort (); + bed = &elf_x86_64_bnd_arch_bed; + } + else + bed = get_elf_x86_64_backend_data (abfd); - while (plt_offset < plt->size) + plt_contents = (bfd_byte *) bfd_malloc (plt->size); + if (plt_contents == NULL) + return NULL; + if (!bfd_get_section_contents (abfd, (asection *) plt, + plt_contents, 0, plt->size)) { - bfd_vma reloc_index; - bfd_byte reloc_index_raw[4]; - - if (!bfd_get_section_contents (abfd, (asection *) plt, - reloc_index_raw, - plt_offset + bed->plt_reloc_offset, - sizeof (reloc_index_raw))) - return (bfd_vma) -1; - - reloc_index = H_GET_32 (abfd, reloc_index_raw); - if (reloc_index == i) - return plt->vma + plt_offset; - plt_offset += bed->plt_entry_size; +bad_return: + free (plt_contents); + return NULL; } - abort (); -} + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + goto bad_return; -/* Return offset in .plt.bnd section for the Ith GOTPLT relocation with - PLT section, or (bfd_vma) -1 if it should not be included. */ + hdr = &elf_section_data (relplt)->this_hdr; + count = relplt->size / hdr->sh_entsize; -static bfd_vma -elf_x86_64_plt_sym_val_offset_plt_bnd (bfd_vma i, const asection *plt) -{ - const struct elf_x86_64_backend_data *bed = &elf_x86_64_bnd_arch_bed; - bfd *abfd = plt->owner; - bfd_vma plt_offset = bed->plt_entry_size; + plt_sym_val = (bfd_vma *) bfd_malloc (sizeof (bfd_vma) * count); + if (plt_sym_val == NULL) + goto bad_return; - if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU) - return i * sizeof (elf_x86_64_legacy_plt2_entry); + for (i = 0; i < count; i++, p++) + plt_sym_val[i] = -1; - while (plt_offset < plt->size) + plt_offset = bed->plt_entry_size; + p = relplt->relocation; + for (i = 0; i < count; i++, p++) { - bfd_vma reloc_index; - bfd_byte reloc_index_raw[4]; + long reloc_index; - if (!bfd_get_section_contents (abfd, (asection *) plt, - reloc_index_raw, - plt_offset + bed->plt_reloc_offset, - sizeof (reloc_index_raw))) - return (bfd_vma) -1; + if (p->howto->type != R_X86_64_JUMP_SLOT + && p->howto->type != R_X86_64_IRELATIVE) + continue; - reloc_index = H_GET_32 (abfd, reloc_index_raw); - if (reloc_index == i) + reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset + + bed->plt_reloc_offset)); + if (reloc_index >= count) + abort (); + if (plt_bnd) { /* This is the index in .plt section. */ long plt_index = plt_offset / bed->plt_entry_size; - /* Return the offset in .plt.bnd section. */ - return (plt_index - 1) * sizeof (elf_x86_64_legacy_plt2_entry); + /* Store VMA + the offset in .plt.bnd section. */ + plt_sym_val[reloc_index] = + (plt_bnd->vma + + (plt_index - 1) * sizeof (elf_x86_64_legacy_plt2_entry)); } + else + plt_sym_val[reloc_index] = plt->vma + plt_offset; plt_offset += bed->plt_entry_size; } - abort (); + free (plt_contents); + + return plt_sym_val; } /* Similar to _bfd_elf_get_synthetic_symtab, with .plt.bnd section @@ -5575,108 +5584,15 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd, asymbol **dynsyms, asymbol **ret) { - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - asection *relplt; - asymbol *s; - bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); - arelent *p; - long count, i, n; - size_t size; - Elf_Internal_Shdr *hdr; - char *names; - asection *plt, *plt_push; - - plt_push = bfd_get_section_by_name (abfd, ".plt"); - if (plt_push == NULL) - return 0; - - plt = bfd_get_section_by_name (abfd, ".plt.bnd"); - /* Use the generic ELF version if there is no .plt.bnd section. */ + /* Pass the .plt.bnd section to _bfd_elf_ifunc_get_synthetic_symtab + as PLT if it exists. */ + asection *plt = bfd_get_section_by_name (abfd, ".plt.bnd"); if (plt == NULL) - return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms, - dynsymcount, dynsyms, ret); - - *ret = NULL; - - if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) - return 0; - - if (dynsymcount <= 0) - return 0; - - relplt = bfd_get_section_by_name (abfd, ".rela.plt"); - 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) - size += sizeof ("+0x") - 1 + 8 + 8; - } - - s = *ret = (asymbol *) bfd_malloc (size); - if (s == NULL) - return -1; - - names = (char *) (s + count); - p = relplt->relocation; - n = 0; - for (i = 0; i < count; i++, p++) - { - bfd_vma offset; - size_t len; - - if (p->howto->type != R_X86_64_JUMP_SLOT - && p->howto->type != R_X86_64_IRELATIVE) - continue; - - offset = elf_x86_64_plt_sym_val_offset_plt_bnd (i, plt_push); - - *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 = offset; - 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; - } - - return n; + plt = bfd_get_section_by_name (abfd, ".plt"); + return _bfd_elf_ifunc_get_synthetic_symtab (abfd, symcount, syms, + dynsymcount, dynsyms, ret, + plt, + elf_x86_64_get_plt_sym_val); } /* Handle an x86-64 specific section when reading an object file. This @@ -5935,7 +5851,6 @@ static const struct bfd_elf_special_section #define elf_backend_size_dynamic_sections elf_x86_64_size_dynamic_sections #define elf_backend_always_size_sections elf_x86_64_always_size_sections #define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_plt_sym_val elf_x86_64_plt_sym_val #define elf_backend_object_p elf64_x86_64_elf_object_p #define bfd_elf64_mkobject elf_x86_64_mkobject #define bfd_elf64_get_synthetic_symtab elf_x86_64_get_synthetic_symtab @@ -6009,8 +5924,6 @@ static const struct bfd_elf_special_section #include "elf64-target.h" -#undef bfd_elf64_get_synthetic_symtab - /* Native Client support. */ static bfd_boolean -- 2.30.2