Add Intel MCU support to bfd
[deliverable/binutils-gdb.git] / bfd / elf32-i386.c
index 5c35d6509d1e9c3aa63d901b40b9528b9fa15dd1..f7a7818248dacb534342318f804f88b269cff9f4 100644 (file)
@@ -1,5 +1,5 @@
 /* Intel 80386/80486-specific support for 32-bit ELF
-   Copyright (C) 1993-2014 Free Software Foundation, Inc.
+   Copyright (C) 1993-2015 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -37,7 +37,7 @@
 
 static reloc_howto_type elf_howto_table[]=
 {
-  HOWTO(R_386_NONE, 0, 0, 0, FALSE, 0, complain_overflow_bitfield,
+  HOWTO(R_386_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont,
        bfd_elf_generic_reloc, "R_386_NONE",
        TRUE, 0x00000000, 0x00000000, FALSE),
   HOWTO(R_386_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
@@ -379,7 +379,9 @@ elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
                             abfd, (int) r_type);
       indx = R_386_NONE;
     }
-  BFD_ASSERT (elf_howto_table [indx].type == r_type);
+  /* PR 17512: file: 0f67f69d.  */
+  if (elf_howto_table [indx].type != r_type)
+    return NULL;
   return &elf_howto_table[indx];
 }
 
@@ -754,6 +756,9 @@ struct elf_i386_link_hash_entry
   (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type))
   unsigned char tls_type;
 
+  /* Symbol is referenced by R_386_GOTOFF relocation.  */
+  unsigned int gotoff_ref : 1;
+
   /* Information about the GOT PLT entry. Filled when there are both
      GOT and PLT relocations against the same function.  */
   union gotplt_union plt_got;
@@ -877,6 +882,7 @@ elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry,
       eh = (struct elf_i386_link_hash_entry *) entry;
       eh->dyn_relocs = NULL;
       eh->tls_type = GOT_UNKNOWN;
+      eh->gotoff_ref = 0;
       eh->plt_got.offset = (bfd_vma) -1;
       eh->tlsdesc_got = (bfd_vma) -1;
     }
@@ -1020,13 +1026,28 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
     return FALSE;
 
   htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
-  if (!info->shared)
-    htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss");
-
-  if (!htab->sdynbss
-      || (!info->shared && !htab->srelbss))
+  if (!htab->sdynbss)
     abort ();
 
+  if (info->executable)
+    {
+      /* Always allow copy relocs for building executables.  */
+      asection *s = bfd_get_linker_section (dynobj, ".rel.bss");
+      if (s == NULL)
+       {
+         const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
+         s = bfd_make_section_anyway_with_flags (dynobj,
+                                                 ".rel.bss",
+                                                 (bed->dynamic_sec_flags
+                                                  | SEC_READONLY));
+         if (s == NULL
+             || ! bfd_set_section_alignment (dynobj, s,
+                                             bed->s->log_file_align))
+           return FALSE;
+       }
+      htab->srelbss = s;
+    }
+
   if (get_elf_i386_backend_data (dynobj)->is_vxworks
       && !elf_vxworks_create_dynamic_sections (dynobj, info,
                                               &htab->srelplt2))
@@ -1099,6 +1120,10 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info,
       eind->tls_type = GOT_UNKNOWN;
     }
 
+  /* Copy gotoff_ref so that elf_i386_adjust_dynamic_symbol will
+     generate a R_386_COPY reloc.  */
+  edir->gotoff_ref |= eind->gotoff_ref;
+
   if (ELIMINATE_COPY_RELOCS
       && ind->root.type != bfd_link_hash_indirect
       && dir->dynamic_adjusted)
@@ -1427,6 +1452,10 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
   return TRUE;
 }
 
+/* Rename some of the generic section flags to better document how they
+   are used here.  */
+#define need_convert_mov_to_lea sec_flg0
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure linkage
    table, and dynamic reloc sections.  */
