daily update
[deliverable/binutils-gdb.git] / bfd / elfxx-sparc.c
index ef7ff482d2ed0f787d4df7c8f5c49307d5bcdf3e..d3fe1bafae02dd4afc880ed27f0154760d53d25a 100644 (file)
@@ -1,11 +1,11 @@
 /* SPARC-specific support for ELF
-   Copyright 2005, 2006 Free Software Foundation, Inc.
+   Copyright 2005, 2006, 2007, 2008, 2009 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,
 
    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.  */
+
 
 /* This file handles functionality common to the different SPARC ABI's.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "libiberty.h"
@@ -256,7 +258,12 @@ static reloc_howto_type _bfd_sparc_elf_howto_table[] =
   HOWTO(R_SPARC_TLS_DTPOFF32,0,2,32,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_TLS_DTPOFF32",FALSE,0,0xffffffff,TRUE),
   HOWTO(R_SPARC_TLS_DTPOFF64,0,4,64,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_TLS_DTPOFF64",FALSE,0,MINUS_ONE,TRUE),
   HOWTO(R_SPARC_TLS_TPOFF32,0,0, 0,FALSE,0,complain_overflow_dont,   bfd_elf_generic_reloc,  "R_SPARC_TLS_TPOFF32",FALSE,0,0x00000000,TRUE),
-  HOWTO(R_SPARC_TLS_TPOFF64,0,0, 0,FALSE,0,complain_overflow_dont,   bfd_elf_generic_reloc,  "R_SPARC_TLS_TPOFF64",FALSE,0,0x00000000,TRUE)
+  HOWTO(R_SPARC_TLS_TPOFF64,0,0, 0,FALSE,0,complain_overflow_dont,   bfd_elf_generic_reloc,  "R_SPARC_TLS_TPOFF64",FALSE,0,0x00000000,TRUE),
+  HOWTO(R_SPARC_GOTDATA_HIX22,0,2,0,FALSE,0,complain_overflow_bitfield,sparc_elf_hix22_reloc,"R_SPARC_GOTDATA_HIX22",FALSE,0,0x003fffff, FALSE),
+  HOWTO(R_SPARC_GOTDATA_LOX10,0,2,0,FALSE,0,complain_overflow_dont,  sparc_elf_lox10_reloc,  "R_SPARC_GOTDATA_LOX10",FALSE,0,0x000003ff, FALSE),
+  HOWTO(R_SPARC_GOTDATA_OP_HIX22,0,2,0,FALSE,0,complain_overflow_bitfield,sparc_elf_hix22_reloc,"R_SPARC_GOTDATA_OP_HIX22",FALSE,0,0x003fffff, FALSE),
+  HOWTO(R_SPARC_GOTDATA_OP_LOX10,0,2,0,FALSE,0,complain_overflow_dont,  sparc_elf_lox10_reloc,  "R_SPARC_GOTDATA_OP_LOX10",FALSE,0,0x000003ff, FALSE),
+  HOWTO(R_SPARC_GOTDATA_OP,0,0, 0,FALSE,0,complain_overflow_dont,   bfd_elf_generic_reloc,  "R_SPARC_GOTDATA_OP",FALSE,0,0x00000000,TRUE),
 };
 static reloc_howto_type sparc_vtinherit_howto =
   HOWTO (R_SPARC_GNU_VTINHERIT, 0,2,0,FALSE,0,complain_overflow_dont, NULL, "R_SPARC_GNU_VTINHERIT", FALSE,0, 0, FALSE);
@@ -347,6 +354,11 @@ static const struct elf_reloc_map sparc_reloc_map[] =
   { BFD_RELOC_SPARC_H44, R_SPARC_H44 },
   { BFD_RELOC_SPARC_M44, R_SPARC_M44 },
   { BFD_RELOC_SPARC_L44, R_SPARC_L44 },
+  { BFD_RELOC_SPARC_GOTDATA_HIX22, R_SPARC_GOTDATA_HIX22 },
+  { BFD_RELOC_SPARC_GOTDATA_LOX10, R_SPARC_GOTDATA_LOX10 },
+  { BFD_RELOC_SPARC_GOTDATA_OP_HIX22, R_SPARC_GOTDATA_OP_HIX22 },
+  { BFD_RELOC_SPARC_GOTDATA_OP_LOX10, R_SPARC_GOTDATA_OP_LOX10 },
+  { BFD_RELOC_SPARC_GOTDATA_OP, R_SPARC_GOTDATA_OP },
   { BFD_RELOC_SPARC_REGISTER, R_SPARC_REGISTER },
   { BFD_RELOC_VTABLE_INHERIT, R_SPARC_GNU_VTINHERIT },
   { BFD_RELOC_VTABLE_ENTRY, R_SPARC_GNU_VTENTRY },
@@ -384,6 +396,30 @@ _bfd_sparc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     return NULL;
 }
 
+reloc_howto_type *
+_bfd_sparc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                                 const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < (sizeof (_bfd_sparc_elf_howto_table)
+           / sizeof (_bfd_sparc_elf_howto_table[0]));
+       i++)
+    if (_bfd_sparc_elf_howto_table[i].name != NULL
+       && strcasecmp (_bfd_sparc_elf_howto_table[i].name, r_name) == 0)
+      return &_bfd_sparc_elf_howto_table[i];
+
+  if (strcasecmp (sparc_vtinherit_howto.name, r_name) == 0)
+    return &sparc_vtinherit_howto;
+  if (strcasecmp (sparc_vtentry_howto.name, r_name) == 0)
+    return &sparc_vtentry_howto;
+  if (strcasecmp (sparc_rev32_howto.name, r_name) == 0)
+    return &sparc_rev32_howto;
+
+  return NULL;
+}
+
 reloc_howto_type *
 _bfd_sparc_elf_info_to_howto_ptr (unsigned int r_type)
 {
@@ -484,14 +520,16 @@ struct _bfd_sparc_elf_obj_tdata
 #define _bfd_sparc_elf_local_got_tls_type(abfd) \
   (_bfd_sparc_elf_tdata (abfd)->local_got_tls_type)
 
+#define is_sparc_elf(bfd)                              \
+  (bfd_get_flavour (bfd) == bfd_target_elf_flavour     \
+   && elf_tdata (bfd) != NULL                          \
+   && elf_object_id (bfd) == SPARC_ELF_TDATA)
+
 bfd_boolean
 _bfd_sparc_elf_mkobject (bfd *abfd)
 {
-  bfd_size_type amt = sizeof (struct _bfd_sparc_elf_obj_tdata);
-  abfd->tdata.any = bfd_zalloc (abfd, amt);
-  if (abfd->tdata.any == NULL)
-    return FALSE;
-  return TRUE;
+  return bfd_elf_allocate_object (abfd, sizeof (struct _bfd_sparc_elf_obj_tdata),
+                                 SPARC_ELF_TDATA);
 }
 
 static void
@@ -507,27 +545,14 @@ sparc_put_word_64 (bfd *bfd, bfd_vma val, void *ptr)
 }
 
 static void
-sparc_elf_append_rela_64 (bfd *abfd ATTRIBUTE_UNUSED,
-                         asection *s ATTRIBUTE_UNUSED,
-                         Elf_Internal_Rela *rel ATTRIBUTE_UNUSED)
-{
-#ifdef BFD64
-  Elf64_External_Rela *loc64;
-
-  loc64 = (Elf64_External_Rela *) s->contents;
-  loc64 += s->reloc_count++;
-  bfd_elf64_swap_reloca_out (abfd, rel, (bfd_byte *) loc64);
-#endif
-}
-
-static void
-sparc_elf_append_rela_32 (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
+sparc_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
 {
-  Elf32_External_Rela *loc32;
+  const struct elf_backend_data *bed;
+  bfd_byte *loc;
 
-  loc32 = (Elf32_External_Rela *) s->contents;
-  loc32 += s->reloc_count++;
-  bfd_elf32_swap_reloca_out (abfd, rel, (bfd_byte *) loc32);
+  bed = get_elf_backend_data (abfd);
+  loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela);
+  bed->s->swap_reloca_out (abfd, rel, loc);
 }
 
 static bfd_vma
@@ -746,9 +771,6 @@ static const bfd_vma sparc_vxworks_shared_plt_entry[] =
 #define SPARC_ELF_PUT_WORD(htab, bfd, val, ptr)        \
        htab->put_word(bfd, val, ptr)
 
-#define SPARC_ELF_APPEND_RELA(htab, bfd, sec, rela)    \
-       htab->append_rela(bfd, sec, rela)
-
 #define SPARC_ELF_R_INFO(htab, in_rel, index, type)    \
        htab->r_info(in_rel, index, type)
 
@@ -824,7 +846,6 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd)
   if (ABI_64_P (abfd))
     {
       ret->put_word = sparc_put_word_64;
-      ret->append_rela = sparc_elf_append_rela_64;
       ret->r_info = sparc_elf_r_info_64;
       ret->r_symndx = sparc_elf_r_symndx_64;
       ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF64;
@@ -840,7 +861,6 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd)
   else
     {
       ret->put_word = sparc_put_word_32;
-      ret->append_rela = sparc_elf_append_rela_32;
       ret->r_info = sparc_elf_r_info_32;
       ret->r_symndx = sparc_elf_r_symndx_32;
       ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF32;
@@ -879,13 +899,7 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   htab->sgot = bfd_get_section_by_name (dynobj, ".got");
   BFD_ASSERT (htab->sgot != NULL);
 
-  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);
+  htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
   if (htab->srelgot == NULL
       || ! bfd_set_section_alignment (dynobj, htab->srelgot,
                                      htab->word_align_power))
@@ -1079,7 +1093,7 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
     return TRUE;
 
   htab = _bfd_sparc_elf_hash_table (info);
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   local_got_offsets = elf_local_got_offsets (abfd);
 
@@ -1089,6 +1103,9 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
     num_relocs = NUM_SHDR_ENTRIES (& elf_section_data (sec)->rel_hdr);
   else
     num_relocs = sec->reloc_count;
+
+  BFD_ASSERT (is_sparc_elf (abfd) || num_relocs == 0);
+
   rel_end = relocs + num_relocs;
   for (rel = relocs; rel < rel_end; rel++)
     {
@@ -1165,6 +1182,10 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_SPARC_GOT10:
        case R_SPARC_GOT13:
        case R_SPARC_GOT22:
+       case R_SPARC_GOTDATA_HIX22:
+       case R_SPARC_GOTDATA_LOX10:
+       case R_SPARC_GOTDATA_OP_HIX22:
+       case R_SPARC_GOTDATA_OP_LOX10:
        case R_SPARC_TLS_GD_HI22:
        case R_SPARC_TLS_GD_LO10:
          /* This symbol requires a global offset table entry.  */
