diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 5144eb6901..9185b8b40e 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 43686584e5..3e54ab13da 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 dd8992bf87..f5ab47f3f7 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 dcf37b14a8..2bd7f43ade 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; - /* 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; - - abfd = plt->owner; - bed = get_elf_i386_backend_data (abfd); - plt_offset = bed->plt->plt_entry_size; - - if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU) - return plt->vma + (i + 1) * plt_offset; - - while (plt_offset < plt->size) + /* 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)) { - bfd_vma reloc_offset; - bfd_byte reloc_offset_raw[4]; +bad_return: + free (plt_contents); + return NULL; + } - 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; + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + goto bad_return; - reloc_offset = H_GET_32 (abfd, reloc_offset_raw); - if (reloc_offset == i * sizeof (Elf32_External_Rel)) - return plt->vma + plt_offset; + 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; + + for (i = 0; i < count; i++, p++) + plt_sym_val[i] = -1; + + plt_offset = bed->plt->plt_entry_size; + p = relplt->relocation; + for (i = 0; i < count; i++, p++) + { + 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 566502f23b..710e7ea8b8 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; - - while (plt_offset < plt->size) + /* 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) { - bfd_vma reloc_index; - bfd_byte reloc_index_raw[4]; + 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); - 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; + 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; } - 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