@@ -1469,6 +1498,7 @@ elf_i386_check_relocs (bfd *abfd,
       unsigned int r_type;
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
+      struct elf_i386_link_hash_entry *eh;
       Elf_Internal_Sym *isym;
       const char *name;
       bfd_boolean size_reloc;
@@ -1518,6 +1548,7 @@ elf_i386_check_relocs (bfd *abfd,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
+      eh = (struct elf_i386_link_hash_entry *) h;
       if (h != NULL)
        {
          /* Create the ifunc sections for static executables.  If we
@@ -1529,11 +1560,12 @@ elf_i386_check_relocs (bfd *abfd,
            default:
              break;
 
+           case R_386_GOTOFF:
+             eh->gotoff_ref = 1;
            case R_386_32:
            case R_386_PC32:
            case R_386_PLT32:
            case R_386_GOT32:
-           case R_386_GOTOFF:
              if (htab->elf.dynobj == NULL)
                htab->elf.dynobj = abfd;
              if (!_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
@@ -1785,7 +1817,7 @@ do_size:
                 relocations we need for this symbol.  */
              if (h != NULL)
                {
-                 head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs;
+                 head = &eh->dyn_relocs;
                }
              else
                {
@@ -1882,6 +1914,10 @@ do_size:
                                             plt_got_align))
            return FALSE;
        }
+
+      if (r_type == R_386_GOT32
+         && (h == NULL || h->type != STT_GNU_IFUNC))
+       sec->need_convert_mov_to_lea = 1;
     }
 
   return TRUE;
@@ -2165,12 +2201,14 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section.  */
-  if (info->shared)
+  if (!info->executable)
     return TRUE;
 
   /* If there are no references to this symbol that do not use the
-     GOT, we don't need to generate a copy reloc.  */
-  if (!h->non_got_ref)
+     GOT nor R_386_GOTOFF relocation, we don't need to generate a copy
+     reloc.  */
+  eh = (struct elf_i386_link_hash_entry *) h;
+  if (!h->non_got_ref && !eh->gotoff_ref)
     return TRUE;
 
   /* If -z nocopyreloc was given, we won't generate them either.  */
@@ -2184,14 +2222,15 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (htab == NULL)
     return FALSE;
 
-  /* If there aren't any dynamic relocs in read-only sections, then
-     we can keep the dynamic relocs and avoid the copy reloc.  This
-     doesn't work on VxWorks, where we can not have dynamic relocations
-     (other than copy and jump slot relocations) in an executable.  */
+  /* If there aren't any dynamic relocs in read-only sections nor
+     R_386_GOTOFF relocation, then we can keep the dynamic relocs and
+     avoid the copy reloc.  This doesn't work on VxWorks, where we can
+     not have dynamic relocations (other than copy and jump slot
+     relocations) in an executable.  */
   if (ELIMINATE_COPY_RELOCS
+      && !eh->gotoff_ref
       && !get_elf_i386_backend_data (info->output_bfd)->is_vxworks)
     {
-      eh = (struct elf_i386_link_hash_entry *) h;
       for (p = eh->dyn_relocs; p != NULL; p = p->next)
        {
          s = p->sec->output_section;
@@ -2227,7 +2266,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   s = htab->sdynbss;
 
-  return _bfd_elf_adjust_dynamic_copy (h, s);
+  return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
 /* Allocate space in .plt, .got and associated reloc sections for
@@ -2598,8 +2637,9 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
          info->flags |= DF_TEXTREL;
 
-         if (info->warn_shared_textrel && info->shared)
-           info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'.\n"),
+         if ((info->warn_shared_textrel && info->shared)
+             || info->error_textrel)
+           info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'\n"),
                                    p->sec->owner, h->root.root.string,
                                    p->sec);
 
@@ -2633,9 +2673,9 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec,
   if (!is_elf_hash_table (link_info->hash))
     return FALSE;
 
-  /* Nothing to do if there are no codes, no relocations or no output.  */
+  /* Nothing to do if there is no need or no output.  */
   if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC)
-      || sec->reloc_count == 0
+      || sec->need_convert_mov_to_lea == 0
       || bfd_is_abs_section (sec->output_section))
     return TRUE;
 