@@ -1177,6 +1198,10 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              case R_SPARC_GOT10:
              case R_SPARC_GOT13:
              case R_SPARC_GOT22:
+             case R_SPARC_GOTDATA_HIX22:
+             case R_SPARC_GOTDATA_LOX10:
+             case R_SPARC_GOTDATA_OP_HIX22:
+             case R_SPARC_GOTDATA_OP_LOX10:
                tls_type = GOT_NORMAL;
                break;
              case R_SPARC_TLS_GD_HI22:
@@ -1298,6 +1323,9 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    goto r_sparc_plt32;
                  break;
                }
+             /* PR 7027: We need similar behaviour for 64-bit binaries.  */
+             else if (r_type == R_SPARC_WPLT30)
+               break;
 
              /* It does not make sense to have a procedure linkage
                  table entry for a local symbol.  */
@@ -1417,42 +1445,15 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                 section in dynobj and make room for the reloc.  */
              if (sreloc == NULL)
                {
-                 const char *name;
-                 bfd *dynobj;
-
-                 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 (strncmp (name, ".rela", 5) == 0
-                             && strcmp (bfd_get_section_name (abfd, sec),
-                                        name + 5) == 0);
-
                  if (htab->elf.dynobj == NULL)
                    htab->elf.dynobj = abfd;
-                 dynobj = htab->elf.dynobj;
 
-                 sreloc = bfd_get_section_by_name (dynobj, name);
+                 sreloc = _bfd_elf_make_dynamic_reloc_section
+                   (sec, htab->elf.dynobj, htab->word_align_power,
+                    abfd, /*rela?*/ TRUE);
+
                  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,
-                                                         htab->word_align_power))
-                       return FALSE;
-                   }
-                 elf_section_data (sec)->sreloc = sreloc;
+                   return FALSE;
                }
 
              /* If this is a global symbol, we count the number of
@@ -1464,15 +1465,19 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  /* Track dynamic relocs needed for local syms too.
                     We really need local syms available to do this
                     easily.  Oh well.  */
