bfd/
[binutils-gdb.git] / bfd / elf64-sh64.c
index 6d343b78bff8706b5abdf0ad610740e0f1c44543..e041bdae418f78cf7cdb19e265f3c85a8623046f 100644 (file)
@@ -1,12 +1,12 @@
 /* SuperH SH64-specific support for 64-bit ELF
-   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+   2010, 2011, 2012 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -16,7 +16,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 #define SH64_ELF64
 
@@ -88,26 +89,14 @@ struct elf_sh64_link_hash_entry
   struct elf_sh64_pcrel_relocs_copied *pcrel_relocs_copied;
 };
 
-/* sh ELF linker hash table.  */
-
-struct elf_sh64_link_hash_table
-{
-  struct elf_link_hash_table root;
-};
-
 /* Traverse an sh ELF linker hash table.  */
 
-#define sh64_elf64_link_hash_traverse(table, func, info)               \
-  (elf_link_hash_traverse                                              \
-   (&(table)->root,                                                    \
+#define sh64_elf64_link_hash_traverse(table, func, info)       \
+  (elf_link_hash_traverse                                      \
+   ((table),                                                   \
     (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
     (info)))
 
-/* Get the sh ELF linker hash table from a link_info structure.  */
-
-#define sh64_elf64_hash_table(p) \
-  ((struct elf_sh64_link_hash_table *) ((p)->hash))
-
 static bfd_reloc_status_type sh_elf64_ignore_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_reloc_status_type sh_elf64_reloc
@@ -1525,7 +1514,7 @@ sh_elf64_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
              _("Unexpected STO_SH5_ISA32 on local symbol is not handled"),
              input_bfd, input_section, rel->r_offset));
 
-         if (sec != NULL && elf_discarded_section (sec))
+         if (sec != NULL && discarded_section (sec))
            /* Handled below.  */
            ;
          else if (info->relocatable)
@@ -1641,7 +1630,11 @@ sh_elf64_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
                                 STT_DATALABEL on the way to it.  */
                              | ((h->other & STO_SH5_ISA32) != 0
                                 && ! seen_stt_datalabel));
-             else if (!info->relocatable)
+             else if (!info->relocatable
+                      && (_bfd_elf_section_offset (output_bfd, info,
+                                                   input_section,
+                                                   rel->r_offset)
+                          != (bfd_vma) -1))
                {
                  (*_bfd_error_handler)
                    (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
@@ -1668,16 +1661,9 @@ sh_elf64_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
            }
        }
 
-      if (sec != NULL && elf_discarded_section (sec))
-       {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  Avoid any special processing.  */
-         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
-       }
+      if (sec != NULL && discarded_section (sec))
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, 1, relend, howto, 0, contents);
 
       if (info->relocatable)
        continue;
@@ -1724,22 +1710,10 @@ sh_elf64_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
 
              if (sreloc == NULL)
                {
-                 const char *name;
-
-                 name = (bfd_elf_string_from_elf_section
-                         (input_bfd,
-                          elf_elfheader (input_bfd)->e_shstrndx,
-                          elf_section_data (input_section)->rel_hdr.sh_name));
-                 if (name == NULL)
+                 sreloc = _bfd_elf_get_dynamic_reloc_section
+                   (input_bfd, input_section, /*rela?*/ TRUE);
+                 if (sreloc == NULL)
                    return FALSE;
-
-                 BFD_ASSERT (CONST_STRNEQ (name, ".rela")
-                             && strcmp (bfd_get_section_name (input_bfd,
-                                                              input_section),
-                                        name + 5) == 0);
-
-                 sreloc = bfd_get_section_by_name (dynobj, name);
-                 BFD_ASSERT (sreloc != NULL);
                }
 
              skip = FALSE;
@@ -2194,17 +2168,12 @@ sh_elf64_get_relocated_section_contents (bfd *output_bfd,
 
          if (isymp->st_shndx == SHN_UNDEF)
            isec = bfd_und_section_ptr;
-         else if (isymp->st_shndx > 0 && isymp->st_shndx < SHN_LORESERVE)
-           isec = bfd_section_from_elf_index (input_bfd, isymp->st_shndx);
          else if (isymp->st_shndx == SHN_ABS)
            isec = bfd_abs_section_ptr;
          else if (isymp->st_shndx == SHN_COMMON)
            isec = bfd_com_section_ptr;
          else
-           {
-             /* Who knows?  */
-             isec = NULL;
-           }
+           isec = bfd_section_from_elf_index (input_bfd, isymp->st_shndx);
 
          *secpp = isec;
        }
@@ -2418,7 +2387,7 @@ sh_elf64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                       asection *sec, const Elf_Internal_Rela *relocs)
 {
   Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   bfd *dynobj;
@@ -2436,9 +2405,6 @@ sh_elf64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf64_External_Sym);
-  if (!elf_bad_symtab (abfd))
-    sym_hashes_end -= symtab_hdr->sh_info;
 
   dynobj = elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (abfd);
@@ -2507,7 +2473,9 @@ sh_elf64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
         case R_SH_GNU_VTENTRY:
-          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+          BFD_ASSERT (h != NULL);
+          if (h != NULL
+              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
             return FALSE;
           break;
 
@@ -2716,35 +2684,11 @@ sh_elf64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                 section in dynobj and make room for this reloc.  */
              if (sreloc == NULL)
                {
-                 const char *name;
-
-                 name = (bfd_elf_string_from_elf_section
-                         (abfd,
-                          elf_elfheader (abfd)->e_shstrndx,
-                          elf_section_data (sec)->rel_hdr.sh_name));
-                 if (name == NULL)
-                   return FALSE;
-
-                 BFD_ASSERT (CONST_STRNEQ (name, ".rela")
-                             && strcmp (bfd_get_section_name (abfd, sec),
-                                        name + 5) == 0);
+                 sreloc = _bfd_elf_make_dynamic_reloc_section
+                   (sec, dynobj, 2, abfd, /*rela?*/ TRUE);
 
-                 sreloc = bfd_get_section_by_name (dynobj, name);
                  if (sreloc == NULL)
-                   {
-                     flagword flags;
-
-                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-                     if ((sec->flags & SEC_ALLOC) != 0)
-                       flags |= SEC_ALLOC | SEC_LOAD;
-                     sreloc = bfd_make_section_with_flags (dynobj,
-                                                           name,
-                                                           flags);
-                     if (sreloc == NULL
-                         || ! bfd_set_section_alignment (dynobj, sreloc, 2))
-                       return FALSE;
-                   }
+                   return FALSE;
                }
 
              sreloc->size += sizeof (Elf64_External_Rela);
@@ -2920,7 +2864,7 @@ sh64_elf64_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
    we don't need to look up and make sure to emit the main symbol for each
    DataLabel symbol.  */
 
-static bfd_boolean
+static int
 sh64_elf64_link_output_symbol_hook (struct bfd_link_info *info,
                                    const char *cname,
                                    Elf_Internal_Sym *sym,
@@ -2935,7 +2879,7 @@ sh64_elf64_link_output_symbol_hook (struct bfd_link_info *info,
        name[strlen (name) - strlen (DATALABEL_SUFFIX)] = 0;
     }
 
-  return TRUE;
+  return 1;
 }
 
 /* Set bit 0 on the entry address; it always points to SHmedia code.  This
@@ -3125,22 +3069,22 @@ sh64_elf64_link_hash_newfunc (struct bfd_hash_entry *entry,
 static struct bfd_link_hash_table *
 sh64_elf64_link_hash_table_create (bfd *abfd)
 {
-  struct elf_sh64_link_hash_table *ret;
+  struct elf_link_hash_table *ret;
 
-  ret = ((struct elf_sh64_link_hash_table *)
-        bfd_malloc (sizeof (struct elf_sh64_link_hash_table)));
-  if (ret == (struct elf_sh64_link_hash_table *) NULL)
+  ret = (struct elf_link_hash_table *) bfd_malloc (sizeof (* ret));
+  if (ret == (struct elf_link_hash_table *) NULL)
     return NULL;
 
-  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+  if (!_bfd_elf_link_hash_table_init (ret, abfd,
                                      sh64_elf64_link_hash_newfunc,
-                                     sizeof (struct elf_sh64_link_hash_entry)))
+                                     sizeof (struct elf_sh64_link_hash_entry),
+                                     GENERIC_ELF_DATA))
     {
       free (ret);
       return NULL;
     }
 
-  return &ret->root.root;
+  return &ret->root;
 }
 
 inline static void
@@ -3432,13 +3376,6 @@ sh64_elf64_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (!h->non_got_ref)
     return TRUE;
 
-  if (h->size == 0)
-    {
-      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
-                            h->root.root.string);
-      return TRUE;
-    }
-
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -3456,7 +3393,7 @@ sh64_elf64_adjust_dynamic_symbol (struct bfd_link_info *info,
      copy the initial value out of the dynamic object and into the
      runtime process image.  We need to remember the offset into the
      .rela.bss section we are going to use.  */
-  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
     {
       asection *srel;
 
@@ -3482,9 +3419,6 @@ sh64_elf64_discard_copies (struct elf_sh64_link_hash_entry *h,
 {
   struct elf_sh64_pcrel_relocs_copied *s;
 
-  if (h->root.root.type == bfd_link_hash_warning)
-    h = (struct elf_sh64_link_hash_entry *) h->root.root.u.i.link;
-
   /* We only discard relocs for symbols defined in a regular object.  */
   if (!h->root.def_regular)
     return TRUE;
@@ -3538,7 +3472,7 @@ sh64_elf64_size_dynamic_sections (bfd *output_bfd,
      We allocated space for them in the check_relocs routine, but we
      will not fill them in in the relocate_section routine.  */
   if (info->shared && info->symbolic)
-    sh64_elf64_link_hash_traverse (sh64_elf64_hash_table (info),
+    sh64_elf64_link_hash_traverse (elf_hash_table (info),
                                   sh64_elf64_discard_copies, NULL);
 
   /* The check_relocs and adjust_dynamic_symbol entry points have