[PR ld/22269] aarch64: Handle local undefined weak symbols
[external/binutils.git] / bfd / elfnn-aarch64.c
index 542c98a..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;
@@ -4907,6 +4909,18 @@ elfNN_aarch64_write_section (bfd *output_bfd  ATTRIBUTE_UNUSED,
   return FALSE;
 }
 
+/* Return TRUE if RELOC is a relocation against the base of GOT table.  */
+
+static bfd_boolean
+aarch64_relocation_aginst_gp_p (bfd_reloc_code_real_type reloc)
+{
+  return (reloc == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14
+         || reloc == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
+         || reloc == BFD_RELOC_AARCH64_LD64_GOTOFF_LO15
+         || reloc == BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC
+         || reloc == BFD_RELOC_AARCH64_MOVW_GOTOFF_G1);
+}
+
 /* Perform a relocation as part of a final link.  The input relocation type
    should be TLS relaxed.  */
 
@@ -4932,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);
 
@@ -4967,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;
@@ -4978,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
@@ -4989,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)
@@ -5002,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
@@ -5130,21 +5166,9 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
                                                     value, output_bfd,
                                                     unresolved_reloc_p);
 
-         switch (bfd_r_type)
-           {
-           case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
-           case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
-             addend = (globals->root.sgot->output_section->vma
-                       + globals->root.sgot->output_offset);
-             break;
-           case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
-           case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
-           case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
-             value = (value - globals->root.sgot->output_section->vma
-                      - globals->root.sgot->output_offset);
-           default:
-             break;
-           }
+         if (aarch64_relocation_aginst_gp_p (bfd_r_type))
+           addend = (globals->root.sgot->output_section->vma
+                     + globals->root.sgot->output_offset);
 
          value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
                                                       addend, weak_undef_p);
@@ -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
@@ -5329,19 +5357,19 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
       if (bfd_link_pic (info)
          && (input_section->flags & SEC_ALLOC) != 0
          && (input_section->flags & SEC_READONLY) != 0
-         && h != NULL
-         && !h->def_regular)
+         && !SYMBOL_REFERENCES_LOCAL (info, h))
        {
          int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
 
          _bfd_error_handler
            /* xgettext:c-format */
-           (_("%B: relocation %s against external symbol `%s' can not be used"
-              " when making a shared object; recompile with -fPIC"),
+           (_("%B: relocation %s against symbol `%s' which may bind "
+              "externally can not be used when making a shared object; "
+              "recompile with -fPIC"),
             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.  */
 
@@ -5377,17 +5405,39 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
     case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
     case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
     case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+    case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+    case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
       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);
-         if (bfd_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
-             || bfd_r_type == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14)
+         /* 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);
          value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
@@ -5412,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);
          }
@@ -5446,81 +5484,27 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
           the direct data access into indirect data access through GOT.  */
        value = got_entry_addr;
 
-       if (bfd_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
-           || bfd_r_type == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14)
+       if (aarch64_relocation_aginst_gp_p (bfd_r_type))
          addend = base_got->output_section->vma + base_got->output_offset;
 
        value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
                                                     addend, weak_undef_p);
       }
 
-      break;
-
-    case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
-    case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
-    case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
-      if (h != NULL)
-         value = aarch64_calculate_got_entry_vma (h, globals, info, value,
-                                                  output_bfd,
-                                                  unresolved_reloc_p);
-      else
+      if (relative_reloc)
        {
-         struct elf_aarch64_local_symbol *locals
-           = elf_aarch64_locals (input_bfd);
-
-         if (locals == NULL)
-           {
-             int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
-             _bfd_error_handler
-               /* xgettext:c-format */
-               (_("%B: Local symbol descriptor table be NULL when applying "
-                  "relocation %s against local symbol"),
-                input_bfd, elfNN_aarch64_howto_table[howto_index].name);
-             abort ();
-           }
+         asection *s;
+         Elf_Internal_Rela outrel;
 
-         off = symbol_got_offset (input_bfd, h, r_symndx);
-         base_got = globals->root.sgot;
-         if (base_got == NULL)
+         s = globals->root.srelgot;
+         if (s == NULL)
            abort ();
 
-         bfd_vma 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);
-
-             if (bfd_link_pic (info))
-               {
-                 asection *s;
-                 Elf_Internal_Rela outrel;
-
-                 /* For local symbol, we have done absolute relocation in static
-                    linking stage.  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);
-               }
-
-             symbol_got_offset_mark (input_bfd, h, r_symndx);
-           }
+         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);
        }
-
-      /* Update the relocation value to GOT entry addr as we have transformed
-        the direct data access into indirect data access through GOT.  */
-      value = symbol_got_offset (input_bfd, h, r_symndx);
-      value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
-                                                  0, weak_undef_p);
-      *unresolved_reloc_p = FALSE;
       break;
 
     case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
@@ -6114,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;
@@ -6204,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
@@ -6476,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;
        }
@@ -6715,185 +6693,24 @@ 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_ADR_HI21_NC_PCREL:
-       case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
-       case BFD_RELOC_AARCH64_ADR_LO21_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_executable (info))
-           {
-             if (h->plt.refcount > 0)
-               h->plt.refcount -= 1;
-           }
-         break;
-
-       default:
-         break;
-       }
-    }
-
-  return TRUE;
-}
-
-/* Return true if we have dynamic relocs against EH or any of its weak
-   aliases, that apply to read-only sections.  */
+/* Return true if we need copy relocation against EH.  */
 
 static bfd_boolean
