gdb/
[binutils-gdb.git] / bfd / elf64-aarch64.c
index 629907403c18ba05a39c1a341e06cac0345b1eb9..aef472f2e8bc017e376756e1a7626c8371b249c0 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF support for AArch64.
-   Copyright 2009, 2010, 2011, 2012  Free Software Foundation, Inc.
+   Copyright 2009-2013 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -908,7 +908,23 @@ static reloc_howto_type elf64_aarch64_howto_table[] =
   EMPTY_HOWTO (306),
   EMPTY_HOWTO (307),
   EMPTY_HOWTO (308),
-  EMPTY_HOWTO (309),
+
+  /* Set a load-literal immediate field to bits
+     0x1FFFFC of G(S)-P */
+  HOWTO (R_AARCH64_GOT_LD_PREL19,      /* type */
+        2,                             /* rightshift */
+        2,                             /* size (0 = byte,1 = short,2 = long) */
+        19,                            /* bitsize */
+        TRUE,                          /* pc_relative */
+        0,                             /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc,         /* special_function */
+        "R_AARCH64_GOT_LD_PREL19",     /* name */
+        FALSE,                         /* partial_inplace */
+        0xffffe0,                      /* src_mask */
+        0xffffe0,                      /* dst_mask */
+        TRUE),                         /* pcrel_offset */
+
   EMPTY_HOWTO (310),
 
   /* Get to the page for the GOT entry for the symbol
@@ -1060,7 +1076,7 @@ static reloc_howto_type elf64_aarch64_tls_howto_table[] =
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_AARCH64_TLSIE_LD_GOTTPREL_PREL19,   /* type */
-        0,                     /* rightshift */
+        2,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         21,                    /* bitsize */
         FALSE,                 /* pc_relative */
@@ -1074,7 +1090,7 @@ static reloc_howto_type elf64_aarch64_tls_howto_table[] =
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_AARCH64_TLSLE_MOVW_TPREL_G2,        /* type */
-        8,                     /* rightshift */
+        32,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         12,                    /* bitsize */
         FALSE,                 /* pc_relative */
@@ -1088,7 +1104,7 @@ static reloc_howto_type elf64_aarch64_tls_howto_table[] =
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_AARCH64_TLSLE_MOVW_TPREL_G1,        /* type */
-        4,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         12,                    /* bitsize */
         FALSE,                 /* pc_relative */
@@ -1102,7 +1118,7 @@ static reloc_howto_type elf64_aarch64_tls_howto_table[] =
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_AARCH64_TLSLE_MOVW_TPREL_G1_NC,     /* type */
-        4,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         12,                    /* bitsize */
         FALSE,                 /* pc_relative */
@@ -1144,7 +1160,7 @@ static reloc_howto_type elf64_aarch64_tls_howto_table[] =
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_AARCH64_TLSLE_ADD_TPREL_HI12,       /* type */
-        3,                     /* rightshift */
+        12,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         12,                    /* bitsize */
         FALSE,                 /* pc_relative */
@@ -1189,7 +1205,7 @@ static reloc_howto_type elf64_aarch64_tls_howto_table[] =
 static reloc_howto_type elf64_aarch64_tlsdesc_howto_table[] =
 {
   HOWTO (R_AARCH64_TLSDESC_LD64_PREL19,        /* type */
-        0,                     /* rightshift */
+        2,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         21,                    /* bitsize */
         TRUE,                  /* pc_relative */
@@ -1263,7 +1279,7 @@ static reloc_howto_type elf64_aarch64_tlsdesc_howto_table[] =
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_AARCH64_TLSDESC_OFF_G1,     /* type */
-        4,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         12,                    /* bitsize */
         FALSE,                 /* pc_relative */
@@ -1427,6 +1443,7 @@ static const struct elf64_aarch64_reloc_map elf64_aarch64_reloc_map[] =
   {BFD_RELOC_AARCH64_CALL26, R_AARCH64_CALL26},
 
   /* Relocations for PIC.  */
+  {BFD_RELOC_AARCH64_GOT_LD_PREL19, R_AARCH64_GOT_LD_PREL19},
   {BFD_RELOC_AARCH64_ADR_GOT_PAGE, R_AARCH64_ADR_GOT_PAGE},
   {BFD_RELOC_AARCH64_LD64_GOT_LO12_NC, R_AARCH64_LD64_GOT_LO12_NC},
 
@@ -1499,11 +1516,47 @@ elf64_aarch64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return NULL;
 }
 
+/* Support for core dump NOTE sections.  */
+
+static bfd_boolean
+elf64_aarch64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+  int offset;
+  size_t size;
+
+  switch (note->descsz)
+    {
+      default:
+       return FALSE;
+
+      case 408:                /* sizeof(struct elf_prstatus) on Linux/arm64.  */
+       /* pr_cursig */
+       elf_tdata (abfd)->core->signal
+         = bfd_get_16 (abfd, note->descdata + 12);
+
+       /* pr_pid */
+       elf_tdata (abfd)->core->lwpid
+         = bfd_get_32 (abfd, note->descdata + 32);
+
+       /* pr_reg */
+       offset = 112;
+       size = 272;
+
+       break;
+    }
+
+  /* Make a ".reg/999" section.  */
+  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+                                         size, note->descpos + offset);
+}
+
 #define TARGET_LITTLE_SYM               bfd_elf64_littleaarch64_vec
 #define TARGET_LITTLE_NAME              "elf64-littleaarch64"
 #define TARGET_BIG_SYM                  bfd_elf64_bigaarch64_vec
 #define TARGET_BIG_NAME                 "elf64-bigaarch64"
 