-
                  asection *s;
                  void *vpp;
+                 Elf_Internal_Sym *isym;
 
-                 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 _bfd_sparc_elf_dyn_relocs **) vpp;
                }
@@ -1505,7 +1510,9 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          break;
 
        case R_SPARC_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;
 
@@ -1529,35 +1536,14 @@ _bfd_sparc_elf_gc_mark_hook (asection *sec,
                             Elf_Internal_Sym *sym)
 {
   if (h != NULL)
-    {
-      struct _bfd_sparc_elf_link_hash_table *htab;
-
-      htab = _bfd_sparc_elf_hash_table (info);
-      switch (SPARC_ELF_R_TYPE (rel->r_info))
+    switch (SPARC_ELF_R_TYPE (rel->r_info))
       {
       case R_SPARC_GNU_VTINHERIT:
       case R_SPARC_GNU_VTENTRY:
-       break;
-
-      default:
-       switch (h->root.type)
-         {
-         case bfd_link_hash_defined:
-         case bfd_link_hash_defweak:
-           return h->root.u.def.section;
-
-         case bfd_link_hash_common:
-           return h->root.u.c.p->section;
-
-         default:
-           break;
-         }
+       return NULL;
       }
-    }
-  else
-    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
 
-  return NULL;
+  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
 
 /* Update the got entry reference counts for the section being removed.  */
@@ -1571,10 +1557,15 @@ _bfd_sparc_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;
+
+  BFD_ASSERT (is_sparc_elf (abfd) || sec->reloc_count == 0);
+
   elf_section_data (sec)->local_dynrel = NULL;
 
   htab = _bfd_sparc_elf_hash_table (info);
-  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);
 
