]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Various fixes for capability IFUNCs
authorMatthew Malcomson <matthew.malcomson@arm.com>
Thu, 13 Oct 2022 10:19:47 +0000 (11:19 +0100)
committerMatthew Malcomson <matthew.malcomson@arm.com>
Thu, 13 Oct 2022 10:22:52 +0000 (11:22 +0100)
1) Enable having a CAPINIT relocation against an IFUNC.
   We update the `final_link_relocate` switch case around IFUNC's to
   also handle CAPINIT relocations.  The handling of CAPINIT relocations
   is slightly different than for AARCH64_NN (i.e. ABS64) relocations
   since we generally need to emit a dynamic relocation.

   Handling this relocation also needs to manage the PDE case when a
   hard-coded address has been put into code to satisfy something like
   an `adrp`.  In these cases the canonical address of the IFUNC becomes
   its PLT stub rather than the result of the resolver.  We then need to
   use a RELATIVE relocation rather than an IRELATIVE one.
   N.b. unlike the ABS64 relocation, since a CAPINIT will always emit a
   dynamic relocation we do not require pointer equality adjustments on
   a symbol from having seen a CAPINIT.  That means we do not need to
   request that the PLT stub of an IFUNC is treated as the canonical
   address just from having seen a CAPINIT relocation.

   A CAPINIT relocation against an IFUNC needs to be recorded internally
   so that _bfd_elf_allocate_ifunc_dyn_relocs does not garbage collect
   the PLT stub and associated IRELATIVE relocation.

   See changes in the CAPINIT case of the IFUNC switch of
   elfNN_aarch64_final_link_relocate, and in the CAPINIT case of
   elfNN_aarch64_check_relocs.

2) Ensure that GOT relocations against an IFUNC have their fragment
   populated with the LSB set.

   For GOT relocations against a capability IFUNC we need to introduce a
   relocation for the runtime to provide us with a valid capability.

   See changes in the GOT cases of the IFUNC switch of
   elfNN_aarch64_final_link_relocate, changes in the
   elfNN_aarch64_allocate_ifunc_dynrelocs function, and changes around
   handling an IFUNC GOT entry in elfNN_aarch64_finish_dynamic_symbol.

3) Ensure that mapping symbols are emitted for the .iplt.  Without this
   many of the testcases here are disassembled incorrectly.

   See changes in elfNN_aarch64_output_arch_local_syms.

4) IRELATIVE relocations are against symbols which are not in the
   dynamic symbol table, hence they need their fragment populated to
   inform the dynamic linker the bounds and permissions to call the
   associated resolver with.

   See part of the CAPINIT IFUNC handling in
   elfNN_aarch64_final_link_relocate, and the IRELATIVE handling in
   elfNN_aarch64_create_small_pltn_entry.

5) Disallow an ABS64 relocation against a purecap IFUNC.  Such a
   relocation is expecting a 64-bit value but the function will return a
   capability.  Some handling could be implemented by some communication
   method to the dynamic linker that this particular value should be
   64-bit (maybe by emitting an AARCH64_IRELATIVE relocation rather than
   a MORELLO_IRELATIVE one), but as yet GCC doesn't generate such a
   relocation and we believe it's unlikely to be needed.

   See new error check in AARCH64_NN clause of
   elfNN_aarch64_final_link_relocate.

6) Ensure that for statically linked PDE's, we segregate IRELATIVE and
   RELATIVE relocations.  IRELATIVE relocs should be in the .rela.iplt
   section, while RELATIVE relocs should be in the .rela.dyn section.

   Correspondingly all RELATIVE relocations should be between the
   __rela_dyn_{start,end} symbols, and all IRELATIVE relocations should
   be between the __rela_iplt_{start,end} symbols.

   This segregation is made based on dynamic relocation type rather than
   static relocation that generates it.  The segregation allows the
   static libc to more easily handle relocations.

Update testcases accordingly.
We introduce some new testcases, morello-ifunc.s contains uses of an
IFUNC which has been referenced directly in code.  When compiling a PDE
this triggers the pointer equality requirement and hence the canonical
address for this symbol becomes the PLT stub rather than the result of
the resolver.

morello-ifunc1.s does not use the IFUNC directly in code so that the
address used everywhere is the result of the resolver.

Both of these have testcases assembled and linked for static,
dynamically linked PDE, and PIE.  The testcase without a hard-coded
access also has a testcase for -shared.

morello-ifunc2.s is written to check that a CAPINIT relocation does
indeed stop the garbage collection of an IFUNC's PLT and IRELATIVE
relocation.

morello-ifunc3.s tests that we error on an ABS64 relocation against a
C64 IFUNC.

morello-ifunc-dynlink.s tests that a CAPINIT relocation against an IFUNC
symbol defined in a shared library behaves the same way as one against a
FUNC symbol defined in a shared library.

Implementation note:
When segregating IRELATIVE and RELATIVE relocs the change for
relocations against IFUNC symbols populated in the GOT is
straightforward.

For CAPINIT relocations the change is not as straightforward.  The
problem is that on sight of CAPINIT relocations in check_relocs we
immediately allocate space in the srelcaps section.  In trying to
satisfy the above we need to know whether we're going to be emitting an
IRELATIVE relocation or RELATIVE one in order to know which section it
should go in.  The determining factor between these two kinds of
relocations is whether there is a text relocation to this IFUNC symbol,
since that determines whether we need to make this CAPINIT relocation
a RELATIVE relocation pointing to the PLT stub (in order to satisfy
pointer equality) or an IRELATIVE relocation pointing to the resolver.

Whether such a relocation occurs is recorded against each symbol in the
pointer_equality_needed member.  This can only be known after all
relocations have been seen in check_relocs.  Hence, when coming across a
CAPINIT relocation in check_relocs we do not in general know whether
this CAPINIT relocation should end up as an IRELATIVE or RELATIVE
relocation.

This patch postpones the decision by recording the number of CAPINIT
relocations against a given symbol in a hash table while going through
check_relocs and allocating the relevant space in the required section
in size_dynamic_sections.

N.b. this is similar in purpose to the dyn_relocs linked list on a
symbol.  We do not use that existing member which is on every symbol
since the structure does not allow any indication of what kind of
relocation triggered the need.  Moreover the structure is used for
different purposes throughout the linker and disentangling the new
meaning from the existing ones seems overly confusing.

Overall, the decisions about which sections relocations against an IFUNC
should go in are:
  CAPINIT relocations:
    If this is a static PDE link, and the symbol does not need pointer
    equality handling, then this should emit an IRELATIVE relocation and
    that should go in the .rela.iplt section.

    If this is a PIC link, then this should go in the .rela.ifunc
    section (along with all other dynamic relocations against the IFUNC,
    as commented in _bfd_elf_allocate_ifunc_dyn_relocs).

    Otherwise this relocation should go in the srelcaps section (which
    goes in .rela.dyn).

  GOT relocations:
    If this is a static PDE link, and the symbol does not need pointer
    equality, then this should emit an IRELATIVE relocation into the
    .rela.iplt section.

    If this is a static PDE link, then this should emit a RELATIVE
    relocation and that should go in the srelcaps section (which is in
    .rela.dyn).

    Otherwise this should go in .rela.got section.

27 files changed:
bfd/elfnn-aarch64.c
ld/testsuite/ld-aarch64/aarch64-elf.exp
ld/testsuite/ld-aarch64/c64-ifunc-2-local.d
ld/testsuite/ld-aarch64/c64-ifunc-2.d
ld/testsuite/ld-aarch64/c64-ifunc-3a.d
ld/testsuite/ld-aarch64/morello-ifunc-a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc-b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc-dynlink-pie.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc-dynlink.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc-dynlink.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc-shared.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc1-a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc1-b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc1-c.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc1.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc1.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc2-b.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc2.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc2.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc3.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc3.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc4.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc4.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc4a.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/morello-ifunc4a.s [new file with mode: 0644]

index 4dce36d81489aacb5b5b2a47f3e02fcaf65e986c..be4c735753db7716dc5868ec4e0277aa10f52cb3 100644 (file)
@@ -3049,6 +3049,13 @@ struct elf_c64_tls_data_stub_hash_entry
   bfd_boolean populated;
 };
 
+struct elf_c64_ifunc_capinit_record
+{
+  struct elf_link_hash_entry *h;
+  /* Number of CAPINIT relocations this hash entry has against it.  */
+  unsigned long count;
+};
+
 /* Used to build a map of a section.  This is required for mixed-endian
    code/data.  */
 
@@ -3357,6 +3364,11 @@ struct elf_aarch64_link_hash_table
   void **c64_sec_info;
   unsigned min_output_section_id;
   unsigned max_output_section_id;
+
+  /* Used for CAPINIT relocations on a STT_GNU_IFUNC symbols in a static PDE.
+   * */
+  htab_t c64_ifunc_capinit_hash_table;
+  void * c64_ifunc_capinit_memory;
 };
 
 /* Create an entry in an AArch64 ELF linker hash table.  */
@@ -3543,6 +3555,55 @@ c64_tls_stub_find (struct elf_link_hash_entry *h,
   return (struct elf_c64_tls_data_stub_hash_entry *)ret;
 }
 
+static hashval_t
+c64_ifunc_capinit_hash (const void *ptr)
+{
+  struct elf_c64_ifunc_capinit_record *entry
+    = (struct elf_c64_ifunc_capinit_record *) ptr;
+  return htab_hash_pointer (entry->h);
+}
+
+static int
+c64_ifunc_capinit_eq (const void *ptr1, const void *ptr2)
+{
+  struct elf_c64_ifunc_capinit_record *entry1
+     = (struct elf_c64_ifunc_capinit_record *) ptr1;
+  struct elf_c64_ifunc_capinit_record *entry2
+    = (struct elf_c64_ifunc_capinit_record *) ptr2;
+
+  return entry1->h == entry2->h;
+}
+
+static bfd_boolean
+c64_record_ifunc_capinit (struct elf_aarch64_link_hash_table *htab,
+                         struct elf_link_hash_entry *h)
+{
+  BFD_ASSERT (h && h->type == STT_GNU_IFUNC);
+  struct elf_c64_ifunc_capinit_record e, *new_entry;
+  e.h = h;
+  void **slot = htab_find_slot (htab->c64_ifunc_capinit_hash_table, &e,
+                               INSERT);
+  if (!slot)
+    return FALSE;
+  if (*slot)
+    {
+      ((struct elf_c64_ifunc_capinit_record *)*slot)->count += 1;
+      return TRUE;
+    }
+
+  new_entry = (struct elf_c64_ifunc_capinit_record *)
+    objalloc_alloc ((struct objalloc *) htab->c64_ifunc_capinit_memory,
+                   sizeof (struct elf_c64_ifunc_capinit_record));
+  if (new_entry)
+    {
+      new_entry->h = h;
+      new_entry->count = 1;
+      *slot = new_entry;
+      return TRUE;
+    }
+  return FALSE;
+}
+
 /* 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
@@ -3685,6 +3746,11 @@ elfNN_aarch64_link_hash_table_free (bfd *obfd)
   if (ret->tls_data_stub_memory)
     objalloc_free ((struct objalloc *) ret->tls_data_stub_memory);
 
+  if (ret->c64_ifunc_capinit_hash_table)
+    htab_delete (ret->c64_ifunc_capinit_hash_table);
+  if (ret->c64_ifunc_capinit_memory)
+    objalloc_free ((struct objalloc *) ret->c64_ifunc_capinit_memory);
+
   bfd_hash_table_free (&ret->stub_hash_table);
   _bfd_elf_link_hash_table_free (obfd);
 }
@@ -3734,6 +3800,16 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
+  ret->c64_ifunc_capinit_hash_table
+    = htab_try_create (256, c64_ifunc_capinit_hash, c64_ifunc_capinit_eq,
+                      NULL);
+  ret->c64_ifunc_capinit_memory = objalloc_create ();
+  if (!ret->c64_ifunc_capinit_hash_table || !ret->c64_ifunc_capinit_memory)
+    {
+      elfNN_aarch64_link_hash_table_free (abfd);
+      return NULL;
+    }
+
   ret->loc_hash_table = htab_try_create (1024,
                                         elfNN_aarch64_local_htab_hash,
                                         elfNN_aarch64_local_htab_eq,
@@ -7133,6 +7209,26 @@ c64_symbol_adjust (struct elf_link_hash_entry *h,
   return FALSE;
 }
 
+static bfd_boolean
+c64_ifunc_reloc_static_irelative (struct bfd_link_info *info,
+                             struct elf_link_hash_entry *h)
+{
+  return (static_pde (info) && !h->pointer_equality_needed);
+}
+
+static asection *
+c64_ifunc_got_reloc_section (struct bfd_link_info *info,
+                            struct elf_link_hash_entry *h)
+{
+  struct elf_aarch64_link_hash_table *htab;
+  htab = elf_aarch64_hash_table (info);
+  if (c64_ifunc_reloc_static_irelative (info, h))
+    return htab->root.irelplt;
+  if (static_pde (info))
+    return htab->srelcaps;
+  return htab->root.srelgot;
+}
+
 /* Perform a relocation as part of a final link.  The input relocation type
    should be TLS relaxed.  */
 
