Automatic date update in version.in
[platform/upstream/binutils.git] / bfd / elf64-x86-64.c
index aa6fd80..3881f60 100644 (file)
@@ -1,7 +1,5 @@
 /* X86-64 specific support for ELF
-   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011, 2012, 2013
-   Free Software Foundation, Inc.
+   Copyright (C) 2000-2014 Free Software Foundation, Inc.
    Contributed by Jan Hubicka <jh@suse.cz>.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -969,6 +967,21 @@ elf_x86_64_get_local_sym_hash (struct elf_x86_64_link_hash_table *htab,
   return &ret->elf;
 }
 
+/* Destroy an X86-64 ELF linker hash table.  */
+
+static void
+elf_x86_64_link_hash_table_free (bfd *obfd)
+{
+  struct elf_x86_64_link_hash_table *htab
+    = (struct elf_x86_64_link_hash_table *) obfd->link.hash;
+
+  if (htab->loc_hash_table)
+    htab_delete (htab->loc_hash_table);
+  if (htab->loc_hash_memory)
+    objalloc_free ((struct objalloc *) htab->loc_hash_memory);
+  _bfd_elf_link_hash_table_free (obfd);
+}
+
 /* Create an X86-64 ELF linker hash table.  */
 
 static struct bfd_link_hash_table *
@@ -1014,28 +1027,14 @@ elf_x86_64_link_hash_table_create (bfd *abfd)
   ret->loc_hash_memory = objalloc_create ();
   if (!ret->loc_hash_table || !ret->loc_hash_memory)
     {
-      free (ret);
+      elf_x86_64_link_hash_table_free (abfd);
       return NULL;
     }
+  ret->elf.root.hash_table_free = elf_x86_64_link_hash_table_free;
 
   return &ret->elf.root;
 }
 
-/* Destroy an X86-64 ELF linker hash table.  */
-
-static void
-elf_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash)
-{
-  struct elf_x86_64_link_hash_table *htab
-    = (struct elf_x86_64_link_hash_table *) hash;
-
-  if (htab->loc_hash_table)
-    htab_delete (htab->loc_hash_table);
-  if (htab->loc_hash_memory)
-    objalloc_free ((struct objalloc *) htab->loc_hash_memory);
-  _bfd_elf_link_hash_table_free (hash);
-}
-
 /* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
    .rela.bss sections in DYNOBJ, and set up shortcuts to them in our
    hash table.  */
@@ -1630,11 +1629,16 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
            case R_X86_64_PC32_BND:
            case R_X86_64_PLT32_BND:
+           case R_X86_64_PC32:
+           case R_X86_64_PLT32:
+           case R_X86_64_32:
+           case R_X86_64_64:
              /* MPX PLT is supported only if elf_x86_64_arch_bed
                 is used in 64-bit mode.  */
              if (ABI_64_P (abfd)
-                 && (get_elf_x86_64_backend_data (abfd)
-                     == &elf_x86_64_arch_bed))
+                     && info->bndplt
+                     && (get_elf_x86_64_backend_data (abfd)
+                         == &elf_x86_64_arch_bed))
                {
                  elf_x86_64_hash_entry (h)->has_bnd_reloc = TRUE;
 
@@ -1676,11 +1680,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                }
 
            case R_X86_64_32S:
-           case R_X86_64_32:
-           case R_X86_64_64:
-           case R_X86_64_PC32:
            case R_X86_64_PC64:
-           case R_X86_64_PLT32:
            case R_X86_64_GOTPCREL:
            case R_X86_64_GOTPCREL64:
              if (htab->elf.dynobj == NULL)
@@ -2778,7 +2778,7 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
   /* Nothing to do if there are no codes, no relocations or no output.  */
   if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC)
       || sec->reloc_count == 0
-      || discarded_section (sec))
+      || bfd_is_abs_section (sec->output_section))
     return TRUE;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -2937,7 +2937,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