@@ -1623,6 +1614,10 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
        case R_SPARC_GOT10:
        case R_SPARC_GOT13:
        case R_SPARC_GOT22:
+       case R_SPARC_GOTDATA_HIX22:
+       case R_SPARC_GOTDATA_LOX10:
+       case R_SPARC_GOTDATA_OP_HIX22:
+       case R_SPARC_GOTDATA_OP_LOX10:
          if (h != NULL)
            {
              if (h->got.refcount > 0)
@@ -1713,7 +1708,6 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   struct _bfd_sparc_elf_link_hash_entry * eh;
   struct _bfd_sparc_elf_dyn_relocs *p;
   asection *s;
-  unsigned int power_of_two;
 
   htab = _bfd_sparc_elf_hash_table (info);
 
@@ -1830,29 +1824,9 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       h->needs_copy = 1;
     }
 
-  /* We need to figure out the alignment required for this symbol.  I
-     have no idea how ELF linkers handle this.  */
-  power_of_two = bfd_log2 (h->size);
-  if (power_of_two > htab->align_power_max)
-    power_of_two = htab->align_power_max;
-
-  /* Apply the required alignment.  */
   s = htab->sdynbss;
-  s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
-  if (power_of_two > bfd_get_section_alignment (dynobj, s))
-    {
-      if (! bfd_set_section_alignment (dynobj, s, power_of_two))
-       return FALSE;
-    }
-
-  /* Define the symbol as being at this point in the section.  */
-  h->root.u.def.section = s;
-  h->root.u.def.value = s->size;
 
-  /* Increment the section size to make room for the symbol.  */
-  s->size += h->size;
-
-  return TRUE;
+  return _bfd_elf_adjust_dynamic_copy (h, s);
 }
 
 /* Allocate space in .plt, .got and associated reloc sections for
@@ -2038,6 +2012,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
            }
        }
 
+      if (htab->is_vxworks)
+       {
+         struct _bfd_sparc_elf_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
@@ -2183,7 +2170,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
 
-      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+      if (! is_sparc_elf (ibfd))
        continue;
 
       for (s = ibfd->sections; s != NULL; s = s->next)
@@ -2200,6 +2187,13 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
                     linker script /DISCARD/, so we'll be discarding
                     the relocs too.  */
                }
+             else if (htab->is_vxworks
+                      && 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;
@@ -2214,7 +2208,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
       if (!local_got)
        continue;
 
-      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+      symtab_hdr = &elf_symtab_hdr (ibfd);
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
       local_tls_type = _bfd_sparc_elf_local_got_tls_type (ibfd);
@@ -2287,7 +2281,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
          /* Strip this section if we don't need it; see the
             comment below.  */
        }
