[PR ld/22269] aarch64: Handle local undefined weak symbols
[external/binutils.git] / bfd / elfnn-aarch64.c
index 4817e42..7571a16 100644 (file)
@@ -2610,6 +2610,8 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd)
   return &ret->root.root;
 }
 
+/* Perform relocation R_TYPE.  Returns TRUE upon success, FALSE otherwise.  */
+
 static bfd_boolean
 aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
                  bfd_vma offset, bfd_vma value)
@@ -2625,7 +2627,7 @@ aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
   value = _bfd_aarch64_elf_resolve_relocation (r_type, place, value, 0, FALSE);
   return _bfd_aarch64_elf_put_addend (input_bfd,
                                      input_section->contents + offset, r_type,
-                                     howto, value);
+                                     howto, value) == bfd_reloc_ok;
 }
 
 static enum elf_aarch64_stub_type
@@ -2965,22 +2967,22 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
   switch (stub_entry->stub_type)
     {
     case aarch64_stub_adrp_branch:
-      if (aarch64_relocate (AARCH64_R (ADR_PREL_PG_HI21), stub_bfd, stub_sec,
-                           stub_entry->stub_offset, sym_value))
+      if (!aarch64_relocate (AARCH64_R (ADR_PREL_PG_HI21), stub_bfd, stub_sec,
+                            stub_entry->stub_offset, sym_value))
        /* The stub would not have been relaxed if the offset was out
           of range.  */
        BFD_FAIL ();
 
-      if (aarch64_relocate (AARCH64_R (ADD_ABS_LO12_NC), stub_bfd, stub_sec,
-                           stub_entry->stub_offset + 4, sym_value))
+      if (!aarch64_relocate (AARCH64_R (ADD_ABS_LO12_NC), stub_bfd, stub_sec,
+                            stub_entry->stub_offset + 4, sym_value))
        BFD_FAIL ();
       break;
 
     case aarch64_stub_long_branch:
       /* We want the value relative to the address 12 bytes back from the
          value itself.  */
-      if (aarch64_relocate (AARCH64_R (PRELNN), stub_bfd, stub_sec,
-                           stub_entry->stub_offset + 16, sym_value + 12))
+      if (!aarch64_relocate (AARCH64_R (PRELNN), stub_bfd, stub_sec,
+                            stub_entry->stub_offset + 16, sym_value + 12))
        BFD_FAIL ();
       break;
 
@@ -3001,8 +3003,8 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
       break;
 
     case aarch64_stub_erratum_843419_veneer:
-      if (aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
-                           stub_entry->stub_offset + 4, sym_value + 4))
+      if (!aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
+                            stub_entry->stub_offset + 4, sym_value + 4))
        BFD_FAIL ();
       break;
 