@@ -4282,17 +4282,27 @@ direct:
              else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTTPOFF)
                {
                  /* IE->LE transition:
-                    Originally it can be one of:
+                    For 64bit, originally it can be one of:
                     movq foo@gottpoff(%rip), %reg
                     addq foo@gottpoff(%rip), %reg
                     We change it into:
                     movq $foo, %reg
                     leaq foo(%reg), %reg
-                    addq $foo, %reg.  */
+                    addq $foo, %reg.
+                    For 32bit, originally it can be one of:
+                    movq foo@gottpoff(%rip), %reg
+                    addl foo@gottpoff(%rip), %reg
+                    We change it into:
+                    movq $foo, %reg
+                    leal foo(%reg), %reg
+                    addl $foo, %reg. */
 
                  unsigned int val, type, reg;
 
-                 val = bfd_get_8 (input_bfd, contents + roff - 3);
+                 if (roff >= 3)
+                   val = bfd_get_8 (input_bfd, contents + roff - 3);
+                 else
+                   val = 0;
                  type = bfd_get_8 (input_bfd, contents + roff - 2);
                  reg = bfd_get_8 (input_bfd, contents + roff - 1);
                  reg >>= 3;
@@ -4312,8 +4322,8 @@ direct:
                    }
                  else if (reg == 4)
                    {
-                     /* addq -> addq - addressing with %rsp/%r12 is
-                        special  */
+                     /* addq/addl -> addq/addl - addressing with %rsp/%r12
+                        is special  */
                      if (val == 0x4c)
                        bfd_put_8 (output_bfd, 0x49,
                                   contents + roff - 3);
@@ -4327,7 +4337,7 @@ direct:
                    }
                  else
                    {
-                     /* addq -> leaq */
+                     /* addq/addl -> leaq/leal */
                      if (val == 0x4c)
                        bfd_put_8 (output_bfd, 0x4d,
                                   contents + roff - 3);
@@ -5293,14 +5303,85 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
   return TRUE;
 }
 
-/* Return address for Ith PLT stub in section PLT, for relocation REL
-   or (bfd_vma) -1 if it should not be included.  */
+/* Return address in section PLT for the Ith GOTPLT relocation, for
+   relocation REL or (bfd_vma) -1 if it should not be included.  */
 
 static bfd_vma
 elf_x86_64_plt_sym_val (bfd_vma i, const asection *plt,
-                       const arelent *rel ATTRIBUTE_UNUSED)
+                       const arelent *rel)
 {
-  return plt->vma + (i + 1) * GET_PLT_ENTRY_SIZE (plt->owner);
+  bfd *abfd;
+  const struct elf_x86_64_backend_data *bed;
+  bfd_vma plt_offset;
+
+  /* Only match R_X86_64_JUMP_SLOT and R_X86_64_IRELATIVE.  */
+  if (rel->howto->type != R_X86_64_JUMP_SLOT
+      && rel->howto->type != R_X86_64_IRELATIVE)
+    return (bfd_vma) -1;
+
+  abfd = plt->owner;
+  bed = get_elf_x86_64_backend_data (abfd);
+  plt_offset = bed->plt_entry_size;
+
+  if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU)
+    return plt->vma + (i + 1) * plt_offset;
+
+  while (plt_offset < plt->size)
+    {
+      bfd_vma reloc_index;
+      bfd_byte reloc_index_raw[4];
+
+      if (!bfd_get_section_contents (abfd, (asection *) plt,
+                                    reloc_index_raw,
+                                    plt_offset + bed->plt_reloc_offset,
+                                    sizeof (reloc_index_raw)))
+       return (bfd_vma) -1;
+
+      reloc_index = H_GET_32 (abfd, reloc_index_raw);
+      if (reloc_index == i)
+       return plt->vma + plt_offset;
+      plt_offset += bed->plt_entry_size;
+    }
+
+  abort ();
+}
+
+/* Return offset in .plt.bnd section for the Ith GOTPLT relocation with
+   PLT section, or (bfd_vma) -1 if it should not be included.  */
+
+static bfd_vma
+elf_x86_64_plt_sym_val_offset_plt_bnd (bfd_vma i, const asection *plt)
+{
+  const struct elf_x86_64_backend_data *bed = &elf_x86_64_bnd_arch_bed;
+  bfd *abfd = plt->owner;
+  bfd_vma plt_offset = bed->plt_entry_size;
+
+  if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU)
+    return i * sizeof (elf_x86_64_legacy_plt2_entry);
+
+  while (plt_offset < plt->size)
+    {
+      bfd_vma reloc_index;
+      bfd_byte reloc_index_raw[4];
+
+      if (!bfd_get_section_contents (abfd, (asection *) plt,
+                                    reloc_index_raw,
+                                    plt_offset + bed->plt_reloc_offset,
+                                    sizeof (reloc_index_raw)))
+       return (bfd_vma) -1;
+
+      reloc_index = H_GET_32 (abfd, reloc_index_raw);
+      if (reloc_index == i)
+       {
+         /* This is the index in .plt section.  */
+         long plt_index = plt_offset / bed->plt_entry_size;
+         /* Return the offset in .plt.bnd section.  */
+         return (plt_index - 1) * sizeof (elf_x86_64_legacy_plt2_entry);
+       }
+      plt_offset += bed->plt_entry_size;
+    }
+
+  abort ();
 }
 
 /* Similar to _bfd_elf_get_synthetic_symtab, with .plt.bnd section
@@ -5323,8 +5404,11 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd,
   size_t size;
   Elf_Internal_Shdr *hdr;
   char *names;
-  asection *plt;
-  bfd_vma addr;
+  asection *plt, *plt_push;
+
+  plt_push = bfd_get_section_by_name (abfd, ".plt");
+  if (plt_push == NULL)
+    return 0;
 
   plt = bfd_get_section_by_name (abfd, ".plt.bnd");
   /* Use the generic ELF version if there is no .plt.bnd section.  */
