Support %Lx, %Lu, %Ld in _bfd_error_handler format
[deliverable/binutils-gdb.git] / bfd / elfnn-aarch64.c
index 542c98a46f0d46649d4c631cb1f9d759e720f5b2..11954486e16b3a257b483e202b47ccfe1ca802f7 100644 (file)
@@ -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);
 
@@ -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);
@@ -5329,15 +5331,15 @@ 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);
@@ -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:
@@ -6859,15 +6817,22 @@ elfNN_aarch64_gc_sweep_hook (bfd *abfd,
            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_executable (info))
+         if (h != NULL && !bfd_link_pic (info))
            {
              if (h->plt.refcount > 0)
                h->plt.refcount -= 1;
@@ -6882,18 +6847,24 @@ elfNN_aarch64_gc_sweep_hook (bfd *abfd,
   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;
     }
@@ -6980,7 +6951,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;
@@ -7241,6 +7212,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 +7269,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 +7290,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 +7354,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 +7459,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
@@ -8065,7 +8046,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 +8128,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;
@@ -8265,6 +8248,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;
        }
@@ -8287,6 +8271,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;
 
@@ -8907,6 +8892,13 @@ elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd,
   struct elf_aarch64_link_hash_table *htab;
   htab = elf_aarch64_hash_table (info);
 
+  /* Sanity check to make sure no unexpected symbol reaches here.  */
+    if (h->dynindx == -1
+       && !h->forced_local
+       && h->root.type != bfd_link_hash_undefweak
+       && bfd_link_pic (info))
+      abort ();
+
   if (h->plt.offset != (bfd_vma) - 1)
     {
       asection *plt, *gotplt, *relplt;
This page took 0.031022 seconds and 4 git commands to generate.