-alias_readonly_dynrelocs (struct elf_aarch64_link_hash_entry *eh)
+need_copy_relocation_p (struct elf_aarch64_link_hash_entry *eh)
 {
   struct elf_dyn_relocs *p;
   asection *s;
 
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
+      /* If there is any pc-relative reference, we need to keep copy relocation
+        to avoid propagating the relocation into runtime that current glibc
+        does not support.  */
+      if (p->pc_count)
+       return TRUE;
+
       s = p->sec->output_section;
+      /* Need copy relocation if it's against read-only section.  */
       if (s != NULL && (s->flags & SEC_READONLY) != 0)
        return TRUE;
     }
@@ -6944,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;
     }
 
@@ -6980,7 +6797,7 @@ elfNN_aarch64_adjust_dynamic_symbol (struct bfd_link_info *info,
       /* If we didn't find any dynamic relocs in read-only sections, then
         we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
       eh = (struct elf_aarch64_link_hash_entry *) h;
-      if (eh->dyn_relocs && !alias_readonly_dynrelocs (eh))
+      if (!need_copy_relocation_p (eh))
        {
          h->non_got_ref = 0;
          return TRUE;
@@ -7130,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;
@@ -7241,6 +7058,41 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
       switch (bfd_r_type)
        {
+       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:
+         if (bfd_link_pic (info))
+           {
+             int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%B: relocation %s against `%s' can not be used when making "
+                  "a shared object; recompile with -fPIC"),
+                abfd, elfNN_aarch64_howto_table[howto_index].name,
+                (h) ? h->root.root.string : "a local symbol");
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
+         /* Fall through.  */
+
+       case BFD_RELOC_AARCH64_16_PCREL:
+       case BFD_RELOC_AARCH64_32_PCREL:
+       case BFD_RELOC_AARCH64_64_PCREL:
+       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:
+         if (h == NULL || bfd_link_pic (info))
+           break;
+         /* Fall through.  */
+
        case BFD_RELOC_AARCH64_NN:
 
          /* We don't need to handle relocs into sections not going into
@@ -7263,7 +7115,17 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                /* If on the other hand, we are creating an executable, we
                   may need to keep relocations for symbols satisfied by a
                   dynamic library if we manage to avoid copy relocs for the
-                  symbol.  */
+                  symbol.
+
+                  NOTE: Currently, there is no support of copy relocs
+                  elimination on pc-relative relocation types, because there is
+                  no dynamic relocation support for them in glibc.  We still
+                  record the dynamic symbol reference for them.  This is
+                  because one symbol may be referenced by both absolute
+                  relocation (for example, BFD_RELOC_AARCH64_NN) and
+                  pc-relative relocation.  We need full symbol reference
+                  information to make correct decision later in
+                  elfNN_aarch64_adjust_dynamic_symbol.  */
                || (ELIMINATE_COPY_RELOCS
                    && !bfd_link_pic (info)
                    && h != NULL
@@ -7274,6 +7136,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          {
            struct elf_dyn_relocs *p;
            struct elf_dyn_relocs **head;
+           int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
 
            /* We must copy these reloc types into the output file.
               Create a reloc section in dynobj and make room for
@@ -7337,6 +7200,8 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
            p->count += 1;
 
+           if (elfNN_aarch64_howto_table[howto_index].pc_relative)
+             p->pc_count += 1;
          }
          break;
 
@@ -7440,44 +7305,6 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            break;
          }
 
-       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:
-         if (bfd_link_pic (info))
-           {
-             int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
-             _bfd_error_handler
-               /* xgettext:c-format */
-               (_("%B: relocation %s against `%s' can not be used when making "
-                  "a shared object; recompile with -fPIC"),
-                abfd, elfNN_aarch64_howto_table[howto_index].name,
-                (h) ? h->root.root.string : "a local symbol");
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
-           }
-         /* Fall through.  */
-
-       case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
-       case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
-       case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
-         if (h != NULL && bfd_link_executable (info))
-           {
-             /* If this reloc is in a read-only section, we might
-                need a copy reloc.  We can't check reliably at this
-                stage whether the section is read-only, as input
-                sections have not yet been mapped to output sections.
-                Tentatively set the flag for now, and correct in
-                adjust_dynamic_symbol.  */
-             h->non_got_ref = 1;
-             h->plt.refcount += 1;
-             h->pointer_equality_needed = 1;
-           }
-         /* FIXME:: RR need to handle these in shared libraries
-            and essentially bomb out as these being non-PIC
-            relocations in shared libraries.  */
-         break;
-
        case BFD_RELOC_AARCH64_CALL26:
        case BFD_RELOC_AARCH64_JUMP26:
          /* If this is a local symbol then we resolve it
@@ -7653,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):
@@ -8065,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;
@@ -8146,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;
@@ -8162,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);
            }
@@ -8258,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;
        }
@@ -8287,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;
 
@@ -8737,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
@@ -8960,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;
@@ -9460,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