+#define elf_backend_grok_prstatus      elf64_aarch64_grok_prstatus
+
 typedef unsigned long int insn32;
 
 /* The linker script knows the section names for placement.
@@ -2040,7 +2093,7 @@ elf64_aarch64_link_hash_table_create (bfd *abfd)
   struct elf64_aarch64_link_hash_table *ret;
   bfd_size_type amt = sizeof (struct elf64_aarch64_link_hash_table);
 
-  ret = bfd_malloc (amt);
+  ret = bfd_zmalloc (amt);
   if (ret == NULL)
     return NULL;
 
@@ -2052,23 +2105,9 @@ elf64_aarch64_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
-  ret->sdynbss = NULL;
-  ret->srelbss = NULL;
-
   ret->plt_header_size = PLT_ENTRY_SIZE;
   ret->plt_entry_size = PLT_SMALL_ENTRY_SIZE;
-
-  ret->sym_cache.abfd = NULL;
   ret->obfd = abfd;
-
-  ret->stub_bfd = NULL;
-  ret->add_stub_section = NULL;
-  ret->layout_sections_again = NULL;
-  ret->stub_group = NULL;
-  ret->bfd_count = 0;
-  ret->top_index = 0;
-  ret->input_list = NULL;
-  ret->tlsdesc_plt = 0;
   ret->dt_tlsdesc_got = (bfd_vma) - 1;
 
   if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
@@ -2090,7 +2129,7 @@ elf64_aarch64_hash_table_free (struct bfd_link_hash_table *hash)
     = (struct elf64_aarch64_link_hash_table *) hash;
 
   bfd_hash_table_free (&ret->stub_hash_table);
-  _bfd_generic_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (hash);
 }
 
 static bfd_vma
@@ -2143,6 +2182,10 @@ aarch64_resolve_relocation (unsigned int r_type, bfd_vma place, bfd_vma value,
       value = PG (value + addend) - PG (place);
       break;
 
+    case R_AARCH64_GOT_LD_PREL19:
+      value = value + addend - place;
+      break;
+
     case R_AARCH64_ADR_GOT_PAGE:
     case R_AARCH64_TLSDESC_ADR_PAGE:
     case R_AARCH64_TLSGD_ADR_PAGE21:
@@ -3362,6 +3405,7 @@ bfd_elf_aarch64_put_addend (bfd *abfd,
       break;
 
     case R_AARCH64_LD_PREL_LO19:
+    case R_AARCH64_GOT_LD_PREL19:
       if (old_addend & ((1 << howto->rightshift) - 1))
        return bfd_reloc_overflow;
       contents = reencode_ld_lit_ofs_19 (contents, addend);
@@ -3570,6 +3614,7 @@ aarch64_reloc_got_type (unsigned int r_type)
     {
     case R_AARCH64_LD64_GOT_LO12_NC:
     case R_AARCH64_ADR_GOT_PAGE:
+    case R_AARCH64_GOT_LD_PREL19:
       return GOT_NORMAL;
 
     case R_AARCH64_TLSGD_ADR_PAGE21:
@@ -3992,6 +4037,7 @@ elf64_aarch64_final_link_relocate (reloc_howto_type *howto,
 
     case R_AARCH64_LD64_GOT_LO12_NC:
     case R_AARCH64_ADR_GOT_PAGE:
+    case R_AARCH64_GOT_LD_PREL19:
       if (globals->root.sgot == NULL)
        BFD_ASSERT (h != NULL);
 
@@ -4030,7 +4076,7 @@ elf64_aarch64_final_link_relocate (reloc_howto_type *howto,
     case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
     case R_AARCH64_TLSLE_MOVW_TPREL_G2:
       value = aarch64_resolve_relocation (r_type, place, value,
-                                         - tpoff_base (info), weak_undef_p);
+                                         signed_addend - tpoff_base (info), weak_undef_p);
       *unresolved_reloc_p = FALSE;
       break;
 
@@ -4260,6 +4306,14 @@ elf64_aarch64_relocate_section (bfd *output_bfd,
       bfd_reloc.howto = elf64_aarch64_howto_from_type (r_type);
       howto = bfd_reloc.howto;
 
+      if (howto == NULL)
+       {
+         (*_bfd_error_handler)
+           (_("%B: unrecognized relocation (0x%x) in section `%A'"),
+            input_bfd, input_section, r_type);
+         return FALSE;
+       }
+
       h = NULL;
       sym = NULL;
       sec = NULL;
@@ -4284,12 +4338,6 @@ elf64_aarch64_relocate_section (bfd *output_bfd,
                return FALSE;
            }
 
-         if (r_type >= R_AARCH64_dyn_max)
-           {
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
-           }
-
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
        }
       else
@@ -4823,12 +4871,142 @@ elf64_aarch64_print_private_bfd_data (bfd *abfd, void *ptr)
 /* Update the got entry reference counts for the section being removed.  */
 
 static bfd_boolean