-      else if (strncmp (s->name, ".rela", 5) == 0)
+      else if (CONST_STRNEQ (s->name, ".rela"))
        {
          if (s->size != 0)
            {
@@ -2425,6 +2419,9 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
                eht->dynsymcount++;
              }
        }
+      if (htab->is_vxworks
+         && !elf_vxworks_add_dynamic_entries (output_bfd, info))
+       return FALSE;
     }
 #undef add_dynamic_entry
 
@@ -2434,13 +2431,16 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
 bfd_boolean
 _bfd_sparc_elf_new_section_hook (bfd *abfd, asection *sec)
 {
-  struct _bfd_sparc_elf_section_data *sdata;
-  bfd_size_type amt = sizeof (*sdata);
+  if (!sec->used_by_bfd)
+    {
+      struct _bfd_sparc_elf_section_data *sdata;
+      bfd_size_type amt = sizeof (*sdata);
 
-  sdata = (struct _bfd_sparc_elf_section_data *) bfd_zalloc (abfd, amt);
-  if (sdata == NULL)
-    return FALSE;
-  sec->used_by_bfd = (PTR) sdata;
+      sdata = bfd_zalloc (abfd, amt);
+      if (sdata == NULL)
+       return FALSE;
+      sec->used_by_bfd = sdata;
+    }
 
   return _bfd_elf_new_section_hook (abfd, sec);
 }
@@ -2451,6 +2451,10 @@ _bfd_sparc_elf_relax_section (bfd *abfd ATTRIBUTE_UNUSED,
                              struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
                              bfd_boolean *again)
 {
+  if (link_info->relocatable)
+    (*link_info->callbacks->einfo)
+      (_("%P%F: --relax and -r may not be used together\n"));
+
   *again = FALSE;
   sec_do_relax (section) = 1;
   return TRUE;
@@ -2486,10 +2490,14 @@ tpoff (struct bfd_link_info *info, bfd_vma address)
 /* Relocate a SPARC ELF section.  */
 
 bfd_boolean
-_bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
-                                bfd *input_bfd, asection *input_section,
-                                bfd_byte *contents, Elf_Internal_Rela *relocs,
-                                Elf_Internal_Sym *local_syms, asection **local_sections)
+_bfd_sparc_elf_relocate_section (bfd *output_bfd,
+                                struct bfd_link_info *info,
+                                bfd *input_bfd,
+                                asection *input_section,
+                                bfd_byte *contents,
+                                Elf_Internal_Rela *relocs,
+                                Elf_Internal_Sym *local_syms,
+                                asection **local_sections)
 {
   struct _bfd_sparc_elf_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
@@ -2500,12 +2508,10 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
   int num_relocs;
-
-  if (info->relocatable)
-    return TRUE;
+  bfd_boolean is_vxworks_tls;
 
   htab = _bfd_sparc_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);
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
@@ -2515,6 +2521,11 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
     got_base = elf_hash_table (info)->hgot->root.u.def.value;
 
   sreloc = elf_section_data (input_section)->sreloc;
+  /* We have to handle relocations in vxworks .tls_vars sections
+     specially, because the dynamic loader is 'weird'.  */
+  is_vxworks_tls = (htab->is_vxworks && info->shared
+                   && !strcmp (input_section->output_section->name,
+                               ".tls_vars"));
 
   rel = relocs;
   if (ABI_64_P (output_bfd))
@@ -2547,7 +2558,6 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        }
       howto = _bfd_sparc_elf_howto_table + r_type;
 
-      /* This is a final link.  */
       r_symndx = SPARC_ELF_R_SYMNDX (htab, rel->r_info);
       h = NULL;
       sym = NULL;
@@ -2579,8 +2589,37 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
            }
        }
 
+      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 (info->relocatable)
+       continue;
+
       switch (r_type)
        {
+       case R_SPARC_GOTDATA_HIX22:
+       case R_SPARC_GOTDATA_LOX10:
+       case R_SPARC_GOTDATA_OP_HIX22:
+       case R_SPARC_GOTDATA_OP_LOX10:
+         /* We don't support these code transformation optimizations
+            yet, so just leave the sequence alone and treat as
+            GOT22/GOT10.  */
+         if (r_type == R_SPARC_GOTDATA_HIX22
+             || r_type == R_SPARC_GOTDATA_OP_HIX22)
+           r_type = R_SPARC_GOT22;
+         else
+           r_type = R_SPARC_GOT10;
+         /* Fall through. */
+
        case R_SPARC_GOT10:
        case R_SPARC_GOT13:
        case R_SPARC_GOT22:
@@ -2660,7 +2699,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                                                        0, R_SPARC_RELATIVE);
                      outrel.r_addend = relocation;
                      relocation = 0;
