This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [RFC, PATCH] aarch64: Add support for GNU indirect functions.
- From: Will Newton <will dot newton at linaro dot org>
- To: "binutils at sourceware dot org" <binutils at sourceware dot org>
- Cc: Patch Tracking <patches at linaro dot org>
- Date: Tue, 28 May 2013 14:36:49 +0100
- Subject: Re: [RFC, PATCH] aarch64: Add support for GNU indirect functions.
- References: <519614BA dot 8000004 at linaro dot org>
Hi all,
The reloc number has now been officially assigned as 1032 so the below
patch should be able to go in as is.
On 17 May 2013 12:30, Will Newton <will.newton@linaro.org> wrote:
>
> PLEASE DO NOT APPLY THIS PATCH!
>
> The relocation number has not yet been assigned for R_AARCH64_IRELATIVE so
> this patch is not ready to go in yet. However the code is complete so I would
> really like to get some review feedback if possible.
>
> Add support for STT_GNU_IFUNC symbols to the AArch64 bfd backend. The tests
> are ported from the ld-ifunc tests but are enabled for cross builds so can
> be run easily without hardware or a simulator.
>
> bfd/ChangeLog:
>
> 2013-05-17 Will Newton <will.newton@linaro.org>
>
> * configure.in: Build elf-ifunc.o for AArch64.
> * elf64-aarch64.c: Include objalloc.h.
> (elf64_aarch64_howto_dynrelocs): Add R_AARCH64_IRELATIVE howto.
> (struct elf64_aarch64_link_hash_table): Add members for handling
> R_AARCH64_IRELATIVE relocations.
> (elf_aarch64_local_htab_hash): New function.
> (elf_aarch64_local_htab_eq): New function.
> (elf_aarch64_get_local_sym_hash): New function.
> (elf64_aarch64_link_hash_table_create): Initialize local STT_GNU_IFUNC
> symbol hash.
> (elf64_aarch64_hash_table_free): Free local STT_GNU_IFUNC symbol hash.
> (elf64_aarch64_final_link_relocate): Add sym argument. Add support
> for handling STT_GNU_IFUNC symbols.
> (elf64_aarch64_gc_sweep_hook): Add support for garbage collecting
> references to STT_GNU_IFUNC symbols.
> (elf64_aarch64_adjust_dynamic_symbol): Add support for handling
> STT_GNU_IFUNC symbols.
> (elf64_aarch64_check_relocs): Add support for handling STT_GNU_IFUNC
> symbols. Ensure we don't increase plt.refcount from -1 to 0.
> (elf64_aarch64_post_process_headers): Call _bfd_elf_set_osabi.
> (elf64_aarch64_is_function_type): Remove function.
> (elf64_aarch64_allocate_dynrelocs): Call
> _bfd_elf_allocate_ifunc_dyn_relocs for STT_GNU_IFUNC symbols.
> (elf_aarch64_allocate_local_dynrelocs): New function.
> (elf64_aarch64_size_dynamic_sections): Call
> elf_aarch64_allocate_local_dynrelocs. Initialize next_irelative_index.
> (elf64_aarch64_create_small_pltn_entry): Add info argument.
> Add support for creating .iplt entries for STT_GNU_IFUNC symbols.
> (elf64_aarch64_finish_dynamic_symbol): Add support for handling
> STT_GNU_IFUNC symbols and .iplt.
> (elf_aarch64_finish_local_dynamic_symbol): New function.
> (elf64_aarch64_finish_dynamic_sections): Call
> elf_aarch64_finish_local_dynamic_symbol.
> (elf64_aarch64_add_symbol_hook): New function.
>
> include/elf/ChangeLog:
>
> 2013-05-17 Will Newton <will.newton@linaro.org>
>
> * aarch64.h: Add R_AARCH64_IRELATIVE reloc.
>
> ld/testsuite/ChangeLog:
>
> 2013-05-17 Will Newton <will.newton@linaro.org>
>
> * ld-ifunc/ifunc.exp: Enable ifunc tests for AArch64.
> * ld-aarch64/aarch64-elf.exp: Add ifunc tests.
> * ld-aarch64/ifunc-1-local.d: New file.
> * ld-aarch64/ifunc-1-local.s: Likewise.
> * ld-aarch64/ifunc-1.d: Likewise.
> * ld-aarch64/ifunc-1.s: Likewise.
> * ld-aarch64/ifunc-10.d: Likewise.
> * ld-aarch64/ifunc-10.s: Likewise.
> * ld-aarch64/ifunc-11.d: Likewise.
> * ld-aarch64/ifunc-11.s: Likewise.
> * ld-aarch64/ifunc-12.d: Likewise.
> * ld-aarch64/ifunc-12.s: Likewise.
> * ld-aarch64/ifunc-13.d: Likewise.
> * ld-aarch64/ifunc-13a.s: Likewise.
> * ld-aarch64/ifunc-13b.s: Likewise.
> * ld-aarch64/ifunc-14a.d: Likewise.
> * ld-aarch64/ifunc-14a.s: Likewise.
> * ld-aarch64/ifunc-14b.d: Likewise.
> * ld-aarch64/ifunc-14b.s: Likewise.
> * ld-aarch64/ifunc-14c.d: Likewise.
> * ld-aarch64/ifunc-14c.s: Likewise.
> * ld-aarch64/ifunc-14d.d: Likewise.
> * ld-aarch64/ifunc-14e.d: Likewise.
> * ld-aarch64/ifunc-14f.d: Likewise.
> * ld-aarch64/ifunc-15.d: Likewise.
> * ld-aarch64/ifunc-15.s: Likewise.
> * ld-aarch64/ifunc-16.d: Likewise.
> * ld-aarch64/ifunc-16.s: Likewise.
> * ld-aarch64/ifunc-17a.d: Likewise.
> * ld-aarch64/ifunc-17a.s: Likewise.
> * ld-aarch64/ifunc-17b.d: Likewise.
> * ld-aarch64/ifunc-17b.s: Likewise.
> * ld-aarch64/ifunc-18a.d: Likewise.
> * ld-aarch64/ifunc-18a.s: Likewise.
> * ld-aarch64/ifunc-18b.d: Likewise.
> * ld-aarch64/ifunc-18b.s: Likewise.
> * ld-aarch64/ifunc-19a.d: Likewise.
> * ld-aarch64/ifunc-19a.s: Likewise.
> * ld-aarch64/ifunc-19b.d: Likewise.
> * ld-aarch64/ifunc-19b.s: Likewise.
> * ld-aarch64/ifunc-2-local.d: Likewise.
> * ld-aarch64/ifunc-2-local.s: Likewise.
> * ld-aarch64/ifunc-2.d: Likewise.
> * ld-aarch64/ifunc-2.s: Likewise.
> * ld-aarch64/ifunc-20.d: Likewise.
> * ld-aarch64/ifunc-20.s: Likewise.
> * ld-aarch64/ifunc-3.s: Likewise.
> * ld-aarch64/ifunc-3a.d: Likewise.
> * ld-aarch64/ifunc-3b.d: Likewise.
> * ld-aarch64/ifunc-4.d: Likewise.
> * ld-aarch64/ifunc-4.s: Likewise.
> * ld-aarch64/ifunc-4a.d: Likewise.
> * ld-aarch64/ifunc-5-local.s: Likewise.
> * ld-aarch64/ifunc-5.s: Likewise.
> * ld-aarch64/ifunc-5a-local.d: Likewise.
> * ld-aarch64/ifunc-5a.d: Likewise.
> * ld-aarch64/ifunc-5b-local.d: Likewise.
> * ld-aarch64/ifunc-5b.d: Likewise.
> * ld-aarch64/ifunc-5r-local.d: Likewise.
> * ld-aarch64/ifunc-6.s: Likewise.
> * ld-aarch64/ifunc-6a.d: Likewise.
> * ld-aarch64/ifunc-6b.d: Likewise.
> * ld-aarch64/ifunc-7.s: Likewise.
> * ld-aarch64/ifunc-7a.d: Likewise.
> * ld-aarch64/ifunc-7b.d: Likewise.
> * ld-aarch64/ifunc-8.d: Likewise.
> * ld-aarch64/ifunc-8a.s: Likewise.
> * ld-aarch64/ifunc-8b.s: Likewise.
> * ld-aarch64/ifunc-9.d: Likewise.
> * ld-aarch64/ifunc-9.s: Likewise.
> ---
> bfd/configure.in | 4 +-
> bfd/elf64-aarch64.c | 660 +++++++++++++++++++++++++++----
> include/elf/aarch64.h | 3 +-
> ld/testsuite/ld-aarch64/aarch64-elf.exp | 40 ++
> ld/testsuite/ld-aarch64/ifunc-1-local.d | 7 +
> ld/testsuite/ld-aarch64/ifunc-1-local.s | 13 +
> ld/testsuite/ld-aarch64/ifunc-1.d | 7 +
> ld/testsuite/ld-aarch64/ifunc-1.s | 16 +
> ld/testsuite/ld-aarch64/ifunc-10.d | 5 +
> ld/testsuite/ld-aarch64/ifunc-10.s | 25 ++
> ld/testsuite/ld-aarch64/ifunc-11.d | 5 +
> ld/testsuite/ld-aarch64/ifunc-11.s | 26 ++
> ld/testsuite/ld-aarch64/ifunc-12.d | 5 +
> ld/testsuite/ld-aarch64/ifunc-12.s | 24 ++
> ld/testsuite/ld-aarch64/ifunc-13.d | 13 +
> ld/testsuite/ld-aarch64/ifunc-13a.s | 11 +
> ld/testsuite/ld-aarch64/ifunc-13b.s | 5 +
> ld/testsuite/ld-aarch64/ifunc-14a.d | 10 +
> ld/testsuite/ld-aarch64/ifunc-14a.s | 7 +
> ld/testsuite/ld-aarch64/ifunc-14b.d | 10 +
> ld/testsuite/ld-aarch64/ifunc-14b.s | 5 +
> ld/testsuite/ld-aarch64/ifunc-14c.d | 10 +
> ld/testsuite/ld-aarch64/ifunc-14c.s | 7 +
> ld/testsuite/ld-aarch64/ifunc-14d.d | 10 +
> ld/testsuite/ld-aarch64/ifunc-14e.d | 11 +
> ld/testsuite/ld-aarch64/ifunc-14f.d | 11 +
> ld/testsuite/ld-aarch64/ifunc-15.d | 12 +
> ld/testsuite/ld-aarch64/ifunc-15.s | 11 +
> ld/testsuite/ld-aarch64/ifunc-16.d | 9 +
> ld/testsuite/ld-aarch64/ifunc-16.s | 17 +
> ld/testsuite/ld-aarch64/ifunc-17a.d | 9 +
> ld/testsuite/ld-aarch64/ifunc-17a.s | 11 +
> ld/testsuite/ld-aarch64/ifunc-17b.d | 9 +
> ld/testsuite/ld-aarch64/ifunc-17b.s | 6 +
> ld/testsuite/ld-aarch64/ifunc-18a.d | 14 +
> ld/testsuite/ld-aarch64/ifunc-18a.s | 5 +
> ld/testsuite/ld-aarch64/ifunc-18b.d | 14 +
> ld/testsuite/ld-aarch64/ifunc-18b.s | 15 +
> ld/testsuite/ld-aarch64/ifunc-19a.d | 13 +
> ld/testsuite/ld-aarch64/ifunc-19a.s | 5 +
> ld/testsuite/ld-aarch64/ifunc-19b.d | 13 +
> ld/testsuite/ld-aarch64/ifunc-19b.s | 15 +
> ld/testsuite/ld-aarch64/ifunc-2-local.d | 9 +
> ld/testsuite/ld-aarch64/ifunc-2-local.s | 18 +
> ld/testsuite/ld-aarch64/ifunc-2.d | 9 +
> ld/testsuite/ld-aarch64/ifunc-2.s | 18 +
> ld/testsuite/ld-aarch64/ifunc-20.d | 12 +
> ld/testsuite/ld-aarch64/ifunc-20.s | 16 +
> ld/testsuite/ld-aarch64/ifunc-3.s | 16 +
> ld/testsuite/ld-aarch64/ifunc-3a.d | 8 +
> ld/testsuite/ld-aarch64/ifunc-3b.d | 8 +
> ld/testsuite/ld-aarch64/ifunc-4.d | 7 +
> ld/testsuite/ld-aarch64/ifunc-4.s | 18 +
> ld/testsuite/ld-aarch64/ifunc-4a.d | 8 +
> ld/testsuite/ld-aarch64/ifunc-5-local.s | 19 +
> ld/testsuite/ld-aarch64/ifunc-5.s | 20 +
> ld/testsuite/ld-aarch64/ifunc-5a-local.d | 8 +
> ld/testsuite/ld-aarch64/ifunc-5a.d | 8 +
> ld/testsuite/ld-aarch64/ifunc-5b-local.d | 8 +
> ld/testsuite/ld-aarch64/ifunc-5b.d | 12 +
> ld/testsuite/ld-aarch64/ifunc-5r-local.d | 10 +
> ld/testsuite/ld-aarch64/ifunc-6.s | 21 +
> ld/testsuite/ld-aarch64/ifunc-6a.d | 8 +
> ld/testsuite/ld-aarch64/ifunc-6b.d | 12 +
> ld/testsuite/ld-aarch64/ifunc-7.s | 21 +
> ld/testsuite/ld-aarch64/ifunc-7a.d | 8 +
> ld/testsuite/ld-aarch64/ifunc-7b.d | 8 +
> ld/testsuite/ld-aarch64/ifunc-8.d | 9 +
> ld/testsuite/ld-aarch64/ifunc-8a.s | 13 +
> ld/testsuite/ld-aarch64/ifunc-8b.s | 7 +
> ld/testsuite/ld-aarch64/ifunc-9.d | 3 +
> ld/testsuite/ld-aarch64/ifunc-9.s | 23 ++
> ld/testsuite/ld-ifunc/ifunc.exp | 3 +-
> 73 files changed, 1420 insertions(+), 76 deletions(-)
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-1-local.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-1-local.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-1.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-1.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-10.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-10.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-11.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-11.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-12.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-12.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-13.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-13a.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-13b.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-14a.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-14a.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-14b.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-14b.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-14c.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-14c.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-14d.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-14e.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-14f.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-15.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-15.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-16.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-16.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-17a.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-17a.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-17b.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-17b.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-18a.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-18a.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-18b.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-18b.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-19a.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-19a.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-19b.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-19b.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-2-local.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-2-local.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-2.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-2.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-20.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-20.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-3.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-3a.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-3b.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-4.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-4.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-4a.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-5-local.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-5.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-5a-local.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-5a.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-5b-local.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-5b.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-5r-local.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-6.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-6a.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-6b.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-7.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-7a.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-7b.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-8.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-8a.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-8b.s
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-9.d
> create mode 100644 ld/testsuite/ld-aarch64/ifunc-9.s
>
> diff --git a/bfd/configure.in b/bfd/configure.in
> index befcf27..d7222f6 100644
> --- a/bfd/configure.in
> +++ b/bfd/configure.in
> @@ -859,7 +859,7 @@ do
> bfd_elf32_xtensa_be_vec) tb="$tb xtensa-isa.lo xtensa-modules.lo elf32-xtensa.lo elf32.lo $elf" ;;
> bfd_elf64_alpha_freebsd_vec) tb="$tb elf64-alpha.lo elf64.lo $elf"; target_size=64 ;;
> bfd_elf64_alpha_vec) tb="$tb elf64-alpha.lo elf64.lo $elf"; target_size=64 ;;
> - bfd_elf64_bigaarch64_vec) tb="$tb elf64-aarch64.lo elf64.lo $elf"; target_size=64 ;;
> + bfd_elf64_bigaarch64_vec) tb="$tb elf64-aarch64.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;;
> bfd_elf64_big_generic_vec) tb="$tb elf64-gen.lo elf64.lo $elf"; target_size=64 ;;
> bfd_elf64_bigmips_vec) tb="$tb elf64-mips.lo elf64.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
> bfd_elf64_hppa_linux_vec) tb="$tb elf64-hppa.lo elf64.lo $elf"; target_size=64 ;;
> @@ -868,7 +868,7 @@ do
> bfd_elf64_ia64_hpux_big_vec) tb="$tb elf64-ia64.lo elfxx-ia64.lo elf64.lo $elf"; target_size=64 ;;
> bfd_elf64_ia64_little_vec) tb="$tb elf64-ia64.lo elfxx-ia64.lo elf64.lo $elf"; target_size=64 ;;
> bfd_elf64_ia64_vms_vec) tb="$tb elf64-ia64-vms.lo elf64-ia64.lo elfxx-ia64.lo elf64.lo vms-lib.lo vms-misc.lo $elf"; target_size=64 ;;
> - bfd_elf64_littleaarch64_vec)tb="$tb elf64-aarch64.lo elf64.lo $elf"; target_size=64 ;;
> + bfd_elf64_littleaarch64_vec)tb="$tb elf64-aarch64.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;;
> bfd_elf64_little_generic_vec) tb="$tb elf64-gen.lo elf64.lo $elf"; target_size=64 ;;
> bfd_elf64_littlemips_vec) tb="$tb elf64-mips.lo elf64.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
> bfd_elf64_mmix_vec) tb="$tb elf64-mmix.lo elf64.lo $elf" target_size=64 ;;
> diff --git a/bfd/elf64-aarch64.c b/bfd/elf64-aarch64.c
> index aef472f..7337256 100644
> --- a/bfd/elf64-aarch64.c
> +++ b/bfd/elf64-aarch64.c
> @@ -142,6 +142,7 @@
> #include "bfd_stdint.h"
> #include "elf-bfd.h"
> #include "bfdlink.h"
> +#include "objalloc.h"
> #include "elf/aarch64.h"
>
> static bfd_reloc_status_type
> @@ -398,6 +399,20 @@ static reloc_howto_type elf64_aarch64_howto_dynrelocs[] =
> ALL_ONES, /* dst_mask */
> FALSE), /* pcrel_offset */
>
> + HOWTO (R_AARCH64_IRELATIVE, /* type */
> + 0, /* rightshift */
> + 2, /* size (0 = byte, 1 = short, 2 = long) */
> + 64, /* bitsize */
> + FALSE, /* pc_relative */
> + 0, /* bitpos */
> + complain_overflow_bitfield, /* complain_on_overflow */
> + bfd_elf_generic_reloc, /* special_function */
> + "R_AARCH64_IRELATIVE", /* name */
> + FALSE, /* partial_inplace */
> + 0, /* src_mask */
> + ALL_ONES, /* dst_mask */
> + FALSE), /* pcrel_offset */
> +
> };
>
> /* Note: code such as elf64_aarch64_reloc_type_lookup expect to use e.g.
> @@ -1887,6 +1902,15 @@ struct elf64_aarch64_link_hash_table
> loader via DT_TLSDESC_GOT. The magic value (bfd_vma) -1
> indicates an offset is not allocated. */
> bfd_vma dt_tlsdesc_got;
> +
> + /* Used by local STT_GNU_IFUNC symbols. */
> + htab_t loc_hash_table;
> + void * loc_hash_memory;
> +
> + /* The index of the next R_AARCH64_JUMP_SLOT entry in .rela.plt. */
> + bfd_vma next_jump_slot_index;
> + /* The index of the next R_AARCH64_IRELATIVE entry in .rela.plt. */
> + bfd_vma next_irelative_index;
> };
>
>
> @@ -1997,6 +2021,72 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
> return entry;
> }
>
> +/* Compute a hash of a local hash entry. We use elf_link_hash_entry
> + for local symbol so that we can handle local STT_GNU_IFUNC symbols
> + as global symbol. We reuse indx and dynstr_index for local symbol
> + hash since they aren't used by global symbols in this backend. */
> +
> +static hashval_t
> +elf_aarch64_local_htab_hash (const void *ptr)
> +{
> + struct elf_link_hash_entry *h
> + = (struct elf_link_hash_entry *) ptr;
> + return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index);
> +}
> +
> +/* Compare local hash entries. */
> +
> +static int
> +elf_aarch64_local_htab_eq (const void *ptr1, const void *ptr2)
> +{
> + struct elf_link_hash_entry *h1
> + = (struct elf_link_hash_entry *) ptr1;
> + struct elf_link_hash_entry *h2
> + = (struct elf_link_hash_entry *) ptr2;
> +
> + return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index;
> +}
> +
> +/* Find and/or create a hash entry for local symbol. */
> +
> +static struct elf_link_hash_entry *
> +elf_aarch64_get_local_sym_hash (struct elf64_aarch64_link_hash_table *htab,
> + bfd *abfd, const Elf_Internal_Rela *rel,
> + bfd_boolean create)
> +{
> + struct elf64_aarch64_link_hash_entry e, *ret;
> + asection *sec = abfd->sections;
> + hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id,
> + ELF32_R_SYM (rel->r_info));
> + void **slot;
> +
> + e.root.indx = sec->id;
> + e.root.dynstr_index = ELF32_R_SYM (rel->r_info);
> + slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h,
> + create ? INSERT : NO_INSERT);
> +
> + if (!slot)
> + return NULL;
> +
> + if (*slot)
> + {
> + ret = (struct elf64_aarch64_link_hash_entry *) *slot;
> + return &ret->root;
> + }
> +
> + ret = (struct elf64_aarch64_link_hash_entry *)
> + objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
> + sizeof (struct elf64_aarch64_link_hash_entry));
> + if (ret)
> + {
> + memset (ret, 0, sizeof (*ret));
> + ret->root.indx = sec->id;
> + ret->root.dynstr_index = ELF32_R_SYM (rel->r_info);
> + ret->root.dynindx = -1;
> + *slot = ret;
> + }
> + return &ret->root;
> +}
>
> /* Copy the extra info we tack onto an elf_link_hash_entry. */
>
> @@ -2117,6 +2207,17 @@ elf64_aarch64_link_hash_table_create (bfd *abfd)
> return NULL;
> }
>
> + ret->loc_hash_table = htab_try_create (1024,
> + elf_aarch64_local_htab_hash,
> + elf_aarch64_local_htab_eq,
> + NULL);
> + ret->loc_hash_memory = objalloc_create ();
> + if (!ret->loc_hash_table || !ret->loc_hash_memory)
> + {
> + free (ret);
> + return NULL;
> + }
> +
> return &ret->root.root;
> }
>
> @@ -2128,6 +2229,11 @@ elf64_aarch64_hash_table_free (struct bfd_link_hash_table *hash)
> struct elf64_aarch64_link_hash_table *ret
> = (struct elf64_aarch64_link_hash_table *) hash;
>
> + if (ret->loc_hash_table)
> + htab_delete (ret->loc_hash_table);
> + if (ret->loc_hash_memory)
> + objalloc_free ((struct objalloc *) ret->loc_hash_memory);
> +
> bfd_hash_table_free (&ret->stub_hash_table);
> _bfd_elf_link_hash_table_free (hash);
> }
> @@ -3825,8 +3931,10 @@ elf64_aarch64_final_link_relocate (reloc_howto_type *howto,
> struct elf_link_hash_entry *h,
> bfd_boolean *unresolved_reloc_p,
> bfd_boolean save_addend,
> - bfd_vma *saved_addend)
> + bfd_vma *saved_addend,
> + Elf_Internal_Sym *sym)
> {
> + Elf_Internal_Shdr *symtab_hdr;
> unsigned int r_type = howto->type;
> unsigned long r_symndx;
> bfd_byte *hit_data = contents + rel->r_offset;
> @@ -3837,6 +3945,8 @@ elf64_aarch64_final_link_relocate (reloc_howto_type *howto,
>
> globals = elf64_aarch64_hash_table (info);
>
> + symtab_hdr = &elf_symtab_hdr (input_bfd);
> +
> BFD_ASSERT (is_aarch64_elf (input_bfd));
>
> r_symndx = ELF64_R_SYM (rel->r_info);
> @@ -3858,6 +3968,181 @@ elf64_aarch64_final_link_relocate (reloc_howto_type *howto,
>
> weak_undef_p = (h ? h->root.type == bfd_link_hash_undefweak
> : bfd_is_und_section (sym_sec));
> +
> + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
> + it here if it is defined in a non-shared object. */
> + if (h != NULL
> + && h->type == STT_GNU_IFUNC
> + && h->def_regular)
> + {
> + asection *plt;
> + const char *name;
> + asection *base_got;
> + bfd_vma off;
> +
> + if ((input_section->flags & SEC_ALLOC) == 0
> + || h->plt.offset == (bfd_vma) -1)
> + abort ();
> +
> + /* STT_GNU_IFUNC symbol must go through PLT. */
> + plt = globals->root.splt ? globals->root.splt : globals->root.iplt;
> + value = (plt->output_section->vma + plt->output_offset + h->plt.offset);
> +
> + switch (r_type)
> + {
> + default:
> + if (h->root.root.string)
> + name = h->root.root.string;
> + else
> + name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
> + NULL);
> + (*_bfd_error_handler)
> + (_("%B: relocation %s against STT_GNU_IFUNC "
> + "symbol `%s' isn't handled by %s"), input_bfd,
> + howto->name, name, __FUNCTION__);
> + bfd_set_error (bfd_error_bad_value);
> + return FALSE;
> +
> + case R_AARCH64_ABS64:
> + if (rel->r_addend != 0)
> + {
> + if (h->root.root.string)
> + name = h->root.root.string;
> + else
> + name = bfd_elf_sym_name (input_bfd, symtab_hdr,
> + sym, NULL);
> + (*_bfd_error_handler)
> + (_("%B: relocation %s against STT_GNU_IFUNC "
> + "symbol `%s' has non-zero addend: %d"),
> + input_bfd, howto->name, name, rel->r_addend);
> + bfd_set_error (bfd_error_bad_value);
> + return FALSE;
> + }
> +
> + /* Generate dynamic relocation only when there is a
> + non-GOT reference in a shared object. */
> + if (info->shared && h->non_got_ref)
> + {
> + Elf_Internal_Rela outrel;
> + asection *sreloc;
> +
> + /* Need a dynamic relocation to get the real function
> + address. */
> + outrel.r_offset = _bfd_elf_section_offset (output_bfd,
> + info,
> + input_section,
> + rel->r_offset);
> + if (outrel.r_offset == (bfd_vma) -1
> + || outrel.r_offset == (bfd_vma) -2)
> + abort ();
> +
> + outrel.r_offset += (input_section->output_section->vma
> + + input_section->output_offset);
> +
> + if (h->dynindx == -1
> + || h->forced_local
> + || info->executable)
> + {
> + /* This symbol is resolved locally. */
> + outrel.r_info = ELF64_R_INFO (0, R_AARCH64_IRELATIVE);
> + outrel.r_addend = (h->root.u.def.value
> + + h->root.u.def.section->output_section->vma
> + + h->root.u.def.section->output_offset);
> + }
> + else
> + {
> + outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
> + outrel.r_addend = 0;
> + }
> +
> + sreloc = globals->root.irelifunc;
> + elf_append_rela (output_bfd, sreloc, &outrel);
> +
> + /* If this reloc is against an external symbol, we
> + do not want to fiddle with the addend. Otherwise,
> + we need to include the symbol value so that it
> + becomes an addend for the dynamic reloc. For an
> + internal symbol, we have updated addend. */
> + return bfd_reloc_ok;
> + }
> + /* FALLTHROUGH */
> + case R_AARCH64_JUMP26:
> + case R_AARCH64_CALL26:
> + return _bfd_final_link_relocate (howto, input_bfd, input_section,
> + contents, rel->r_offset, value,
> + signed_addend);
> + case R_AARCH64_LD64_GOT_LO12_NC:
> + case R_AARCH64_ADR_GOT_PAGE:
> + case R_AARCH64_GOT_LD_PREL19:
> + base_got = globals->root.sgot;
> + off = h->got.offset;
> +
> + if (base_got == NULL)
> + abort ();
> +
> + if (off == (bfd_vma) -1)
> + {
> + bfd_vma plt_index;
> +
> + /* We can't use h->got.offset here to save state, or
> + even just remember the offset, as finish_dynamic_symbol
> + would use that as offset into .got. */
> +
> + if (globals->root.splt != NULL)
> + {
> + plt_index = h->plt.offset / globals->plt_entry_size - 1;
> + off = (plt_index + 3) * GOT_ENTRY_SIZE;
> + base_got = globals->root.sgotplt;
> + }
> + else
> + {
> + plt_index = h->plt.offset / globals->plt_entry_size;
> + off = plt_index * GOT_ENTRY_SIZE;
> + base_got = globals->root.igotplt;
> + }
> +
> + if (h->dynindx == -1
> + || h->forced_local
> + || info->symbolic)
> + {
> + /* This references the local defitionion. We must
> + initialize this entry in the global offset table.
> + Since the offset must always be a multiple of 8,
> + we use the least significant bit to record
> + whether we have initialized it already.
> +
> + When doing a dynamic link, we create a .rela.got
> + relocation entry to initialize the value. This
> + is done in the finish_dynamic_symbol routine. */
> + if ((off & 1) != 0)
> + off &= ~1;
> + else
> + {
> + bfd_put_64 (output_bfd, value,
> + base_got->contents + off);
> + /* Note that this is harmless for the GOTPLT64
> + case, as -1 | 1 still is -1. */
> + h->got.offset |= 1;
> + }
> + }
> + value = (base_got->output_section->vma
> + + base_got->output_offset + off);
> + }
> + else
> + value = aarch64_calculate_got_entry_vma (h, globals, info,
> + value, output_bfd,
> + unresolved_reloc_p);
> + value = aarch64_resolve_relocation (r_type, place, value,
> + 0, weak_undef_p);
> + return _bfd_final_link_relocate (howto, input_bfd, input_section,
> + contents, rel->r_offset, value,
> + signed_addend);
> + case R_AARCH64_ADR_PREL_PG_HI21:
> + case R_AARCH64_ADD_ABS_LO12_NC:
> + break;
> + }
> + }
> +
> switch (r_type)
> {
> case R_AARCH64_NONE:
> @@ -3884,11 +4169,6 @@ elf64_aarch64_final_link_relocate (reloc_howto_type *howto,
>
> *unresolved_reloc_p = FALSE;
>
> - sreloc = _bfd_elf_get_dynamic_reloc_section (input_bfd,
> - input_section, 1);
> - if (sreloc == NULL)
> - return bfd_reloc_notsupported;
> -
> skip = FALSE;
> relocate = FALSE;
>
> @@ -3925,10 +4205,14 @@ elf64_aarch64_final_link_relocate (reloc_howto_type *howto,
> outrel.r_addend += value;
> }
>
> - loc = sreloc->contents + sreloc->reloc_count++ * RELOC_SIZE (htab);
> + sreloc = elf_section_data (input_section)->sreloc;
> + if (sreloc == NULL || sreloc->contents == NULL)
> + return bfd_reloc_notsupported;
> +
> + loc = sreloc->contents + sreloc->reloc_count++ * RELOC_SIZE (globals);
> bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
>
> - if (sreloc->reloc_count * RELOC_SIZE (htab) > sreloc->size)
> + if (sreloc->reloc_count * RELOC_SIZE (globals) > sreloc->size)
> {
> /* Sanity to check that we have previously allocated
> sufficient space in the relocation section for the
> @@ -4339,6 +4623,20 @@ elf64_aarch64_relocate_section (bfd *output_bfd,
> }
>
> relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
> +
> + /* Relocate against local STT_GNU_IFUNC symbol. */
> + if (!info->relocatable
> + && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
> + {
> + h = elf_aarch64_get_local_sym_hash (globals, input_bfd,
> + rel, FALSE);
> + if (h == NULL)
> + abort ();
> +
> + /* Set STT_GNU_IFUNC symbol value. */
> + h->root.u.def.value = sym->st_value;
> + h->root.u.def.section = sec;
> + }
> }
> else
> {
> @@ -4428,7 +4726,7 @@ elf64_aarch64_relocate_section (bfd *output_bfd,
> input_section, contents, rel,
> relocation, info, sec,
> h, &unresolved_reloc,
> - save_addend, &addend);
> + save_addend, &addend, sym);
>
> switch (r_type)
> {
> @@ -4905,38 +5203,46 @@ elf64_aarch64_gc_sweep_hook (bfd *abfd,
> struct elf_link_hash_entry *h = NULL;
>
> r_symndx = ELF64_R_SYM (rel->r_info);
> -
> if (r_symndx >= symtab_hdr->sh_info)
> {
> - struct elf64_aarch64_link_hash_entry *eh;
> - struct elf_dyn_relocs **pp;
> - struct elf_dyn_relocs *p;
> -
> h = sym_hashes[r_symndx - symtab_hdr->sh_info];
> while (h->root.type == bfd_link_hash_indirect
> || h->root.type == bfd_link_hash_warning)
> h = (struct elf_link_hash_entry *) h->root.u.i.link;
> - eh = (struct elf64_aarch64_link_hash_entry *) h;
> -
> - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
> - {
> - if (p->sec == sec)
> - {
> - /* Everything must go for SEC. */
> - *pp = p->next;
> - break;
> - }
> - }
> }
> else
> {
> + /* A local symbol. */
> Elf_Internal_Sym *isym;
>
> - /* A local symbol. */
> isym = bfd_sym_from_r_symndx (&htab->sym_cache,
> abfd, r_symndx);
> - if (isym == NULL)
> - return FALSE;
> +
> + /* Check relocation against local STT_GNU_IFUNC symbol. */
> + if (isym != NULL
> + && ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
> + {
> + h = elf_aarch64_get_local_sym_hash (htab, abfd, rel, FALSE);
> + if (h == NULL)
> + abort ();
> + }
> + }
> +
> + if (h)
> + {
> + struct elf64_aarch64_link_hash_entry *eh;
> + struct elf_dyn_relocs **pp;
> + struct elf_dyn_relocs *p;
> +
> + eh = (struct elf64_aarch64_link_hash_entry *) h;
> +
> + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
> + if (p->sec == sec)
> + {
> + /* Everything must go for SEC. */
> + *pp = p->next;
> + break;
> + }
> }
>
> r_type = ELF64_R_TYPE (rel->r_info);
> @@ -4965,6 +5271,12 @@ elf64_aarch64_gc_sweep_hook (bfd *abfd,
> {
> if (h->got.refcount > 0)
> h->got.refcount -= 1;
> +
> + if (h->type == STT_GNU_IFUNC)
> + {
> + if (h->plt.refcount > 0)
> + h->plt.refcount -= 1;
> + }
> }
> else if (locals != NULL)
> {
> @@ -4995,7 +5307,7 @@ elf64_aarch64_gc_sweep_hook (bfd *abfd,
> break;
>
> case R_AARCH64_ABS64:
> - if (h != NULL && info->executable)
> + if (h != NULL)
> {
> if (h->plt.refcount > 0)
> h->plt.refcount -= 1;
> @@ -5026,12 +5338,13 @@ elf64_aarch64_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* If this is a function, put it in the procedure linkage table. We
> will fill in the contents of the procedure linkage table later,
> when we know the address of the .got section. */
> - if (h->type == STT_FUNC || h->needs_plt)
> + if (h->type == STT_FUNC || h->type == STT_GNU_IFUNC || h->needs_plt)
> {
> if (h->plt.refcount <= 0
> - || SYMBOL_CALLS_LOCAL (info, h)
> - || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
> - && h->root.type == bfd_link_hash_undefweak))
> + || (h->type != STT_GNU_IFUNC
> + && (SYMBOL_CALLS_LOCAL (info, h)
> + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
> + && h->root.type == bfd_link_hash_undefweak))))
> {
> /* This case can occur if we saw a CALL26 reloc in
> an input file, but the symbol wasn't referred to
> @@ -5160,6 +5473,7 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
> struct elf_link_hash_entry *h;
> unsigned long r_symndx;
> unsigned int r_type;
> + Elf_Internal_Sym *isym;
>
> r_symndx = ELF64_R_SYM (rel->r_info);
> r_type = ELF64_R_TYPE (rel->r_info);
> @@ -5172,7 +5486,31 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
> }
>
> if (r_symndx < symtab_hdr->sh_info)
> - h = NULL;
> + {
> + /* A local symbol. */
> + isym = bfd_sym_from_r_symndx (&htab->sym_cache,
> + abfd, r_symndx);
> + if (isym == NULL)
> + return FALSE;
> +
> + /* Check relocation against local STT_GNU_IFUNC symbol. */
> + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
> + {
> + h = elf_aarch64_get_local_sym_hash (htab, abfd, rel,
> + TRUE);
> + if (h == NULL)
> + return FALSE;
> +
> + /* Fake a STT_GNU_IFUNC symbol. */
> + h->type = STT_GNU_IFUNC;
> + h->def_regular = 1;
> + h->ref_regular = 1;
> + h->forced_local = 1;
> + h->root.type = bfd_link_hash_defined;
> + }
> + else
> + h = NULL;
> + }
> else
> {
> h = sym_hashes[r_symndx - symtab_hdr->sh_info];
> @@ -5185,6 +5523,37 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
> h->root.non_ir_ref = 1;
> }
>
> + if (h != NULL)
> + {
> + /* Create the ifunc sections for static executables. If we
> + never see an indirect function symbol nor we are building
> + a static executable, those sections will be empty and
> + won't appear in output. */
> + switch (r_type)
> + {
> + default:
> + break;
> +
> + case R_AARCH64_ABS64:
> + case R_AARCH64_CALL26:
> + case R_AARCH64_JUMP26:
> + case R_AARCH64_LD64_GOT_LO12_NC:
> + case R_AARCH64_ADR_GOT_PAGE:
> + case R_AARCH64_GOT_LD_PREL19:
> + case R_AARCH64_ADR_PREL_PG_HI21:
> + case R_AARCH64_ADD_ABS_LO12_NC:
> + if (htab->root.dynobj == NULL)
> + htab->root.dynobj = abfd;
> + if (!_bfd_elf_create_ifunc_sections (htab->root.dynobj, info))
> + return FALSE;
> + break;
> + }
> +
> + /* It is referenced by a non-shared object. */
> + h->ref_regular = 1;
> + h->root.non_ir_ref = 1;
> + }
> +
> /* Could be done earlier, if h were already available. */
> r_type = aarch64_tls_transition (abfd, info, r_type, h, r_symndx);
>
> @@ -5246,7 +5615,6 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
>
> asection *s;
> void **vpp;
> - Elf_Internal_Sym *isym;
>
> isym = bfd_sym_from_r_symndx (&htab->sym_cache,
> abfd, r_symndx);
> @@ -5396,7 +5764,10 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
> continue;
>
> h->needs_plt = 1;
> - h->plt.refcount += 1;
> + if (h->plt.refcount <= 0)
> + h->plt.refcount = 1;
> + else
> + h->plt.refcount += 1;
> break;
> }
> }
> @@ -5540,14 +5911,14 @@ elf64_aarch64_find_inliner_info (bfd *abfd,
>
> static void
> elf64_aarch64_post_process_headers (bfd *abfd,
> - struct bfd_link_info *link_info
> - ATTRIBUTE_UNUSED)
> + struct bfd_link_info *link_info)
> {
> Elf_Internal_Ehdr *i_ehdrp; /* ELF file header, internal form. */
>
> i_ehdrp = elf_elfheader (abfd);
> - i_ehdrp->e_ident[EI_OSABI] = 0;
> i_ehdrp->e_ident[EI_ABIVERSION] = AARCH64_ELF_ABI_VERSION;
> +
> + _bfd_elf_set_osabi (abfd, link_info);
> }
>
> static enum elf_reloc_type_class
> @@ -5939,12 +6310,6 @@ elf64_aarch64_bfd_free_cached_info (bfd *abfd)
> return _bfd_free_cached_info (abfd);
> }
>
> -static bfd_boolean
> -elf64_aarch64_is_function_type (unsigned int type)
> -{
> - return type == STT_FUNC;
> -}
> -
> /* Create dynamic sections. This is different from the ARM backend in that
> the got, plt, gotplt and their relocation sections are all created in the
> standard part of the bfd elf backend. */
> @@ -6011,7 +6376,18 @@ elf64_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> info = (struct bfd_link_info *) inf;
> htab = elf64_aarch64_hash_table (info);
>
> - if (htab->root.dynamic_sections_created && h->plt.refcount > 0)
> + eh = (struct elf64_aarch64_link_hash_entry *) h;
> +
> + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
> + here if it is defined and referenced in a non-shared object. */
> + if (h->type == STT_GNU_IFUNC
> + && h->def_regular)
> + return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
> + &eh->dyn_relocs,
> + htab->plt_entry_size,
> + htab->plt_header_size,
> + GOT_ENTRY_SIZE);
> + else if (htab->root.dynamic_sections_created && h->plt.refcount > 0)
> {
> /* Make sure this symbol is output as a dynamic symbol.
> Undefined weak syms won't yet be marked as dynamic. */
> @@ -6082,7 +6458,6 @@ elf64_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> h->needs_plt = 0;
> }
>
> - eh = (struct elf64_aarch64_link_hash_entry *) h;
> eh->tlsdesc_got_jump_table_offset = (bfd_vma) - 1;
>
> if (h->got.refcount > 0)
> @@ -6267,6 +6642,24 @@ elf64_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> }
>
>
> +/* Allocate space in .plt, .got and associated reloc sections for
> + local dynamic relocs. */
> +
> +static bfd_boolean
> +elf_aarch64_allocate_local_dynrelocs (void **slot, void *inf)
> +{
> + struct elf_link_hash_entry *h
> + = (struct elf_link_hash_entry *) *slot;
> +
> + if (h->type != STT_GNU_IFUNC
> + || !h->def_regular
> + || !h->ref_regular
> + || !h->forced_local
> + || h->root.type != bfd_link_hash_defined)
> + abort ();
> +
> + return elf64_aarch64_allocate_dynrelocs (h, inf);
> +}
>
>
> /* This is the most important function of all . Innocuosly named
> @@ -6406,6 +6799,10 @@ elf64_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> elf_link_hash_traverse (&htab->root, elf64_aarch64_allocate_dynrelocs,
> info);
>
> + /* Allocate .plt and .got entries, and space for local symbols. */
> + htab_traverse (htab->loc_hash_table,
> + elf_aarch64_allocate_local_dynrelocs,
> + info);
>
> /* For every jump slot reserved in the sgotplt, reloc_count is
> incremented. However, when we reserve space for TLS descriptors,
> @@ -6414,7 +6811,12 @@ elf64_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> slot size. */
>
> if (htab->root.srelplt)
> - htab->sgotplt_jump_table_size = aarch64_compute_jump_table_size (htab);
> + {
> + htab->sgotplt_jump_table_size = aarch64_compute_jump_table_size (htab);
> + htab->next_irelative_index = htab->root.srelplt->reloc_count - 1;
> + }
> + else if (htab->root.irelplt)
> + htab->next_irelative_index = htab->root.irelplt->reloc_count - 1;
>
> if (htab->tlsdesc_plt)
> {
> @@ -6561,7 +6963,8 @@ elf64_aarch64_update_plt_entry (bfd *output_bfd,
> static void
> elf64_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
> struct elf64_aarch64_link_hash_table
> - *htab, bfd *output_bfd)
> + *htab, bfd *output_bfd,
> + struct bfd_link_info *info)
> {
> bfd_byte *plt_entry;
> bfd_vma plt_index;
> @@ -6570,17 +6973,50 @@ elf64_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
> bfd_vma plt_entry_address;
> Elf_Internal_Rela rela;
> bfd_byte *loc;
> + asection *plt, *gotplt, *relplt;
>
> - plt_index = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size;
> + /* When building a static executable, use .iplt, .igot.plt and
> + .rela.iplt sections for STT_GNU_IFUNC symbols. */
> + if (htab->root.splt != NULL)
> + {
> + plt = htab->root.splt;
> + gotplt = htab->root.sgotplt;
> + relplt = htab->root.srelplt;
> + }
> + else
> + {
> + plt = htab->root.iplt;
> + gotplt = htab->root.igotplt;
> + relplt = htab->root.irelplt;
> + }
>
> - /* Offset in the GOT is PLT index plus got GOT headers(3)
> - times 8. */
> - got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
> - plt_entry = htab->root.splt->contents + h->plt.offset;
> - plt_entry_address = htab->root.splt->output_section->vma
> - + htab->root.splt->output_section->output_offset + h->plt.offset;
> - gotplt_entry_address = htab->root.sgotplt->output_section->vma +
> - htab->root.sgotplt->output_offset + got_offset;
> + /* Get the index in the procedure linkage table which
> + corresponds to this symbol. This is the index of this symbol
> + in all the symbols for which we are making plt entries. The
> + first entry in the procedure linkage table is reserved.
> +
> + Get the offset into the .got table of the entry that
> + corresponds to this function. Each .got entry is GOT_ENTRY_SIZE
> + bytes. The first three are reserved for the dynamic linker.
> +
> + For static executables, we don't reserve anything. */
> +
> + if (plt == htab->root.splt)
> + {
> + got_offset = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size;
> + got_offset = (got_offset + 3) * GOT_ENTRY_SIZE;
> + }
> + else
> + {
> + got_offset = h->plt.offset / htab->plt_entry_size;
> + got_offset = got_offset * GOT_ENTRY_SIZE;
> + }
> +
> + plt_entry = plt->contents + h->plt.offset;
> + plt_entry_address = plt->output_section->vma
> + + plt->output_section->output_offset + h->plt.offset;
> + gotplt_entry_address = gotplt->output_section->vma +
> + gotplt->output_offset + got_offset;
>
> /* Copy in the boiler-plate for the PLTn entry. */
> memcpy (plt_entry, elf64_aarch64_small_plt_entry, PLT_SMALL_ENTRY_SIZE);
> @@ -6604,19 +7040,38 @@ elf64_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
>
> /* All the GOTPLT Entries are essentially initialized to PLT0. */
> bfd_put_64 (output_bfd,
> - (htab->root.splt->output_section->vma
> - + htab->root.splt->output_offset),
> - htab->root.sgotplt->contents + got_offset);
> + plt->output_section->vma + plt->output_offset,
> + gotplt->contents + got_offset);
>
> - /* Fill in the entry in the .rela.plt section. */
> rela.r_offset = gotplt_entry_address;
> - rela.r_info = ELF64_R_INFO (h->dynindx, R_AARCH64_JUMP_SLOT);
> - rela.r_addend = 0;
> +
> + if (h->dynindx == -1
> + || ((info->executable
> + || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
> + && h->def_regular
> + && h->type == STT_GNU_IFUNC))
> + {
> + /* If an STT_GNU_IFUNC symbol is locally defined, generate
> + R_AARCH64_IRELATIVE instead of R_AARCH64_JUMP_SLOT. */
> + rela.r_info = ELF64_R_INFO (0, R_AARCH64_IRELATIVE);
> + rela.r_addend = (h->root.u.def.value
> + + h->root.u.def.section->output_section->vma
> + + h->root.u.def.section->output_offset);
> + /* R_AARCH64_IRELATIVE comes last. */
> + plt_index = htab->next_irelative_index--;
> + }
> + else
> + {
> + /* Fill in the entry in the .rela.plt section. */
> + rela.r_info = ELF64_R_INFO (h->dynindx, R_AARCH64_JUMP_SLOT);
> + rela.r_addend = 0;
> + plt_index = htab->next_jump_slot_index++;
> + }
>
> /* Compute the relocation entry to used based on PLT index and do
> not adjust reloc_count. The reloc_count has already been adjusted
> to account for this entry. */
> - loc = htab->root.srelplt->contents + plt_index * RELOC_SIZE (htab);
> + loc = relplt->contents + plt_index * RELOC_SIZE (htab);
> bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
> }
>
> @@ -6676,15 +7131,38 @@ elf64_aarch64_finish_dynamic_symbol (bfd *output_bfd,
>
> if (h->plt.offset != (bfd_vma) - 1)
> {
> + asection *plt, *gotplt, *relplt;
> +
> /* This symbol has an entry in the procedure linkage table. Set
> it up. */
>
> - if (h->dynindx == -1
> - || htab->root.splt == NULL
> - || htab->root.sgotplt == NULL || htab->root.srelplt == NULL)
> + /* When building a static executable, use .iplt, .igot.plt and
> + .rela.iplt sections for STT_GNU_IFUNC symbols. */
> + if (htab->root.splt != NULL)
> + {
> + plt = htab->root.splt;
> + gotplt = htab->root.sgotplt;
> + relplt = htab->root.srelplt;
> + }
> + else
> + {
> + plt = htab->root.iplt;
> + gotplt = htab->root.igotplt;
> + relplt = htab->root.irelplt;
> + }
> +
> + /* This symbol has an entry in the procedure linkage table. Set
> + it up. */
> + if ((h->dynindx == -1
> + && !((h->forced_local || info->executable)
> + && h->def_regular
> + && h->type == STT_GNU_IFUNC))
> + || plt == NULL
> + || gotplt == NULL
> + || relplt == NULL)
> abort ();
>
> - elf64_aarch64_create_small_pltn_entry (h, htab, output_bfd);
> + elf64_aarch64_create_small_pltn_entry (h, htab, output_bfd, info);
> if (!h->def_regular)
> {
> /* Mark the symbol as undefined, rather than as defined in
> @@ -6769,6 +7247,21 @@ elf64_aarch64_finish_dynamic_symbol (bfd *output_bfd,
> return TRUE;
> }
>
> +/* Finish up local dynamic symbol handling. We set the contents of
> + various dynamic sections here. */
> +
> +static bfd_boolean
> +elf_aarch64_finish_local_dynamic_symbol (void **slot, void *inf)
> +{
> + struct elf_link_hash_entry *h
> + = (struct elf_link_hash_entry *) *slot;
> + struct bfd_link_info *info
> + = (struct bfd_link_info *) inf;
> +
> + return elf64_aarch64_finish_dynamic_symbol (info->output_bfd,
> + info, h, NULL);
> +}
> +
> static void
> elf64_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED,
> struct elf64_aarch64_link_hash_table
> @@ -7011,6 +7504,11 @@ elf64_aarch64_finish_dynamic_sections (bfd *output_bfd,
> elf_section_data (htab->root.sgot->output_section)->this_hdr.sh_entsize
> = GOT_ENTRY_SIZE;
>
> + /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */
> + htab_traverse (htab->loc_hash_table,
> + elf_aarch64_finish_local_dynamic_symbol,
> + info);
> +
> return TRUE;
> }
>
> @@ -7024,6 +7522,24 @@ elf64_aarch64_plt_sym_val (bfd_vma i, const asection *plt,
> return plt->vma + PLT_ENTRY_SIZE + i * PLT_SMALL_ENTRY_SIZE;
> }
>
> +/* Hook called by the linker routine which adds symbols from an object
> + file. */
> +
> +static bfd_boolean
> +elf64_aarch64_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
> + Elf_Internal_Sym *sym,
> + const char **namep ATTRIBUTE_UNUSED,
> + flagword *flagsp ATTRIBUTE_UNUSED,
> + asection **secp ATTRIBUTE_UNUSED,
> + bfd_vma *valp ATTRIBUTE_UNUSED)
> +{
> + if ((abfd->flags & DYNAMIC) == 0
> + && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
> + || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
> + elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
> +
> + return TRUE;
> +}
>
> /* We use this so we can override certain functions
> (though currently we don't). */
> @@ -7130,9 +7646,6 @@ const struct elf_size_info elf64_aarch64_size_info =
> #define elf_backend_init_index_section \
> _bfd_elf_init_2_index_sections
>
> -#define elf_backend_is_function_type \
> - elf64_aarch64_is_function_type
> -
> #define elf_backend_finish_dynamic_sections \
> elf64_aarch64_finish_dynamic_sections
>
> @@ -7172,6 +7685,9 @@ const struct elf_size_info elf64_aarch64_size_info =
> #define elf_backend_size_info \
> elf64_aarch64_size_info
>
> +#define elf_backend_add_symbol_hook \
> + elf64_aarch64_add_symbol_hook
> +
> #define elf_backend_can_refcount 1
> #define elf_backend_can_gc_sections 1
> #define elf_backend_plt_readonly 1
> diff --git a/include/elf/aarch64.h b/include/elf/aarch64.h
> index e3af444..072d841 100644
> --- a/include/elf/aarch64.h
> +++ b/include/elf/aarch64.h
> @@ -208,7 +208,8 @@ RELOC_NUMBER (R_AARCH64_TLS_DTPMOD64, 1028)
> RELOC_NUMBER (R_AARCH64_TLS_DTPREL64, 1029)
> RELOC_NUMBER (R_AARCH64_TLS_TPREL64, 1030)
> RELOC_NUMBER (R_AARCH64_TLSDESC, 1031)
> -FAKE_RELOC (R_AARCH64_dyn_max, 1032)
> +RELOC_NUMBER (R_AARCH64_IRELATIVE, 1032)
> +FAKE_RELOC (R_AARCH64_dyn_max, 1033)
>
> END_RELOC_NUMBERS (R_AARCH64_end)
>
> diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
> index d687cc2..58236e2 100644
> --- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
> +++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
> @@ -114,3 +114,43 @@ run_dump_test "gc-tls-relocs"
> run_dump_test "gc-plt-relocs"
> run_dump_test "gc-relocs-257-dyn"
> run_dump_test "gc-relocs-257"
> +
> +# ifunc tests
> +run_dump_test "ifunc-1"
> +run_dump_test "ifunc-1-local"
> +run_dump_test "ifunc-2"
> +run_dump_test "ifunc-2-local"
> +run_dump_test "ifunc-3a"
> +run_dump_test "ifunc-3b"
> +run_dump_test "ifunc-4"
> +run_dump_test "ifunc-4a"
> +run_dump_test "ifunc-5a"
> +run_dump_test "ifunc-5b"
> +run_dump_test "ifunc-5a-local"
> +run_dump_test "ifunc-5b-local"
> +run_dump_test "ifunc-5r-local"
> +run_dump_test "ifunc-6a"
> +run_dump_test "ifunc-6b"
> +run_dump_test "ifunc-7a"
> +run_dump_test "ifunc-7b"
> +run_dump_test "ifunc-8"
> +run_dump_test "ifunc-9"
> +run_dump_test "ifunc-10"
> +run_dump_test "ifunc-11"
> +run_dump_test "ifunc-12"
> +run_dump_test "ifunc-13"
> +run_dump_test "ifunc-14a"
> +run_dump_test "ifunc-14b"
> +run_dump_test "ifunc-14c"
> +run_dump_test "ifunc-14d"
> +run_dump_test "ifunc-14e"
> +run_dump_test "ifunc-14f"
> +run_dump_test "ifunc-15"
> +run_dump_test "ifunc-16"
> +run_dump_test "ifunc-17a"
> +run_dump_test "ifunc-17b"
> +run_dump_test "ifunc-18a"
> +run_dump_test "ifunc-18b"
> +run_dump_test "ifunc-19a"
> +run_dump_test "ifunc-19b"
> +run_dump_test "ifunc-20"
> diff --git a/ld/testsuite/ld-aarch64/ifunc-1-local.d b/ld/testsuite/ld-aarch64/ifunc-1-local.d
> new file mode 100644
> index 0000000..0cce7f6
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-1-local.d
> @@ -0,0 +1,7 @@
> +#ld: -shared
> +#objdump: -dw
> +#target: aarch64-*-*
> +
> +#...
> +[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+0x2a0@plt>
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-1-local.s b/ld/testsuite/ld-aarch64/ifunc-1-local.s
> new file mode 100644
> index 0000000..7b9d117
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-1-local.s
> @@ -0,0 +1,13 @@
> + .type foo, %gnu_indirect_function
> + .set __GI_foo, foo
> + .text
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> +.globl bar
> + .type bar, @function
> +bar:
> + bl __GI_foo
> + ret
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-aarch64/ifunc-1.d b/ld/testsuite/ld-aarch64/ifunc-1.d
> new file mode 100644
> index 0000000..8a17cd7
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-1.d
> @@ -0,0 +1,7 @@
> +#ld: -shared
> +#objdump: -dw
> +#target: aarch64-*-*
> +
> +#...
> +[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+0x2c0@plt>
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-1.s b/ld/testsuite/ld-aarch64/ifunc-1.s
> new file mode 100644
> index 0000000..6f86c8a
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-1.s
> @@ -0,0 +1,16 @@
> + .type foo, %gnu_indirect_function
> + .global __GI_foo
> + .hidden __GI_foo
> + .set __GI_foo, foo
> + .text
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> +.globl bar
> + .type bar, @function
> +bar:
> + bl __GI_foo
> + ret
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-aarch64/ifunc-10.d b/ld/testsuite/ld-aarch64/ifunc-10.d
> new file mode 100644
> index 0000000..6931c7f
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-10.d
> @@ -0,0 +1,5 @@
> +#ld: -e bar --gc-sections
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +There are no relocations in this file.
> diff --git a/ld/testsuite/ld-aarch64/ifunc-10.s b/ld/testsuite/ld-aarch64/ifunc-10.s
> new file mode 100644
> index 0000000..10468c1
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-10.s
> @@ -0,0 +1,25 @@
> + .section .text.foo,"ax",@progbits
> + .type foo, @function
> +foo:
> + .global foo
> + adrp x0, :got:ifunc
> + ldr x0, [x0, #:got_lo12:ifunc]
> + bl ifunc
> + adrp x0, xxx
> + add x0, x0, :lo12:xxx
> + ret
> +
> + .section .text.bar,"ax",@progbits
> + .type bar, @function
> +bar:
> + .global bar
> + ret
> +
> + .section .text.ifunc,"ax",@progbits
> + .type ifunc, @gnu_indirect_function
> +ifunc:
> + ret
> +
> + .section .data.foo,"aw",@progbits
> +xxx:
> + .quad ifunc
> diff --git a/ld/testsuite/ld-aarch64/ifunc-11.d b/ld/testsuite/ld-aarch64/ifunc-11.d
> new file mode 100644
> index 0000000..6931c7f
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-11.d
> @@ -0,0 +1,5 @@
> +#ld: -e bar --gc-sections
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +There are no relocations in this file.
> diff --git a/ld/testsuite/ld-aarch64/ifunc-11.s b/ld/testsuite/ld-aarch64/ifunc-11.s
> new file mode 100644
> index 0000000..e1820de
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-11.s
> @@ -0,0 +1,26 @@
> + .section .text.foo,"ax",@progbits
> + .type foo, @function
> +foo:
> + .global foo
> + adrp x0, :got:ifunc
> + ldr x0, [x0, #:got_lo12:ifunc]
> + bl ifunc
> + adrp x0, xxx
> + add x0, x0, :lo12:xxx
> + ret
> +
> + .section .text.bar,"ax",@progbits
> + .type bar, @function
> +bar:
> + .global bar
> + ret
> +
> + .section .text.ifunc,"ax",@progbits
> + .type ifunc, @gnu_indirect_function
> + .global ifunc
> +ifunc:
> + ret
> +
> + .section .data.foo,"aw",@progbits
> +xxx:
> + .quad ifunc
> diff --git a/ld/testsuite/ld-aarch64/ifunc-12.d b/ld/testsuite/ld-aarch64/ifunc-12.d
> new file mode 100644
> index 0000000..55fe925
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-12.d
> @@ -0,0 +1,5 @@
> +#ld: -shared -e bar --gc-sections
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +There are no relocations in this file.
> diff --git a/ld/testsuite/ld-aarch64/ifunc-12.s b/ld/testsuite/ld-aarch64/ifunc-12.s
> new file mode 100644
> index 0000000..aad30df
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-12.s
> @@ -0,0 +1,24 @@
> + .section .text.foo,"ax",@progbits
> + .type foo, @function
> +foo:
> + adrp x0, :got:ifunc
> + ldr x0, [x0, #:got_lo12:ifunc]
> + bl ifunc
> + adrp x0, xxx
> + add x0, x0, :lo12:xxx
> + ret
> +
> + .section .text.bar,"ax",@progbits
> + .type bar, @function
> +bar:
> + .global bar
> + ret
> +
> + .section .text.ifunc,"ax",@progbits
> + .type ifunc, @gnu_indirect_function
> +ifunc:
> + ret
> +
> + .section .data.foo,"aw",@progbits
> +xxx:
> + .quad ifunc
> diff --git a/ld/testsuite/ld-aarch64/ifunc-13.d b/ld/testsuite/ld-aarch64/ifunc-13.d
> new file mode 100644
> index 0000000..191d839
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-13.d
> @@ -0,0 +1,13 @@
> +#source: ifunc-13a.s
> +#source: ifunc-13b.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.ifunc' at offset 0x[0-9a-f]+ contains 1 entries:
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_ABS64[ ]+ifunc\(\)[ ]+ifunc \+ 0
> +
> +Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entries:
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_JUMP_SLOT[ ]+ifunc\(\)[ ]+ifunc \+ 0
> diff --git a/ld/testsuite/ld-aarch64/ifunc-13a.s b/ld/testsuite/ld-aarch64/ifunc-13a.s
> new file mode 100644
> index 0000000..873e06e
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-13a.s
> @@ -0,0 +1,11 @@
> + .text
> + .type foo, @function
> + .global foo
> +foo:
> + adrp x0, xxx
> + add x0, x0, :lo12:xxx
> + ret
> +
> + .data
> +xxx:
> + .quad ifunc
> diff --git a/ld/testsuite/ld-aarch64/ifunc-13b.s b/ld/testsuite/ld-aarch64/ifunc-13b.s
> new file mode 100644
> index 0000000..3560394
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-13b.s
> @@ -0,0 +1,5 @@
> + .text
> + .type ifunc, @gnu_indirect_function
> + .globl ifunc
> +ifunc:
> + ret
> diff --git a/ld/testsuite/ld-aarch64/ifunc-14a.d b/ld/testsuite/ld-aarch64/ifunc-14a.d
> new file mode 100644
> index 0000000..174d20f
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-14a.d
> @@ -0,0 +1,10 @@
> +#source: ifunc-14a.s
> +#source: ifunc-14b.s
> +#ld: -shared -z nocombreloc
> +#readelf: -d
> +#target: aarch64-*-*
> +
> +#failif
> +#...
> +.*\(TEXTREL\).*
> +#...
> diff --git a/ld/testsuite/ld-aarch64/ifunc-14a.s b/ld/testsuite/ld-aarch64/ifunc-14a.s
> new file mode 100644
> index 0000000..7d6183c
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-14a.s
> @@ -0,0 +1,7 @@
> + .text
> + .globl bar
> + .type bar, @function
> +bar:
> + bl foo
> + .size bar, .-bar
> + .hidden foo
> diff --git a/ld/testsuite/ld-aarch64/ifunc-14b.d b/ld/testsuite/ld-aarch64/ifunc-14b.d
> new file mode 100644
> index 0000000..509a3a2
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-14b.d
> @@ -0,0 +1,10 @@
> +#source: ifunc-14b.s
> +#source: ifunc-14a.s
> +#ld: -shared -z nocombreloc
> +#readelf: -d
> +#target: aarch64-*-*
> +
> +#failif
> +#...
> +.*\(TEXTREL\).*
> +#...
> diff --git a/ld/testsuite/ld-aarch64/ifunc-14b.s b/ld/testsuite/ld-aarch64/ifunc-14b.s
> new file mode 100644
> index 0000000..bac22eb
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-14b.s
> @@ -0,0 +1,5 @@
> + .type foo, %gnu_indirect_function
> + .globl foo
> +foo:
> + ret
> + .size foo, .-foo
> diff --git a/ld/testsuite/ld-aarch64/ifunc-14c.d b/ld/testsuite/ld-aarch64/ifunc-14c.d
> new file mode 100644
> index 0000000..0b63753
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-14c.d
> @@ -0,0 +1,10 @@
> +#source: ifunc-14a.s
> +#source: ifunc-14b.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +#failif
> +#...
> +.* +R_AARCH64_NONE +.*
> +#...
> diff --git a/ld/testsuite/ld-aarch64/ifunc-14c.s b/ld/testsuite/ld-aarch64/ifunc-14c.s
> new file mode 100644
> index 0000000..7853280
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-14c.s
> @@ -0,0 +1,7 @@
> + .text
> + .globl xxx
> + .type xxx, @function
> +xxx:
> + bl foo
> + .size xxx, .-xxx
> + .hidden foo
> diff --git a/ld/testsuite/ld-aarch64/ifunc-14d.d b/ld/testsuite/ld-aarch64/ifunc-14d.d
> new file mode 100644
> index 0000000..fd08f03
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-14d.d
> @@ -0,0 +1,10 @@
> +#source: ifunc-14b.s
> +#source: ifunc-14a.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +#failif
> +#...
> +.* +R_AARCH64_NONE +.*
> +#...
> diff --git a/ld/testsuite/ld-aarch64/ifunc-14e.d b/ld/testsuite/ld-aarch64/ifunc-14e.d
> new file mode 100644
> index 0000000..37c470b
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-14e.d
> @@ -0,0 +1,11 @@
> +#source: ifunc-14a.s
> +#source: ifunc-14c.s
> +#source: ifunc-14b.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +#failif
> +#...
> +.* +R_AARCH64_NONE +.*
> +#...
> diff --git a/ld/testsuite/ld-aarch64/ifunc-14f.d b/ld/testsuite/ld-aarch64/ifunc-14f.d
> new file mode 100644
> index 0000000..3fad96f
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-14f.d
> @@ -0,0 +1,11 @@
> +#source: ifunc-14a.s
> +#source: ifunc-14b.s
> +#source: ifunc-14c.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +#failif
> +#...
> +.* +R_AARCH64_NONE +.*
> +#...
> diff --git a/ld/testsuite/ld-aarch64/ifunc-15.d b/ld/testsuite/ld-aarch64/ifunc-15.d
> new file mode 100644
> index 0000000..79a9a77
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-15.d
> @@ -0,0 +1,12 @@
> +#source: ifunc-15.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.got' at offset 0x[0-9a-f]+ contains 1 entries:
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_GLOB_DAT[ ]+ifunc\(\)[ ]+ifunc \+ 0
> +
> +Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entries:
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_JUMP_SLOT[ ]+ifunc\(\)[ ]+ifunc \+ 0
> diff --git a/ld/testsuite/ld-aarch64/ifunc-15.s b/ld/testsuite/ld-aarch64/ifunc-15.s
> new file mode 100644
> index 0000000..f94b4a6
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-15.s
> @@ -0,0 +1,11 @@
> + .text
> + .type foo, @function
> + .global foo
> +foo:
> + adrp x0, :got:ifunc
> + ldr x0, [x0, #:got_lo12:ifunc]
> + ret
> + .type ifunc, @gnu_indirect_function
> + .globl ifunc
> +ifunc:
> + ret
> diff --git a/ld/testsuite/ld-aarch64/ifunc-16.d b/ld/testsuite/ld-aarch64/ifunc-16.d
> new file mode 100644
> index 0000000..1336257
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-16.d
> @@ -0,0 +1,9 @@
> +#source: ifunc-16.s
> +#ld: -shared
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_JUMP_SLOT[ ]+0+[ ]+ifunc \+ 0
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-16.s b/ld/testsuite/ld-aarch64/ifunc-16.s
> new file mode 100644
> index 0000000..ded401a
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-16.s
> @@ -0,0 +1,17 @@
> + .text
> + .globl fct
> + .type fct, @gnu_indirect_function
> + .set fct,resolve
> + .hidden int_fct
> + .globl int_fct
> + .set int_fct,fct
> + .p2align 4,,15
> + .type resolve, @function
> +resolve:
> + bl ifunc
> + .size resolve, .-resolve
> + .globl g
> + .type g, @function
> +g:
> + bl int_fct
> + .size g, .-g
> diff --git a/ld/testsuite/ld-aarch64/ifunc-17a.d b/ld/testsuite/ld-aarch64/ifunc-17a.d
> new file mode 100644
> index 0000000..b414be3
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-17a.d
> @@ -0,0 +1,9 @@
> +#source: ifunc-17a.s
> +#source: ifunc-17b.s
> +#ld: -static
> +#readelf: -s --wide
> +#target: aarch64-*-*
> +
> +#...
> + +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-17a.s b/ld/testsuite/ld-aarch64/ifunc-17a.s
> new file mode 100644
> index 0000000..e0bde49
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-17a.s
> @@ -0,0 +1,11 @@
> + .globl main
> + .globl start
> + .globl _start
> + .globl __start
> + .text
> +main:
> +start:
> +_start:
> +__start:
> + .byte 0
> + .common foo,4,4
> diff --git a/ld/testsuite/ld-aarch64/ifunc-17b.d b/ld/testsuite/ld-aarch64/ifunc-17b.d
> new file mode 100644
> index 0000000..1566bcb
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-17b.d
> @@ -0,0 +1,9 @@
> +#source: ifunc-17b.s
> +#source: ifunc-17a.s
> +#ld: -static
> +#readelf: -s --wide
> +#target: aarch64-*-*
> +
> +#...
> + +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-17b.s b/ld/testsuite/ld-aarch64/ifunc-17b.s
> new file mode 100644
> index 0000000..66abe04
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-17b.s
> @@ -0,0 +1,6 @@
> + .weak foo
> + .type foo, %gnu_indirect_function
> + .size foo,1
> + .text
> +foo:
> + .byte 1
> diff --git a/ld/testsuite/ld-aarch64/ifunc-18a.d b/ld/testsuite/ld-aarch64/ifunc-18a.d
> new file mode 100644
> index 0000000..682e7a3
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-18a.d
> @@ -0,0 +1,14 @@
> +#source: ifunc-18a.s
> +#source: ifunc-18b.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.ifunc' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-18a.s b/ld/testsuite/ld-aarch64/ifunc-18a.s
> new file mode 100644
> index 0000000..c29c121
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-18a.s
> @@ -0,0 +1,5 @@
> + .section .data.rel,"aw",@progbits
> + .globl foo_ptrt
> + .type foo_ptr, @object
> +foo_ptr:
> + .dc.a foo
> diff --git a/ld/testsuite/ld-aarch64/ifunc-18b.d b/ld/testsuite/ld-aarch64/ifunc-18b.d
> new file mode 100644
> index 0000000..40b39e1
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-18b.d
> @@ -0,0 +1,14 @@
> +#source: ifunc-18b.s
> +#source: ifunc-18a.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.ifunc' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-18b.s b/ld/testsuite/ld-aarch64/ifunc-18b.s
> new file mode 100644
> index 0000000..2e46c1e
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-18b.s
> @@ -0,0 +1,15 @@
> + .text
> + .type foo, %gnu_indirect_function
> + .hidden foo
> + .globl foo
> +foo:
> + ret
> + .size foo, .-foo
> + .globl bar
> +bar:
> + bl foo1
> + ret
> + .size bar, .-bar
> + .hidden foo1
> + .globl foo1
> + foo1 = foo
> diff --git a/ld/testsuite/ld-aarch64/ifunc-19a.d b/ld/testsuite/ld-aarch64/ifunc-19a.d
> new file mode 100644
> index 0000000..9f083c9
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-19a.d
> @@ -0,0 +1,13 @@
> +#source: ifunc-19a.s
> +#source: ifunc-19b.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.ifunc' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-19a.s b/ld/testsuite/ld-aarch64/ifunc-19a.s
> new file mode 100644
> index 0000000..3a3d0cd
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-19a.s
> @@ -0,0 +1,5 @@
> + .section .data.rel,"aw",@progbits
> + .globl foo_ptrt
> + .type foo_ptr, @object
> +foo_ptr:
> + .dc.a foo1
> diff --git a/ld/testsuite/ld-aarch64/ifunc-19b.d b/ld/testsuite/ld-aarch64/ifunc-19b.d
> new file mode 100644
> index 0000000..dea5b16
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-19b.d
> @@ -0,0 +1,13 @@
> +#source: ifunc-19b.s
> +#source: ifunc-19a.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.ifunc' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-19b.s b/ld/testsuite/ld-aarch64/ifunc-19b.s
> new file mode 100644
> index 0000000..2e46c1e
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-19b.s
> @@ -0,0 +1,15 @@
> + .text
> + .type foo, %gnu_indirect_function
> + .hidden foo
> + .globl foo
> +foo:
> + ret
> + .size foo, .-foo
> + .globl bar
> +bar:
> + bl foo1
> + ret
> + .size bar, .-bar
> + .hidden foo1
> + .globl foo1
> + foo1 = foo
> diff --git a/ld/testsuite/ld-aarch64/ifunc-2-local.d b/ld/testsuite/ld-aarch64/ifunc-2-local.d
> new file mode 100644
> index 0000000..07616ca
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-2-local.d
> @@ -0,0 +1,9 @@
> +#ld: -shared
> +#objdump: -dw
> +#target: aarch64-*-*
> +
> +#...
> +[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+0x2c0@plt>
> +[ \t0-9a-f]+:[ \t0-9a-f]+adrp[ \t]+x0, 0 <_GLOBAL_OFFSET_TABLE_>
> +[ \t0-9a-f]+:[ \t0-9a-f]+add[ \t]+x0, x0, #0x2b0
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-2-local.s b/ld/testsuite/ld-aarch64/ifunc-2-local.s
> new file mode 100644
> index 0000000..da350df
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-2-local.s
> @@ -0,0 +1,18 @@
> + .type foo, %gnu_indirect_function
> + .global __GI_foo
> + .hidden __GI_foo
> + .set __GI_foo, foo
> + .text
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> +.globl bar
> + .type bar, @function
> +bar:
> + bl __GI_foo
> + adrp x0, __GI_foo
> + add x0, x0, :lo12:__GI_foo
> + ret
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-aarch64/ifunc-2.d b/ld/testsuite/ld-aarch64/ifunc-2.d
> new file mode 100644
> index 0000000..07616ca
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-2.d
> @@ -0,0 +1,9 @@
> +#ld: -shared
> +#objdump: -dw
> +#target: aarch64-*-*
> +
> +#...
> +[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+0x2c0@plt>
> +[ \t0-9a-f]+:[ \t0-9a-f]+adrp[ \t]+x0, 0 <_GLOBAL_OFFSET_TABLE_>
> +[ \t0-9a-f]+:[ \t0-9a-f]+add[ \t]+x0, x0, #0x2b0
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-2.s b/ld/testsuite/ld-aarch64/ifunc-2.s
> new file mode 100644
> index 0000000..da350df
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-2.s
> @@ -0,0 +1,18 @@
> + .type foo, %gnu_indirect_function
> + .global __GI_foo
> + .hidden __GI_foo
> + .set __GI_foo, foo
> + .text
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> +.globl bar
> + .type bar, @function
> +bar:
> + bl __GI_foo
> + adrp x0, __GI_foo
> + add x0, x0, :lo12:__GI_foo
> + ret
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-aarch64/ifunc-20.d b/ld/testsuite/ld-aarch64/ifunc-20.d
> new file mode 100644
> index 0000000..cee34bf
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-20.d
> @@ -0,0 +1,12 @@
> +#source: ifunc-20.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.ifunc' at offset 0x[0-9a-f]+ contains 1 entries:
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_ABS64[ ]+ifunc\(\)[ ]+ifunc \+ 0
> +
> +Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entries:
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_JUMP_SLOT[ ]+ifunc\(\)[ ]+ifunc \+ 0
> diff --git a/ld/testsuite/ld-aarch64/ifunc-20.s b/ld/testsuite/ld-aarch64/ifunc-20.s
> new file mode 100644
> index 0000000..17393cb
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-20.s
> @@ -0,0 +1,16 @@
> + .section .data.rel,"aw",@progbits
> + .globl ifunc_ptrt
> + .type ifunc_ptr, @object
> +ifunc_ptr:
> + .dc.a ifunc
> + .text
> + .type ifunc, @gnu_indirect_function
> + .globl ifunc
> +ifunc:
> + ret
> + .size ifunc, .-ifunc
> + .type bar, @function
> + .globl bar
> +bar:
> + bl ifunc
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-aarch64/ifunc-3.s b/ld/testsuite/ld-aarch64/ifunc-3.s
> new file mode 100644
> index 0000000..c68b1b7
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-3.s
> @@ -0,0 +1,16 @@
> + .type foo, %gnu_indirect_function
> + .global __GI_foo
> + .protected __GI_foo
> + .set __GI_foo, foo
> + .text
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> +.globl bar
> + .type bar, @function
> +bar:
> + bl __GI_foo
> + ret
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-aarch64/ifunc-3a.d b/ld/testsuite/ld-aarch64/ifunc-3a.d
> new file mode 100644
> index 0000000..1335480
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-3a.d
> @@ -0,0 +1,8 @@
> +#source: ifunc-3.s
> +#ld: -shared
> +#objdump: -dw
> +#target: aarch64-*-*
> +
> +#...
> +[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+0x2e0@plt>
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-3b.d b/ld/testsuite/ld-aarch64/ifunc-3b.d
> new file mode 100644
> index 0000000..d90ed5c
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-3b.d
> @@ -0,0 +1,8 @@
> +#source: ifunc-3.s
> +#ld: -shared
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +#...
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_[_0-9A-Z]+_IRELATIVE[ ]*[0-9a-f]*
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-4.d b/ld/testsuite/ld-aarch64/ifunc-4.d
> new file mode 100644
> index 0000000..9a3e308
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-4.d
> @@ -0,0 +1,7 @@
> +#ld:
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +#...
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_[_0-9A-Z]+_IRELATIVE[ ]*[0-9a-f]*
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-4.s b/ld/testsuite/ld-aarch64/ifunc-4.s
> new file mode 100644
> index 0000000..c2b66f5
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-4.s
> @@ -0,0 +1,18 @@
> + .text
> + .type foo, %gnu_indirect_function
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> + .type start,"function"
> + .global start
> +start:
> + .type _start,"function"
> + .global _start
> +_start:
> + .type __start,"function"
> + .global __start
> +__start:
> + .type __start,"function"
> + bl foo
> diff --git a/ld/testsuite/ld-aarch64/ifunc-4a.d b/ld/testsuite/ld-aarch64/ifunc-4a.d
> new file mode 100644
> index 0000000..3329782
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-4a.d
> @@ -0,0 +1,8 @@
> +#ld: -s
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +#source: ifunc-4.s
> +
> +#...
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_[_0-9A-Z]+_IRELATIVE[ ]*[0-9a-f]*
> +#pass
> diff --git a/ld/testsuite/ld-aarch64/ifunc-5-local.s b/ld/testsuite/ld-aarch64/ifunc-5-local.s
> new file mode 100644
> index 0000000..8d23bab
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-5-local.s
> @@ -0,0 +1,19 @@
> + .text
> + .type foo, %gnu_indirect_function
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> + .type start,"function"
> + .global start
> +start:
> + .type _start,"function"
> + .global _start
> +_start:
> + .type __start,"function"
> + .global __start
> +__start:
> + .type __start,"function"
> + bl foo
> + adrp x0, :got:foo
> + ldr x0, [x0, #:got_lo12:foo]
> diff --git a/ld/testsuite/ld-aarch64/ifunc-5.s b/ld/testsuite/ld-aarch64/ifunc-5.s
> new file mode 100644
> index 0000000..b1bbf1a
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-5.s
> @@ -0,0 +1,20 @@
> + .text
> + .type foo, %gnu_indirect_function
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> + .type start,"function"
> + .global start
> +start:
> + .type _start,"function"
> + .global _start
> +_start:
> + .type __start,"function"
> + .global __start
> +__start:
> + .type __start,"function"
> + bl foo
> + adrp x0, :got:foo
> + ldr x0, [x0, #:got_lo12:foo]
> diff --git a/ld/testsuite/ld-aarch64/ifunc-5a-local.d b/ld/testsuite/ld-aarch64/ifunc-5a-local.d
> new file mode 100644
> index 0000000..8bc6862
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-5a-local.d
> @@ -0,0 +1,8 @@
> +#source: ifunc-5-local.s
> +#ld:
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-5a.d b/ld/testsuite/ld-aarch64/ifunc-5a.d
> new file mode 100644
> index 0000000..781db3c
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-5a.d
> @@ -0,0 +1,8 @@
> +#source: ifunc-5.s
> +#ld:
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-5b-local.d b/ld/testsuite/ld-aarch64/ifunc-5b-local.d
> new file mode 100644
> index 0000000..b0d6dda
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-5b-local.d
> @@ -0,0 +1,8 @@
> +#source: ifunc-5-local.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-5b.d b/ld/testsuite/ld-aarch64/ifunc-5b.d
> new file mode 100644
> index 0000000..82c5479
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-5b.d
> @@ -0,0 +1,12 @@
> +#source: ifunc-5.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_GLOB_DAT[ ]+foo\(\)[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_JUMP_SLOT[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-aarch64/ifunc-5r-local.d b/ld/testsuite/ld-aarch64/ifunc-5r-local.d
> new file mode 100644
> index 0000000..1c87ec1
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-5r-local.d
> @@ -0,0 +1,10 @@
> +#source: ifunc-5-local.s
> +#ld: -r
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.text' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_CALL26[ ]+foo\(\)[ ]+foo \+ 0
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_ADR_GOT_PAGE[ ]+foo\(\)[ ]+foo \+ 0
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_LD64_GOT_LO1[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-aarch64/ifunc-6.s b/ld/testsuite/ld-aarch64/ifunc-6.s
> new file mode 100644
> index 0000000..56486d6
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-6.s
> @@ -0,0 +1,21 @@
> + .text
> + .type foo, %gnu_indirect_function
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> + .protected foo
> + .type start,"function"
> + .global start
> +start:
> + .type _start,"function"
> + .global _start
> +_start:
> + .type __start,"function"
> + .global __start
> +__start:
> + .type __start,"function"
> + bl foo
> + adrp x0, :got:foo
> + ldr x0, [x0, #:got_lo12:foo]
> diff --git a/ld/testsuite/ld-aarch64/ifunc-6a.d b/ld/testsuite/ld-aarch64/ifunc-6a.d
> new file mode 100644
> index 0000000..06b9042
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-6a.d
> @@ -0,0 +1,8 @@
> +#source: ifunc-6.s
> +#ld:
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-6b.d b/ld/testsuite/ld-aarch64/ifunc-6b.d
> new file mode 100644
> index 0000000..8f06cd1
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-6b.d
> @@ -0,0 +1,12 @@
> +#source: ifunc-6.s
> +#ld: -shared -z nocombreloc
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_GLOB_DAT[ ]+foo\(\)[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-7.s b/ld/testsuite/ld-aarch64/ifunc-7.s
> new file mode 100644
> index 0000000..51485af
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-7.s
> @@ -0,0 +1,21 @@
> + .text
> + .type foo, %gnu_indirect_function
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> + .hidden foo
> + .type start,"function"
> + .global start
> +start:
> + .type _start,"function"
> + .global _start
> +_start:
> + .type __start,"function"
> + .global __start
> +__start:
> + .type __start,"function"
> + bl foo
> + adrp x0, :got:foo
> + ldr x0, [x0, #:got_lo12:foo]
> diff --git a/ld/testsuite/ld-aarch64/ifunc-7a.d b/ld/testsuite/ld-aarch64/ifunc-7a.d
> new file mode 100644
> index 0000000..e462f90
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-7a.d
> @@ -0,0 +1,8 @@
> +#source: ifunc-7.s
> +#ld:
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-7b.d b/ld/testsuite/ld-aarch64/ifunc-7b.d
> new file mode 100644
> index 0000000..3f6060c
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-7b.d
> @@ -0,0 +1,8 @@
> +#source: ifunc-7.s
> +#ld: -shared
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-8.d b/ld/testsuite/ld-aarch64/ifunc-8.d
> new file mode 100644
> index 0000000..97201bf
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-8.d
> @@ -0,0 +1,9 @@
> +#source: ifunc-8a.s
> +#source: ifunc-8b.s
> +#ld:
> +#readelf: -r --wide
> +#target: aarch64-*-*
> +
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_AARCH64_IRELATIVE[ ]+[0-9a-f]*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-8a.s b/ld/testsuite/ld-aarch64/ifunc-8a.s
> new file mode 100644
> index 0000000..94c073a
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-8a.s
> @@ -0,0 +1,13 @@
> + .text
> + .type start,"function"
> + .global start
> +start:
> + .type _start,"function"
> + .global _start
> +_start:
> + .type __start,"function"
> + .global __start
> +__start:
> + .type __start,"function"
> + adrp x0, :got:foo
> + ldr x0, [x0, #:got_lo12:foo]
> diff --git a/ld/testsuite/ld-aarch64/ifunc-8b.s b/ld/testsuite/ld-aarch64/ifunc-8b.s
> new file mode 100644
> index 0000000..1f108f8
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-8b.s
> @@ -0,0 +1,7 @@
> + .text
> + .type foo, %gnu_indirect_function
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> diff --git a/ld/testsuite/ld-aarch64/ifunc-9.d b/ld/testsuite/ld-aarch64/ifunc-9.d
> new file mode 100644
> index 0000000..85f5e61
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-9.d
> @@ -0,0 +1,3 @@
> +#ld: --export-dynamic
> +#error: .*dynamic STT_GNU_IFUNC symbol `foo' with pointer equality in `.*.o' can not be used when making an executable; recompile with -fPIE and relink with -pie
> +#target: aarch64-*-*
> diff --git a/ld/testsuite/ld-aarch64/ifunc-9.s b/ld/testsuite/ld-aarch64/ifunc-9.s
> new file mode 100644
> index 0000000..2e2f577
> --- /dev/null
> +++ b/ld/testsuite/ld-aarch64/ifunc-9.s
> @@ -0,0 +1,23 @@
> + .text
> + .type foo, %gnu_indirect_function
> +.globl foo
> + .type foo, @function
> +foo:
> + ret
> + .size foo, .-foo
> + .type start,"function"
> + .global start
> +start:
> + .type _start,"function"
> + .global _start
> +_start:
> + .type __start,"function"
> + .global __start
> +__start:
> + .type __start,"function"
> + adrp x0, .LANCHOR0
> + add x0, x0, :lo12:.LANCHOR0
> + .data
> + .align 3
> +.LANCHOR0 = . + 0
> + .xword foo
> diff --git a/ld/testsuite/ld-ifunc/ifunc.exp b/ld/testsuite/ld-ifunc/ifunc.exp
> index df913d8..a4cc06d 100644
> --- a/ld/testsuite/ld-ifunc/ifunc.exp
> +++ b/ld/testsuite/ld-ifunc/ifunc.exp
> @@ -24,10 +24,11 @@
>
>
> # IFUNC support has only been implemented for the ix86, x86_64, powerpc,
> -# and sparc so far.
> +# aarch64 and sparc so far.
> if {!(([istarget "i?86-*-*"]
> || [istarget "x86_64-*-*"]
> || [istarget "powerpc*-*-*"]
> + || [istarget "aarch64-*-*"]
> || [istarget "sparc*-*-*"])
> && ([istarget "*-*-elf*"]
> || [istarget "*-*-nacl*"]
> --
> 1.8.1.4
>
--
Will Newton
Toolchain Working Group, Linaro