From cae1fbbb7e3d770702a0d7a5027b46835e6adc13 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Tue, 18 Aug 2015 09:47:59 -0700 Subject: [PATCH] Return reloc_class_ifunc for reloc against IFUNC elf_XXX_reloc_type_class should return reloc_class_ifunc for relocation against STT_GNU_IFUNC symbol. bfd/ PR ld/18841 * elf-bfd.h (elf_link_hash_table): Add dynsym. * elf32-i386.c (elf_i386_reloc_type_class): Return reloc_class_ifunc for relocation against STT_GNU_IFUNC symbol. * elf64-x86-64.c (elf_x86_64_reloc_type_class): Likewise. * elflink.c (_bfd_elf_link_create_dynamic_sections): Set dynsym. (bfd_elf_size_dynsym_hash_dynstr): Use dynsym. (elf_final_link_info): Remove dynsym_sec. (elf_link_output_extsym): Replace dynsym_sec with dynsym. (bfd_elf_final_link): Remove reference to dynsym_sec. Replace dynsym_sec with dynsym. ld/testsuite/ PR ld/18841 * ld-ifunc/ifunc.exp: Add a test for PR ld/18841. * ld-ifunc/pr18841.out: New file. * ld-ifunc/pr18841a.c: Likewise. * ld-ifunc/pr18841b.c: Likewise. --- bfd/ChangeLog | 14 ++++++++++++++ bfd/elf-bfd.h | 1 + bfd/elf32-i386.c | 19 ++++++++++++++++++- bfd/elf64-x86-64.c | 19 ++++++++++++++++++- bfd/elflink.c | 21 ++++++++++----------- ld/testsuite/ChangeLog | 8 ++++++++ ld/testsuite/ld-ifunc/ifunc.exp | 16 ++++++++++++++++ ld/testsuite/ld-ifunc/pr18841.out | 1 + ld/testsuite/ld-ifunc/pr18841a.c | 12 ++++++++++++ ld/testsuite/ld-ifunc/pr18841b.c | 21 +++++++++++++++++++++ 10 files changed, 119 insertions(+), 13 deletions(-) create mode 100644 ld/testsuite/ld-ifunc/pr18841.out create mode 100644 ld/testsuite/ld-ifunc/pr18841a.c create mode 100644 ld/testsuite/ld-ifunc/pr18841b.c diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 14290ab93ea..c0fbbe94015 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -5,6 +5,20 @@ (elfNN_aarch64_gc_sweep_hook): Likewise. (elfNN_aarch64_check_relocs): Likewise. +2015-08-18 H.J. Lu + + PR ld/18841 + * elf-bfd.h (elf_link_hash_table): Add dynsym. + * elf32-i386.c (elf_i386_reloc_type_class): Return + reloc_class_ifunc for relocation against STT_GNU_IFUNC symbol. + * elf64-x86-64.c (elf_x86_64_reloc_type_class): Likewise. + * elflink.c (_bfd_elf_link_create_dynamic_sections): Set dynsym. + (bfd_elf_size_dynsym_hash_dynstr): Use dynsym. + (elf_final_link_info): Remove dynsym_sec. + (elf_link_output_extsym): Replace dynsym_sec with dynsym. + (bfd_elf_final_link): Remove reference to dynsym_sec. Replace + dynsym_sec with dynsym. + 2015-08-18 H.J. Lu * bfd/aoutx.h: Replace shared, executable, relocatable and pie diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index f5a1f453554..e0e372f1c05 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -595,6 +595,7 @@ struct elf_link_hash_table asection *iplt; asection *irelplt; asection *irelifunc; + asection *dynsym; }; /* Look up an entry in an ELF linker hash table. */ diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 507eecf365f..7642d0f9e57 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -4973,10 +4973,27 @@ elf_i386_finish_local_dynamic_symbol (void **slot, void *inf) dynamic linker, before writing them out. */ static enum elf_reloc_type_class -elf_i386_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, +elf_i386_reloc_type_class (const struct bfd_link_info *info, const asection *rel_sec ATTRIBUTE_UNUSED, const Elf_Internal_Rela *rela) { + bfd *abfd = info->output_bfd; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_link_hash_table *htab = elf_hash_table (info); + unsigned long r_symndx = ELF32_R_SYM (rela->r_info); + Elf_Internal_Sym sym; + + if (htab->dynsym == NULL + || !bed->s->swap_symbol_in (abfd, + (htab->dynsym->contents + + r_symndx * sizeof (Elf32_External_Sym)), + 0, &sym)) + abort (); + + /* Check relocation against STT_GNU_IFUNC symbol. */ + if (ELF32_ST_TYPE (sym.st_info) == STT_GNU_IFUNC) + return reloc_class_ifunc; + switch (ELF32_R_TYPE (rela->r_info)) { case R_386_RELATIVE: diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 987ce0e5b77..f15d33ecc59 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -5464,10 +5464,27 @@ elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf) dynamic linker, before writing them out. */ static enum elf_reloc_type_class -elf_x86_64_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, +elf_x86_64_reloc_type_class (const struct bfd_link_info *info, const asection *rel_sec ATTRIBUTE_UNUSED, const Elf_Internal_Rela *rela) { + bfd *abfd = info->output_bfd; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_x86_64_link_hash_table *htab = elf_x86_64_hash_table (info); + unsigned long r_symndx = htab->r_sym (rela->r_info); + Elf_Internal_Sym sym; + + if (htab->elf.dynsym == NULL + || !bed->s->swap_symbol_in (abfd, + (htab->elf.dynsym->contents + + r_symndx * bed->s->sizeof_sym), + 0, &sym)) + abort (); + + /* Check relocation against STT_GNU_IFUNC symbol. */ + if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC) + return reloc_class_ifunc; + switch ((int) ELF32_R_TYPE (rela->r_info)) { case R_X86_64_RELATIVE: diff --git a/bfd/elflink.c b/bfd/elflink.c index e4a9ceded98..7f042711e7f 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -279,6 +279,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) if (s == NULL || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) return FALSE; + elf_hash_table (info)->dynsym = s; s = bfd_make_section_anyway_with_flags (abfd, ".dynstr", flags | SEC_READONLY); @@ -6545,7 +6546,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) the final symbol table, because until then we do not know the correct value to give the symbols. We built the .dynstr section as we went along in elf_link_add_object_symbols. */ - s = bfd_get_linker_section (dynobj, ".dynsym"); + s = elf_hash_table (info)->dynsym; BFD_ASSERT (s != NULL); s->size = dynsymcount * bed->s->sizeof_sym; @@ -7541,8 +7542,6 @@ struct elf_final_link_info bfd *output_bfd; /* Symbol string table. */ struct elf_strtab_hash *symstrtab; - /* .dynsym section. */ - asection *dynsym_sec; /* .hash section. */ asection *hash_sec; /* symbol version section (.gnu.version). */ @@ -9314,7 +9313,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) /* If this symbol should be put in the .dynsym section, then put it there now. We already know the symbol index. We also fill in the entry in the .hash section. */ - if (flinfo->dynsym_sec != NULL + if (elf_hash_table (flinfo->info)->dynsym != NULL && h->dynindx != -1 && elf_hash_table (flinfo->info)->dynamic_sections_created) { @@ -9344,7 +9343,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) } sym.st_name = h->dynstr_index; - esym = flinfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym; + esym = (elf_hash_table (flinfo->info)->dynsym->contents + + h->dynindx * bed->s->sizeof_sym); if (!check_dynsym (flinfo->output_bfd, &sym)) { eoinfo->failed = TRUE; @@ -10868,13 +10868,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) if (! dynamic) { - flinfo.dynsym_sec = NULL; flinfo.hash_sec = NULL; flinfo.symver_sec = NULL; } else { - flinfo.dynsym_sec = bfd_get_linker_section (dynobj, ".dynsym"); flinfo.hash_sec = bfd_get_linker_section (dynobj, ".hash"); /* Note that dynsym_sec can be NULL (on VMS). */ flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version"); @@ -11407,11 +11405,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) symtab_hdr->sh_info = bfd_get_symcount (abfd); if (dynamic - && flinfo.dynsym_sec != NULL - && flinfo.dynsym_sec->output_section != bfd_abs_section_ptr) + && elf_hash_table (info)->dynsym != NULL + && (elf_hash_table (info)->dynsym->output_section + != bfd_abs_section_ptr)) { Elf_Internal_Sym sym; - bfd_byte *dynsym = flinfo.dynsym_sec->contents; + bfd_byte *dynsym = elf_hash_table (info)->dynsym->contents; long last_local = 0; /* Write out the section symbols for the output sections. */ @@ -11484,7 +11483,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) } } - elf_section_data (flinfo.dynsym_sec->output_section)->this_hdr.sh_info = + elf_section_data (elf_hash_table (info)->dynsym->output_section)->this_hdr.sh_info = last_local + 1; } diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 5ae5cd46fe6..b8546d0b42a 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2015-08-18 H.J. Lu + + PR ld/18841 + * ld-ifunc/ifunc.exp: Add a test for PR ld/18841. + * ld-ifunc/pr18841.out: New file. + * ld-ifunc/pr18841a.c: Likewise. + * ld-ifunc/pr18841b.c: Likewise. + 2015-08-13 H.J. Lu PR ld/18801 diff --git a/ld/testsuite/ld-ifunc/ifunc.exp b/ld/testsuite/ld-ifunc/ifunc.exp index 498cb2d2d89..b0f6de07a16 100644 --- a/ld/testsuite/ld-ifunc/ifunc.exp +++ b/ld/testsuite/ld-ifunc/ifunc.exp @@ -472,6 +472,14 @@ run_cc_link_tests [list \ {} \ "libpr18808.so" \ ] \ + [list \ + "Build libpr18841.so" \ + "-shared" \ + "-fPIC -O0 -g" \ + { pr18841b.c } \ + {} \ + "libpr18841.so" \ + ] \ ] run_ld_link_exec_tests [] [list \ @@ -483,4 +491,12 @@ run_ld_link_exec_tests [] [list \ "pr18808" \ "pr18808.out" \ ] \ + [list \ + "Run pr18841" \ + "tmpdir/libpr18841.so" \ + "" \ + { pr18841a.c } \ + "pr18841" \ + "pr18841.out" \ + ] \ ] diff --git a/ld/testsuite/ld-ifunc/pr18841.out b/ld/testsuite/ld-ifunc/pr18841.out new file mode 100644 index 00000000000..d86bac9de59 --- /dev/null +++ b/ld/testsuite/ld-ifunc/pr18841.out @@ -0,0 +1 @@ +OK diff --git a/ld/testsuite/ld-ifunc/pr18841a.c b/ld/testsuite/ld-ifunc/pr18841a.c new file mode 100644 index 00000000000..72179d2dc97 --- /dev/null +++ b/ld/testsuite/ld-ifunc/pr18841a.c @@ -0,0 +1,12 @@ +#include + +extern void test(void); + +void zoo(){} + +int main() +{ + test(); + printf("OK\n"); + return 0; +} diff --git a/ld/testsuite/ld-ifunc/pr18841b.c b/ld/testsuite/ld-ifunc/pr18841b.c new file mode 100644 index 00000000000..1e87469c5f9 --- /dev/null +++ b/ld/testsuite/ld-ifunc/pr18841b.c @@ -0,0 +1,21 @@ +void foo() __attribute__((ifunc("resolve_foo"))); + +static void foo_impl() {} + +extern void abort (void); +void test() +{ + void (*pg)(void) = foo; + if (pg != foo_impl) + abort (); + pg(); +} + +static void* resolve_foo() +{ + extern void zoo(void); + + void (*pz)(void) = zoo; + pz(); + return foo_impl; +} -- 2.30.2