-                     SPARC_ELF_APPEND_RELA (htab, output_bfd, s, &outrel);
+                     sparc_elf_append_rela (output_bfd, s, &outrel);
                    }
 
                  SPARC_ELF_PUT_WORD (htab, output_bfd, relocation,
@@ -2699,6 +2738,9 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              if (h == NULL)
                break;
            }
+         /* PR 7027: We need similar behaviour for 64-bit binaries.  */ 
+         else if (r_type == R_SPARC_WPLT30 && h == NULL)
+           break;
          else
            {
              BFD_ASSERT (h != NULL);
@@ -2767,11 +2809,8 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        case R_SPARC_L44:
        case R_SPARC_UA64:
        r_sparc_plt32:
-         /* r_symndx will be zero only for relocs against symbols
-            from removed linkonce sections, or sections discarded by
-            a linker script.  */
-         if (r_symndx == 0
-             || (input_section->flags & SEC_ALLOC) == 0)
+         if ((input_section->flags & SEC_ALLOC) == 0
+             || is_vxworks_tls)
            break;
 
          if ((info->shared
@@ -2879,6 +2918,8 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                    {
                      long indx;
 
+                     outrel.r_addend = relocation + rel->r_addend;
+
                      if (is_plt)
                        sec = htab->splt;
 
@@ -2893,9 +2934,20 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                        {
                          asection *osec;
 
+                         /* We are turning this relocation into one
+                            against a section symbol.  It would be
+                            proper to subtract the symbol's value,
+                            osec->vma, from the emitted reloc addend,
+                            but ld.so expects buggy relocs.  */
                          osec = sec->output_section;
                          indx = elf_section_data (osec)->dynindx;
 
+                         if (indx == 0)
+                           {
+                             osec = htab->elf.text_index_section;
+                             indx = elf_section_data (osec)->dynindx;
+                           }
+
                          /* FIXME: we really should be able to link non-pic
                             shared libraries.  */
                          if (indx == 0)
@@ -2909,12 +2961,12 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                            }
                        }
 
-                     outrel.r_info = SPARC_ELF_R_INFO (htab, rel, indx, r_type);
-                     outrel.r_addend = relocation + rel->r_addend;
+                     outrel.r_info = SPARC_ELF_R_INFO (htab, rel, indx,
+                                                       r_type);
                    }
                }
 
-             SPARC_ELF_APPEND_RELA (htab, output_bfd, sreloc, &outrel);
+             sparc_elf_append_rela (output_bfd, sreloc, &outrel);
 
              /* This reloc will be computed at runtime, so there's no
                 need to do anything now.  */
@@ -3022,7 +3074,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              else
                outrel.r_addend = 0;
              outrel.r_info = SPARC_ELF_R_INFO (htab, NULL, indx, dr_type);
-             SPARC_ELF_APPEND_RELA (htab, output_bfd, htab->srelgot, &outrel);
+             sparc_elf_append_rela (output_bfd, htab->srelgot, &outrel);
 
              if (r_type == R_SPARC_TLS_GD_HI22
                  || r_type == R_SPARC_TLS_GD_LO10)
@@ -3043,7 +3095,8 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                      outrel.r_info = SPARC_ELF_R_INFO (htab, NULL, indx,
                                                        SPARC_ELF_DTPOFF_RELOC (htab));
                      outrel.r_offset += SPARC_ELF_WORD_BYTES (htab);
-                     SPARC_ELF_APPEND_RELA (htab, output_bfd, htab->srelgot, &outrel);
+                     sparc_elf_append_rela (output_bfd, htab->srelgot,
+                                            &outrel);
                    }
                }
              else if (dr_type == SPARC_ELF_DTPMOD_RELOC (htab))
@@ -3112,7 +3165,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                                    + rel->r_addend;
                }
 
-             SPARC_ELF_APPEND_RELA (htab, output_bfd, sreloc, &outrel);
+             sparc_elf_append_rela (output_bfd, sreloc, &outrel);
              continue;
            }
          relocation = tpoff (info, relocation);