-elf64_aarch64_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
-                            struct bfd_link_info *info ATTRIBUTE_UNUSED,
-                            asection *sec ATTRIBUTE_UNUSED,
-                            const Elf_Internal_Rela *
-                            relocs ATTRIBUTE_UNUSED)
+elf64_aarch64_gc_sweep_hook (bfd *abfd,
+                            struct bfd_link_info *info,
+                            asection *sec,
+                            const Elf_Internal_Rela * relocs)
 {
+  struct elf64_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 (info->relocatable)
+    return TRUE;
+
+  htab = elf64_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 = elf64_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 = ELF64_R_SYM (rel->r_info);
+
+      if (r_symndx >= symtab_hdr->sh_info)
+       {
+         struct elf64_aarch64_link_hash_entry *eh;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
+
+         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;
+         eh = (struct elf64_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;
+               }
+           }
+        }
+      else
+       {
+         Elf_Internal_Sym *isym;
+
+         /* A local symbol.  */
+         isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                       abfd, r_symndx);
+         if (isym == NULL)
+           return FALSE;
+       }
+
+      r_type = ELF64_R_TYPE (rel->r_info);
+      r_type = aarch64_tls_transition (abfd,info, r_type, h ,r_symndx);
+      switch (r_type)
+       {
+       case R_AARCH64_LD64_GOT_LO12_NC:
+       case R_AARCH64_GOT_LD_PREL19:
+       case R_AARCH64_ADR_GOT_PAGE:
+       case R_AARCH64_TLSGD_ADR_PAGE21:
+       case R_AARCH64_TLSGD_ADD_LO12_NC:
+       case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+       case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+       case R_AARCH64_TLSLE_ADD_TPREL_LO12:
+       case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+       case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+       case R_AARCH64_TLSLE_MOVW_TPREL_G2:
+       case R_AARCH64_TLSLE_MOVW_TPREL_G1:
+       case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+       case R_AARCH64_TLSLE_MOVW_TPREL_G0:
+       case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+       case R_AARCH64_TLSDESC_ADR_PAGE:
+       case R_AARCH64_TLSDESC_ADD_LO12_NC:
+       case R_AARCH64_TLSDESC_LD64_LO12_NC:
+          if (h != NULL)
+           {
+             if (h->got.refcount > 0)
+               h->got.refcount -= 1;
+           }
+         else if (locals != NULL)
+           {
+             if (locals[r_symndx].got_refcount > 0)
+               locals[r_symndx].got_refcount -= 1;
+           }
+         break;
+
+       case R_AARCH64_ADR_PREL_PG_HI21_NC:
+       case R_AARCH64_ADR_PREL_PG_HI21:
+       case R_AARCH64_ADR_PREL_LO21:
+         if (h != NULL && info->executable)
+           {
+             if (h->plt.refcount > 0)
+               h->plt.refcount -= 1;
+           }
+         break;
+
+       case R_AARCH64_CALL26:
+       case R_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 R_AARCH64_ABS64:
+         if (h != NULL && info->executable)
+           {
+             if (h->plt.refcount > 0)
+               h->plt.refcount -= 1;
+           }
+         break;
+        
+       default:
+         break;
+       }
+    }
+
   return TRUE;
 }
 
