aarch64: Add support for GNU indirect functions.
authorWill Newton <willnewton@sourceware.org>
Thu, 3 Oct 2013 14:46:09 +0000 (14:46 +0000)
committerWill Newton <willnewton@sourceware.org>
Thu, 3 Oct 2013 14:46:09 +0000 (14:46 +0000)
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-10-03  Will Newton  <will.newton@linaro.org>

* configure: Regenerate.
* configure.in: Build elf-ifunc.o for AArch64.
* elfnn-aarch64.c: Include objalloc.h.
(elfNN_aarch64_local_htab_hash): New function.
(elfNN_aarch64_local_htab_eq): New function.
(elfNN_aarch64_get_local_sym_hash): New function.
(elfNN_aarch64_link_hash_table_create): Initialize local STT_GNU_IFUNC
symbol hash.
(elfNN_aarch64_hash_table_free): Free local STT_GNU_IFUNC symbol hash.
(elfNN_aarch64_final_link_relocate): Add sym argument.  Add support
for handling STT_GNU_IFUNC symbols.
(elfNN_aarch64_gc_sweep_hook): Add support for garbage collecting
references to STT_GNU_IFUNC symbols.
(elfNN_aarch64_adjust_dynamic_symbol): Add support for handling
STT_GNU_IFUNC symbols.
(elfNN_aarch64_check_relocs): Add support for handling STT_GNU_IFUNC
symbols.  Ensure we don't increase plt.refcount from -1 to 0.
(elfNN_aarch64_post_process_headers): Call _bfd_elf_set_osabi.
(elfNN_aarch64_is_function_type): Remove function.
(elfNN_aarch64_allocate_dynrelocs): Handle STT_GNU_IFUNC symbols.
(elfNN_aarch64_allocate_ifunc_dynrelocs): New function.
(elfNN_aarch64_allocate_local_dynrelocs): New function.
(elfNN_aarch64_allocate_local_ifunc_dynrelocs): New function.
(elfNN_aarch64_size_dynamic_sections): Call
elfNN_aarch64_allocate_local_dynrelocs.
(elfNN_aarch64_create_small_pltn_entry): Add info argument.
Add support for creating .iplt entries for STT_GNU_IFUNC symbols.
(elfNN_aarch64_finish_dynamic_symbol): Add support for handling
STT_GNU_IFUNC symbols and .iplt.
(elfNN_aarch64_finish_local_dynamic_symbol): New function.
(elfNN_aarch64_finish_dynamic_sections): Call
elfNN_aarch64_finish_local_dynamic_symbol.

ld/ChangeLog:

2013-10-03  Will Newton  <will.newton@linaro.org>

* emulparams/aarch64elf.sh: Add IREL_IN_PLT.
* emulparams/aarch64elf32.sh: Likewise.

ld/testsuite/ChangeLog:

2013-10-03  Will Newton  <will.newton@linaro.org>

* ld-ifunc/ifunc.exp: Enable ifunc tests for AArch64.
* ld-aarch64/aarch64-elf.exp: Run 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-7c.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.