@@ -3220,6 +3273,11 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
            }
          continue;
 
+       case R_SPARC_GOTDATA_OP:
+         /* We don't support gotdata code transformation optimizations
+            yet, so simply leave the sequence as-is.  */
+         continue;
+
        case R_SPARC_TLS_IE_LD:
        case R_SPARC_TLS_IE_LDX:
          if (! info->shared && (h == NULL || h->dynindx == -1))
@@ -3633,9 +3691,11 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
 {
   bfd *dynobj;
   struct _bfd_sparc_elf_link_hash_table *htab;
+  const struct elf_backend_data *bed;
 
   htab = _bfd_sparc_elf_hash_table (info);
   dynobj = htab->elf.dynobj;
+  bed = get_elf_backend_data (output_bfd);
 
   if (h->plt.offset != (bfd_vma) -1)
     {
@@ -3705,18 +3765,8 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
         thus .plt[4] has corresponding .rela.plt[0] and so on.  */
 
       loc = srela->contents;
-#ifdef BFD64
-      if (ABI_64_P (output_bfd))
-       {
-         loc += rela_index * sizeof (Elf64_External_Rela);
-         bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
-       }
-      else
-#endif
-       {
-         loc += rela_index * sizeof (Elf32_External_Rela);
-         bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-       }
+      loc += rela_index * bed->s->sizeof_rela;
+      bed->s->swap_reloca_out (output_bfd, &rela, loc);
 
       if (!h->def_regular)
        {
@@ -3773,7 +3823,7 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
       SPARC_ELF_PUT_WORD (htab, output_bfd, 0,
                          sgot->contents + (h->got.offset & ~(bfd_vma) 1));
-      SPARC_ELF_APPEND_RELA (htab, output_bfd, srela, &rela);
+      sparc_elf_append_rela (output_bfd, srela, &rela);
     }
 
   if (h->needs_copy)
@@ -3793,7 +3843,7 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
                       + h->root.u.def.section->output_offset);
       rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, R_SPARC_COPY);
       rela.r_addend = 0;
-      SPARC_ELF_APPEND_RELA (htab, output_bfd, s, &rela);
+      sparc_elf_append_rela (output_bfd, s, &rela);
     }
 
   /* Mark some specially defined symbols as absolute.  On VxWorks,
@@ -3809,83 +3859,30 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
 /* Finish up the dynamic sections.  */
 
-#ifdef BFD64
 static bfd_boolean