@@ -3281,7 +3283,7 @@ aarch64_mem_op_p (uint32_t insn, unsigned int *rt, unsigned int *rt2,
   uint32_t v = 0;
   uint32_t opc_v = 0;
 
-  /* Bail out quickly if INSN doesn't fall into the the load-store
+  /* Bail out quickly if INSN doesn't fall into the load-store
      encoding space.  */
   if (!AARCH64_LDST (insn))
     return FALSE;
@@ -4944,11 +4946,14 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
     = elfNN_aarch64_bfd_reloc_from_howto (howto);
   unsigned long r_symndx;
   bfd_byte *hit_data = contents + rel->r_offset;
-  bfd_vma place, off;
+  bfd_vma place, off, got_entry_addr = 0;
   bfd_signed_vma signed_addend;
   struct elf_aarch64_link_hash_table *globals;
   bfd_boolean weak_undef_p;
+  bfd_boolean relative_reloc;
   asection *base_got;
+  bfd_vma orig_value = value;
+  bfd_boolean resolved_to_zero;
 
   globals = elf_aarch64_hash_table (info);
 
@@ -4979,9 +4984,27 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
       const char *name;
       bfd_vma addend = 0;
 
-      if ((input_section->flags & SEC_ALLOC) == 0
-         || h->plt.offset == (bfd_vma) -1)
-       abort ();
+      if ((input_section->flags & SEC_ALLOC) == 0)
+       {
+         /* Dynamic relocs are not propagated for SEC_DEBUGGING
+            sections because such sections are not SEC_ALLOC and
+            thus ld.so will not process them.  */
+         if ((input_section->flags & SEC_DEBUGGING) != 0)
+           return bfd_reloc_ok;
+
+         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
+           /* xgettext:c-format */
+           (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"),
+            input_bfd, input_section, rel->r_offset, howto->name, name);
+         bfd_set_error (bfd_error_bad_value);
+         return bfd_reloc_notsupported;
+       }
+      else if (h->plt.offset == (bfd_vma) -1)
+       goto bad_ifunc_reloc;
 
       /* STT_GNU_IFUNC symbol must go through PLT.  */
       plt = globals->root.splt ? globals->root.splt : globals->root.iplt;
@@ -4990,6 +5013,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
       switch (bfd_r_type)
        {
        default:
+bad_ifunc_reloc:
          if (h->root.root.string)
            name = h->root.root.string;
          else
@@ -5001,7 +5025,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
               "symbol `%s' isn't handled by %s"), input_bfd,
             howto->name, name, __FUNCTION__);
          bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         return bfd_reloc_notsupported;
 
        case BFD_RELOC_AARCH64_NN:
          if (rel->r_addend != 0)
@@ -5014,10 +5038,10 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
              _bfd_error_handler
                /* xgettext:c-format */
                (_("%B: relocation %s against STT_GNU_IFUNC "
-                  "symbol `%s' has non-zero addend: %d"),
+                  "symbol `%s' has non-zero addend: %Ld"),
                 input_bfd, howto->name, name, rel->r_addend);
              bfd_set_error (bfd_error_bad_value);
-             return FALSE;
+             return bfd_reloc_notsupported;
            }
 
          /* Generate dynamic relocation only when there is a
@@ -5155,6 +5179,9 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
        }
     }
 
+  resolved_to_zero = (h != NULL
+                     && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+
   switch (bfd_r_type)
     {
     case BFD_RELOC_AARCH64_NONE:
@@ -5173,7 +5200,8 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
            || globals->root.is_relocatable_executable)
           && (input_section->flags & SEC_ALLOC)
           && (h == NULL
-              || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+              || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                  && !resolved_to_zero)
               || h->root.type != bfd_link_hash_undefweak))
          /* Or we are creating an executable, we may need to keep relocations
             for symbols satisfied by a dynamic library if we manage to avoid
@@ -5341,7 +5369,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
             input_bfd, elfNN_aarch64_howto_table[howto_index].name,
             h->root.root.string);
          bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         return bfd_reloc_notsupported;
        }
       /* Fall through.  */
 
@@ -5383,12 +5411,32 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
       if (globals->root.sgot == NULL)
        BFD_ASSERT (h != NULL);
 