@@ -5370,11 +5454,17 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd,
   names = (char *) (s + count);
   p = relplt->relocation;
   n = 0;
-  addr = 0;
   for (i = 0; i < count; i++, p++)
     {
+      bfd_vma offset;
       size_t len;
 
+      if (p->howto->type != R_X86_64_JUMP_SLOT
+         && p->howto->type != R_X86_64_IRELATIVE)
+       continue;
+
+      offset = elf_x86_64_plt_sym_val_offset_plt_bnd (i, plt_push);
+
       *s = **p->sym_ptr_ptr;
       /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set.  Since
         we are defining a symbol, ensure one of them is set.  */
@@ -5382,7 +5472,7 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd,
        s->flags |= BSF_GLOBAL;
       s->flags |= BSF_SYNTHETIC;
       s->section = plt;
-      s->value = addr;
+      s->value = offset;
       s->name = names;
       s->udata.p = NULL;
       len = strlen ((*p->sym_ptr_ptr)->name);
@@ -5404,7 +5494,6 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd,
       memcpy (names, "@plt", sizeof ("@plt"));
       names += sizeof ("@plt");
       ++s, ++n;
-      addr += sizeof (elf_x86_64_legacy_plt2_entry);
     }
 
   return n;
@@ -5461,9 +5550,10 @@ elf_x86_64_add_symbol_hook (bfd *abfd,
       return TRUE;
     }
 
-  if ((abfd->flags & DYNAMIC) == 0
-      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-         || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+  if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+       || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
+      && (abfd->flags & DYNAMIC) == 0
+      && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
     elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   return TRUE;
@@ -5620,7 +5710,7 @@ static const struct bfd_elf_special_section
   { NULL,                      0,          0, 0,            0 }
 };
 
-#define TARGET_LITTLE_SYM                  bfd_elf64_x86_64_vec
+#define TARGET_LITTLE_SYM                  x86_64_elf64_vec
 #define TARGET_LITTLE_NAME                 "elf64-x86-64"
 #define ELF_ARCH                           bfd_arch_i386
 #define ELF_TARGET_ID                      X86_64_ELF_DATA
@@ -5642,8 +5732,6 @@ static const struct bfd_elf_special_section
 
 #define bfd_elf64_bfd_link_hash_table_create \
   elf_x86_64_link_hash_table_create