-sparc64_finish_dyn (bfd *output_bfd, struct bfd_link_info *info,
-                   bfd *dynobj, asection *sdyn,
-                   asection *splt ATTRIBUTE_UNUSED)
+sparc_finish_dyn (bfd *output_bfd, struct bfd_link_info *info,
+                 bfd *dynobj, asection *sdyn,
+                 asection *splt ATTRIBUTE_UNUSED)
 {
-  Elf64_External_Dyn *dyncon, *dynconend;
-  int stt_regidx = -1;
-
-  dyncon = (Elf64_External_Dyn *) sdyn->contents;
-  dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
-  for (; dyncon < dynconend; dyncon++)
-    {
-      Elf_Internal_Dyn dyn;
-      const char *name;
-      bfd_boolean size;
-
-      bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
-
-      switch (dyn.d_tag)
-       {
-       case DT_PLTGOT:   name = ".plt"; size = FALSE; break;
-       case DT_PLTRELSZ: name = ".rela.plt"; size = TRUE; break;
-       case DT_JMPREL:   name = ".rela.plt"; size = FALSE; break;
-       case DT_SPARC_REGISTER:
-         if (stt_regidx == -1)
-           {
-             stt_regidx =
-               _bfd_elf_link_lookup_local_dynindx (info, output_bfd, -1);
-             if (stt_regidx == -1)
-               return FALSE;
-           }
-         dyn.d_un.d_val = stt_regidx++;
-         bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
-         /* fallthrough */
-       default:          name = NULL; size = FALSE; break;
-       }
-
-      if (name != NULL)
-       {
-         asection *s;
-
-         s = bfd_get_section_by_name (output_bfd, name);
-         if (s == NULL)
-           dyn.d_un.d_val = 0;
-         else
-           {
-             if (! size)
-               dyn.d_un.d_ptr = s->vma;
-             else
-               dyn.d_un.d_val = s->size;
-           }
-         bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
-       }
-    }
-  return TRUE;
-}
-#endif
-
-static bfd_boolean
-sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info,
-                   bfd *dynobj, asection *sdyn,
-                   asection *splt ATTRIBUTE_UNUSED)
-{
-  Elf32_External_Dyn *dyncon, *dynconend;
   struct _bfd_sparc_elf_link_hash_table *htab;
+  const struct elf_backend_data *bed;
+  bfd_byte *dyncon, *dynconend;
+  size_t dynsize;
+  int stt_regidx = -1;
+  bfd_boolean abi_64_p;
 
   htab = _bfd_sparc_elf_hash_table (info);
-  dyncon = (Elf32_External_Dyn *) sdyn->contents;
-  dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
-  for (; dyncon < dynconend; dyncon++)
+  bed = get_elf_backend_data (output_bfd);
+  dynsize = bed->s->sizeof_dyn;
+  dynconend = sdyn->contents + sdyn->size;
+  abi_64_p = ABI_64_P (output_bfd);
+  for (dyncon = sdyn->contents; dyncon < dynconend; dyncon += dynsize)
     {
       Elf_Internal_Dyn dyn;
       const char *name;
       bfd_boolean size;
 
-      bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+      bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
 
       if (htab->is_vxworks && dyn.d_tag == DT_RELASZ)
        {
@@ -3894,7 +3891,7 @@ sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info,
          if (htab->srelplt)
            {
              dyn.d_un.d_val -= htab->srelplt->size;
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
            }
        }
       else if (htab->is_vxworks && dyn.d_tag == DT_PLTGOT)
@@ -3905,9 +3902,24 @@ sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info,
            {
              dyn.d_un.d_val = (htab->sgotplt->output_section->vma
                                + htab->sgotplt->output_offset);
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
            }
        }
+      else if (htab->is_vxworks
+              && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
+       bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
+      else if (abi_64_p && dyn.d_tag == DT_SPARC_REGISTER)
+       {
+         if (stt_regidx == -1)
+           {
+             stt_regidx =
+               _bfd_elf_link_lookup_local_dynindx (info, output_bfd, -1);
+             if (stt_regidx == -1)
+               return FALSE;
+           }
+         dyn.d_un.d_val = stt_regidx++;
+         bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
+       }
       else
        {
          switch (dyn.d_tag)
@@ -3915,7 +3927,7 @@ sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info,
            case DT_PLTGOT:   name = ".plt"; size = FALSE; break;
            case DT_PLTRELSZ: name = ".rela.plt"; size = TRUE; break;
            case DT_JMPREL:   name = ".rela.plt"; size = FALSE; break;
-           default:      name = NULL; size = FALSE; break;
+           default:          name = NULL; size = FALSE; break;
            }
 
          if (name != NULL)
@@ -3932,7 +3944,7 @@ sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info,
                  else
                    dyn.d_un.d_val = s->size;
                }
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
            }
        }
     }
@@ -4046,20 +4058,12 @@ _bfd_sparc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *i
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       asection *splt;
-      bfd_boolean ret;
 
       splt = bfd_get_section_by_name (dynobj, ".plt");
       BFD_ASSERT (splt != NULL && sdyn != NULL);
 
-#ifdef BFD64
-      if (ABI_64_P (output_bfd))
-       ret = sparc64_finish_dyn (output_bfd, info, dynobj, sdyn, splt);
-      else
-#endif
-       ret = sparc32_finish_dyn (output_bfd, info, dynobj, sdyn, splt);
-
-      if (ret != TRUE)
-       return ret;
+      if (!sparc_finish_dyn (output_bfd, info, dynobj, sdyn, splt))
+       return FALSE;
 
       /* Initialize the contents of the .plt section.  */
       if (splt->size > 0)
@@ -4081,7 +4085,8 @@ _bfd_sparc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *i
        }
 
       elf_section_data (splt->output_section)->this_hdr.sh_entsize
-       = htab->plt_entry_size;
+       = (htab->is_vxworks || !ABI_64_P (output_bfd))
+         ? 0 : htab->plt_entry_size;
     }
 
   /* Set the first entry in the global offset table to the address of
This page took 0.038198 seconds and 4 git commands to generate.