]> oss.titaniummirror.com Git - msp430-binutils.git/blobdiff - bfd/elf32-sh.c
Merge commit 'upstream/2.20'
[msp430-binutils.git] / bfd / elf32-sh.c
index c71354e0b81f96d7977f00af138af6c3da1f08fd..7b81aab7c946d38d4c86f7234169f6796c5a56be 100644 (file)
@@ -1,6 +1,6 @@
 /* Renesas / SuperH SH specific support for 32-bit ELF
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007 Free Software Foundation, Inc.
+   2006, 2007, 2008, 2009 Free Software Foundation, Inc.
    Contributed by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -487,7 +487,7 @@ sh_elf_relax_section (bfd *abfd, asection *sec,
     }
 #endif
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (abfd);
 
   internal_relocs = (_bfd_elf_link_read_relocs
                     (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
@@ -852,7 +852,7 @@ sh_elf_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr,
   unsigned int symcount;
   asection *o;
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (abfd);
   isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
 
   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
@@ -2154,20 +2154,19 @@ struct sh_elf_obj_tdata
 #define sh_elf_local_got_tls_type(abfd) \
   (sh_elf_tdata (abfd)->local_got_tls_type)
 
+#define is_sh_elf(bfd) \
+  (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+   && elf_tdata (bfd) != NULL \
+   && elf_object_id (bfd) == SH_ELF_TDATA)
+
 /* Override the generic function because we need to store sh_elf_obj_tdata
    as the specific tdata.  */
 
 static bfd_boolean
 sh_elf_mkobject (bfd *abfd)
 {
-  if (abfd->tdata.any == NULL)
-    {
-      bfd_size_type amt = sizeof (struct sh_elf_obj_tdata);
-      abfd->tdata.any = bfd_zalloc (abfd, amt);
-      if (abfd->tdata.any == NULL)
-       return FALSE;
-    }
-  return bfd_elf_mkobject (abfd);
+  return bfd_elf_allocate_object (abfd, sizeof (struct sh_elf_obj_tdata),
+                                 SH_ELF_TDATA);
 }
 
 /* sh ELF linker hash table.  */
@@ -2188,8 +2187,8 @@ struct elf_sh_link_hash_table
   /* The (unloaded but important) VxWorks .rela.plt.unloaded section.  */
   asection *srelplt2;
 
-  /* Small local sym to section mapping cache.  */
-  struct sym_sec_cache sym_sec;
+  /* Small local sym cache.  */
+  struct sym_cache sym_cache;
 
   /* A counter or offset to track a TLS got entry.  */
   union
@@ -2282,7 +2281,7 @@ sh_elf_link_hash_table_create (bfd *abfd)
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
   ret->srelplt2 = NULL;
-  ret->sym_sec.abfd = NULL;
+  ret->sym_cache.abfd = NULL;
   ret->tls_ldm_got.refcount = 0;
   ret->plt_info = NULL;
   ret->vxworks_p = vxworks_object_p (abfd);
@@ -2304,18 +2303,9 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   htab = sh_elf_hash_table (info);
   htab->sgot = bfd_get_section_by_name (dynobj, ".got");
   htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
-  if (! htab->sgot || ! htab->sgotplt)
+  htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+  if (! htab->sgot || ! htab->sgotplt || ! htab->srelgot)
     abort ();
-
-  htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
-                                              (SEC_ALLOC | SEC_LOAD
-                                               | SEC_HAS_CONTENTS
-                                               | SEC_IN_MEMORY
-                                               | SEC_LINKER_CREATED
-                                               | SEC_READONLY));
-  if (htab->srelgot == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
-    return FALSE;
   return TRUE;
 }
 
@@ -2818,6 +2808,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            }
        }
 
+      if (htab->vxworks_p)
+       {
+         struct elf_sh_dyn_relocs **pp;
+
+         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+           {
+             if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
+               *pp = p->next;
+             else
+               pp = &p->next;
+           }
+       }
+
       /* Also discard relocs on undefined weak syms with non-default
         visibility.  */
       if (eh->dyn_relocs != NULL
@@ -2958,7 +2961,7 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
 
-      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+      if (! is_sh_elf (ibfd))
        continue;
 
       for (s = ibfd->sections; s != NULL; s = s->next)
@@ -2978,6 +2981,13 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                     linker script /DISCARD/, so we'll be discarding
                     the relocs too.  */
                }
+             else if (htab->vxworks_p
+                      && strcmp (p->sec->output_section->name,
+                                 ".tls_vars") == 0)
+               {
+                 /* Relocations in vxworks .tls_vars sections are
+                    handled specially by the loader.  */
+               }
              else if (p->count != 0)
                {
                  srel = elf_section_data (p->sec)->sreloc;
@@ -2992,7 +3002,7 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       if (!local_got)
        continue;
 
-      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+      symtab_hdr = &elf_symtab_hdr (ibfd);
       locsymcount = symtab_hdr->sh_info;
 #ifdef INCLUDE_SHMEDIA
       /* Count datalabel local GOT.  */
@@ -3138,6 +3148,9 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                return FALSE;
            }
        }
+      if (htab->vxworks_p
+         && !elf_vxworks_add_dynamic_entries (output_bfd, info))
+       return FALSE;
     }
 #undef add_dynamic_entry
 