@@ -2684,11 +2724,9 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec,
          /* STT_GNU_IFUNC must keep R_386_GOT32 relocation.  */
          if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC
              && irel->r_offset >= 2
-             && bfd_get_8 (input_bfd,
-                           contents + irel->r_offset - 2) == 0x8b)
+             && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b)
            {
-             bfd_put_8 (output_bfd, 0x8d,
-                        contents + irel->r_offset - 2);
+             bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2);
              irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF);
              if (local_got_refcounts != NULL
                  && local_got_refcounts[r_symndx] > 0)
@@ -2714,11 +2752,9 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec,
          && h != htab->elf.hdynamic
          && SYMBOL_REFERENCES_LOCAL (link_info, h)
          && irel->r_offset >= 2
-         && bfd_get_8 (input_bfd,
-                       contents + irel->r_offset - 2) == 0x8b)
+         && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b)
        {
-         bfd_put_8 (output_bfd, 0x8d,
-                    contents + irel->r_offset - 2);
+         bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2);
          irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF);
          if (h->got.refcount > 0)
            h->got.refcount -= 1;
@@ -2840,8 +2876,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
                      && (info->flags & DF_TEXTREL) == 0)
                    {
                      info->flags |= DF_TEXTREL;
-                     if (info->warn_shared_textrel && info->shared)
-                       info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'.\n"),
+                     if ((info->warn_shared_textrel && info->shared)
+                         || info->error_textrel)
+                       info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'\n"),
                                                p->sec->owner, p->sec);
                    }
                }
@@ -3139,6 +3176,7 @@ elf_i386_always_size_sections (bfd *output_bfd,
          tlsbase = (struct elf_link_hash_entry *)bh;
          tlsbase->def_regular = 1;
          tlsbase->other = STV_HIDDEN;
+         tlsbase->root.linker_def = 1;
          (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
        }
     }