78 files changed:
bfd/ChangeLog
bfd/configure.in
bfd/elfnn-aarch64.c
ld/ChangeLog
ld/emulparams/aarch64elf.sh
ld/emulparams/aarch64elf32.sh
ld/testsuite/ChangeLog
ld/testsuite/ld-aarch64/aarch64-elf.exp
ld/testsuite/ld-aarch64/ifunc-1-local.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-1-local.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-1.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-1.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-10.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-10.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-11.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-11.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-12.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-12.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-13.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-13a.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-13b.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-14a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-14a.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-14b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-14b.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-14c.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-14c.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-14d.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-14e.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-14f.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-15.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-15.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-16.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-16.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-17a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-17a.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-17b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-17b.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-18a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-18a.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-18b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-18b.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-19a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-19a.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-19b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-19b.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-2-local.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-2-local.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-2.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-2.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-20.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-20.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-3.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-3a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-3b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-4.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-4.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-4a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-5-local.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-5.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-5a-local.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-5a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-5b-local.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-5b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-5r-local.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-6.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-6a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-6b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-7.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-7a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-7b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-7c.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-8.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-8a.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-8b.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-9.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/ifunc-9.s [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc.exp

index 57bafdcb017cd0b4b803b9378b06377aec1e9971..bf6d5fbd190e79fcdbba7e37657d539d1ed4f44c 100644 (file)
@@ -1,3 +1,38 @@
+2013-10-03  Will Newton  <will.newton@linaro.org>
+
+       * configure: Regenerate.
+       * configure.in: Build elf-ifunc.o for AArch64.
+       * elfnn-aarch64.c: Include objalloc.h.
+       (elfNN_aarch64_local_htab_hash): New function.
+       (elfNN_aarch64_local_htab_eq): New function.
+       (elfNN_aarch64_get_local_sym_hash): New function.
+       (elfNN_aarch64_link_hash_table_create): Initialize local STT_GNU_IFUNC
+       symbol hash.
+       (elfNN_aarch64_hash_table_free): Free local STT_GNU_IFUNC symbol hash.
+       (elfNN_aarch64_final_link_relocate): Add sym argument.  Add support
+       for handling STT_GNU_IFUNC symbols.
+       (elfNN_aarch64_gc_sweep_hook): Add support for garbage collecting
+       references to STT_GNU_IFUNC symbols.
+       (elfNN_aarch64_adjust_dynamic_symbol): Add support for handling
+       STT_GNU_IFUNC symbols.
+       (elfNN_aarch64_check_relocs): Add support for handling STT_GNU_IFUNC
+       symbols.  Ensure we don't increase plt.refcount from -1 to 0.
+       (elfNN_aarch64_post_process_headers): Call _bfd_elf_set_osabi.
+       (elfNN_aarch64_is_function_type): Remove function.
+       (elfNN_aarch64_allocate_dynrelocs): Handle STT_GNU_IFUNC symbols.
+       (elfNN_aarch64_allocate_ifunc_dynrelocs): New function.
+       (elfNN_aarch64_allocate_local_dynrelocs): New function.
+       (elfNN_aarch64_allocate_local_ifunc_dynrelocs): New function.
+       (elfNN_aarch64_size_dynamic_sections): Call
+       elfNN_aarch64_allocate_local_dynrelocs.
+       (elfNN_aarch64_create_small_pltn_entry): Add info argument.
+       Add support for creating .iplt entries for STT_GNU_IFUNC symbols.
+       (elfNN_aarch64_finish_dynamic_symbol): Add support for handling
+       STT_GNU_IFUNC symbols and .iplt.
+       (elfNN_aarch64_finish_local_dynamic_symbol): New function.
+       (elfNN_aarch64_finish_dynamic_sections): Call
+       elfNN_aarch64_finish_local_dynamic_symbol.
+
 2013-09-30  Nick Clifton  <nickc@redhat.com>
 
        * cpu-msp430.c: Use printable names that match the values
index 86659370771426530bb5428061ffb937dd11527c..748c2935f8dceb7223e1cf8ef7b658623987de57 100644 (file)
@@ -859,8 +859,8 @@ 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 elfxx-aarch64.lo elf64.lo $elf"; target_size=64 ;;
-    bfd_elf32_bigaarch64_vec)  tb="$tb elf32-aarch64.lo elfxx-aarch64.lo elf32.lo $elf"; target_size=64 ;;
+    bfd_elf64_bigaarch64_vec)  tb="$tb elf64-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;;
+    bfd_elf32_bigaarch64_vec)  tb="$tb elf32-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf32.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 ;;
@@ -869,8 +869,8 @@ 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 elfxx-aarch64.lo elf64.lo $elf"; target_size=64 ;;
-    bfd_elf32_littleaarch64_vec)tb="$tb elf32-aarch64.lo elfxx-aarch64.lo elf32.lo $elf"; target_size=64 ;;
+    bfd_elf64_littleaarch64_vec)tb="$tb elf64-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;;
+    bfd_elf32_littleaarch64_vec)tb="$tb elf32-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf32.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 ;;
index 26968ab131e2462f0f5d2fd9cc706dd3f2e282c3..8f0e71699fdc1626d674f06bc029c53410a8f6ea 100644 (file)
 #include "bfd_stdint.h"
 #include "elf-bfd.h"
 #include "bfdlink.h"
+#include "objalloc.h"
 #include "elf/aarch64.h"
 #include "elfxx-aarch64.h"
 
@@ -1842,6 +1843,10 @@ struct elf_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;
 };
 
 /* Create an entry in an AArch64 ELF linker hash table.  */