@@ -3164,9 +3177,12 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   asection *splt;
   asection *sreloc;
   asection *srelgot;
+  bfd_boolean is_vxworks_tls;
+
+  BFD_ASSERT (is_sh_elf (input_bfd));
 
   htab = sh_elf_hash_table (info);
-  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (input_bfd);
   sym_hashes = elf_sym_hashes (input_bfd);
   dynobj = htab->root.dynobj;
   local_got_offsets = elf_local_got_offsets (input_bfd);
@@ -3176,6 +3192,11 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   splt = htab->splt;
   sreloc = NULL;
   srelgot = NULL;
+  /* We have to handle relocations in vxworks .tls_vars sections
+     specially, because the dynamic loader is 'weird'.  */
+  is_vxworks_tls = (htab->vxworks_p && info->shared
+                   && !strcmp (input_section->output_section->name,
+                               ".tls_vars"));
 
   rel = relocs;
   relend = relocs + input_section->reloc_count;
@@ -3582,6 +3603,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  || h->root.type != bfd_link_hash_undefweak)
              && r_symndx != 0
              && (input_section->flags & SEC_ALLOC) != 0
+             && !is_vxworks_tls
              && (r_type == R_SH_DIR32
                  || !SYMBOL_CALLS_LOCAL (info, h)))
            {
@@ -3595,22 +3617,10 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
              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;
@@ -4321,22 +4331,10 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
            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);
              }
 
            if (h == NULL || h->dynindx == -1)
@@ -4424,7 +4422,7 @@ sh_elf_get_relocated_section_contents (bfd *output_bfd,
                                                       relocatable,
                                                       symbols);
 
-  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (input_bfd);
 
   memcpy (data, elf_section_data (input_section)->this_hdr.contents,
          (size_t) input_section->size);
@@ -4561,9 +4559,12 @@ sh_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
   bfd_signed_vma *local_got_refcounts;
   const Elf_Internal_Rela *rel, *relend;
 
+  if (info->relocatable)
+    return TRUE;
+
   elf_section_data (sec)->local_dynrel = NULL;
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   local_got_refcounts = elf_local_got_refcounts (abfd);
 
@@ -4835,7 +4836,7 @@ sh_elf_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;
   struct elf_sh_link_hash_table *htab;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
@@ -4853,11 +4854,10 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
   if (info->relocatable)
     return TRUE;
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  BFD_ASSERT (is_sh_elf (abfd));
+
+  symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
-  if (!elf_bad_symtab (abfd))
-    sym_hashes_end -= symtab_hdr->sh_info;
 
   htab = sh_elf_hash_table (info);
   local_got_offsets = elf_local_got_offsets (abfd);
@@ -4959,7 +4959,9 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
          /* 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;
 
@@ -5188,37 +5190,11 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
                 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, htab->root.dynobj, 2, abfd, /*rela?*/ TRUE);
 
-                 sreloc = bfd_get_section_by_name (htab->root.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 (htab->root.dynobj,
-                                                           name,
-                                                           flags);
-                     if (sreloc == NULL
-                         || ! bfd_set_section_alignment (htab->root.dynobj,
-                                                         sreloc, 2))
-                       return FALSE;
-                   }
-                 elf_section_data (sec)->sreloc = sreloc;
+                   return FALSE;
                }
 
              /* If this is a global symbol, we count the number of
@@ -5227,15 +5203,20 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
                head = &((struct elf_sh_link_hash_entry *) h)->dyn_relocs;
              else
                {
+                 /* Track dynamic relocs needed for local syms too.  */
                  asection *s;
                  void *vpp;
+                 Elf_Internal_Sym *isym;
 
-                 /* Track dynamic relocs needed for local syms too.  */
-                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
-                                                sec, r_symndx);
-                 if (s == NULL)
+                 isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                               abfd, r_symndx);
+                 if (isym == NULL)
                    return FALSE;
 
+                 s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+                 if (s == NULL)
+                   s = sec;
+
                  vpp = &elf_section_data (s)->local_dynrel;
                  head = (struct elf_sh_dyn_relocs **) vpp;
                }
@@ -5353,13 +5334,12 @@ sh_elf_set_private_flags (bfd *abfd, flagword flags)
 static bfd_boolean
 sh_elf_copy_private_data (bfd * ibfd, bfd * obfd)
 {
-  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return TRUE;
-
   /* Copy object attributes.  */
   _bfd_elf_copy_obj_attributes (ibfd, obfd);
 
+  if (! is_sh_elf (ibfd) || ! is_sh_elf (obfd))
+    return TRUE;
+
   return sh_elf_set_private_flags (obfd, elf_elfheader (ibfd)->e_flags);
 }
 #endif /* not sh_elf_copy_private_data */
@@ -5386,8 +5366,7 @@ sh_elf_merge_private_data (bfd *ibfd, bfd *obfd)
 {
   extern bfd_boolean sh_merge_bfd_arch (bfd *, bfd *);
 
-  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+  if (! is_sh_elf (ibfd) || ! is_sh_elf (obfd))
     return TRUE;
 
   if (! elf_flags_init (obfd))
@@ -5764,6 +5743,9 @@ sh_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
          switch (dyn.d_tag)
            {
            default:
+             if (htab->vxworks_p
+                 && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
+               bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
 #ifdef INCLUDE_SHMEDIA