+      relative_reloc = FALSE;
       if (h != NULL)
        {
          bfd_vma addend = 0;
+
+         /* If a symbol is not dynamic and is not undefined weak, bind it
+            locally and generate a RELATIVE relocation under PIC mode.
+
+            NOTE: one symbol may be referenced by several relocations, we
+            should only generate one RELATIVE relocation for that symbol.
+            Therefore, check GOT offset mark first.  */
+         if (h->dynindx == -1
+             && !h->forced_local
+             && h->root.type != bfd_link_hash_undefweak
+             && bfd_link_pic (info)
+             && !symbol_got_offset_mark_p (input_bfd, h, r_symndx))
+           relative_reloc = TRUE;
+
          value = aarch64_calculate_got_entry_vma (h, globals, info, value,
                                                   output_bfd,
                                                   unresolved_reloc_p);
+         /* Record the GOT entry address which will be used when generating
+            RELATIVE relocation.  */
+         if (relative_reloc)
+           got_entry_addr = value;
+
          if (aarch64_relocation_aginst_gp_p (bfd_r_type))
            addend = (globals->root.sgot->output_section->vma
                      + globals->root.sgot->output_offset);
@@ -5414,32 +5462,20 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 
        off = symbol_got_offset (input_bfd, h, r_symndx);
        base_got = globals->root.sgot;
-       bfd_vma got_entry_addr = (base_got->output_section->vma
-                                 + base_got->output_offset + off);
+       got_entry_addr = (base_got->output_section->vma
+                         + base_got->output_offset + off);
 
        if (!symbol_got_offset_mark_p (input_bfd, h, r_symndx))
          {
            bfd_put_64 (output_bfd, value, base_got->contents + off);
 
+           /* For local symbol, we have done absolute relocation in static
+              linking stage.  While for shared library, we need to update the
+              content of GOT entry according to the shared object's runtime
+              base address.  So, we need to generate a R_AARCH64_RELATIVE reloc
+              for dynamic linker.  */
            if (bfd_link_pic (info))
-             {
-               asection *s;
-               Elf_Internal_Rela outrel;
-
-               /* For local symbol, we have done absolute relocation in static
-                  linking stageh. While for share library, we need to update
-                  the content of GOT entry according to the share objects
-                  loading base address. So we need to generate a
-                  R_AARCH64_RELATIVE reloc for dynamic linker.  */
-               s = globals->root.srelgot;
-               if (s == NULL)
-                 abort ();
-
-               outrel.r_offset = got_entry_addr;
-               outrel.r_info = ELFNN_R_INFO (0, AARCH64_R (RELATIVE));
-               outrel.r_addend = value;
-               elf_append_rela (output_bfd, s, &outrel);
-             }
+             relative_reloc = TRUE;
 
            symbol_got_offset_mark (input_bfd, h, r_symndx);
          }
@@ -5454,6 +5490,21 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
        value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
                                                     addend, weak_undef_p);
       }
+
+      if (relative_reloc)
+       {
+         asection *s;
+         Elf_Internal_Rela outrel;
+
+         s = globals->root.srelgot;
+         if (s == NULL)
+           abort ();
+
+         outrel.r_offset = got_entry_addr;
+         outrel.r_info = ELFNN_R_INFO (0, AARCH64_R (RELATIVE));
+         outrel.r_addend = orig_value;
+         elf_append_rela (output_bfd, s, &outrel);
+       }
       break;
 
     case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
@@ -6047,17 +6098,11 @@ elfNN_aarch64_relocate_section (bfd *output_bfd,
       r_symndx = ELFNN_R_SYM (rel->r_info);
       r_type = ELFNN_R_TYPE (rel->r_info);
 
-      bfd_reloc.howto = elfNN_aarch64_howto_from_type (r_type);
-      howto = bfd_reloc.howto;
+      howto = bfd_reloc.howto = elfNN_aarch64_howto_from_type (r_type);
 
       if (howto == NULL)
-       {
-         /* xgettext:c-format */
-         _bfd_error_handler
-           (_("%B: unrecognized relocation (0x%x) in section `%A'"),
-            input_bfd, r_type, input_section);
-         return FALSE;
-       }
+       return _bfd_unrecognized_reloc (input_bfd, input_section, r_type);
+
       bfd_r_type = elfNN_aarch64_bfd_reloc_from_howto (howto);
 
       h = NULL;
@@ -6137,11 +6182,11 @@ elfNN_aarch64_relocate_section (bfd *output_bfd,
          _bfd_error_handler
            ((sym_type == STT_TLS
              /* xgettext:c-format */
-             ? _("%B(%A+0x%lx): %s used with TLS symbol %s")
+             ? _("%B(%A+%#Lx): %s used with TLS symbol %s")
              /* xgettext:c-format */
-             : _("%B(%A+0x%lx): %s used with non-TLS symbol %s")),
+             : _("%B(%A+%#Lx): %s used with non-TLS symbol %s")),
             input_bfd,
-            input_section, (long) rel->r_offset, howto->name, name);
+            input_section, rel->r_offset, howto->name, name);
        }
 
       /* We relax only if we can see that there can be a valid transition
@@ -6409,8 +6454,8 @@ elfNN_aarch64_relocate_section (bfd *output_bfd,
        {
          _bfd_error_handler
            /* xgettext:c-format */