@@ -1915,6 +1920,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
+elfNN_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
+elfNN_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 *
+elfNN_aarch64_get_local_sym_hash (struct elf_aarch64_link_hash_table *htab,
+                                 bfd *abfd, const Elf_Internal_Rela *rel,
+                                 bfd_boolean create)
+{
+  struct elf_aarch64_link_hash_entry e, *ret;
+  asection *sec = abfd->sections;
+  hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id,
+                                      ELFNN_R_SYM (rel->r_info));
+  void **slot;
+
+  e.root.indx = sec->id;
+  e.root.dynstr_index = ELFNN_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 elf_aarch64_link_hash_entry *) *slot;
+      return &ret->root;
+    }
+
+  ret = (struct elf_aarch64_link_hash_entry *)
+       objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
+                       sizeof (struct elf_aarch64_link_hash_entry));
+  if (ret)
+    {
+      memset (ret, 0, sizeof (*ret));
+      ret->root.indx = sec->id;
+      ret->root.dynstr_index = ELFNN_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.  */
 
@@ -2004,6 +2075,17 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
+  ret->loc_hash_table = htab_try_create (1024,
+                                        elfNN_aarch64_local_htab_hash,
+                                        elfNN_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;
 }
 
@@ -2015,6 +2097,11 @@ elfNN_aarch64_hash_table_free (struct bfd_link_hash_table *hash)
   struct elf_aarch64_link_hash_table *ret
     = (struct elf_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);
 }
@@ -3321,8 +3408,10 @@ elfNN_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;
   bfd_reloc_code_real_type bfd_r_type
     = elfNN_aarch64_bfd_reloc_from_howto (howto);
@@ -3336,6 +3425,8 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 
   globals = elf_aarch64_hash_table (info);
 
+  symtab_hdr = &elf_symtab_hdr (input_bfd);
+
   BFD_ASSERT (is_aarch64_elf (input_bfd));
 
   r_symndx = ELFNN_R_SYM (rel->r_info);