@@ -7263,6 +7359,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
          bfd_set_error (bfd_error_bad_value);
          return bfd_reloc_notsupported;
 
+       case BFD_RELOC_MORELLO_CAPINIT:
        case BFD_RELOC_AARCH64_NN:
          if (rel->r_addend != 0)
            {
@@ -7280,9 +7377,29 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
              return bfd_reloc_notsupported;
            }
 
-         /* Generate dynamic relocation only when there is a
-            non-GOT reference in a shared object.  */
-         if (bfd_link_pic (info) && h->non_got_ref)
+         /* N.b. Having an AARCH64_NN relocation (i.e. an ABS64
+            relocation) against a capability ifunc is not yet defined.  */
+         if (globals->c64_rel && bfd_r_type == BFD_RELOC_AARCH64_NN)
+           {
+             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 (_("%pB: relocation %s against a C64 "
+                                   "STT_GNU_IFUNC symbol `%s'"),
+                                 input_bfd, howto->name, name);
+             bfd_set_error (bfd_error_bad_value);
+             return bfd_reloc_notsupported;
+           }
+
+         /* Generate dynamic relocation for AArch64 only when there is a
+            non-GOT reference in a shared object.
+            Need a dynamic relocation for a CAPINIT whenever
+            c64_needs_relocation.  */
+         if ((bfd_link_pic (info) && h->non_got_ref)
+             || (bfd_r_type == BFD_RELOC_MORELLO_CAPINIT
+                 && c64_needs_relocation (info, h)))
            {
              Elf_Internal_Rela outrel;
              asection *sreloc;
@@ -7300,17 +7417,57 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
 
+
              if (h->dynindx == -1
                  || h->forced_local
                  || bfd_link_executable (info))
                {
-                 /* This symbol is resolved locally.  */
-                 outrel.r_info = (globals->c64_rel
-                                  ? ELFNN_R_INFO (0, MORELLO_R (IRELATIVE))
-                                  : 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);
+                 /* This symbol is resolved locally.
+                    N.b. a MORELLO_IRELATIVE relocation is not suitable for
+                    populating an 8-byte value.  We don't handle ABS64
+                    relocations against a capability IFUNC.  */
+                 bfd_vma resolver_loc = (h->root.u.def.value
+                                         + h->root.u.def.section->output_section->vma
+                                         + h->root.u.def.section->output_offset);
+
+                 if (bfd_r_type == BFD_RELOC_MORELLO_CAPINIT)
+                   {
+                     bfd_vma frag_value = 0, value_tmp;
+                     if (h->pointer_equality_needed && !bfd_link_pic (info))
+                       {
+                         outrel.r_info = ELFNN_R_INFO (0, MORELLO_R (RELATIVE));
+                         /* Use the PLT as the canonical address.  */
+                         value_tmp = value;
+                       }
+                     else
+                       {
+                         outrel.r_info = ELFNN_R_INFO (0, MORELLO_R (IRELATIVE));
+                         value_tmp = resolver_loc;
+                       }
+                     BFD_ASSERT (c64_symbol_adjust (h, value_tmp, sym_sec, info,
+                                                    &frag_value));
+                     outrel.r_addend
+                       = (value_tmp | h->target_internal) - frag_value;
+                     /* Can feel safe asserting things here since we've
+                        created all of the values.  I.e. nothing is coming
+                        from the user and hence we don't need gracious error
+                        handling.  */
+                     BFD_ASSERT (_bfd_aarch64_elf_put_addend (input_bfd,
+                                                              hit_data,
+                                                              bfd_r_type,
+                                                              howto, frag_value)
+                                 == bfd_reloc_ok);
+                     BFD_ASSERT (c64_fixup_frag (input_bfd, info, bfd_r_type,
+                                                 sym, h, sym_sec,
+                                                 input_section, hit_data + 8,
+                                                 value_tmp, 0, rel->r_offset)
+                                 == bfd_reloc_continue);
+                   }
+                 else
+                   {
+                     outrel.r_info = ELFNN_R_INFO (0, AARCH64_R (IRELATIVE));
+                     outrel.r_addend = resolver_loc;
+                   }
                }
              else
                {
@@ -7318,8 +7475,21 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
                  outrel.r_addend = 0;
                }
 
-             sreloc = globals->root.irelifunc;
-             elf_append_rela (output_bfd, sreloc, &outrel);
+             if (c64_ifunc_reloc_static_irelative (info, h))
+               {
+                 /* In the same way as TLS descriptor PLT stubs, we want
+                    IRELATIVE relocations coming from CAPINIT relocations to
+                    be after all the relocations for PLT stub entries.  */
+                 BFD_ASSERT (bfd_r_type == BFD_RELOC_MORELLO_CAPINIT);
+                 sreloc = globals->root.irelplt;
+                 bfd_byte *loc = sreloc->contents
+                   + sreloc->reloc_count++ * RELOC_SIZE (globals);
+                 bfd_elfNN_swap_reloca_out (output_bfd, &outrel, loc);
+               }
+             else if (bfd_link_pic (info))
+               elf_append_rela (output_bfd, globals->root.irelifunc, &outrel);
+             else
+               elf_append_rela (output_bfd, globals->srelcaps, &outrel);
 
              /* If this reloc is against an external symbol, we
                 do not want to fiddle with the addend.  Otherwise,
@@ -7356,6 +7526,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
          if (base_got == NULL)
            abort ();
 
+         value |= h->target_internal;
          if (off == (bfd_vma) -1)
            {
              bfd_vma plt_index;
@@ -9950,6 +10121,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
              h->ref_regular = 1;
              h->forced_local = 1;
              h->root.type = bfd_link_hash_defined;
+             h->target_internal = isym->st_target_internal;
            }
          else
            h = NULL;
@@ -10040,6 +10212,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
            case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
            case BFD_RELOC_AARCH64_NN:
+           case BFD_RELOC_MORELLO_CAPINIT:
              if (htab->root.dynobj == NULL)
                htab->root.dynobj = abfd;
              if (!_bfd_elf_create_ifunc_sections (htab->root.dynobj, info))
@@ -10384,6 +10557,13 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            /* If this symbol does not need a relocation, then there's no
               reason to increase the srelcaps size for a relocation.  */
            break;
+         /* Always create srelcaps, even if there's the possibility that this
+            relocation will not end up in srelcaps (i.e. in the special case
+            that our CAPINIT relocation will end up as an IRELATIVE relocation
+            in .rela.iplt for static PDE).  If we don't actually put anything
+            into this section it will be empty and won't appear in the output
+            (similar to how we use `_bfd_elf_create_ifunc_sections` above).
+            */
          if (htab->srelcaps == NULL)
            {
              if (htab->root.dynobj == NULL)
@@ -10398,6 +10578,49 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
              htab->srelcaps = sreloc;
            }
+
+         /* Mark any IFUNC symbol as requiring a PLT.
+            We do not want to use dyn_relocs since generic code ignores this
+            when not linking PIC but we need the dynamic relocation for
+            capabilities.
+            We would not benefit from using dyn_relocs since a CAPINIT
+            relocation will never be reduced to a hand-coded value and hence
+            can't be garbage collected (even if it may turn from a CAPINIT to
+            an IRELATIVE).
+            However, without dyn_relocs or a greater than zero plt.refcount,
+            _bfd_elf_allocate_ifunc_dyn_relocs would garbage collect the PLT
+            entry for this symbol believing that it is not used.  */
+         if (h && h->type == STT_GNU_IFUNC)
+           {
+             h->needs_plt = 1;
+             h->plt.refcount = h->plt.refcount < 0
+               ? 1 : h->plt.refcount + 1;
+             /* The only time that a CAPINIT relocation should not trigger
+                some dynamic relocation in the srelcaps section of the output
+                binary is when the relocation is against an STT_GNU_IFUNC in
+                a static PDE.  In this case we need to emit the relocations in
+                the .rela.iplt section.  */
+             if (static_pde (info))
+               {
+                 /* As yet we do not know whether this symbol needs pointer
+                    equality or not.  This means that we don't know which
+                    symbols (either __rela_dyn_{start,end} or
+                    __rela_iplt_{start,end}) we need to put this relocation
+                    between.
+
+                    This problem does not exist outside of a static_pde since
+                    there the runtime reads all relocs rather than relying on
+                    symbols to point to where relocations are.  */
+                 BFD_ASSERT (c64_record_ifunc_capinit (htab, h));
+                 break;
+               }
+             else if (bfd_link_pic (info))
+               {
+                 htab->root.irelifunc->size += RELOC_SIZE (htab);
+                 break;
+               }
+             /* Otherwise put into the srelcaps section.  */
+           }
          htab->srelcaps->size += RELOC_SIZE (htab);
 
          break;
@@ -10751,12 +10974,22 @@ elfNN_aarch64_output_arch_local_syms (bfd *output_bfd,
     }
 
   /* Finally, output mapping symbols for the PLT.  */
-  if (!htab->root.splt || htab->root.splt->size == 0)
+  if ((!htab->root.splt || htab->root.splt->size == 0)
+      && (!htab->root.iplt || htab->root.iplt->size == 0))
     return TRUE;
 
-  osi.sec_shndx = _bfd_elf_section_from_bfd_section
-    (output_bfd, htab->root.splt->output_section);
-  osi.sec = htab->root.splt;
+  if (htab->root.splt && htab->root.splt->size != 0)
+    {
+      osi.sec_shndx = _bfd_elf_section_from_bfd_section
+       (output_bfd, htab->root.splt->output_section);
+      osi.sec = htab->root.splt;
+    }
+  else
+    {
+      osi.sec_shndx = _bfd_elf_section_from_bfd_section
+       (output_bfd, htab->root.iplt->output_section);
+      osi.sec = htab->root.iplt;
+    }
 
   elfNN_aarch64_output_map_sym (&osi, (htab->c64_rel ? AARCH64_MAP_C64
                                       : AARCH64_MAP_INSN), 0);
@@ -10892,7 +11125,9 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
             entries are placed by computing their PLT index (0
             .. reloc_count). While other none PLT relocs are placed
             at the slot indicated by reloc_count and reloc_count is
-            updated.  */
+            updated.
+            For reference, a similar abuse of the reloc_count is done for the
+            irelplt section for Morello CAPINIT relocations.  */
 
          htab->root.srelplt->reloc_count++;
 
@@ -11161,12 +11396,29 @@ elfNN_aarch64_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
      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,
-                                              &h->dyn_relocs,
-                                              htab->plt_entry_size,
-                                              htab->plt_header_size,
-                                              GOT_ENTRY_SIZE (htab),
-                                              FALSE);
+    {
+      bfd_boolean ret
+       = _bfd_elf_allocate_ifunc_dyn_relocs (info, h, &h->dyn_relocs,
+                                             htab->plt_entry_size,
+                                             htab->plt_header_size,
+                                             GOT_ENTRY_SIZE (htab), FALSE);
+      if (htab->c64_rel
+         && ret
+         && h->got.offset != (bfd_vma)-1
+         && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)
+         && !bfd_link_pic (info)
+         && !bfd_link_relocatable (info))
+       /* got.offset is not -1 which indicates we have an entry in the got.
+          For non-capabilities we would manually populate the GOT with the
+          known location of the PLT in finish_dynamic_symbol, since this is a
+          non-PIC executable.  For capabilities we need to emit a relocation
+          to populate that entry.  */
+       {
+         asection *reloc_sec = c64_ifunc_got_reloc_section (info, h);
+         reloc_sec->size += RELOC_SIZE (htab);
+       }
+      return ret;
+    }
   return TRUE;
 }
 
@@ -11189,6 +11441,34 @@ elfNN_aarch64_allocate_local_ifunc_dynrelocs (void **slot, void *inf)
   return elfNN_aarch64_allocate_ifunc_dynrelocs (h, inf);
 }
 