-           (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
-            input_bfd, input_section, (long) rel->r_offset, howto->name,
+           (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"),
+            input_bfd, input_section, rel->r_offset, howto->name,
             h->root.root.string);
          return FALSE;
        }
@@ -6648,180 +6693,6 @@ elfNN_aarch64_print_private_bfd_data (bfd *abfd, void *ptr)
   return TRUE;
 }
 
-/* Update the got entry reference counts for the section being removed.  */
-
-static bfd_boolean
-elfNN_aarch64_gc_sweep_hook (bfd *abfd,
-                            struct bfd_link_info *info,
-                            asection *sec,
-                            const Elf_Internal_Rela * relocs)
-{
-  struct elf_aarch64_link_hash_table *htab;
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  struct elf_aarch64_local_symbol *locals;
-  const Elf_Internal_Rela *rel, *relend;
-
-  if (bfd_link_relocatable (info))
-    return TRUE;
-
-  htab = elf_aarch64_hash_table (info);
-
-  if (htab == NULL)
-    return FALSE;
-
-  elf_section_data (sec)->local_dynrel = NULL;
-
-  symtab_hdr = &elf_symtab_hdr (abfd);
-  sym_hashes = elf_sym_hashes (abfd);
-
-  locals = elf_aarch64_locals (abfd);
-
-  relend = relocs + sec->reloc_count;
-  for (rel = relocs; rel < relend; rel++)
-    {
-      unsigned long r_symndx;
-      unsigned int r_type;
-      struct elf_link_hash_entry *h = NULL;
-
-      r_symndx = ELFNN_R_SYM (rel->r_info);
-
-      if (r_symndx >= symtab_hdr->sh_info)
-       {
-
-         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
-        }
-      else
-       {
-         Elf_Internal_Sym *isym;
-
-         /* A local symbol.  */
-         isym = bfd_sym_from_r_symndx (&htab->sym_cache,
-                                       abfd, r_symndx);
-
-         /* Check relocation against local STT_GNU_IFUNC symbol.  */
-         if (isym != NULL
-             && ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
-           {
-             h = elfNN_aarch64_get_local_sym_hash (htab, abfd, rel, FALSE);
-             if (h == NULL)
-               abort ();
-           }
-       }
-
-      if (h)
-       {
-         struct elf_aarch64_link_hash_entry *eh;
-         struct elf_dyn_relocs **pp;
-         struct elf_dyn_relocs *p;
-
-         eh = (struct elf_aarch64_link_hash_entry *) h;
-
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-           if (p->sec == sec)
-             {
-               /* Everything must go for SEC.  */
-               *pp = p->next;
-               break;
-             }
-       }
-
-      r_type = ELFNN_R_TYPE (rel->r_info);
-      switch (aarch64_tls_transition (abfd,info, r_type, h ,r_symndx))
-       {
-       case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
-       case BFD_RELOC_AARCH64_GOT_LD_PREL19:
-       case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
-       case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
-       case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
-       case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
-       case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
-       case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
-       case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
-       case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
-       case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
-       case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
-       case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
-       case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
-       case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
-       case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
-       case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
-       case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
-       case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
-       case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
-       case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
-       case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
-       case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
-       case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
-       case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
-       case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
-       case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
-       case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
-       case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
-       case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
-       case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
-         if (h != NULL)
-           {
-             if (h->got.refcount > 0)
-               h->got.refcount -= 1;
-
-             if (h->type == STT_GNU_IFUNC)
-               {
-                 if (h->plt.refcount > 0)
-                   h->plt.refcount -= 1;
-               }
-           }
-         else if (locals != NULL)
-           {
-             if (locals[r_symndx].got_refcount > 0)
-               locals[r_symndx].got_refcount -= 1;
-           }
-         break;
-
-       case BFD_RELOC_AARCH64_CALL26:
-       case BFD_RELOC_AARCH64_JUMP26:
-         /* If this is a local symbol then we resolve it
-            directly without creating a PLT entry.  */
-         if (h == NULL)
-           continue;
-
-         if (h->plt.refcount > 0)
-           h->plt.refcount -= 1;
-         break;
-
-       case BFD_RELOC_AARCH64_ADD_LO12:
-       case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
-       case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
-       case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
-       case BFD_RELOC_AARCH64_LDST128_LO12:
-       case BFD_RELOC_AARCH64_LDST16_LO12:
-       case BFD_RELOC_AARCH64_LDST32_LO12:
-       case BFD_RELOC_AARCH64_LDST64_LO12:
-       case BFD_RELOC_AARCH64_LDST8_LO12:
-       case BFD_RELOC_AARCH64_LD_LO19_PCREL:
-       case BFD_RELOC_AARCH64_MOVW_G0_NC:
-       case BFD_RELOC_AARCH64_MOVW_G1_NC:
-       case BFD_RELOC_AARCH64_MOVW_G2_NC:
-       case BFD_RELOC_AARCH64_MOVW_G3:
-       case BFD_RELOC_AARCH64_NN:
-         if (h != NULL && !bfd_link_pic (info))
-           {
-             if (h->plt.refcount > 0)
-               h->plt.refcount -= 1;
-           }
-         break;
-
-       default:
-         break;
-       }
-    }
-
-  return TRUE;
-}
-
 /* Return true if we need copy relocation against EH.  */
 
 static bfd_boolean
@@ -6890,14 +6761,14 @@ elfNN_aarch64_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
      real definition first, and we can just use the same value.  */
-  if (h->u.weakdef != NULL)
+  if (h->is_weakalias)
     {
-      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
-                 || h->u.weakdef->root.type == bfd_link_hash_defweak);
-      h->root.u.def.section = h->u.weakdef->root.u.def.section;
-      h->root.u.def.value = h->u.weakdef->root.u.def.value;
+      struct elf_link_hash_entry *def = weakdef (h);
+      BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+      h->root.u.def.section = def->root.u.def.section;
+      h->root.u.def.value = def->root.u.def.value;
       if (ELIMINATE_COPY_RELOCS || info->nocopyreloc)
-       h->non_got_ref = h->u.weakdef->non_got_ref;
+       h->non_got_ref = def->non_got_ref;
       return TRUE;
     }
 