@@ -3362,6 +3453,180 @@ elfNN_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 (bfd_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 BFD_RELOC_AARCH64_NN:
+         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 = ELFNN_R_INFO (0, AARCH64_R (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 = ELFNN_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 BFD_RELOC_AARCH64_JUMP26:
+       case BFD_RELOC_AARCH64_CALL26:
+         value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
+                                                      signed_addend,
+                                                      weak_undef_p);
+         return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type,
+                                             howto, value);
+       case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+       case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+       case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+       case BFD_RELOC_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 definition.  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_NN (output_bfd, value,
+                                 base_got->contents + off);
+                     /* Note that this is harmless 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 = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
+                                                      0, weak_undef_p);
+         return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type, howto, value);
+       case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+       case BFD_RELOC_AARCH64_ADD_LO12:
+         break;
+       }
+    }
+
   switch (bfd_r_type)
     {
     case BFD_RELOC_AARCH64_NONE:
@@ -3387,11 +3652,6 @@ elfNN_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;
 
@@ -3428,10 +3688,14 @@ elfNN_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_elfNN_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
@@ -3851,6 +4115,20 @@ elfNN_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 = elfNN_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
        {
@@ -3940,7 +4218,7 @@ elfNN_aarch64_relocate_section (bfd *output_bfd,
                                               input_section, contents, rel,
                                               relocation, info, sec,
                                               h, &unresolved_reloc,
-                                              save_addend, &addend);
+                                              save_addend, &addend, sym);
 
       switch (elfNN_aarch64_bfd_reloc_from_type (r_type))
        {
@@ -4427,25 +4705,11 @@ elfNN_aarch64_gc_sweep_hook (bfd *abfd,
 
       if (r_symndx >= symtab_hdr->sh_info)
        {
-         struct elf_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 elf_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
        {
@@ -4454,8 +4718,32 @@ elfNN_aarch64_gc_sweep_hook (bfd *abfd,
          /* 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 = elfNN_aarch64_get_local_sym_hash (htab, abfd, rel, FALSE);
+             if (h == NULL)
+               abort ();
+           }
+       }
+
+      if (h)
+       {
+         struct elf_aarch64_link_hash_entry *eh;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
+
+         eh = (struct elf_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 = ELFNN_R_TYPE (rel->r_info);
@@ -4486,6 +4774,12 @@ elfNN_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)
            {
@@ -4547,12 +4841,13 @@ elfNN_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
@@ -4746,6 +5041,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       unsigned int r_type;
       bfd_reloc_code_real_type bfd_r_type;
+      Elf_Internal_Sym *isym;
 
       r_symndx = ELFNN_R_SYM (rel->r_info);
       r_type = ELFNN_R_TYPE (rel->r_info);
@@ -4758,7 +5054,31 @@ elfNN_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 = elfNN_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];
@@ -4774,6 +5094,38 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
       /* Could be done earlier, if h were already available.  */
       bfd_r_type = aarch64_tls_transition (abfd, info, r_type, h, r_symndx);
 
+      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 (bfd_r_type)
+           {
+           default:
+             break;
+
+           case BFD_RELOC_AARCH64_NN:
+           case BFD_RELOC_AARCH64_CALL26:
+           case BFD_RELOC_AARCH64_JUMP26:
+           case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+           case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+           case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+           case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+           case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+           case BFD_RELOC_AARCH64_ADD_LO12:
+             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;
+       }
+
       switch (bfd_r_type)
        {
        case BFD_RELOC_AARCH64_NN:
@@ -4832,7 +5184,6 @@ elfNN_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);
@@ -4982,7 +5333,10 @@ elfNN_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;
 
        default:
@@ -5130,14 +5484,14 @@ elfNN_aarch64_find_inliner_info (bfd *abfd,
 
 static void
 elfNN_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
@@ -5529,12 +5883,6 @@ elfNN_aarch64_bfd_free_cached_info (bfd *abfd)
   return _bfd_free_cached_info (abfd);
 }
 
-static bfd_boolean
-elfNN_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.  */
@@ -5594,7 +5942,12 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   info = (struct bfd_link_info *) inf;
   htab = elf_aarch64_hash_table (info);
 
-  if (htab->root.dynamic_sections_created && h->plt.refcount > 0)
+  /* 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 TRUE;
+  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.  */
@@ -5849,6 +6202,87 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
+/* Allocate space in .plt, .got and associated reloc sections for
+   ifunc dynamic relocs.  */
+
+static bfd_boolean
+elfNN_aarch64_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
+                                       void *inf)
+{
+  struct bfd_link_info *info;
+  struct elf_aarch64_link_hash_table *htab;
+  struct elf_aarch64_link_hash_entry *eh;
+
+  /* An example of a bfd_link_hash_indirect symbol is versioned
+     symbol. For example: __gxx_personality_v0(bfd_link_hash_indirect)
+     -> __gxx_personality_v0(bfd_link_hash_defined)
+
+     There is no need to process bfd_link_hash_indirect symbols here
+     because we will also be presented with the concrete instance of
+     the symbol and elfNN_aarch64_copy_indirect_symbol () will have been
+     called to copy all relevant data from the generic to the concrete
+     symbol instance.
+   */
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  info = (struct bfd_link_info *) inf;
+  htab = elf_aarch64_hash_table (info);
+
+  eh = (struct elf_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);
+  return TRUE;
+}
+
+/* Allocate space in .plt, .got and associated reloc sections for
+   local dynamic relocs.  */
+
+static bfd_boolean
+elfNN_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 elfNN_aarch64_allocate_dynrelocs (h, inf);
+}
+
+/* Allocate space in .plt, .got and associated reloc sections for
+   local ifunc dynamic relocs.  */
+
+static bfd_boolean
+elfNN_aarch64_allocate_local_ifunc_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 elfNN_aarch64_allocate_ifunc_dynrelocs (h, inf);
+}
 
 /* This is the most important function of all . Innocuosly named
    though !  */
@@ -5987,6 +6421,20 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   elf_link_hash_traverse (&htab->root, elfNN_aarch64_allocate_dynrelocs,
                          info);
 