@@ -3701,11 +3739,11 @@ elf_i386_relocate_section (bfd *output_bfd,
          /* Relocation is relative to the start of the global offset
             table.  */
 
-         /* Check to make sure it isn't a protected function symbol
-            for shared library since it may not be local when used
-            as function address.  We also need to make sure that a
-            symbol is defined locally.  */
-         if (info->shared && h)
+         /* Check to make sure it isn't a protected function or data
+            symbol for shared library since it may not be local when
+            used as function address or with copy relocation.  We also
+            need to make sure that a symbol is referenced locally.  */
+         if (!info->executable && h)
            {
              if (!h->def_regular)
                {
@@ -3733,14 +3771,16 @@ elf_i386_relocate_section (bfd *output_bfd,
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
                }
-             else if (!info->executable
-                      && !SYMBOLIC_BIND (info, h)
-                      && h->type == STT_FUNC
+             else if (!SYMBOL_REFERENCES_LOCAL (info, h)
+                      && (h->type == STT_FUNC
+                          || h->type == STT_OBJECT)
                       && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
                {
                  (*_bfd_error_handler)
-                   (_("%B: relocation R_386_GOTOFF against protected function `%s' can not be used when making a shared object"),
-                    input_bfd, h->root.root.string);
+                   (_("%B: relocation R_386_GOTOFF against protected %s `%s' can not be used when making a shared object"),
+                    input_bfd,
+                    h->type == STT_FUNC ? "function" : "data",
+                    h->root.root.string);
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
                }
@@ -5144,46 +5184,91 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd,
   return TRUE;
 }
 
-/* Return address in section PLT for the Ith GOTPLT relocation, for
-   relocation REL or (bfd_vma) -1 if it should not be included.  */
+/* Return an array of PLT entry symbol values.  */
 
-static bfd_vma
-elf_i386_plt_sym_val (bfd_vma i, const asection *plt, const arelent *rel)
+static bfd_vma *
+elf_i386_get_plt_sym_val (bfd *abfd, asymbol **dynsyms, asection *plt,
+                         asection *relplt)
 {
-  bfd *abfd;
-  const struct elf_i386_backend_data *bed;
+  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+  arelent *p;
+  long count, i;
+  bfd_vma *plt_sym_val;
   bfd_vma plt_offset;
+  bfd_byte *plt_contents;
+  const struct elf_i386_backend_data *bed
+    = get_elf_i386_backend_data (abfd);
+  Elf_Internal_Shdr *hdr;
+
+  /* Get the .plt section contents.  */
+  plt_contents = (bfd_byte *) bfd_malloc (plt->size);
+  if (plt_contents == NULL)
+    return NULL;
+  if (!bfd_get_section_contents (abfd, (asection *) plt,
+                                plt_contents, 0, plt->size))
+    {
+bad_return:
+      free (plt_contents);
+      return NULL;
+    }
 
-  /* Only match R_386_JUMP_SLOT and R_386_IRELATIVE.  */
-  if (rel->howto->type != R_386_JUMP_SLOT
-      && rel->howto->type != R_386_IRELATIVE)
-    return (bfd_vma) -1;
+  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+  if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+    goto bad_return;
 
-  abfd = plt->owner;
-  bed = get_elf_i386_backend_data (abfd);
-  plt_offset = bed->plt->plt_entry_size;
+  hdr = &elf_section_data (relplt)->this_hdr;
+  count = relplt->size / hdr->sh_entsize;
+
+  plt_sym_val = (bfd_vma *) bfd_malloc (sizeof (bfd_vma) * count);
+  if (plt_sym_val == NULL)
+    goto bad_return;
 
-  if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU)
-    return plt->vma + (i + 1) * plt_offset;
+  for (i = 0; i < count; i++)
+    plt_sym_val[i] = -1;
 
-  while (plt_offset < plt->size)
+  plt_offset = bed->plt->plt_entry_size;
+  p = relplt->relocation;
+  for (i = 0; i < count; i++, p++)
     {
-      bfd_vma reloc_offset;
-      bfd_byte reloc_offset_raw[4];
-
-      if (!bfd_get_section_contents (abfd, (asection *) plt,
-                                    reloc_offset_raw,
-                                    plt_offset + bed->plt->plt_reloc_offset,
-                                    sizeof (reloc_offset_raw)))
-       return (bfd_vma) -1;
-
-      reloc_offset = H_GET_32 (abfd, reloc_offset_raw);
-      if (reloc_offset == i * sizeof (Elf32_External_Rel))
-       return plt->vma + plt_offset;
+      long reloc_index;
+
+      /* Skip unknown relocation.  PR 17512: file: bc9d6cf5.  */
+      if (p->howto == NULL)
+       continue;
+
+      if (p->howto->type != R_386_JUMP_SLOT
+         && p->howto->type != R_386_IRELATIVE)
+       continue;
+
+      reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset
+                                    + bed->plt->plt_reloc_offset));
+      reloc_index /= sizeof (Elf32_External_Rel);
+      if (reloc_index >= count)
+       abort ();
+      plt_sym_val[reloc_index] = plt->vma + plt_offset;
       plt_offset += bed->plt->plt_entry_size;
     }
 
-  abort ();
+  free (plt_contents);
+
+  return plt_sym_val;
+}
+
+/* Similar to _bfd_elf_get_synthetic_symtab.  */
+
+static long
+elf_i386_get_synthetic_symtab (bfd *abfd,
+                              long symcount,
+                              asymbol **syms,
+                              long dynsymcount,
+                              asymbol **dynsyms,
+                              asymbol **ret)
+{
+  asection *plt = bfd_get_section_by_name (abfd, ".plt");
+  return _bfd_elf_ifunc_get_synthetic_symtab (abfd, symcount, syms,
+                                             dynsymcount, dynsyms, ret,
+                                             plt,
+                                             elf_i386_get_plt_sym_val);
 }
 
 /* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
@@ -5234,6 +5319,7 @@ elf_i386_add_symbol_hook (bfd * abfd,
 #define elf_backend_want_plt_sym       0
 #define elf_backend_got_header_size    12
 #define elf_backend_plt_alignment      4
+#define elf_backend_extern_protected_data 1
 
 /* Support RELA for objdump of prelink objects.  */
 #define elf_info_to_howto                    elf_i386_info_to_howto_rel
@@ -5245,6 +5331,7 @@ elf_i386_add_symbol_hook (bfd * abfd,
 #define bfd_elf32_bfd_link_hash_table_create  elf_i386_link_hash_table_create
 #define bfd_elf32_bfd_reloc_type_lookup              elf_i386_reloc_type_lookup
 #define bfd_elf32_bfd_reloc_name_lookup              elf_i386_reloc_name_lookup
+#define bfd_elf32_get_synthetic_symtab       elf_i386_get_synthetic_symtab
 
 #define elf_backend_adjust_dynamic_symbol     elf_i386_adjust_dynamic_symbol
 #define elf_backend_relocs_compatible        _bfd_elf_relocs_compatible
@@ -5264,7 +5351,6 @@ elf_i386_add_symbol_hook (bfd * abfd,
 #define elf_backend_always_size_sections      elf_i386_always_size_sections
 #define elf_backend_omit_section_dynsym \
   ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
-#define elf_backend_plt_sym_val                      elf_i386_plt_sym_val
 #define elf_backend_hash_symbol                      elf_i386_hash_symbol
 #define elf_backend_add_symbol_hook           elf_i386_add_symbol_hook
 
@@ -5313,6 +5399,8 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
 #undef TARGET_LITTLE_NAME
 #define        TARGET_LITTLE_NAME              "elf32-i386-sol2"
 
+#undef elf_backend_post_process_headers
+
 /* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE
    objects won't be recognized.  */
 #undef ELF_OSABI
@@ -5334,6 +5422,47 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
 
 #include "elf32-target.h"
 
+/* Intel MCU support.  */
+
+static bfd_boolean
+elf32_iamcu_elf_object_p (bfd *abfd)
+{
+  /* Set the right machine number for an IAMCU elf32 file.  */
+  bfd_default_set_arch_mach (abfd, bfd_arch_iamcu, bfd_mach_i386_iamcu);
+  return TRUE;
+}
+
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM              iamcu_elf32_vec
+#undef  TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME             "elf32-iamcu"
+#undef ELF_ARCH
+#define ELF_ARCH                       bfd_arch_iamcu
+
+#undef ELF_MACHINE_CODE
+#define        ELF_MACHINE_CODE                EM_IAMCU
+
+#undef ELF_OSABI
+
+#undef  elf32_bed
+#define elf32_bed                      elf32_iamcu_bed
+
+#undef elf_backend_object_p
+#define elf_backend_object_p           elf32_iamcu_elf_object_p
+
+#undef elf_backend_static_tls_alignment
+
+#undef elf_backend_want_plt_sym
+#define elf_backend_want_plt_sym           0
+
+#include "elf32-target.h"
+
+/* Restore defaults.  */
+#undef ELF_ARCH
+#define ELF_ARCH                       bfd_arch_i386
+#undef ELF_MACHINE_CODE
+#define ELF_MACHINE_CODE               EM_386
+
 /* Native Client support.  */
 
 #undef TARGET_LITTLE_SYM
This page took 0.03028 seconds and 4 git commands to generate.