Improve "unrecognized relocation" error messages to add the suggestion that the linke...
[binutils-gdb.git] / bfd / elfnn-aarch64.c
index b61bb8aa5be70202b0da5c410d364d365c5633e0..0d8332e69ce847e0a190ac5cf540eb9345ddb3a0 100644 (file)
@@ -3281,7 +3281,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 +4907,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 +4944,13 @@ 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;
   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;
 
   globals = elf_aarch64_hash_table (info);
 
@@ -5002,7 +5016,7 @@ 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;
@@ -5130,21 +5144,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);
@@ -5377,17 +5379,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 +5436,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 +5458,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 +6072,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 +6156,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 +6428,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;
        }
@@ -7143,7 +7095,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;
@@ -7676,8 +7628,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):
@@ -8088,7 +8071,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;
@@ -8169,7 +8153,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;
@@ -8288,6 +8273,7 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
             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;
        }
@@ -8310,6 +8296,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;