+  /* Allocate global ifunc sym .plt and .got entries, and space for global
+     ifunc sym dynamic relocs.  */
+  elf_link_hash_traverse (&htab->root, elfNN_aarch64_allocate_ifunc_dynrelocs,
+                         info);
+
+  /* Allocate .plt and .got entries, and space for local symbols.  */
+  htab_traverse (htab->loc_hash_table,
+                elfNN_aarch64_allocate_local_dynrelocs,
+                info);
+
+  /* Allocate .plt and .got entries, and space for local ifunc symbols.  */
+  htab_traverse (htab->loc_hash_table,
+                elfNN_aarch64_allocate_local_ifunc_dynrelocs,
+                info);
 
   /* For every jump slot reserved in the sgotplt, reloc_count is
      incremented.  However, when we reserve space for TLS descriptors,
@@ -6140,7 +6588,8 @@ elf_aarch64_update_plt_entry (bfd *output_bfd,
 static void
 elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
                                       struct elf_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;
@@ -6149,17 +6598,50 @@ elfNN_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;
+
+  /* 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;
+    }
+
+  /* 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.
 
-  plt_index = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size;
+     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.
 
-  /* Offset in the GOT is PLT index plus got GOT headers(3)
-     times GOT_ENTRY_SIZE.  */
-  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;
+     For static executables, we don't reserve anything.  */
+
+  if (plt == htab->root.splt)
+    {
+      plt_index = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size;
+      got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
+    }
+  else
+    {
+      plt_index = h->plt.offset / htab->plt_entry_size;
+      got_offset = plt_index * 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, elfNN_aarch64_small_plt_entry, PLT_SMALL_ENTRY_SIZE);
@@ -6183,19 +6665,35 @@ elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
 
   /* All the GOTPLT Entries are essentially initialized to PLT0.  */
   bfd_put_NN (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 = ELFNN_R_INFO (h->dynindx, AARCH64_R (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 = ELFNN_R_INFO (0, AARCH64_R (IRELATIVE));
+      rela.r_addend = (h->root.u.def.value
+                      + h->root.u.def.section->output_section->vma
+                      + h->root.u.def.section->output_offset);
+    }
+  else
+    {
+      /* Fill in the entry in the .rela.plt section.  */
+      rela.r_info = ELFNN_R_INFO (h->dynindx, AARCH64_R (JUMP_SLOT));
+      rela.r_addend = 0;
+    }
 
   /* 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_elfNN_swap_reloca_out (output_bfd, &rela, loc);
 }
 
@@ -6255,15 +6753,38 @@ elfNN_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 ();
 
-      elfNN_aarch64_create_small_pltn_entry (h, htab, output_bfd);
+      elfNN_aarch64_create_small_pltn_entry (h, htab, output_bfd, info);
       if (!h->def_regular)
        {
          /* Mark the symbol as undefined, rather than as defined in
@@ -6348,6 +6869,21 @@ elfNN_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
+elfNN_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 elfNN_aarch64_finish_dynamic_symbol (info->output_bfd,
+                                             info, h, NULL);
+}
+
 static void
 elfNN_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED,
                                     struct elf_aarch64_link_hash_table
@@ -6587,6 +7123,11 @@ elfNN_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,
+                elfNN_aarch64_finish_local_dynamic_symbol,
+                info);
+
   return TRUE;
 }
 
@@ -6706,9 +7247,6 @@ const struct elf_size_info elfNN_aarch64_size_info =
 #define elf_backend_init_index_section         \
   _bfd_elf_init_2_index_sections
 
-#define elf_backend_is_function_type           \
-  elfNN_aarch64_is_function_type
-
 #define elf_backend_finish_dynamic_sections    \
   elfNN_aarch64_finish_dynamic_sections
 
index 87f834310b32f720efd881dff4af2c1d6776b711..75f21fd35767cb35a55e9b6188a146633c74ec8a 100644 (file)
@@ -1,3 +1,8 @@
+2013-10-03  Will Newton  <will.newton@linaro.org>
+
+       * emulparams/aarch64elf.sh: Add IREL_IN_PLT.
+       * emulparams/aarch64elf32.sh: Likewise.
+
 2013-09-30  Nick Clifton  <nickc@redhat.com>
 
        * emulparams/msp430all.sh: Update ARCH names.
index 53ccd6ab921307b407dd0d46a908f12ca5ada637..6864d65711d4063322acfe2a17f3e2ab9562e1da 100644 (file)
@@ -18,6 +18,7 @@ MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
 ENTRY=_start
 EMBEDDED=yes
 SEPARATE_GOTPLT=24
+IREL_IN_PLT=
 TEXT_START_ADDR=0x00400000
 
 DATA_START_SYMBOLS='__data_start = . ;';
index 5fe08e247f6c3a87d4bb318aa90b9b5320647bda..68a4d8002c715371140737346a7cae72f69f881a 100644 (file)
@@ -18,6 +18,7 @@ MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
 ENTRY=_start
 EMBEDDED=yes
 SEPARATE_GOTPLT=24
+IREL_IN_PLT=
 TEXT_START_ADDR=0x00400000
 
 DATA_START_SYMBOLS='__data_start = . ;';
index da06c70d0d2256f067fcd191262f2e4ce517bd71..6beeb25d5042e80ca3cbd2a4ea6651eccb2a8130 100644 (file)
@@ -1,3 +1,77 @@
+2013-10-03  Will Newton  <will.newton@linaro.org>
+
+       * ld-ifunc/ifunc.exp: Enable ifunc tests for AArch64.
+       * ld-aarch64/aarch64-elf.exp: Run 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-7c.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.
+
 2013-09-24  Gregory Fong  <gregory.0xf0@gmail.com>
 
        * ld-mips-elf/eh-frame5.d, ld-mips-elf/jalx-2.dd,
index d687cc23db1f3c385d911d58e86cc1311572e9fa..5c150dde92c67a096ffb85441e29ff17832bdb24 100644 (file)
@@ -114,3 +114,44 @@ 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-7c"
+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 (file)
index 0000000..0e307e0
--- /dev/null
@@ -0,0 +1,7 @@
+#ld: -shared
+#objdump: -dw
+#target: aarch64*-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+(0x2a0|0x2f0)@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 (file)
index 0000000..7b9d117
--- /dev/null
@@ -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 (file)
index 0000000..9e522c9
--- /dev/null
@@ -0,0 +1,7 @@
+#ld: -shared
+#objdump: -dw
+#target: aarch64*-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+(0x2c0|0x308)@plt>
+#pass
diff --git a/ld/testsuite/ld-aarch64/ifunc-1.s b/ld/testsuite/ld-aarch64/ifunc-1.s
new file mode 100644 (file)
index 0000000..6f86c8a
--- /dev/null
@@ -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 (file)
index 0000000..782b078
--- /dev/null
@@ -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 (file)
index 0000000..10468c1
--- /dev/null
@@ -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 (file)
index 0000000..782b078
--- /dev/null
@@ -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 (file)
index 0000000..e1820de
--- /dev/null
@@ -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 (file)
index 0000000..8fa8ce0
--- /dev/null
@@ -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 (file)
index 0000000..aad30df
--- /dev/null
@@ -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 (file)
index 0000000..e1b5c10
--- /dev/null
@@ -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 (file)
index 0000000..873e06e
--- /dev/null
@@ -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 (file)
index 0000000..3560394
--- /dev/null
@@ -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 (file)
index 0000000..ff580d0
--- /dev/null
@@ -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 (file)
index 0000000..7d6183c
--- /dev/null
@@ -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 (file)
index 0000000..52ed2b4
--- /dev/null
@@ -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 (file)
index 0000000..bac22eb
--- /dev/null
@@ -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 (file)
index 0000000..a83126f
--- /dev/null
@@ -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 (file)
index 0000000..7853280
--- /dev/null
@@ -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 (file)
index 0000000..4ae88d2
--- /dev/null
@@ -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 (file)
index 0000000..62de35e
--- /dev/null
@@ -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 (file)
index 0000000..ab8bdbf
--- /dev/null
@@ -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 (file)
index 0000000..51d9242
--- /dev/null
@@ -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 (file)
index 0000000..f94b4a6
--- /dev/null
@@ -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 (file)
index 0000000..31ec162
--- /dev/null
@@ -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 (file)
index 0000000..ded401a
--- /dev/null
@@ -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 (file)
index 0000000..a87de7c
--- /dev/null
@@ -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 (file)
index 0000000..e0bde49
--- /dev/null
@@ -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 (file)
index 0000000..9286a9f
--- /dev/null
@@ -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 (file)
index 0000000..66abe04
--- /dev/null
@@ -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 (file)
index 0000000..3db91d3
--- /dev/null
@@ -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 (file)
index 0000000..c29c121
--- /dev/null
@@ -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 (file)
index 0000000..b27f526
--- /dev/null
@@ -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 (file)
index 0000000..2e46c1e
--- /dev/null
@@ -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 (file)
index 0000000..dd82b24
--- /dev/null
@@ -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 (file)
index 0000000..3a3d0cd
--- /dev/null
@@ -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 (file)
index 0000000..1e0819c
--- /dev/null
@@ -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 (file)
index 0000000..2e46c1e
--- /dev/null
@@ -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 (file)
index 0000000..103f3e4
--- /dev/null
@@ -0,0 +1,9 @@
+#ld: -shared
+#objdump: -dw
+#target: aarch64*-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+(0x2a0|0x2f0)@plt>
+[ \t0-9a-f]+:[ \t0-9a-f]+adrp[ \t]+x0, 0 <.*>
+[ \t0-9a-f]+:[ \t0-9a-f]+add[ \t]+x0, x0, #(0x290|0x2e0)
+#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 (file)
index 0000000..632c31f
--- /dev/null
@@ -0,0 +1,15 @@
+       .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
+        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 (file)
index 0000000..70ce224
--- /dev/null
@@ -0,0 +1,9 @@
+#ld: -shared
+#objdump: -dw
+#target: aarch64*-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+(0x2c0|0x308)@plt>
+[ \t0-9a-f]+:[ \t0-9a-f]+adrp[ \t]+x0, 0 <.*>
+[ \t0-9a-f]+:[ \t0-9a-f]+add[ \t]+x0, x0, #(0x2b0|0x2f8)
+#pass
diff --git a/ld/testsuite/ld-aarch64/ifunc-2.s b/ld/testsuite/ld-aarch64/ifunc-2.s
new file mode 100644 (file)
index 0000000..da350df
--- /dev/null
@@ -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 (file)
index 0000000..3380479
--- /dev/null
@@ -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 (file)
index 0000000..17393cb
--- /dev/null
@@ -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 (file)
index 0000000..c68b1b7
--- /dev/null
@@ -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 (file)
index 0000000..4f61a8b
--- /dev/null
@@ -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|0x330)@plt>
+#pass
diff --git a/ld/testsuite/ld-aarch64/ifunc-3b.d b/ld/testsuite/ld-aarch64/ifunc-3b.d
new file mode 100644 (file)
index 0000000..7e177a6
--- /dev/null
@@ -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 (file)
index 0000000..5e69b05
--- /dev/null
@@ -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 (file)
index 0000000..c2b66f5
--- /dev/null
@@ -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 (file)
index 0000000..801e6cd
--- /dev/null
@@ -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 (file)
index 0000000..8d23bab
--- /dev/null
@@ -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 (file)
index 0000000..b1bbf1a
--- /dev/null
@@ -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 (file)
index 0000000..9693585
--- /dev/null
@@ -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 (file)
index 0000000..f0ee59f
--- /dev/null
@@ -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 (file)
index 0000000..e8e620c
--- /dev/null
@@ -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 (file)
index 0000000..0175982
--- /dev/null
@@ -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 (file)
index 0000000..463cd25
--- /dev/null
@@ -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 (file)
index 0000000..56486d6
--- /dev/null
@@ -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 (file)
index 0000000..a50ad3a
--- /dev/null
@@ -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 (file)
index 0000000..c415bc3
--- /dev/null
@@ -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 (file)
index 0000000..51485af
--- /dev/null
@@ -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 (file)
index 0000000..c246c99
--- /dev/null
@@ -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 (file)
index 0000000..efdd379
--- /dev/null
@@ -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-7c.d b/ld/testsuite/ld-aarch64/ifunc-7c.d
new file mode 100644 (file)
index 0000000..1967742
--- /dev/null
@@ -0,0 +1,19 @@
+#source: ifunc-7.s
+#ld: -shared
+#objdump: -dr -j .text
+#target: aarch64*-*-*
+
+# Check if adrp and ldr have been relocated correctly.
+
+.*:     file format elf.+aarch64.*
+
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo>:
+ [0-9a-f]+:    d65f03c0        ret
+
+[0-9a-f]+ <__start>:
+ [0-9a-f]+:    [0-9a-f]+       bl      [0-9a-f]+ <\*ABS\*\+0x[0-9a-f]+@plt>
+ [0-9a-f]+:    [0-9a-f]+       adrp    x0, [0-9]+ <__start\+0x[0-9a-f]+>
+ [0-9a-f]+:    [0-9a-f]+       ldr     x0, \[x0,.+\]
diff --git a/ld/testsuite/ld-aarch64/ifunc-8.d b/ld/testsuite/ld-aarch64/ifunc-8.d
new file mode 100644 (file)
index 0000000..8aadc51
--- /dev/null
@@ -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 (file)
index 0000000..94c073a
--- /dev/null
@@ -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 (file)
index 0000000..1f108f8
--- /dev/null
@@ -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 (file)
index 0000000..3b4e995
--- /dev/null
@@ -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 (file)
index 0000000..2e2f577
--- /dev/null
@@ -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
index df913d89bdb6bcdf8989afded778dc34feef6ccc..1d64efcd678e76c9bc8626fa02e87548f38a367b 100644 (file)
 
 
 # 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*"]