From d8045f234d8865a7a7bfce71e81fcbeaf4098a7e Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 30 Apr 2009 15:47:13 +0000 Subject: include/elf 2009-04-30 Nick Clifton * common.h (STT_GNU_IFUNC): Define. elfcpp 2009-04-30 Nick Clifton * (enum STT): Add STT_GNU_IFUNC. gas 2009-04-30 Nick Clifton * config/obj-elf.c (obj_elf_type): Add support for a gnu_indirect_function type. * config/tc-i386.c (tc_i386_fix_adjustable): Do not adjust fixups against indirect function symbols. * doc/as.texinfo (.type): Document the support for the gnu_indirect_function symbol type. * NEWS: Mention the new feature. gas/testsuite 2009-04-30 Nick Clifton * gas/elf/elf.exp: Extend type test to include an ifunc symbol. Provide an alternative test for targets which do not support ifunc symbols. (type.s): Add entry for an ifunc symbol. (type.e): Add ifunc entry to expected symbol dump. (section2.e-armelf): Add entry for ifunc symbol. (type-noifunc.s): New file. (type-noifunc.e): New file. bfd/ 2009-04-30 Nick Clifton * elf-bfd.h (struct bfd_elf_section_data): Add indirect_relocs section pointer. (struct elf_obj_data): Add has_ifunc_symbols boolean. * elf.c (swap_out_syms): Convert BSF_GNU_INDIRECT_FUNCTION flags into a STT_GNU_IFUNC symbol type. (_bfd_elf_is_function_type): Accept STT_GNU_IFUNC as a function type. (_bfd_elf_set_osabi): Set the osasbi field to ELFOSABI_LINUX if the binary contains ifunc symbols. * elfcode.h (elf_slurp_symbol_table): Translate the STT_GNU_IFUNC symbol type into a BSF_GNU_INDIRECT_FUNCTION flag. * elf32-i386.c (is_indirect_function): New function. (elf_i386_check_relocs): Create an ifunc output section. (allocate_dynrelocs): Create dynamic relocs in the ifunc output section if necessary. (elf_i386_relocate_section): Emit a reloc against an ifunc symbol if necessary. (elf_i386_add_symbol_hook): New function. Set the has_ifunc_symbols field of the elf_obj_data structure if an ifunc symbol is encountered. (elf_backend_post_process_headers): Define. (elf_backend_add_symbol_hook): Define. (elf_i386_post_process_headers): Rename to elf_i388_fbsd_post_process_headers. * elf64-x86_64.c (IS_X86_64_PCREL_TYPE): New macro. (is_indirect_function): New function. (elf64_x86_64_check_relocs): Create an ifunc output section. (allocate_dynrelocs): Create dynamic relocs in the ifunc output section if necessary. (elf64_x86_64_relocate_section): Emit a reloc against an ifunc symbol if necessary. (elf_i386_add_symbol_hook): Set the has_ifunc_symbols field of the elf_obj_data structure if an ifunc symbol is encountered. (elf_backend_post_process_headers): Define. * elflink.c (_bfd_elf_adjust_dynamic_symbol): Always create a PLT if we have ifunc symbols to handle. (get_ifunc_reloc_section_name): New function. Computes the name for an ifunc section. (_bfd_elf_make_ifunc_reloc_section): New function. Creates a section to hold ifunc relocs. * syms.c (BSF_GNU_INDIRECT_FUNCTION): Define. (bfd_print_symbol_vandf): Handle ifunc symbols. (bfd_decode_symclass): Likewise. * bfd-in2.h: Regenerate. binutils 2009-04-30 Nick Clifton * readelf.c (dump_relocations): Display a relocation against an ifunc symbol as if it were a function invocation. (get_symbol_type): Handle STT_GNU_IFUNC. ld 2009-04-30 Nick Clifton * NEWS: Mention support for IFUNC symbols. ld/testsuite 2009-04-30 Nick Clifton * ld-ifunc: New directory. * ld-ifunc/ifunc.exp: New file: Run the IFUNC tests. * ld-ifunc/prog.c: New file. * ld-ifunc/lib.c: New file. --- bfd/elf64-x86-64.c | 133 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 41 deletions(-) (limited to 'bfd/elf64-x86-64.c') diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 58be143..b82bcd1 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -161,6 +161,12 @@ static reloc_howto_type x86_64_elf_howto_table[] = FALSE) }; +#define IS_X86_64_PCREL_TYPE(TYPE) \ + ( ((TYPE) == R_X86_64_PC8) \ + || ((TYPE) == R_X86_64_PC16) \ + || ((TYPE) == R_X86_64_PC32) \ + || ((TYPE) == R_X86_64_PC64)) + /* Map BFD relocs to the x86_64 elf relocs. */ struct elf_reloc_map { @@ -977,6 +983,25 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, return TRUE; } +/* Returns true if the hash entry refers to a symbol + marked for indirect handling during reloc processing. */ + +static bfd_boolean +is_indirect_symbol (bfd * abfd, struct elf_link_hash_entry * h) +{ + const struct elf_backend_data * bed; + + if (abfd == NULL || h == NULL) + return FALSE; + + bed = get_elf_backend_data (abfd); + + return h->type == STT_GNU_IFUNC + && (bed->elf_osabi == ELFOSABI_LINUX + /* GNU/Linux is still using the default value 0. */ + || bed->elf_osabi == ELFOSABI_NONE); +} + /* Look through the relocs for a section during the first phase, and calculate needed space in the global offset table, procedure linkage table, and dynamic reloc sections. */ @@ -1003,7 +1028,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, sym_hashes = elf_sym_hashes (abfd); sreloc = NULL; - + rel_end = relocs + sec->reloc_count; for (rel = relocs; rel < rel_end; rel++) { @@ -1259,13 +1284,9 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, may need to keep relocations for symbols satisfied by a dynamic library if we manage to avoid copy relocs for the symbol. */ - if ((info->shared && (sec->flags & SEC_ALLOC) != 0 - && (((r_type != R_X86_64_PC8) - && (r_type != R_X86_64_PC16) - && (r_type != R_X86_64_PC32) - && (r_type != R_X86_64_PC64)) + && (! IS_X86_64_PCREL_TYPE (r_type) || (h != NULL && (! SYMBOLIC_BIND (info, h) || h->root.type == bfd_link_hash_defweak @@ -1293,6 +1314,12 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (sreloc == NULL) return FALSE; + + /* Create the ifunc section, even if we will not encounter an + indirect function symbol. We may not even see one in the input + object file, but we can still encounter them in libraries. */ + (void) _bfd_elf_make_ifunc_reloc_section + (abfd, sec, htab->elf.dynobj, 2); } /* If this is a global symbol, we count the number of @@ -1324,6 +1351,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (p == NULL || p->sec != sec) { bfd_size_type amt = sizeof *p; + p = ((struct elf64_x86_64_dyn_relocs *) bfd_alloc (htab->elf.dynobj, amt)); if (p == NULL) @@ -1336,10 +1364,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, } p->count += 1; - if (r_type == R_X86_64_PC8 - || r_type == R_X86_64_PC16 - || r_type == R_X86_64_PC32 - || r_type == R_X86_64_PC64) + if (IS_X86_64_PCREL_TYPE (r_type)) p->pc_count += 1; } break; @@ -1650,6 +1675,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) struct elf64_x86_64_link_hash_table *htab; struct elf64_x86_64_link_hash_entry *eh; struct elf64_x86_64_dyn_relocs *p; + bfd_boolean use_indirect_section = FALSE; if (h->root.type == bfd_link_hash_indirect) return TRUE; @@ -1728,7 +1754,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) && !info->shared && h->dynindx == -1 && elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE) - h->got.offset = (bfd_vma) -1; + { + h->got.offset = (bfd_vma) -1; + } else if (h->got.refcount > 0) { asection *s; @@ -1827,13 +1855,21 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Make sure undefined weak symbols are output as a dynamic symbol in PIEs. */ else if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } + && ! h->forced_local + && ! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; } } + else if (is_indirect_symbol (info->output_bfd, h) + && h->dynindx == -1 + && ! h->forced_local) + { + if (bfd_elf_link_record_dynamic_symbol (info, h) + && h->dynindx != -1) + use_indirect_section = TRUE; + else + return FALSE; + } else if (ELIMINATE_COPY_RELOCS) { /* For the non-shared case, discard space for relocs against @@ -1850,11 +1886,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } + && ! h->forced_local + && ! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; /* If that succeeded, we know we'll be keeping all the relocs. */ @@ -1872,7 +1906,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) { asection * sreloc; - sreloc = elf_section_data (p->sec)->sreloc; + if (use_indirect_section) + sreloc = elf_section_data (p->sec)->indirect_relocs; + else + sreloc = elf_section_data (p->sec)->sreloc; BFD_ASSERT (sreloc != NULL); @@ -2674,11 +2711,14 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, && (h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak) - && ((r_type != R_X86_64_PC8 - && r_type != R_X86_64_PC16 - && r_type != R_X86_64_PC32 - && r_type != R_X86_64_PC64) - || !SYMBOL_CALLS_LOCAL (info, h))) + && (! IS_X86_64_PCREL_TYPE (r_type) + || ! SYMBOL_CALLS_LOCAL (info, h))) + || (! info->shared + && h != NULL + && h->dynindx != -1 + && ! h->forced_local + && ((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs != NULL + && is_indirect_symbol (output_bfd, h)) || (ELIMINATE_COPY_RELOCS && !info->shared && h != NULL @@ -2718,13 +2758,10 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, become local. */ else if (h != NULL && h->dynindx != -1 - && (r_type == R_X86_64_PC8 - || r_type == R_X86_64_PC16 - || r_type == R_X86_64_PC32 - || r_type == R_X86_64_PC64 - || !info->shared - || !SYMBOLIC_BIND (info, h) - || !h->def_regular)) + && (IS_X86_64_PCREL_TYPE (r_type) + || ! info->shared + || ! SYMBOLIC_BIND (info, h) + || ! h->def_regular)) { outrel.r_info = ELF64_R_INFO (h->dynindx, r_type); outrel.r_addend = rel->r_addend; @@ -2773,8 +2810,17 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } } - sreloc = elf_section_data (input_section)->sreloc; - + if (! info->shared + && h != NULL + && h->dynindx != -1 + && ! h->forced_local + && is_indirect_symbol (output_bfd, h) + && elf_section_data (input_section)->indirect_relocs != NULL + && elf_section_data (input_section)->indirect_relocs->contents != NULL) + sreloc = elf_section_data (input_section)->indirect_relocs; + else + sreloc = elf_section_data (input_section)->sreloc; + BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL); loc = sreloc->contents; @@ -3660,11 +3706,12 @@ elf64_x86_64_section_from_shdr (bfd *abfd, static bfd_boolean elf64_x86_64_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct bfd_link_info *info, Elf_Internal_Sym *sym, const char **namep ATTRIBUTE_UNUSED, flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, bfd_vma *valp) + asection **secp, + bfd_vma *valp) { asection *lcomm; @@ -3687,6 +3734,10 @@ elf64_x86_64_add_symbol_hook (bfd *abfd, *valp = sym->st_size; break; } + + if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE; + return TRUE; } @@ -3914,6 +3965,9 @@ static const struct bfd_elf_special_section #define elf_backend_hash_symbol \ elf64_x86_64_hash_symbol +#undef elf_backend_post_process_headers +#define elf_backend_post_process_headers _bfd_elf_set_osabi + #include "elf64-target.h" /* FreeBSD support. */ @@ -3926,9 +3980,6 @@ static const struct bfd_elf_special_section #undef ELF_OSABI #define ELF_OSABI ELFOSABI_FREEBSD -#undef elf_backend_post_process_headers -#define elf_backend_post_process_headers _bfd_elf_set_osabi - #undef elf64_bed #define elf64_bed elf64_x86_64_fbsd_bed -- cgit v1.1