@@ -7076,7 +6947,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
   for (rel = relocs; rel < rel_end; rel++)
     {
       struct elf_link_hash_entry *h;
-      unsigned long r_symndx;
+      unsigned int r_symndx;
       unsigned int r_type;
       bfd_reloc_code_real_type bfd_r_type;
       Elf_Internal_Sym *isym;
@@ -7609,8 +7480,39 @@ elfNN_aarch64_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSE
                                const asection *rel_sec ATTRIBUTE_UNUSED,
                                const Elf_Internal_Rela *rela)
 {
+  struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+
+  if (htab->root.dynsym != NULL
+      && htab->root.dynsym->contents != NULL)
+    {
+      /* Check relocation against STT_GNU_IFUNC symbol if there are
+        dynamic symbols.  */
+      bfd *abfd = info->output_bfd;
+      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+      unsigned long r_symndx = ELFNN_R_SYM (rela->r_info);
+      if (r_symndx != STN_UNDEF)
+       {
+         Elf_Internal_Sym sym;
+         if (!bed->s->swap_symbol_in (abfd,
+                                      (htab->root.dynsym->contents
+                                       + r_symndx * bed->s->sizeof_sym),
+                                      0, &sym))
+           {
+             /* xgettext:c-format */
+             _bfd_error_handler (_("%B symbol number %lu references"
+                                   " nonexistent SHT_SYMTAB_SHNDX section"),
+                                   abfd, r_symndx);
+             /* Ideally an error class should be returned here.  */
+           }
+         else if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+           return reloc_class_ifunc;
+       }
+    }
+
   switch ((int) ELFNN_R_TYPE (rela->r_info))
     {
+    case AARCH64_R (IRELATIVE):
+      return reloc_class_ifunc;
     case AARCH64_R (RELATIVE):
       return reloc_class_relative;
     case AARCH64_R (JUMP_SLOT):
@@ -8021,7 +7923,8 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     {
       /* Make sure this symbol is output as a dynamic symbol.
          Undefined weak syms won't yet be marked as dynamic.  */
-      if (h->dynindx == -1 && !h->forced_local)
+      if (h->dynindx == -1 && !h->forced_local
+         && h->root.type == bfd_link_hash_undefweak)
        {
          if (!bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
@@ -8102,7 +8005,8 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
       /* Make sure this symbol is output as a dynamic symbol.
          Undefined weak syms won't yet be marked as dynamic.  */
-      if (dyn && h->dynindx == -1 && !h->forced_local)
+      if (dyn && h->dynindx == -1 && !h->forced_local
+         && h->root.type == bfd_link_hash_undefweak)
        {
          if (!bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
@@ -8118,7 +8022,10 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
          if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
               || h->root.type != bfd_link_hash_undefweak)
              && (bfd_link_pic (info)
-                 || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
+                 || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+             /* Undefined weak symbol in static PIE resolves to 0 without
+                any dynamic relocations.  */
+             && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
            {
              htab->root.srelgot->size += RELOC_SIZE (htab);
            }
@@ -8214,13 +8121,15 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
          visibility.  */
       if (eh->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak)
        {
-         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+             || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
            eh->dyn_relocs = NULL;
 
          /* Make sure undefined weak symbols are output as a dynamic
             symbol in PIEs.  */
          else if (h->dynindx == -1
                   && !h->forced_local
+                  && h->root.type == bfd_link_hash_undefweak
                   && !bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
        }
@@ -8243,6 +8152,7 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
             Undefined weak syms won't yet be marked as dynamic.  */
          if (h->dynindx == -1
              && !h->forced_local
+             && h->root.type == bfd_link_hash_undefweak
              && !bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
 
@@ -8693,7 +8603,8 @@ elf_aarch64_update_plt_entry (bfd *output_bfd,
 {
   reloc_howto_type *howto = elfNN_aarch64_howto_from_bfd_reloc (r_type);
 
-  _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type, howto, value);
+  /* FIXME: We should check the return value from this function call.  */
+  (void) _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type, howto, value);
 }
 
 static void
@@ -8916,7 +8827,10 @@ elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd,
     }
 
   if (h->got.offset != (bfd_vma) - 1
-      && elf_aarch64_hash_entry (h)->got_type == GOT_NORMAL)
+      && elf_aarch64_hash_entry (h)->got_type == GOT_NORMAL
+      /* Undefined weak symbol in static PIE resolves to 0 without
+        any dynamic relocations.  */
+      && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
     {
       Elf_Internal_Rela rela;
       bfd_byte *loc;
@@ -9416,9 +9330,6 @@ const struct elf_size_info elfNN_aarch64_size_info =
 #define elf_backend_finish_dynamic_symbol      \
   elfNN_aarch64_finish_dynamic_symbol
 
-#define elf_backend_gc_sweep_hook              \
-  elfNN_aarch64_gc_sweep_hook
-
 #define elf_backend_object_p                   \
   elfNN_aarch64_object_p