+/* Allocate space for CAPINIT relocations against IFUNC symbols in a static
+   PDE.  This case is special since the IRELATIVE relocations and RELATIVE
+   relocations need to be placed in different sections, and the decision about
+   whether we need to emit an IRELATIVE or RELATIVE relocation is dependent on
+   whether there are *other* relocations.  */
+static bfd_boolean
+c64_allocate_ifunc_capinit_static_relocs (void **slot, void *inf)
+{
+  struct elf_link_hash_entry *h;
+  struct elf_c64_ifunc_capinit_record *rec
+    = (struct elf_c64_ifunc_capinit_record *) *slot;
+  h = rec->h;
+
+  if (h->type != STT_GNU_IFUNC
+      || !h->def_regular
+      || !h->ref_regular
+      || h->root.type != bfd_link_hash_defined)
+    abort ();
+
+  struct bfd_link_info *info = (struct bfd_link_info *) inf;
+  struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+  if (c64_ifunc_reloc_static_irelative (info, h))
+    htab->root.irelplt->size += rec->count * RELOC_SIZE (htab);
+  else
+    htab->srelcaps->size += rec->count * RELOC_SIZE (htab);
+  return TRUE;
+}
+
 /* This is the most important function of all . Innocuosly named
    though !  */
 
@@ -11345,6 +11625,14 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd,
                 elfNN_aarch64_allocate_local_ifunc_dynrelocs,
                 info);
 
+  if (static_pde (info))
+    {
+      htab_traverse (htab->c64_ifunc_capinit_hash_table,
+                    c64_allocate_ifunc_capinit_static_relocs,
+                    info);
+      htab_empty (htab->c64_ifunc_capinit_hash_table);
+    }
+
   if (static_pde (info)
       && htab->srelcaps
       && htab->srelcaps->size > 0)
@@ -11426,7 +11714,8 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd,
 
          /* We use the reloc_count field as a counter if we need
             to copy relocs into the output file.  */
-         if (s != htab->root.srelplt)
+         if (s != htab->root.srelplt
+             && s != htab->root.irelplt)
            s->reloc_count = 0;
        }
       else
@@ -11640,12 +11929,32 @@ elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
     {
       /* If an STT_GNU_IFUNC symbol is locally defined, generate
         R_AARCH64_IRELATIVE instead of R_AARCH64_JUMP_SLOT.  */
-      rela.r_info = (htab->c64_rel
-                    ? ELFNN_R_INFO (0, MORELLO_R (IRELATIVE))
-                    : 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);
+      if (htab->c64_rel)
+       {
+         /* A MORELLO_IRELATIVE relocation is the only kind of relocation that
+            wants something other than PLT0 in the fragment.  It requires the
+            PCC base with associated permissions and size information.  */
+         bfd_vma frag_value = 0;
+         bfd_vma orig_value = rela.r_addend;
+         rela.r_info = ELFNN_R_INFO (0, MORELLO_R (IRELATIVE));
+         BFD_ASSERT (c64_symbol_adjust (h, orig_value, plt, info,
+                                        &frag_value));
+         rela.r_addend = (orig_value | 1) - frag_value;
+         bfd_put_NN (output_bfd, frag_value, gotplt->contents + got_offset);
+         BFD_ASSERT (c64_fixup_frag (output_bfd, info,
+                                     BFD_RELOC_MORELLO_CAPINIT,
+                                     NULL, h, plt, gotplt,
+                                     gotplt->contents + got_offset + 8,
+                                     orig_value, 0, rela.r_offset)
+                     == bfd_reloc_continue);
+       }
+      else
+       {
+         rela.r_info = ELFNN_R_INFO (0, AARCH64_R (IRELATIVE));
+       }
     }
   else
     {
@@ -11807,11 +12116,37 @@ elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd,
                 contains the real function address if we need pointer
                 equality.  We load the GOT entry with the PLT entry.  */
              plt = htab->root.splt ? htab->root.splt : htab->root.iplt;
-             bfd_put_NN (output_bfd, (plt->output_section->vma
-                                      + plt->output_offset
-                                      + h->plt.offset),
-                         htab->root.sgot->contents
-                         + (h->got.offset & ~(bfd_vma) 1));
+
+             bfd_vma value = (plt->output_section->vma + plt->output_offset
+                              + h->plt.offset);
+             bfd_vma got_offset = h->got.offset & ~(bfd_vma)1;
+             if (htab->c64_rel)
+               {
+                 bfd_vma base_value = 0;
+                 BFD_ASSERT (c64_symbol_adjust (h, value, plt, info,
+                                                &base_value));
+                 rela.r_info = ELFNN_R_INFO (0, MORELLO_R (RELATIVE));
+                 rela.r_addend = (value | h->target_internal) - base_value;
+                 asection *s = c64_ifunc_got_reloc_section (info, h);
+                 elf_append_rela (output_bfd, s, &rela);
+
+                 /* N.b. we do not use c64_fixup_frag since in includes a
+                    bunch of features we do not use like error checking the
+                    size and ensuring figuring out whether we need to extend
+                    things depending on the kind of symbol.  We know these due
+                    to the fact this is a STT_GNU_IFUNC symbol.
+                    In order to implement those features it requires quite a
+                    lot of arguments which we don't happen to have here.  */
+                 bfd_boolean guessed = FALSE;
+                 bfd_vma meta = cap_meta (pcc_high - pcc_low, plt, &guessed);
+                 BFD_ASSERT (!guessed);
+                 bfd_put_NN (output_bfd, meta,
+                             htab->root.sgot->contents + got_offset + 8);
+                 value = base_value;
+               }
+
+             bfd_put_NN (output_bfd, value,
+                         htab->root.sgot->contents + got_offset);
              return TRUE;
            }
        }