@@ -4965,8 +5143,6 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
   struct elf64_aarch64_link_hash_table *htab;
 
-  unsigned long nsyms;
-
   if (info->relocatable)
     return TRUE;
 
@@ -4977,7 +5153,6 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
-  nsyms = NUM_SHDR_ENTRIES (symtab_hdr);
 
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
@@ -4996,18 +5171,7 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          return FALSE;
        }
 
-      if (r_symndx >= nsyms
-         /* PR 9934: It is possible to have relocations that do not
-            refer to symbols, thus it is also possible to have an
-            object file containing relocations but no symbol table.  */
-         && (r_symndx > 0 || nsyms > 0))
-       {
-         (*_bfd_error_handler) (_("%B: bad symbol index: %d"), abfd,
-                                r_symndx);
-         return FALSE;
-       }
-
-      if (nsyms == 0 || r_symndx < symtab_hdr->sh_info)
+      if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
        {
@@ -5015,6 +5179,10 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *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;
+
+         /* PR15323, ref flags aren't set for references in the same
+            object.  */
+         h->root.non_ir_ref = 1;
        }
 
       /* Could be done earlier, if h were already available.  */
@@ -5116,6 +5284,7 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* RR: We probably want to keep a consistency check that
             there are no dangling GOT_PAGE relocs.  */
        case R_AARCH64_LD64_GOT_LO12_NC:
+       case R_AARCH64_GOT_LD_PREL19:
        case R_AARCH64_ADR_GOT_PAGE:
        case R_AARCH64_TLSGD_ADR_PAGE21:
        case R_AARCH64_TLSGD_ADD_LO12_NC:
@@ -5201,6 +5370,7 @@ elf64_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
        case R_AARCH64_ADR_PREL_PG_HI21_NC:
        case R_AARCH64_ADR_PREL_PG_HI21:
+       case R_AARCH64_ADR_PREL_LO21:
          if (h != NULL && info->executable)
            {
              /* If this reloc is in a read-only section, we might
@@ -5381,7 +5551,9 @@ elf64_aarch64_post_process_headers (bfd *abfd,
 }
 
 static enum elf_reloc_type_class
-elf64_aarch64_reloc_type_class (const Elf_Internal_Rela *rela)
+elf64_aarch64_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                               const asection *rel_sec ATTRIBUTE_UNUSED,
+                               const Elf_Internal_Rela *rela)
 {
   switch ((int) ELF64_R_TYPE (rela->r_info))
     {
@@ -6590,7 +6762,7 @@ elf64_aarch64_finish_dynamic_symbol (bfd *output_bfd,
   /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  SYM may
      be NULL for local symbols.  */
   if (sym != NULL
-      && (strcmp (h->root.root.string, "_DYNAMIC") == 0
+      && (h == elf_hash_table (info)->hdynamic
          || h == elf_hash_table (info)->hgot))
     sym->st_shndx = SHN_ABS;
 
@@ -7001,7 +7173,7 @@ const struct elf_size_info elf64_aarch64_size_info =
   elf64_aarch64_size_info
 
 #define elf_backend_can_refcount       1
-#define elf_backend_can_gc_sections    0
+#define elf_backend_can_gc_sections    1
 #define elf_backend_plt_readonly       1
 #define elf_backend_want_got_plt       1
 #define elf_backend_want_plt_sym       0
@@ -7009,6 +7181,7 @@ const struct elf_size_info elf64_aarch64_size_info =
 #define elf_backend_may_use_rela_p     1
 #define elf_backend_default_use_rela_p 1
 #define elf_backend_got_header_size (GOT_ENTRY_SIZE * 3)
+#define elf_backend_default_execstack  0
 
 #undef  elf_backend_obj_attrs_section
 #define elf_backend_obj_attrs_section          ".ARM.attributes"