-#define bfd_elf64_bfd_link_hash_table_free \
-  elf_x86_64_link_hash_table_free
 #define bfd_elf64_bfd_reloc_type_lookup            elf_x86_64_reloc_type_lookup
 #define bfd_elf64_bfd_reloc_name_lookup \
   elf_x86_64_reloc_name_lookup
@@ -5701,7 +5789,7 @@ static const struct bfd_elf_special_section
 /* FreeBSD support.  */
 
 #undef  TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM                  bfd_elf64_x86_64_freebsd_vec
+#define TARGET_LITTLE_SYM                  x86_64_elf64_fbsd_vec
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                 "elf64-x86-64-freebsd"
 
@@ -5716,7 +5804,7 @@ static const struct bfd_elf_special_section
 /* Solaris 2 support.  */
 
 #undef  TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM                  bfd_elf64_x86_64_sol2_vec
+#define TARGET_LITTLE_SYM                  x86_64_elf64_sol2_vec
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                 "elf64-x86-64-sol2"
 
@@ -5754,7 +5842,7 @@ elf64_x86_64_nacl_elf_object_p (bfd *abfd)
 }
 
 #undef TARGET_LITTLE_SYM
-#define        TARGET_LITTLE_SYM               bfd_elf64_x86_64_nacl_vec
+#define        TARGET_LITTLE_SYM               x86_64_elf64_nacl_vec
 #undef TARGET_LITTLE_NAME
 #define        TARGET_LITTLE_NAME              "elf64-x86-64-nacl"
 #undef elf64_bed
@@ -5907,7 +5995,7 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd)
 }
 
 #undef  TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM              bfd_elf32_x86_64_nacl_vec
+#define TARGET_LITTLE_SYM              x86_64_elf32_nacl_vec
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME             "elf32-x86-64-nacl"
 #undef elf32_bed
@@ -5915,8 +6003,6 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd)
 
 #define bfd_elf32_bfd_link_hash_table_create \
   elf_x86_64_link_hash_table_create
-#define bfd_elf32_bfd_link_hash_table_free \
-  elf_x86_64_link_hash_table_free
 #define bfd_elf32_bfd_reloc_type_lookup        \
   elf_x86_64_reloc_type_lookup
 #define bfd_elf32_bfd_reloc_name_lookup \
@@ -5958,7 +6044,7 @@ elf64_l1om_elf_object_p (bfd *abfd)
 }
 
 #undef  TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM                  bfd_elf64_l1om_vec
+#define TARGET_LITTLE_SYM                  l1om_elf64_vec
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                 "elf64-l1om"
 #undef ELF_ARCH
@@ -5992,7 +6078,7 @@ elf64_l1om_elf_object_p (bfd *abfd)
 /* FreeBSD L1OM support.  */
 
 #undef  TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM                  bfd_elf64_l1om_freebsd_vec
+#define TARGET_LITTLE_SYM                  l1om_elf64_fbsd_vec
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                 "elf64-l1om-freebsd"
 
@@ -6015,7 +6101,7 @@ elf64_k1om_elf_object_p (bfd *abfd)
 }
 
 #undef  TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM                  bfd_elf64_k1om_vec
+#define TARGET_LITTLE_SYM                  k1om_elf64_vec
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                 "elf64-k1om"
 #undef ELF_ARCH
@@ -6042,7 +6128,7 @@ elf64_k1om_elf_object_p (bfd *abfd)
 /* FreeBSD K1OM support.  */
 
 #undef  TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM                  bfd_elf64_k1om_freebsd_vec
+#define TARGET_LITTLE_SYM                  k1om_elf64_fbsd_vec
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                 "elf64-k1om-freebsd"
 
@@ -6057,7 +6143,7 @@ elf64_k1om_elf_object_p (bfd *abfd)
 /* 32bit x86-64 support.  */
 
 #undef  TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM                  bfd_elf32_x86_64_vec
+#define TARGET_LITTLE_SYM                  x86_64_elf32_vec
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                 "elf32-x86-64"
 #undef elf32_bed