index 2c372e2413837a5413bf45f0888ef0b50c2af98b..73c414ad7b49415fb428afdd3169cc5a26fce4ec 100644 (file)
@@ -106,7 +106,7 @@ proc aarch64_page_plus_decimal_offset { page offset } {
 # Return the 8-hexdigit truncation of an address.
 proc aarch64_8digit_addr { addr { plusLSB 0 } } {
   if { $plusLSB } {
-    return [aarch64_8digit_addr [format %08x [expr "0x$addr + 1"]]];
+    return [format %08x [expr "0x$addr + 1"]];
   }
   return [format %08x "0x$addr"];
 }
@@ -312,6 +312,25 @@ if { [check_shared_lib_support]
   run_dump_test_lp64 "morello-dataptr-through-data"
   run_dump_test_lp64 "morello-dataptr-through-data-pie"
   run_dump_test_lp64 "morello-dataptr-code-and-data"
+  run_dump_test_lp64 "morello-ifunc-a"
+  run_dump_test_lp64 "morello-ifunc1-a"
+}
+run_dump_test_lp64 "morello-ifunc"
+run_dump_test_lp64 "morello-ifunc-b"
+run_dump_test_lp64 "morello-ifunc1"
+run_dump_test_lp64 "morello-ifunc1-b"
+run_dump_test_lp64 "morello-ifunc1-c"
+run_dump_test_lp64 "morello-ifunc2"
+run_dump_test_lp64 "morello-ifunc2-b"
+run_dump_test_lp64 "morello-ifunc3"
+run_dump_test_lp64 "morello-ifunc4"
+run_dump_test_lp64 "morello-ifunc4a"
+
+if { [check_shared_lib_support]
+     && [ld_assemble_flags $as -march=morello+c64 $srcdir/$subdir/morello-ifunc-shared.s tmpdir/morello-ifunc-shared.o]
+     && [ld_link $ld tmpdir/morello-ifunc-shared.so "--shared tmpdir/morello-ifunc-shared.o"] } {
+  run_dump_test_lp64 "morello-ifunc-dynlink"
+  run_dump_test_lp64 "morello-ifunc-dynlink-pie"
 }
 
 if { [check_shared_lib_support]
index c85443fe71acb15f04d749cbb159fc002893d46c..6f00498390bd7420f3a48e4410c14a4d19b077d6 100644 (file)
@@ -1,13 +1,30 @@
 #target: [check_shared_lib_support]
 #as: -march=morello+c64 --defsym C64MODE=1
 #ld: -shared --hash-style=sysv
-#objdump: -dw
+#objdump: -dw --section-headers
 #source: ifunc-2-local.s
 
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn  Flags
+#record: PCC_START
+  0 \.[^ ]* *[0-9a-f]+  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*[0-9]  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#...
+Disassembly of section \.plt:
+
+#record: INDIRECT_LOC FOO_LOCATION
 #...
-0+(110|180|1a0|1b8) <__GI_foo>:
+0+([0-9a-f]{3}).*0x([0-9a-f]+)@plt>:
+#...
+Disassembly of section \.text:
+
+#check: FOO_LOC string tolower $FOO_LOCATION
+#check: FOO_ADDR format %016x [expr "0x$PCC_START + 0x$FOO_LOCATION & ~1"]
+#check: INDIRECT_POS format %x [expr "0x$INDIRECT_LOC + 1"]
+FOO_ADDR <__GI_foo>:
 #...
-[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+0x(110|180|1a0|1b8)@plt>
+[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+0xFOO_LOC@plt>
 [ \t0-9a-f]+:[ \t0-9a-f]+adrp[ \t]+c0, 0 <.*>
-[ \t0-9a-f]+:[ \t0-9a-f]+add[ \t]+c0, c0, #0x(101|171|191|1a9)
+[ \t0-9a-f]+:[ \t0-9a-f]+add[ \t]+c0, c0, #0xINDIRECT_POS
 #pass
index 2954f67b0c50ece30e2e7a002fc7e03f2afb9f4c..1214c310639726d805f99da34a597679f008653f 100644 (file)
@@ -1,18 +1,28 @@
 #target: [check_shared_lib_support]
 #as: -march=morello+c64 --defsym C64MODE=1
 #ld: -shared --hash-style=sysv
-#objdump: -dw
+#objdump: -dw --section-headers
 #source: ifunc-2.s
 
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn  Flags
+#record: PCC_START
+  0 \.[^ ]* *[0-9a-f]+  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*[0-9]  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#...
+Disassembly of section \.plt:
+
 #record: INDIRECT_LOC FOO_LOCATION
 #...
-0+([0-9a-f]{3}).*0x([0-9a-f]{3})@plt>:
+0+([0-9a-f]{3}).*0x([0-9a-f]+)@plt>:
 #...
 Disassembly of section \.text:
 
 #check: FOO_LOC string tolower $FOO_LOCATION
+#check: FOO_ADDR format %016x [expr "0x$PCC_START + 0x$FOO_LOCATION & ~1"]
 #check: INDIRECT_POS format %x [expr "0x$INDIRECT_LOC + 1"]
-0+FOO_LOC <foo>:
+FOO_ADDR <foo>:
 #...
 [ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+0xFOO_LOC@plt>
 [ \t0-9a-f]+:[ \t0-9a-f]+adrp[ \t]+c0, 0 <.*>
index 7690b42edd576039c6e455fcf5bb7a480ee0f8bd..905612ccec2d058713960f185ba4490e2e1dee8e 100644 (file)
@@ -2,14 +2,27 @@
 #target: [check_shared_lib_support]
 #as: -march=morello+c64
 #ld: -shared --hash-style=sysv
-#objdump: -dw
+#objdump: -dw --section-headers
 
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn  Flags
+#record: PCC_START
+  0 \.[^ ]* *[0-9a-f]+  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*[0-9]  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#...
+Disassembly of section \.plt:
+
+#record: INDIRECT_LOC FOO_LOCATION
+#...
+0+([0-9a-f]{3}).*0x([0-9a-f]+)@plt>:
 #...
 Disassembly of section \.text:
 
-#record: INDIRECT_FOO
-([0-9a-f]+) <__GI_foo>:
-#check: FOO_POS format %x 0x$INDIRECT_FOO
+#check: FOO_LOC string tolower $FOO_LOCATION
+#check: FOO_ADDR format %016x [expr "0x$PCC_START + 0x$FOO_LOCATION & ~1"]
+#check: INDIRECT_POS string tolower $INDIRECT_LOC
+FOO_ADDR <__GI_foo>:
 #...
-[ \t0-9a-f]+:[ \t0-9a-f]+bl[ \t0-9a-f]+<\*ABS\*\+0xFOO_POS@plt>
+[ \t0-9a-f]+:[ \t0-9a-f]+bl\tINDIRECT_POS <\*ABS\*\+0xFOO_LOC@plt>
 #pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc-a.d b/ld/testsuite/ld-aarch64/morello-ifunc-a.d
new file mode 100644 (file)
index 0000000..f36b094
--- /dev/null
@@ -0,0 +1,111 @@
+# Checking that the introduction of a CAPINIT relocation against an IFUNC does
+# not change the behaviour of us requiring pointer equality, and checking that
+# the CAPINIT relocation respects that pointer equality requirement by pointing
+# at the PLT stub.
+#source: morello-ifunc.s
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#objdump: -DR --section-headers
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: PCC_START
+  0 \.[^ ]* +[0-9a-f]*  ([0-9a-f]+)  .*
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: PCC_LAST_SIZE PCC_LAST_START
+#...
+ *[0-9]+ \.got\.plt *([0-9a-f]+)  ([0-9a-f]+) .*
+                  CONTENTS, ALLOC, LOAD, DATA
+#...
+Disassembly of section \.plt:
+
+#record: PLT0_ADDR
+([0-9a-f]+) <\.plt>:
+#...
+.*nop
+.*nop
+.*nop
+# Note that for a none-linux-gnu target we don't emit a symbol specific to the
+# PLT stub for an IFUNC, but for a none-elf target we do.  That means we can't
+# generally check the offset in the symbols name matches the `foo` address
+# below.
+#?
+#?[0-9a-f]+ <\*ABS\*\+0x[0-9a-f]+@plt>:
+#record: PLTADDR PLTGOT_PAGE
+ *([0-9a-f]+): .*      adrp    c16, ([0-9a-f]+) .*
+#record: FOO_PLTGOT_OFFSET
+ *[0-9a-f]+:   .*      ldr     c17, \[c16, #([0-9]+)\]
+ *[0-9a-f]+:   .*      add     c16, c16, #0x.*
+ *[0-9a-f]+:   c2c21220        br      c17
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+#...
+
+[0-9a-f]+ <foo_2>:
+#...
+
+#record: FOO_ADDR
+([0-9a-f]+) <foo>:
+ *[0-9a-f]+:   .*      mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   .*      tst     x0, x1
+ *[0-9a-f]+:   .*      b\.ne   .*
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      ret     c30
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      b       .*
+
+[0-9a-f]+ <_start>:
+#check: PLTLOC string tolower $PLTADDR
+#check: PLT_PAGE format %x [expr "0x$PLTADDR & ~0xfff"]
+#check: FOO_PLT_OFF format %x [expr "(0x$PLTADDR & 0xfff) + 1"]
+ *[0-9a-f]+:   .*      bl      PLTLOC .*
+#record: GOT_PAGE
+ *[0-9a-f]+:   .*      adrp    c0, ([0-9a-f]+) .*
+#record: FOO_GOTOFF_DECIMAL
+ *[0-9a-f]+:   .*      ldr     c0, \[c0, #([0-9]+)\]
+ *[0-9a-f]+:   .*      adrp    c0, PLT_PAGE .*
+ *[0-9a-f]+:   .*      add     c0, c0, #0xFOO_PLT_OFF
+ *[0-9a-f]+:   .*      ret     c30
+
+#...
+Disassembly of section \.got:
+
+#check: PLT_ADDEND  format %x [expr "0x$PLTADDR - 0x$PCC_START + 1"]
+#check: FRAGBASE format %08x 0x$PCC_START
+#check: FRAGSIZE format %08x [expr "0x$PCC_LAST_SIZE + 0x$PCC_LAST_START - 0x$PCC_START"]
+#check: FRAGMENT_LOC  aarch64_page_plus_decimal_offset $GOT_PAGE $FOO_GOTOFF_DECIMAL
+#...
+ *FRAGMENT_LOC:        FRAGBASE        .*
+                       [0-9a-f]+: R_MORELLO_RELATIVE   \*ABS\*\+0xPLT_ADDEND
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+
+Disassembly of section \.got\.plt:
+
+#check: PLTGOTLOC  aarch64_page_plus_decimal_offset $PLTGOT_PAGE $FOO_PLTGOT_OFFSET
+#check: FOO_OFFSET format %x [expr "0x$FOO_ADDR + 1 - 0x$PCC_START"]
+[0-9a-f]+ <.*>:
+       \.\.\.
+ *PLTGOTLOC:   FRAGBASE        .*
+                       PLTGOTLOC: R_MORELLO_IRELATIVE  \*ABS\*\+0xFOO_OFFSET
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+       \.\.\.
+
+Disassembly of section \.data:
+
+[0-9a-f]+ <.*>:
+ *[0-9a-f]+:   FRAGBASE        .*
+                       .*: R_MORELLO_RELATIVE  \*ABS\*\+0xPLT_ADDEND
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc-b.d b/ld/testsuite/ld-aarch64/morello-ifunc-b.d
new file mode 100644 (file)
index 0000000..c6938e0
--- /dev/null
@@ -0,0 +1,104 @@
+# Checking that the introduction of a CAPINIT relocation against an IFUNC does
+# not change the behaviour of us requiring pointer equality, and checking that
+# the CAPINIT relocation respects that pointer equality requirement by pointing
+# at the PLT stub.
+#source: morello-ifunc.s
+#as: -march=morello+c64
+#ld: -pie
+#objdump: -DR --section-headers
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: PCC_START
+  0 \.[^ ]* +[0-9a-f]*  ([0-9a-f]+)  .*
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: PCC_LAST_SIZE PCC_LAST_START
+#...
+ *[0-9]+ \.got\.plt *([0-9a-f]+)  ([0-9a-f]+) .*
+                  CONTENTS, ALLOC, LOAD, DATA
+#...
+Disassembly of section \.plt:
+
+#record: PLT0_ADDR
+([0-9a-f]+) <\.plt>:
+#...
+.*nop
+.*nop
+.*nop
+
+#record: RESOLVER_ADDEND
+[0-9a-f]+ <\*ABS\*\+0x([0-9a-f]+)@plt>:
+#record: PLTADDR PLTGOT_PAGE
+ *([0-9a-f]+): .*      adrp    c16, ([0-9a-f]+) .*
+#record: FOO_PLTGOT_OFFSET
+ *[0-9a-f]+:   .*      ldr     c17, \[c16, #([0-9]+)\]
+ *[0-9a-f]+:   .*      add     c16, c16, #0x.*
+ *[0-9a-f]+:   c2c21220        br      c17
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+#...
+
+[0-9a-f]+ <foo_2>:
+#...
+
+#check: FOO_ADDRESS format %x [expr "0x$PCC_START + 0x$RESOLVER_ADDEND - 1"]
+([0-9a-f]+) <foo>:
+ *[0-9a-f]+:   .*      mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   .*      tst     x0, x1
+ *[0-9a-f]+:   .*      b\.ne   .*
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      ret     c30
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      b       .*
+
+[0-9a-f]+ <_start>:
+#check: PLTLOC string tolower $PLTADDR
+#check: PLT_PAGE format %x [expr "0x$PLTADDR & ~0xfff"]
+#check: FOO_PLT_OFF format %x [expr "(0x$PLTADDR & 0xfff) + 1"]
+ *[0-9a-f]+:   .*      bl      PLTLOC .*
+#record: GOT_PAGE
+ *[0-9a-f]+:   .*      adrp    c0, ([0-9a-f]+) .*
+#record: FOO_GOTOFF_DECIMAL
+ *[0-9a-f]+:   .*      ldr     c0, \[c0, #([0-9]+)\]
+ *[0-9a-f]+:   .*      adrp    c0, PLT_PAGE .*
+ *[0-9a-f]+:   .*      add     c0, c0, #0xFOO_PLT_OFF
+ *[0-9a-f]+:   .*      ret     c30
+
+#...
+Disassembly of section \.got:
+
+[0-9a-f]+ <.*>:
+ *[0-9a-f]+:.*
+       \.\.\.
+
+Disassembly of section \.got\.plt:
+
+#check: PLT_ADDEND  format %x [expr "0x$PLTADDR - 0x$PCC_START + 1"]
+#check: FRAGBASE format %08x 0x$PCC_START
+#check: FRAGSIZE format %08x [expr "0x$PCC_LAST_SIZE + 0x$PCC_LAST_START - 0x$PCC_START"]
+#check: FRAGMENT_LOC  aarch64_page_plus_decimal_offset $GOT_PAGE $FOO_GOTOFF_DECIMAL
+#check: PLTGOTLOC  aarch64_page_plus_decimal_offset $PLTGOT_PAGE $FOO_PLTGOT_OFFSET
+#check: FOO_OFFSET string tolower $RESOLVER_ADDEND
+[0-9a-f]+ <.*>:
+       \.\.\.
+ *PLTGOTLOC:   FRAGBASE        .*
+                       PLTGOTLOC: R_MORELLO_IRELATIVE  \*ABS\*\+0xFOO_OFFSET
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#...
+Disassembly of section \.data:
+
+[0-9a-f]+ <.*>:
+ *[0-9a-f]+:   FRAGBASE        .*
+                       .*: R_MORELLO_IRELATIVE \*ABS\*\+0xFOO_OFFSET
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc-dynlink-pie.d b/ld/testsuite/ld-aarch64/morello-ifunc-dynlink-pie.d
new file mode 100644 (file)
index 0000000..e139f02
--- /dev/null
@@ -0,0 +1,20 @@
+# Checking that the sharedfoo symbol is a FUNC and UNDEFINED symbol.
+# It should also have 0 as its value (so that we don't make the PLT stub the
+# canonical address).
+# Also checking that there is a CAPINIT relocation against the sharedfoo symbol
+# (i.e. that it has not been relaxed to some other relocation).
+#source: morello-ifunc-dynlink.s
+#as: -march=morello+c64
+#ld: -pie tmpdir/morello-ifunc-shared.so
+#readelf: --relocs --dyn-syms
+
+Relocation section '\.rela\.dyn' at offset 0x.* contains 1 entry:
+  Offset          Info           Type           Sym\. Value    Sym\. Name \+ Addend
+[0-9a-f]+  00030000e800 R_MORELLO_CAPINIT 0000000000000000 sharedfoo \+ 0
+
+#...
+Symbol table '\.dynsym' contains [0-9]+ entries:
+   Num:    Value          Size Type    Bind   Vis      Ndx Name
+#...
+ +[0-9]+: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sharedfoo
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc-dynlink.d b/ld/testsuite/ld-aarch64/morello-ifunc-dynlink.d
new file mode 100644 (file)
index 0000000..328fe04
--- /dev/null
@@ -0,0 +1,20 @@
+# Checking that the sharedfoo symbol is a FUNC and UNDEFINED symbol.
+# It should also have 0 as its value (so that we don't make the PLT stub the
+# canonical address).
+# Also checking that there is a CAPINIT relocation against the sharedfoo symbol
+# (i.e. that it has not been relaxed to some other relocation).
+#source: morello-ifunc-dynlink.s
+#as: -march=morello+c64
+#ld: tmpdir/morello-ifunc-shared.so
+#readelf: --relocs --dyn-syms
+
+Relocation section '\.rela\.dyn' at offset 0x.* contains 1 entry:
+  Offset          Info           Type           Sym\. Value    Sym\. Name \+ Addend
+[0-9a-f]+  ............ R_MORELLO_CAPINIT 0000000000000000 sharedfoo \+ 0
+
+#...
+Symbol table '\.dynsym' contains [0-9]+ entries:
+   Num:    Value          Size Type    Bind   Vis      Ndx Name
+#...
+ +[0-9]+: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sharedfoo
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc-dynlink.s b/ld/testsuite/ld-aarch64/morello-ifunc-dynlink.s
new file mode 100644 (file)
index 0000000..a6a7e40
--- /dev/null
@@ -0,0 +1,23 @@
+       .text
+       .p2align 4,,11
+#APP
+       .type foo, %gnu_indirect_function
+#NO_APP
+       .global foo
+       .type   foo, @function
+foo:
+       ret
+       .size   foo, .-foo
+
+       .global _start
+       .type   _start,%function
+_start:
+       bl sharedfoo
+       ret
+       .size _start, .-_start
+       .data
+       .align  2
+       .type   var, %object
+       .size   var, 4
+var:
+       .chericap sharedfoo
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc-shared.s b/ld/testsuite/ld-aarch64/morello-ifunc-shared.s
new file mode 100644 (file)
index 0000000..61c2f5a
--- /dev/null
@@ -0,0 +1,23 @@
+       .text
+       .p2align 4,,11
+#APP
+       .type sharedfoo, %gnu_indirect_function
+#NO_APP
+       .global sharedfoo
+       .type   sharedfoo, @function
+sharedfoo:
+       ret
+       .size   sharedfoo, .-sharedfoo
+
+       .global libfunc
+       .type   libfunc,%function
+libfunc:
+       bl foo
+       ret
+       .size libfunc, .-libfunc
+       .data
+       .align  2
+       .type   var, %object
+       .size   var, 4
+var:
+       .chericap foo
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc.d b/ld/testsuite/ld-aarch64/morello-ifunc.d
new file mode 100644 (file)
index 0000000..11ad08d
--- /dev/null
@@ -0,0 +1,138 @@
+# Checking that GOT relocations against a PLT which requires pointer equality
+# use a GOT entry pointing to the PLT stub rather than just using the .got.plt
+# entry.
+#
+# Things we check are:
+#    - __rela_dyn_{start,end} are around the RELATIVE relocation against FOO.
+#    - That RELATIVE relocation initialises a GOT entry.
+#    - The fragment in that GOT entry plus the addend of the RELATIVE
+#      relocation total to point to the foo PLT stub.
+#    - We emit a PLT stub which accesses a PLTGOT entry.
+#as: -march=morello+c64
+#ld:
+#objdump: -Dr --section-headers --syms
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: PCC_START
+  0 \.[^ \t]* +[0-9a-f]*  ([0-9a-f]+)  .*
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: LAST_PCC_SEC_SIZE LAST_PCC_SEC_START
+#...
+ *[0-9]+ \.got\.plt *([0-9a-f]+)  ([0-9a-f]+) .*
+                  CONTENTS, ALLOC, LOAD, DATA
+#...
+SYMBOL TABLE:
+#record: RELA_DYN_END
+#...
+([0-9a-f]+) l     O \.rela\.dyn        0000000000000000 __rela_dyn_end
+#record: RELA_DYN_START
+([0-9a-f]+) l     O \.rela\.dyn        0000000000000000 __rela_dyn_start
+#...
+Disassembly of section \.rela\.dyn:
+
+#check: RELA_START format %016x 0x$RELA_DYN_START
+RELA_START <__rela_dyn_start>:
+#record: CHERICAP_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e803        .*
+ *[0-9a-f]+:   00000000        .*
+#record: CHERICAP_ADDEND
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+#record: FOO_GOT
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e803        .*
+ *[0-9a-f]+:   00000000        .*
+#check: CHERICAP_ADDEND string tolower $CHERICAP_ADDEND
+ *[0-9a-f]+:   CHERICAP_ADDEND         .*
+#check: RELA_DYN_LAST format %x [expr "0x$RELA_DYN_END - 0x4"]
+ *RELA_DYN_LAST:       00000000        .*
+
+Disassembly of section \.rela\.plt:
+
+[0-9a-f]+ <.*>:
+#record: PLTGOT_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e804        .*
+ *[0-9a-f]+:   00000000        .*
+#record: PLTGOT_LOC_ADDEND
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+#...
+Disassembly of section \.plt:
+
+#check: FOO_PLT format %x [expr "0x$PCC_START + 0x$CHERICAP_ADDEND - 1"]
+#check: PLTGOT_PAGE format %x [expr "0x$PLTGOT_LOC & (~0xfff)"]
+#check: PLTGOT_DEC_OFF  expr "0x$PLTGOT_LOC & 0xfff"
+([0-9a-f]+) <\.plt>:
+#...
+ *FOO_PLT:     .*      adrp    c16, PLTGOT_PAGE .*
+ *[0-9a-f]+:   .*      ldr     c17, \[c16, #PLTGOT_DEC_OFF\]
+ *[0-9a-f]+:   .*      add     c16, c16, #0x.*
+ *[0-9a-f]+:   c2c21220        br      c17
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+ *[0-9a-f]+:   52800020        mov     w0, #0x1                        // #1
+ *[0-9a-f]+:   c2c253c0        ret     c30
+
+[0-9a-f]+ <foo_2>:
+ *[0-9a-f]+:   52800040        mov     w0, #0x2                        // #2
+ *[0-9a-f]+:   c2c253c0        ret     c30
+
+#check: RESOLVER_ADDRESS format %016x [expr "0x$PLTGOT_LOC_ADDEND + 0x$PCC_START - 1"]
+RESOLVER_ADDRESS <foo>:
+ *[0-9a-f]+:   .*      mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   .*      tst     x0, x1
+ *[0-9a-f]+:   .*      b\.ne   .*
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      ret     c30
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      b       .*
+
+#clearcheck:
+#check: FOO_PLT format %x [expr "0x$PCC_START + 0x$CHERICAP_ADDEND - 1"]
+#check: GOT_PAGE format %x [expr "0x$FOO_GOT & ~0xfff"]
+#check: FOO_GOTOFF expr "0x$FOO_GOT & 0xfff"
+[0-9a-f]+ <_start>:
+ *[0-9a-f]+:   .*      bl      FOO_PLT .*
+ *[0-9a-f]+:   .*      adrp    c0, GOT_PAGE .*
+ *[0-9a-f]+:   .*      ldr     c0, \[c0, #FOO_GOTOFF\]
+#clearcheck:
+#check: PLT_PAGE format %x [expr "(0x$PCC_START + 0x$CHERICAP_ADDEND) & ~0xfff"]
+#check: FOO_PLT_OFF format %x [expr "(0x$PCC_START + 0x$CHERICAP_ADDEND) & 0xfff"]
+ *[0-9a-f]+:   .*      adrp    c0, PLT_PAGE .*
+ *[0-9a-f]+:   .*      add     c0, c0, #0xFOO_PLT_OFF
+ *[0-9a-f]+:   .*      ret     c30
+
+#...
+Disassembly of section \.got:
+
+#clearcheck:
+#check: FRAGMENT_BASE aarch64_8digit_addr $PCC_START
+#check: FRAGMENT_SIZE format %08x [expr "0x$LAST_PCC_SEC_START + 0x$LAST_PCC_SEC_SIZE - 0x$PCC_START"]
+#check: FRAGMENT_LOC format %x 0x$FOO_GOT
+#...
+ *FRAGMENT_LOC:        FRAGMENT_BASE   .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGMENT_SIZE   .*
+ *[0-9a-f]+:   04000000        .*
+
+Disassembly of section \.got\.plt:
+
+#check: PLTGOTLOC  format %x 0x$PLTGOT_LOC
+[0-9a-f]+ <.*>:
+       \.\.\.
+ *PLTGOTLOC:   FRAGMENT_BASE   .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGMENT_SIZE   .*
+ *[0-9a-f]+:   04000000        .*
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc.s b/ld/testsuite/ld-aarch64/morello-ifunc.s
new file mode 100644 (file)
index 0000000..08efcb3
--- /dev/null
@@ -0,0 +1,52 @@
+       .text
+#APP
+       .type foo, %gnu_indirect_function
+#NO_APP
+       .align  2
+       .type   foo_1, %function
+foo_1:
+       mov     w0, 1
+       ret
+       .size   foo_1, .-foo_1
+       .align  2
+       .type   foo_2, %function
+foo_2:
+       mov     w0, 2
+       ret
+       .size   foo_2, .-foo_2
+       .align  2
+
+       .global foo
+       .type   foo, %function
+foo:
+       mov     x1, 42
+       tst     x0, x1
+       bne     .L5
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+.L4:
+       ret
+.L5:
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+       b       .L4
+       .size   foo, .-foo
+       .align  2
+
+       .global _start
+       .type   _start, %function
+_start:
+       bl      foo
+       adrp    c0, :got:foo
+       ldr     c0, [c0, #:got_lo12:foo]
+       // Adding direct relocation against `foo` to ensure that we need
+       // pointer equality.  This should change the behaviour of the CAPINIT
+       // and GOT relocations.
+       adrp    c0, foo
+       add     c0, c0, :lo12:foo
+       ret
+       .size   _start, .-_start
+
+       .data
+       .align  4
+       .chericap foo
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc1-a.d b/ld/testsuite/ld-aarch64/morello-ifunc1-a.d
new file mode 100644 (file)
index 0000000..062973b
--- /dev/null
@@ -0,0 +1,100 @@
+# Checking that when linking as standard, the BL and the GOT access both use
+# the PLT.  This link does not do anything special to maintain pointer equality
+# since there is no access which directly uses the address.
+#
+# Things this testcase checks:
+#   1) Fragment of IRELATIVE relocation is PCC_START with bounds and
+#      permissions of PCC.
+#   2) GOT access uses IRELATIVE relocation in the PLTGOT when no direct access
+#      to address is used.
+#   3) BL to an IFUNC branches to a PLT stub which uses the a PLTGOT slot
+#      initialised by an IRELATIVE relocation against our resolver.
+#source: morello-ifunc1.s
+#as: -march=morello+c64
+#ld: -pie
+#objdump: -DR --section-headers
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: PCC_START
+  0 \.[^ ]+ +[0-9a-f]+  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: PCC_LAST_SIZE PCC_LAST_START
+#...
+ *[0-9]+ \.got\.plt +([0-9a-f]+)  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, DATA
+#...
+Disassembly of section \.plt:
+
+[0-9a-f]+ <\.plt>:
+#...
+.*nop
+.*nop
+.*nop
+# Note that for a none-linux-gnu target we don't emit a symbol specific to the
+# PLT stub for an IFUNC, but for a none-elf target we do.  That means we can't
+# generally check the offset in the symbols name matches the `foo` address
+# below.
+#?
+#?[0-9a-f]+ <\*ABS\*\+0x[0-9a-f]+@plt>:
+#record: PLTADDR PLTGOT_PAGE
+ *([0-9a-f]+): .*      adrp    c16, ([0-9a-f]+) .*
+#record: PLTGOT_DEC_OFF
+ *[0-9a-f]+:   .*      ldr     c17, \[c16, #([0-9]+)\]
+ *[0-9a-f]+:   .*      add     c16, c16, #0x.*
+ *[0-9a-f]+:   .*      br      c17
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+#...
+
+[0-9a-f]+ <foo_2>:
+#...
+
+#record: FOO_ADDR
+([0-9a-f]+) <foo>:
+ *[0-9a-f]+:   .*      mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   .*      tst     x0, x1
+ *[0-9a-f]+:   .*      b\.ne   .* <foo\+0x18>  // b\.any
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      ret     c30
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, .*
+ *[0-9a-f]+:   .*      b       .* <foo\+0x14>
+
+[0-9a-f]+ <_start>:
+#check: PLTLOC string tolower $PLTADDR
+#check: PLTGOTPAGE string tolower $PLTGOT_PAGE
+#check: PLTGOT_DECOFF string tolower $PLTGOT_DEC_OFF
+ *[0-9a-f]+:   .*      bl      PLTLOC .*
+ *[0-9a-f]+:   .*      adrp    c0, PLTGOTPAGE .*
+ *[0-9a-f]+:   .*      ldr     c0, \[c0, #PLTGOT_DECOFF\]
+ *[0-9a-f]+:   .*      ret     c30
+#...
+Disassembly of section \.got\.plt:
+
+#check: GOTLOC aarch64_page_plus_decimal_offset $PLTGOT_PAGE $PLTGOT_DEC_OFF
+#check: FRAGBASE format %08x 0x$PCC_START
+#check: FRAGSIZE format %08x [expr "0x$PCC_LAST_SIZE + 0x$PCC_LAST_START - 0x$PCC_START"]
+#check: FOO_OFFSET format %x [expr "0x$FOO_ADDR + 1 - 0x$PCC_START"]
+[0-9a-f]+ <.*>:
+       \.\.\.
+ *GOTLOC:      FRAGBASE        .*
+                       GOTLOC: R_MORELLO_IRELATIVE     \*ABS\*\+0xFOO_OFFSET
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#...
+Disassembly of section \.data:
+
+[0-9a-f]+ <.*>:
+ *[0-9a-f]+:   FRAGBASE        .*
+                       [0-9a-f]+: R_MORELLO_IRELATIVE  \*ABS\*\+0xFOO_OFFSET
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc1-b.d b/ld/testsuite/ld-aarch64/morello-ifunc1-b.d
new file mode 100644 (file)
index 0000000..062973b
--- /dev/null
@@ -0,0 +1,100 @@
+# Checking that when linking as standard, the BL and the GOT access both use
+# the PLT.  This link does not do anything special to maintain pointer equality
+# since there is no access which directly uses the address.
+#
+# Things this testcase checks:
+#   1) Fragment of IRELATIVE relocation is PCC_START with bounds and
+#      permissions of PCC.
+#   2) GOT access uses IRELATIVE relocation in the PLTGOT when no direct access
+#      to address is used.
+#   3) BL to an IFUNC branches to a PLT stub which uses the a PLTGOT slot
+#      initialised by an IRELATIVE relocation against our resolver.
+#source: morello-ifunc1.s
+#as: -march=morello+c64
+#ld: -pie
+#objdump: -DR --section-headers
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: PCC_START
+  0 \.[^ ]+ +[0-9a-f]+  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: PCC_LAST_SIZE PCC_LAST_START
+#...
+ *[0-9]+ \.got\.plt +([0-9a-f]+)  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, DATA
+#...
+Disassembly of section \.plt:
+
+[0-9a-f]+ <\.plt>:
+#...
+.*nop
+.*nop
+.*nop
+# Note that for a none-linux-gnu target we don't emit a symbol specific to the
+# PLT stub for an IFUNC, but for a none-elf target we do.  That means we can't
+# generally check the offset in the symbols name matches the `foo` address
+# below.
+#?
+#?[0-9a-f]+ <\*ABS\*\+0x[0-9a-f]+@plt>:
+#record: PLTADDR PLTGOT_PAGE
+ *([0-9a-f]+): .*      adrp    c16, ([0-9a-f]+) .*
+#record: PLTGOT_DEC_OFF
+ *[0-9a-f]+:   .*      ldr     c17, \[c16, #([0-9]+)\]
+ *[0-9a-f]+:   .*      add     c16, c16, #0x.*
+ *[0-9a-f]+:   .*      br      c17
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+#...
+
+[0-9a-f]+ <foo_2>:
+#...
+
+#record: FOO_ADDR
+([0-9a-f]+) <foo>:
+ *[0-9a-f]+:   .*      mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   .*      tst     x0, x1
+ *[0-9a-f]+:   .*      b\.ne   .* <foo\+0x18>  // b\.any
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      ret     c30
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, .*
+ *[0-9a-f]+:   .*      b       .* <foo\+0x14>
+
+[0-9a-f]+ <_start>:
+#check: PLTLOC string tolower $PLTADDR
+#check: PLTGOTPAGE string tolower $PLTGOT_PAGE
+#check: PLTGOT_DECOFF string tolower $PLTGOT_DEC_OFF
+ *[0-9a-f]+:   .*      bl      PLTLOC .*
+ *[0-9a-f]+:   .*      adrp    c0, PLTGOTPAGE .*
+ *[0-9a-f]+:   .*      ldr     c0, \[c0, #PLTGOT_DECOFF\]
+ *[0-9a-f]+:   .*      ret     c30
+#...
+Disassembly of section \.got\.plt:
+
+#check: GOTLOC aarch64_page_plus_decimal_offset $PLTGOT_PAGE $PLTGOT_DEC_OFF
+#check: FRAGBASE format %08x 0x$PCC_START
+#check: FRAGSIZE format %08x [expr "0x$PCC_LAST_SIZE + 0x$PCC_LAST_START - 0x$PCC_START"]
+#check: FOO_OFFSET format %x [expr "0x$FOO_ADDR + 1 - 0x$PCC_START"]
+[0-9a-f]+ <.*>:
+       \.\.\.
+ *GOTLOC:      FRAGBASE        .*
+                       GOTLOC: R_MORELLO_IRELATIVE     \*ABS\*\+0xFOO_OFFSET
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#...
+Disassembly of section \.data:
+
+[0-9a-f]+ <.*>:
+ *[0-9a-f]+:   FRAGBASE        .*
+                       [0-9a-f]+: R_MORELLO_IRELATIVE  \*ABS\*\+0xFOO_OFFSET
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc1-c.d b/ld/testsuite/ld-aarch64/morello-ifunc1-c.d
new file mode 100644 (file)
index 0000000..741fb50
--- /dev/null
@@ -0,0 +1,97 @@
+# Checking that when linking as standard, the BL and the GOT access both use
+# the PLT.  This link does not do anything special to maintain pointer equality
+# since there is no access which directly uses the address.
+#
+# Things this testcase checks:
+#   1) Fragment of IRELATIVE relocation is PCC_START with bounds and
+#      permissions of PCC.
+#   2) GOT access uses IRELATIVE relocation in the PLTGOT when no direct access
+#      to address is used.
+#   3) BL to an IFUNC branches to a PLT stub which uses the a PLTGOT slot
+#      initialised by an IRELATIVE relocation against our resolver.
+#source: morello-ifunc1.s
+#target: [check_shared_lib_support]
+#as: -march=morello+c64
+#ld: -shared
+#objdump: -DR --section-headers
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: PCC_START
+  0 \.[^ ]+ +[0-9a-f]+  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: PCC_LAST_SIZE PCC_LAST_START
+#...
+ *[0-9]+ \.got\.plt +([0-9a-f]+)  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, DATA
+#...
+Disassembly of section \.plt:
+
+#record: PLT0_ADDR
+([0-9a-f]+) <\.plt>:
+#...
+.*nop
+.*nop
+.*nop
+
+[0-9a-f]+ <foo@plt>:
+#record: PLTADDR PLTGOT_PAGE
+ *([0-9a-f]+): .*      adrp    c16, ([0-9a-f]+) .*
+#record: PLTGOT_DEC_OFF
+ *[0-9a-f]+:   .*      ldr     c17, \[c16, #([0-9]+)\]
+ *[0-9a-f]+:   .*      add     c16, c16, #0x.*
+ *[0-9a-f]+:   .*      br      c17
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+#...
+
+[0-9a-f]+ <foo_2>:
+#...
+
+#record: FOO_ADDR
+([0-9a-f]+) <foo>:
+ *[0-9a-f]+:   .*      mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   .*      tst     x0, x1
+ *[0-9a-f]+:   .*      b\.ne   .* <foo\+0x18>  // b\.any
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      ret     c30
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, .*
+ *[0-9a-f]+:   .*      b       .* <foo\+0x14>
+
+[0-9a-f]+ <_start>:
+#check: PLTLOC string tolower $PLTADDR
+ *[0-9a-f]+:   .*      bl      PLTLOC .*
+#record: GOT_PAGE
+ *[0-9a-f]+:   .*      adrp    c0, ([0-9a-f]+) .*
+#record: GOT_DEC_OFF
+ *[0-9a-f]+:   .*      ldr     c0, \[c0, #([0-9]+)\]
+ *[0-9a-f]+:   .*      ret     c30
+#...
+Disassembly of section \.got:
+
+#check: GOTLOC aarch64_page_plus_decimal_offset $GOT_PAGE $GOT_DEC_OFF
+[0-9a-f]+ <.*>:
+#...
+                       GOTLOC: R_MORELLO_GLOB_DAT      foo
+#...
+Disassembly of section \.got\.plt:
+
+#check: PLTGOT_LOC aarch64_page_plus_decimal_offset $PLTGOT_PAGE $PLTGOT_DEC_OFF
+#check: FRAGBASE format %08x [expr "0x$PLT0_ADDR + 1"]
+[0-9a-f]+ <.*>:
+       \.\.\.
+ *PLTGOT_LOC:  FRAGBASE        .*
+                       PLTGOT_LOC: R_MORELLO_JUMP_SLOT foo
+#...
+Disassembly of section \.data:
+
+[0-9a-f]+ <.*>:
+       \.\.\.
+                       [0-9a-f]+: R_MORELLO_CAPINIT    foo
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc1.d b/ld/testsuite/ld-aarch64/morello-ifunc1.d
new file mode 100644 (file)
index 0000000..c205f15
--- /dev/null
@@ -0,0 +1,113 @@
+# Checking that when linking as standard, the BL and the GOT access both use
+# the PLT.  This link does not do anything special to maintain pointer equality
+# since there is no access which directly uses the address.
+#
+# Things this testcase checks:
+#   1) Fragment of IRELATIVE relocation is PCC_START with bounds and
+#      permissions of PCC.
+#   2) GOT access uses IRELATIVE relocation in the PLTGOT when no direct access
+#      to address is used.
+#   3) BL to an IFUNC branches to a PLT stub which uses the a PLTGOT slot
+#      initialised by an IRELATIVE relocation against our resolver.
+#as: -march=morello+c64
+#ld:
+#objdump: -Dr --section-headers
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: PCC_START
+  0 \.[^ ]+ +[0-9a-f]+  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: PCC_LAST_SIZE PCC_LAST_START
+#...
+ *[0-9]+ \.got\.plt +([0-9a-f]+)  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, DATA
+#...
+
+Disassembly of section \.rela\.plt:
+
+[0-9a-f]+ <.*>:
+#record: PLTGOT_LOC
+ +[0-9a-f]+:   ([0-9a-f]+) .*
+ +[0-9a-f]+:   00000000 .*
+ +[0-9a-f]+:   0000e804 .*
+ +[0-9a-f]+:   00000000 .*
+#record: IREL_ADDEND
+ +[0-9a-f]+:   ([0-9a-f]+) .*
+ +[0-9a-f]+:   00000000 .*
+#record: CHERICAP_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e804        .*
+ *[0-9a-f]+:   00000000        .*
+#check: CHERICAP_ADDEND string tolower $IREL_ADDEND
+ *[0-9a-f]+:   CHERICAP_ADDEND         .*
+ *[0-9a-f]+:   00000000        .*
+
+Disassembly of section \.plt:
+
+#check: PLTGOT_PAGE format %x [expr "0x$PLTGOT_LOC & (~0xfff)"]
+#check: PLTGOT_DEC_OFF  expr "0x$PLTGOT_LOC & 0xfff"
+[0-9a-f]+ <\.plt>:
+#record: PLTADDR
+ *([0-9a-f]+): .*      adrp    c16, PLTGOT_PAGE .*
+ *[0-9a-f]+:   .*      ldr     c17, \[c16, #PLTGOT_DEC_OFF\]
+ *[0-9a-f]+:   .*      add     c16, c16, #0x.*
+ *[0-9a-f]+:   .*      br      c17
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+#...
+
+[0-9a-f]+ <foo_2>:
+#...
+
+#check: FOO_ADDR format %016x [expr "0x$PCC_START + (0x$IREL_ADDEND & ~1)"]
+FOO_ADDR <foo>:
+ *[0-9a-f]+:   .*      mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   .*      tst     x0, x1
+ *[0-9a-f]+:   .*      b\.ne   .* <foo\+0x18>  // b\.any
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      ret     c30
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, .*
+ *[0-9a-f]+:   .*      b       .* <foo\+0x14>
+
+[0-9a-f]+ <_start>:
+#check: PLTLOC string tolower $PLTADDR
+ *[0-9a-f]+:   .*      bl      PLTLOC .*
+ *[0-9a-f]+:   .*      adrp    c0, PLTGOT_PAGE .*
+ *[0-9a-f]+:   .*      ldr     c0, \[c0, #PLTGOT_DEC_OFF\]
+ *[0-9a-f]+:   .*      ret     c30
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <.*>:
+       \.\.\.
+
+Disassembly of section \.got\.plt:
+
+#check: GOTLOC format %x 0x$PLTGOT_LOC
+#check: FRAGBASE format %08x 0x$PCC_START
+#check: FRAGSIZE format %08x [expr "0x$PCC_LAST_SIZE + 0x$PCC_LAST_START - 0x$PCC_START"]
+[0-9a-f]+ <.*>:
+       \.\.\.
+ *GOTLOC:      FRAGBASE        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#...
+Disassembly of section \.data:
+
+#check: CHERICAPLOC format %x 0x$CHERICAP_LOC
+[0-9a-f]+ <.*>:
+ *CHERICAPLOC: FRAGBASE        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#pass
+
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc1.s b/ld/testsuite/ld-aarch64/morello-ifunc1.s
new file mode 100644 (file)
index 0000000..9e088b5
--- /dev/null
@@ -0,0 +1,51 @@
+// Want to check that having a CAPINIT relocation on an IFUNC does not require
+// pointer equality (this would mean that a GOT relocation against the symbol
+// would end up using a GOT entry which refers to the PLT, but without
+// requiring pointer equality we end up using the PLTGOT entry that is already
+// around for the use of the PLT).
+#APP
+       .type foo, %gnu_indirect_function
+#NO_APP
+       .align  2
+       .type   foo_1, %function
+foo_1:
+       mov     w0, 1
+       ret
+       .size   foo_1, .-foo_1
+       .align  2
+       .type   foo_2, %function
+foo_2:
+       mov     w0, 2
+       ret
+       .size   foo_2, .-foo_2
+       .align  2
+
+       .global foo
+       .type   foo, %function
+foo:
+       mov     x1, 42
+       tst     x0, x1
+       bne     .L5
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+.L4:
+       ret
+.L5:
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+       b       .L4
+       .size   foo, .-foo
+       .align  2
+
+       .global _start
+       .type   _start, %function
+_start:
+       bl      foo
+       adrp    c0, :got:foo
+       ldr     c0, [c0, #:got_lo12:foo]
+       ret
+       .size   _start, .-_start
+
+       .data
+       .align  4
+       .chericap foo
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc2-b.d b/ld/testsuite/ld-aarch64/morello-ifunc2-b.d
new file mode 100644 (file)
index 0000000..773274b
--- /dev/null
@@ -0,0 +1,82 @@
+# Checking that having a CAPINIT relocation against an IFUNC symbol stops the
+# garbage collection of the IFUNC's PLT.
+# In order to show that the PLT stub is indeed the one related to FOO we show
+# that the PLT stub loads from the PLTGOT, and that the entry in the PLTGOT it
+# loads is initialised with an IRELATIVE relocation pointing to the foo
+# resolver.
+#source: morello-ifunc2.s
+#as: -march=morello+c64
+#ld: -pie
+#objdump: -DR --section-headers
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: TEXT_START
+.* .interp       [0-9a-f]+  ([0-9a-f]+)  .*  .*  2\*\*.
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: DATA_START
+#...
+.* .data         00000010  ([0-9a-f]+)  .*  .*  2\*\*.
+                  CONTENTS, ALLOC, LOAD, DATA
+
+#...
+Disassembly of section \.plt:
+
+[0-9a-f]+ <\.plt>:
+#...
+ *[0-9a-f]+:   d503201f        nop
+ *[0-9a-f]+:   d503201f        nop
+ *[0-9a-f]+:   d503201f        nop
+
+#record: PLTSTUB_ADDR FOO_OFF
+([0-9a-f]+) <\*ABS\*\+0x([0-9a-f]+)@plt>:
+#record: PLTGOT_PAGE
+ *[0-9a-f]+:   ........        adrp    c16, ([0-9a-f]+) <.*
+#record: FOO_PLTGOT_OFF
+ *[0-9a-f]+:   ........        ldr     c17, \[c16, #([0-9]+)\]
+#check: FOO_PLTGOT_HEXOFF format %x $FOO_PLTGOT_OFF
+ *[0-9a-f]+:   ........        add     c16, c16, #0xFOO_PLTGOT_HEXOFF
+ *[0-9a-f]+:   c2c21220        br      c17
+#clearcheck:
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+ *[0-9a-f]+:   52800020        mov     w0, #0x1                        // #1
+ *[0-9a-f]+:   c2c253c0        ret     c30
+
+[0-9a-f]+ <foo_2>:
+ *[0-9a-f]+:   52800040        mov     w0, #0x2                        // #2
+ *[0-9a-f]+:   c2c253c0        ret     c30
+
+#check: FOO_LOC format %016x [expr "0x$TEXT_START + 0x$FOO_OFF - 1"]
+FOO_LOC <foo>:
+ *[0-9a-f]+:   d2800541        mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   ea01001f        tst     x0, x1
+ *[0-9a-f]+:   ........        b\.ne   .*
+ *[0-9a-f]+:   ........        adrp    c0, .*
+ *[0-9a-f]+:   ........        add     c0, c0, .*
+ *[0-9a-f]+:   c2c253c0        ret     c30
+ *[0-9a-f]+:   ........        adrp    c0, .*
+ *[0-9a-f]+:   ........        add     c0, c0, .*
+ *[0-9a-f]+:   17fffffd        b       .* <foo\+0x14>
+
+[0-9a-f]+ <_start>:
+ *[0-9a-f]+:   c2c253c0        ret     c30
+
+#...
+Disassembly of section \.got\.plt:
+#check: PCC_START aarch64_8digit_addr $TEXT_START
+#check: PCC_SIZE  format %08x [expr "0x$DATA_START - 0x$TEXT_START"]
+#check: FOO_OFFSET string tolower $FOO_OFF
+
+[0-9a-f]+ <.*>:
+       \.\.\.
+ *[0-9a-f]+:   PCC_START       .*
+                       .*: R_MORELLO_IRELATIVE \*ABS\*\+0xFOO_OFFSET
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   PCC_SIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc2.d b/ld/testsuite/ld-aarch64/morello-ifunc2.d
new file mode 100644 (file)
index 0000000..b706f0f
--- /dev/null
@@ -0,0 +1,92 @@
+# Checking that having a CAPINIT relocation against an IFUNC symbol stops the
+# garbage collection of the IFUNC's PLT.
+# In order to show that the PLT stub is indeed the one related to FOO we show
+# that the PLT stub loads from the PLTGOT, and that the entry in the PLTGOT it
+# loads is initialised with an IRELATIVE relocation pointing to the foo
+# resolver.
+#as: -march=morello+c64
+#ld:
+#objdump: -Dr --section-headers
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: TEXT_START
+.* .[^ ]+ +[0-9a-f]+  ([0-9a-f]+)  .*  .*  2\*\*.
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: DATA_START
+#...
+.* .data         00000010  ([0-9a-f]+)  .*  .*  2\*\*.
+                  CONTENTS, ALLOC, LOAD, DATA
+
+#...
+Disassembly of section \.rela\.plt:
+
+[0-9a-f]+ <\.rela\.plt>:
+#record: PLTGOT_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e804        .*
+ *[0-9a-f]+:   00000000        .*
+#record: PLTGOT_IREL_ADDEND
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+#record: CAPINIT_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e804        .*
+ *[0-9a-f]+:   00000000        .*
+#check: CAPINIT_ADDEND string tolower $PLTGOT_IREL_ADDEND
+ *[0-9a-f]+:   CAPINIT_ADDEND  .*
+ *[0-9a-f]+:   00000000        .*
+
+
+Disassembly of section \.plt:
+
+#check: PLTGOT_PAGE format %x [expr "0x$PLTGOT_LOC & (~0xfff)"]
+#check: PLTGOT_DEC_OFF  expr "0x$PLTGOT_LOC & 0xfff"
+[0-9a-f]+ <\.plt>:
+ *[0-9a-f]+:   ........        adrp    c16, PLTGOT_PAGE <.*
+ *[0-9a-f]+:   ........        ldr     c17, \[c16, #PLTGOT_DEC_OFF\]
+ *[0-9a-f]+:   ........        add     c16, c16, #0x.*
+ *[0-9a-f]+:   c2c21220        br      c17
+#clearcheck:
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+ *[0-9a-f]+:   52800020        mov     w0, #0x1                        // #1
+ *[0-9a-f]+:   c2c253c0        ret     c30
+
+[0-9a-f]+ <foo_2>:
+ *[0-9a-f]+:   52800040        mov     w0, #0x2                        // #2
+ *[0-9a-f]+:   c2c253c0        ret     c30
+
+#check: FOO_LOC format %016x [expr "0x$TEXT_START + 0x$PLTGOT_IREL_ADDEND - 1"]
+FOO_LOC <foo>:
+ *[0-9a-f]+:   d2800541        mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   ea01001f        tst     x0, x1
+ *[0-9a-f]+:   ........        b\.ne   .*
+ *[0-9a-f]+:   ........        adrp    c0, .*
+ *[0-9a-f]+:   ........        add     c0, c0, .*
+ *[0-9a-f]+:   c2c253c0        ret     c30
+ *[0-9a-f]+:   ........        adrp    c0, .*
+ *[0-9a-f]+:   ........        add     c0, c0, .*
+ *[0-9a-f]+:   17fffffd        b       .* <foo\+0x14>
+
+[0-9a-f]+ <_start>:
+ *[0-9a-f]+:   c2c253c0        ret     c30
+
+#...
+Disassembly of section \.got\.plt:
+
+#check: PLTGOT_LOCATION format %x 0x$PLTGOT_LOC
+#check: PCC_START aarch64_8digit_addr $TEXT_START
+#check: PCC_SIZE  format %08x [expr "0x$DATA_START - 0x$TEXT_START"]
+[0-9a-f]+ <.*>:
+ *PLTGOT_LOCATION:     PCC_START       .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   PCC_SIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc2.s b/ld/testsuite/ld-aarch64/morello-ifunc2.s
new file mode 100644 (file)
index 0000000..cc111f9
--- /dev/null
@@ -0,0 +1,46 @@
+// Want to check that having a CAPINIT relocation on an IFUNC stops the garbage
+// collection of the IFUNC's PLT (so that the CAPINIT relocation has something
+// to point to).
+#APP
+       .type foo, %gnu_indirect_function
+#NO_APP
+       .align  2
+       .type   foo_1, %function
+foo_1:
+       mov     w0, 1
+       ret
+       .size   foo_1, .-foo_1
+       .align  2
+       .type   foo_2, %function
+foo_2:
+       mov     w0, 2
+       ret
+       .size   foo_2, .-foo_2
+       .align  2
+
+       .global foo
+       .type   foo, %function
+foo:
+       mov     x1, 42
+       tst     x0, x1
+       bne     .L5
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+.L4:
+       ret
+.L5:
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+       b       .L4
+       .size   foo, .-foo
+       .align  2
+
+       .global _start
+       .type   _start, %function
+_start:
+       ret
+       .size   _start, .-_start
+
+       .data
+       .align  4
+       .chericap foo
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc3.d b/ld/testsuite/ld-aarch64/morello-ifunc3.d
new file mode 100644 (file)
index 0000000..6eaea61
--- /dev/null
@@ -0,0 +1,4 @@
+#as: -march=morello+c64
+#ld:
+#error: .*: relocation R_AARCH64_ABS64 against a C64 STT_GNU_IFUNC symbol `foo'
+#error: .*: dangerous relocation: unsupported relocation
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc3.s b/ld/testsuite/ld-aarch64/morello-ifunc3.s
new file mode 100644 (file)
index 0000000..f6702f1
--- /dev/null
@@ -0,0 +1,43 @@
+#APP
+       .type foo, %gnu_indirect_function
+#NO_APP
+       .align  2
+       .type   foo_1, %function
+foo_1:
+       mov     w0, 1
+       ret
+       .size   foo_1, .-foo_1
+       .align  2
+       .type   foo_2, %function
+foo_2:
+       mov     w0, 2
+       ret
+       .size   foo_2, .-foo_2
+       .align  2
+
+       .global foo
+       .type   foo, %function
+foo:
+       mov     x1, 42
+       tst     x0, x1
+       bne     .L5
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+.L4:
+       ret
+.L5:
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+       b       .L4
+       .size   foo, .-foo
+       .align  2
+
+       .global _start
+       .type   _start, %function
+_start:
+       ret
+       .size   _start, .-_start
+
+       .data
+       .align  4
+       .xword foo
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc4.d b/ld/testsuite/ld-aarch64/morello-ifunc4.d
new file mode 100644 (file)
index 0000000..ceb213b
--- /dev/null
@@ -0,0 +1,176 @@
+# Checking that the IRELATIVE relocations which are added by CAPINIT
+# static relocations end up between the __rela_iplt_start and __rela_iplt_end
+# symbols and that RELATIVE relocations added by CAPINIT static relocations end
+# up between __rela_dyn_start and __rela_dyn_end.
+#as: -march=morello+c64
+#ld:
+#objdump: -Dzr --section-headers --syms
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: PCC_START
+  0 \.[^ ]+ +[0-9a-f]+  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: PCC_LAST_SIZE PCC_LAST_START
+#...
+ *[0-9]+ \.got\.plt +([0-9a-f]+)  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, DATA
+#...
+SYMBOL TABLE:
+#record: RELA_IPLT_END
+#...
+([0-9a-f]+) l       \.rela\.plt        0000000000000000 __rela_iplt_end
+#record: RELA_IPLT_START
+([0-9a-f]+) l       \.rela\.plt        0000000000000000 __rela_iplt_start
+#record: RELA_DYN_END
+([0-9a-f]+) l     O \.rela\.dyn        0000000000000000 __rela_dyn_end
+#record: RELA_DYN_START
+([0-9a-f]+) l     O \.rela\.dyn        0000000000000000 __rela_dyn_start
+#...
+
+Disassembly of section \.rela\.dyn:
+
+#check: RELA_START format %016x 0x$RELA_DYN_START
+RELA_START <__rela_dyn_start>:
+#record: CHERICAP_A_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e803        .*
+ *[0-9a-f]+:   00000000        .*
+#record: CHERICAP_ADDEND
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+# __rela_iplt_end and __rela_iplt_start relocations.
+# These were just added in order to get the symbols in the output binary.
+# There is nothing we want to check around them.
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+#check: CCAP_ADDEND string tolower $CHERICAP_ADDEND
+#record: CHERICAP_B_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e803        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   CCAP_ADDEND     .*
+ *[0-9a-f]+:   00000000        .*
+#record: CHERICAP_C_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e803        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   CCAP_ADDEND     .*
+ *[0-9a-f]+:   00000000        .*
+#record: GOT_IFUNC_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e803        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   CCAP_ADDEND     .*
+#check: RELA_DYN_LAST format %x [expr "0x$RELA_DYN_END - 0x4"]
+ *RELA_DYN_LAST:       00000000        .*
+
+Disassembly of section \.rela\.plt:
+
+[0-9a-f]+ <__rela_iplt_start>:
+#record: PLTGOT_LOC 
+ +[0-9a-f]+:   ([0-9a-f]+) .*
+ +[0-9a-f]+:   00000000 .*
+ +[0-9a-f]+:   0000e804 .*
+ +[0-9a-f]+:   00000000 .*
+#record: IREL_ADDEND
+ +[0-9a-f]+:   ([0-9a-f]+) .*
+ +[0-9a-f]+:   00000000 .*
+
+Disassembly of section \.plt:
+
+#check: PLTGOT_PAGE format %x [expr "0x$PLTGOT_LOC & (~0xfff)"]
+#check: PLTGOT_DEC_OFF  expr "0x$PLTGOT_LOC & 0xfff"
+#check: PLTADDR_LOC format %x [expr "0x$PCC_START + (0x$CHERICAP_ADDEND & ~1)"]
+[0-9a-f]+ <\.plt>:
+ *PLTADDR_LOC: .*      adrp    c16, PLTGOT_PAGE .*
+ *[0-9a-f]+:   .*      ldr     c17, \[c16, #PLTGOT_DEC_OFF\]
+ *[0-9a-f]+:   .*      add     c16, c16, #0x.*
+ *[0-9a-f]+:   .*      br      c17
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+#...
+
+[0-9a-f]+ <foo_2>:
+#...
+
+#check: FOO_ADDR format %016x [expr "0x$PCC_START + (0x$IREL_ADDEND & ~1)"]
+FOO_ADDR <foo>:
+ *[0-9a-f]+:   .*      mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   .*      tst     x0, x1
+ *[0-9a-f]+:   .*      b\.ne   .* <foo\+0x18>  // b\.any
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      ret     c30
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, .*
+ *[0-9a-f]+:   .*      b       .* <foo\+0x14>
+
+#check: GOT_PAGE format %x [expr "0x$GOT_IFUNC_LOC & (~0xfff)"]
+#check: GOT_DEC_OFF  expr "0x$GOT_IFUNC_LOC & 0xfff"
+#check: PLTADDR_PAGE format %x [expr "(0x$PCC_START + 0x$CHERICAP_ADDEND) & (~0xfff)"]
+#check: PLTADDR_OFF format %x [expr "(0x$PCC_START + 0x$CHERICAP_ADDEND) & 0xfff"]
+[0-9a-f]+ <_start>:
+ *[0-9a-f]+:   .*      bl      PLTADDR_LOC .*
+ *[0-9a-f]+:   .*      adrp    c0, GOT_PAGE .*
+ *[0-9a-f]+:   .*      ldr     c0, \[c0, #GOT_DEC_OFF\]
+ *[0-9a-f]+:   .*      adrp    c0, PLTADDR_PAGE .*
+ *[0-9a-f]+:   .*      add     c0, c0, #0xPLTADDR_OFF
+ *[0-9a-f]+:   .*      ret     c30
+
+Disassembly of section \.got:
+
+#check: GOTLOC format %x 0x$GOT_IFUNC_LOC
+#check: FRAGBASE format %08x 0x$PCC_START
+#check: FRAGSIZE format %08x [expr "0x$PCC_LAST_SIZE + 0x$PCC_LAST_START - 0x$PCC_START"]
+[0-9a-f]+ <.*>:
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *GOTLOC:      FRAGBASE        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+
+Disassembly of section \.got\.plt:
+
+#check: PLTGOT_ADDR format %x 0x$PLTGOT_LOC
+[0-9a-f]+ <.*>:
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *PLTGOT_ADDR: FRAGBASE        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#...
+Disassembly of section \.data:
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc4.s b/ld/testsuite/ld-aarch64/morello-ifunc4.s
new file mode 100644 (file)
index 0000000..5040f9a
--- /dev/null
@@ -0,0 +1,56 @@
+       .text
+#APP
+       .type foo, %gnu_indirect_function
+#NO_APP
+       .align  2
+       .type   foo_1, %function
+foo_1:
+       mov     w0, 1
+       ret
+       .size   foo_1, .-foo_1
+       .align  2
+       .type   foo_2, %function
+foo_2:
+       mov     w0, 2
+       ret
+       .size   foo_2, .-foo_2
+       .align  2
+
+       .global foo
+       .type   foo, %function
+foo:
+       mov     x1, 42
+       tst     x0, x1
+       bne     .L5
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+.L4:
+       ret
+.L5:
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+       b       .L4
+       .size   foo, .-foo
+       .align  2
+
+       .global _start
+       .type   _start, %function
+_start:
+       bl      foo
+       adrp    c0, :got:foo
+       ldr     c0, [c0, #:got_lo12:foo]
+       // Adding direct relocation against `foo` to ensure that we need
+       // pointer equality.  This should change the behaviour of the CAPINIT
+       // and GOT relocations.
+       adrp    c0, foo
+       add     c0, c0, :lo12:foo
+       ret
+       .size   _start, .-_start
+
+       .data
+       .align  4
+       .chericap foo
+       .chericap __rela_iplt_start
+       .chericap __rela_iplt_end
+       .chericap foo
+       .chericap foo
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc4a.d b/ld/testsuite/ld-aarch64/morello-ifunc4a.d
new file mode 100644 (file)
index 0000000..fd6020d
--- /dev/null
@@ -0,0 +1,161 @@
+# Checking that the IRELATIVE relocations which are added by CAPINIT
+# static relocations end up between the __rela_iplt_start and __rela_iplt_end
+# symbols and that RELATIVE relocations added by CAPINIT static relocations end
+# up between __rela_dyn_start and __rela_dyn_end.
+#as: -march=morello+c64
+#ld:
+#objdump: -Dzr --section-headers --syms
+
+.*:     file format .*
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+#record: PCC_START
+  0 \.[^ ]+ +[0-9a-f]+  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+#record: PCC_LAST_SIZE PCC_LAST_START
+#...
+ *[0-9]+ \.got\.plt +([0-9a-f]+)  ([0-9a-f]+)  [0-9a-f]+  [0-9a-f]+  2\*\*.
+                  CONTENTS, ALLOC, LOAD, DATA
+#...
+SYMBOL TABLE:
+#record: RELA_IPLT_END
+#...
+([0-9a-f]+) l       \.rela\.plt        0000000000000000 __rela_iplt_end
+#record: RELA_IPLT_START
+([0-9a-f]+) l       \.rela\.plt        0000000000000000 __rela_iplt_start
+#record: RELA_DYN_END
+([0-9a-f]+) l     O \.rela\.dyn        0000000000000000 __rela_dyn_end
+#record: RELA_DYN_START
+([0-9a-f]+) l     O \.rela\.dyn        0000000000000000 __rela_dyn_start
+#...
+
+Disassembly of section \.rela\.dyn:
+
+#check: RELA_START format %016x 0x$RELA_DYN_START
+RELA_START <__rela_dyn_start>:
+# __rela_iplt_end and __rela_iplt_start relocations.
+# These were just added in order to get the symbols in the output binary.
+# There is nothing we want to check around them.
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+ *[0-9a-f]+:   ........        .*
+#check: RELA_DYN_LAST format %x [expr "0x$RELA_DYN_END - 0x4"]
+ *RELA_DYN_LAST:       00000000        .*
+
+Disassembly of section \.rela\.plt:
+
+[0-9a-f]+ <__rela_iplt_start>:
+#record: PLTGOT_LOC 
+ +[0-9a-f]+:   ([0-9a-f]+) .*
+ +[0-9a-f]+:   00000000 .*
+ +[0-9a-f]+:   0000e804 .*
+ +[0-9a-f]+:   00000000 .*
+#record: IREL_ADDEND
+ +[0-9a-f]+:   ([0-9a-f]+) .*
+ +[0-9a-f]+:   00000000 .*
+#record: CHERICAP_A_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e804        .*
+ *[0-9a-f]+:   00000000        .*
+#check: CCAP_ADDEND string tolower $IREL_ADDEND
+ *[0-9a-f]+:   CCAP_ADDEND     .*
+ *[0-9a-f]+:   00000000        .*
+#record: CHERICAP_B_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e804        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   CCAP_ADDEND     .*
+ *[0-9a-f]+:   00000000        .*
+#record: CHERICAP_C_LOC
+ *[0-9a-f]+:   ([0-9a-f]+)     .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   0000e804        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   CCAP_ADDEND     .*
+#check: RELA_IPLT_LAST format %x [expr "0x$RELA_IPLT_END - 0x4"]
+ *RELA_IPLT_LAST:      00000000        .*
+
+Disassembly of section \.plt:
+
+#check: PLTGOT_PAGE format %x [expr "0x$PLTGOT_LOC & (~0xfff)"]
+#check: PLTGOT_DEC_OFF  expr "0x$PLTGOT_LOC & 0xfff"
+[0-9a-f]+ <\.plt>:
+#record: PLTADDR
+ *([0-9a-f]+): .*      adrp    c16, PLTGOT_PAGE .*
+ *[0-9a-f]+:   .*      ldr     c17, \[c16, #PLTGOT_DEC_OFF\]
+ *[0-9a-f]+:   .*      add     c16, c16, #0x.*
+ *[0-9a-f]+:   .*      br      c17
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo_1>:
+#...
+
+[0-9a-f]+ <foo_2>:
+#...
+
+#check: FOO_ADDR format %016x [expr "0x$PCC_START + (0x$IREL_ADDEND & ~1)"]
+FOO_ADDR <foo>:
+ *[0-9a-f]+:   .*      mov     x1, #0x2a                       // #42
+ *[0-9a-f]+:   .*      tst     x0, x1
+ *[0-9a-f]+:   .*      b\.ne   .* <foo\+0x18>  // b\.any
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, c0, .*
+ *[0-9a-f]+:   .*      ret     c30
+ *[0-9a-f]+:   .*      adrp    c0, .*
+ *[0-9a-f]+:   .*      add     c0, .*
+ *[0-9a-f]+:   .*      b       .* <foo\+0x14>
+
+#check: GOT_PAGE format %x [expr "0x$PLTGOT_LOC & (~0xfff)"]
+#check: GOT_DEC_OFF expr "0x$PLTGOT_LOC & 0xfff"
+#check: PLT_LOC string tolower $PLTADDR
+[0-9a-f]+ <_start>:
+ *[0-9a-f]+:   .*      bl      PLT_LOC .*
+ *[0-9a-f]+:   .*      adrp    c0, GOT_PAGE .*
+ *[0-9a-f]+:   .*      ldr     c0, \[c0, #GOT_DEC_OFF\]
+ *[0-9a-f]+:   .*      ret     c30
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <.*>:
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+
+Disassembly of section \.got\.plt:
+
+#check: FRAGBASE format %08x 0x$PCC_START
+#check: FRAGSIZE format %08x [expr "0x$PCC_LAST_SIZE + 0x$PCC_LAST_START - 0x$PCC_START"]
+#check: PLTGOT_ADDR format %x 0x$PLTGOT_LOC
+[0-9a-f]+ <.*>:
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   00000000        .*
+ *PLTGOT_ADDR: FRAGBASE        .*
+ *[0-9a-f]+:   00000000        .*
+ *[0-9a-f]+:   FRAGSIZE        .*
+ *[0-9a-f]+:   04000000        .*
+#...
+Disassembly of section \.data:
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-ifunc4a.s b/ld/testsuite/ld-aarch64/morello-ifunc4a.s
new file mode 100644 (file)
index 0000000..64c3fac
--- /dev/null
@@ -0,0 +1,51 @@
+       .text
+#APP
+       .type foo, %gnu_indirect_function
+#NO_APP
+       .align  2
+       .type   foo_1, %function
+foo_1:
+       mov     w0, 1
+       ret
+       .size   foo_1, .-foo_1
+       .align  2
+       .type   foo_2, %function
+foo_2:
+       mov     w0, 2
+       ret
+       .size   foo_2, .-foo_2
+       .align  2
+
+       .global foo
+       .type   foo, %function
+foo:
+       mov     x1, 42
+       tst     x0, x1
+       bne     .L5
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+.L4:
+       ret
+.L5:
+       adrp    c0, foo_1
+       add     c0, c0, :lo12:foo_1
+       b       .L4
+       .size   foo, .-foo
+       .align  2
+
+       .global _start
+       .type   _start, %function
+_start:
+       bl      foo
+       adrp    c0, :got:foo
+       ldr     c0, [c0, #:got_lo12:foo]
+       ret
+       .size   _start, .-_start
+
+       .data
+       .align  4
+       .chericap foo
+       .chericap __rela_iplt_start
+       .chericap __rela_iplt_end
+       .chericap foo
+       .chericap foo