daily update
[deliverable/binutils-gdb.git] / bfd / elfxx-sparc.c
index 8fa5305f805df128c3da89f3740e19237ac0c6cc..d3fe1bafae02dd4afc880ed27f0154760d53d25a 100644 (file)
@@ -1,11 +1,11 @@
 /* SPARC-specific support for ELF
-   Copyright 2005 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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"
 #include "elf-bfd.h"
 #include "elf/sparc.h"
 #include "opcode/sparc.h"
 #include "elfxx-sparc.h"
+#include "elf-vxworks.h"
 
 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
 #define MINUS_ONE (~ (bfd_vma) 0)
@@ -254,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);
@@ -345,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 },
@@ -382,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)
 {
@@ -397,7 +435,12 @@ _bfd_sparc_elf_info_to_howto_ptr (unsigned int r_type)
       return &sparc_rev32_howto;
 
     default:
-      BFD_ASSERT (r_type < (unsigned int) R_SPARC_max_std);
+      if (r_type >= (unsigned int) R_SPARC_max_std)
+       {
+         (*_bfd_error_handler) (_("invalid relocation type %d"),
+                                (int) r_type);
+         r_type = R_SPARC_NONE;
+       }
       return &_bfd_sparc_elf_howto_table[r_type];
     }
 }
@@ -477,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
@@ -500,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)
+sparc_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
 {
-#ifdef BFD64
-  Elf64_External_Rela *loc64;
+  const struct elf_backend_data *bed;
+  bfd_byte *loc;
 
-  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)
-{
-  Elf32_External_Rela *loc32;
-
-  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
@@ -692,12 +724,53 @@ sparc64_plt_entry_build (bfd *output_bfd, asection *splt, bfd_vma offset,
   return index - 4;
 }
 
+/* The format of the first PLT entry in a VxWorks executable.  */
+static const bfd_vma sparc_vxworks_exec_plt0_entry[] =
+  {
+    0x05000000,        /* sethi  %hi(_GLOBAL_OFFSET_TABLE_+8), %g2 */
+    0x8410a000,        /* or     %g2, %lo(_GLOBAL_OFFSET_TABLE_+8), %g2 */
+    0xc4008000,        /* ld     [ %g2 ], %g2 */
+    0x81c08000,        /* jmp    %g2 */
+    0x01000000 /* nop */
+  };
+
+/* The format of subsequent PLT entries.  */
+static const bfd_vma sparc_vxworks_exec_plt_entry[] =
+  {
+    0x03000000,        /* sethi  %hi(_GLOBAL_OFFSET_TABLE_+f@got), %g1 */
+    0x82106000,        /* or     %g1, %lo(_GLOBAL_OFFSET_TABLE_+f@got), %g1 */
+    0xc2004000,        /* ld     [ %g1 ], %g1 */
+    0x81c04000,        /* jmp    %g1 */
+    0x01000000,        /* nop */
+    0x03000000,        /* sethi  %hi(f@pltindex), %g1 */
+    0x10800000,        /* b      _PLT_resolve */
+    0x82106000 /* or     %g1, %lo(f@pltindex), %g1 */
+  };
+
+/* The format of the first PLT entry in a VxWorks shared object.  */
+static const bfd_vma sparc_vxworks_shared_plt0_entry[] =
+  {
+    0xc405e008,        /* ld     [ %l7 + 8 ], %g2 */
+    0x81c08000,        /* jmp    %g2 */
+    0x01000000 /* nop */
+  };
+
+/* The format of subsequent PLT entries.  */
+static const bfd_vma sparc_vxworks_shared_plt_entry[] =
+  {
+    0x03000000,        /* sethi  %hi(f@got), %g1 */
+    0x82106000,        /* or     %g1, %lo(f@got), %g1 */
+    0xc205c001,        /* ld     [ %l7 + %g1 ], %g1 */
+    0x81c04000,        /* jmp    %g1 */
+    0x01000000,        /* nop */
+    0x03000000,        /* sethi  %hi(f@pltindex), %g1 */
+    0x10800000,        /* b      _PLT_resolve */
+    0x82106000 /* or     %g1, %lo(f@pltindex), %g1 */
+  };
+
 #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)
 
@@ -773,10 +846,8 @@ _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->build_plt_entry = sparc64_plt_entry_build;
       ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF64;
       ret->dtpmod_reloc = R_SPARC_TLS_DTPMOD64;
       ret->tpoff_reloc = R_SPARC_TLS_TPOFF64;
@@ -790,10 +861,8 @@ _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->build_plt_entry = sparc32_plt_entry_build;
       ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF32;
       ret->dtpmod_reloc = R_SPARC_TLS_DTPMOD32;
       ret->tpoff_reloc = R_SPARC_TLS_TPOFF32;
@@ -805,7 +874,8 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd)
       ret->dynamic_interpreter_size = sizeof ELF32_DYNAMIC_INTERPRETER;
     }
 
-  if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc))
+  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
+                                     sizeof (struct _bfd_sparc_elf_link_hash_entry)))
     {
       free (ret);
       return NULL;
@@ -829,17 +899,19 @@ 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 (dynobj, ".rela.got");
+  htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
   if (htab->srelgot == NULL
-      || ! bfd_set_section_flags (dynobj, htab->srelgot, SEC_ALLOC
-                                                        | SEC_LOAD
-                                                        | SEC_HAS_CONTENTS
-                                                        | SEC_IN_MEMORY
-                                                        | SEC_LINKER_CREATED
-                                                        | SEC_READONLY)
       || ! bfd_set_section_alignment (dynobj, htab->srelgot,
                                      htab->word_align_power))
     return FALSE;
+
+  if (htab->is_vxworks)
+    {
+      htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+      if (!htab->sgotplt)
+       return FALSE;
+    }
+
   return TRUE;
 }
 
@@ -866,6 +938,41 @@ _bfd_sparc_elf_create_dynamic_sections (bfd *dynobj,
   if (!info->shared)
     htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
 
+  if (htab->is_vxworks)
+    {
+      if (!elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2))
+       return FALSE;
+      if (info->shared)
+       {
+         htab->plt_header_size
+           = 4 * ARRAY_SIZE (sparc_vxworks_shared_plt0_entry);
+         htab->plt_entry_size
+           = 4 * ARRAY_SIZE (sparc_vxworks_shared_plt_entry);
+       }
+      else
+       {
+         htab->plt_header_size
+           = 4 * ARRAY_SIZE (sparc_vxworks_exec_plt0_entry);
+         htab->plt_entry_size
+           = 4 * ARRAY_SIZE (sparc_vxworks_exec_plt_entry);
+       }
+    }
+  else
+    {
+      if (ABI_64_P (dynobj))
+       {
+         htab->build_plt_entry = sparc64_plt_entry_build;
+         htab->plt_header_size = PLT64_HEADER_SIZE;
+         htab->plt_entry_size = PLT64_ENTRY_SIZE;
+       }
+      else
+       {
+         htab->build_plt_entry = sparc32_plt_entry_build;
+         htab->plt_header_size = PLT32_HEADER_SIZE;
+         htab->plt_entry_size = PLT32_ENTRY_SIZE;
+       }
+    }
+
   if (!htab->splt || !htab->srelplt || !htab->sdynbss
       || (!info->shared && !htab->srelbss))
     abort ();
@@ -876,7 +983,7 @@ _bfd_sparc_elf_create_dynamic_sections (bfd *dynobj,
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 void
-_bfd_sparc_elf_copy_indirect_symbol (const struct elf_backend_data *bed,
+_bfd_sparc_elf_copy_indirect_symbol (struct bfd_link_info *info,
                                     struct elf_link_hash_entry *dir,
                                     struct elf_link_hash_entry *ind)
 {
@@ -892,10 +999,7 @@ _bfd_sparc_elf_copy_indirect_symbol (const struct elf_backend_data *bed,
          struct _bfd_sparc_elf_dyn_relocs **pp;
          struct _bfd_sparc_elf_dyn_relocs *p;
 
-         if (ind->root.type == bfd_link_hash_indirect)
-           abort ();
-
-         /* Add reloc counts against the weak sym to the strong sym
+         /* Add reloc counts against the indirect sym to the direct sym
             list.  Merge any entries against the same section.  */
          for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
            {
@@ -925,7 +1029,7 @@ _bfd_sparc_elf_copy_indirect_symbol (const struct elf_backend_data *bed,
       edir->tls_type = eind->tls_type;
       eind->tls_type = GOT_UNKNOWN;
     }
-  _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
+  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 }
 
 static int
@@ -989,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);
 
@@ -999,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++)
     {
@@ -1019,7 +1126,12 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+       }
 
       /* Compatibility with old R_SPARC_REV32 reloc conflicting
         with R_SPARC_TLS_GD_HI22.  */
@@ -1070,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.  */
@@ -1082,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:
@@ -1203,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.  */
@@ -1322,41 +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;
-
-                     sreloc = bfd_make_section (dynobj, name);
-                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-                     if ((sec->flags & SEC_ALLOC) != 0)
-                       flags |= SEC_ALLOC | SEC_LOAD;
-                     if (sreloc == NULL
-                         || ! bfd_set_section_flags (dynobj, sreloc, flags)
-                         || ! 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
@@ -1368,15 +1465,21 @@ _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;
-                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
-                                                sec, r_symndx);
-                 if (s == NULL)
+                 void *vpp;
+                 Elf_Internal_Sym *isym;
+
+                 isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                               abfd, r_symndx);
+                 if (isym == NULL)
                    return FALSE;
 
-                 head = ((struct _bfd_sparc_elf_dyn_relocs **)
-                         &elf_section_data (s)->local_dynrel);
+                 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;
                }
 
              p = *head;
@@ -1407,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;
 
@@ -1431,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.  */
@@ -1473,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);
 
@@ -1525,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)
@@ -1615,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);
 
@@ -1705,6 +1797,13 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       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
@@ -1725,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
@@ -1789,10 +1868,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
        {
          asection *s = htab->splt;
 
-         /* The first four entries in .plt is reserved.  */
+         /* Allocate room for the header.  */
          if (s->size == 0)
-           s->size = (SPARC_ELF_WORD_BYTES(htab) == 8 ?
-                      PLT64_HEADER_SIZE : PLT32_HEADER_SIZE);
+           {
+             s->size = htab->plt_header_size;
+
+             /* Allocate space for the .rela.plt.unloaded relocations.  */
+             if (htab->is_vxworks && !info->shared)
+               htab->srelplt2->size = sizeof (Elf32_External_Rela) * 2;
+           }
 
          /* The procedure linkage table size is bounded by the magnitude
             of the offset we can describe in the entry.  */
@@ -1829,11 +1913,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
            }
 
          /* Make room for this entry.  */
-         s->size += (SPARC_ELF_WORD_BYTES(htab) == 8 ?
-                     PLT64_ENTRY_SIZE : PLT32_ENTRY_SIZE);
+         s->size += htab->plt_entry_size;
 
          /* We also need to make an entry in the .rela.plt section.  */
          htab->srelplt->size += SPARC_ELF_RELA_BYTES (htab);
+
+         if (htab->is_vxworks)
+           {
+             /* Allocate space for the .got.plt entry.  */
+             htab->sgotplt->size += 4;
+
+             /* ...and for the .rela.plt.unloaded relocations.  */
+             if (!info->shared)
+               htab->srelplt2->size += sizeof (Elf32_External_Rela) * 3;
+           }
        }
       else
        {
@@ -1918,6 +2011,37 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
                pp = &p->next;
            }
        }
+
+      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
+         && h->root.type == bfd_link_hash_undefweak)
+       {
+         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+           eh->dyn_relocs = NULL;
+
+         /* Make sure undefined weak symbols are output as a dynamic
+            symbol in PIEs.  */
+         else if (h->dynindx == -1
+                  && !h->forced_local)
+           {
+             if (! bfd_elf_link_record_dynamic_symbol (info, h))
+               return FALSE;
+           }
+       }
     }
   else
     {
@@ -2046,17 +2170,14 @@ _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)
        {
          struct _bfd_sparc_elf_dyn_relocs *p;
 
-         for (p = *((struct _bfd_sparc_elf_dyn_relocs **)
-                    &elf_section_data (s)->local_dynrel);
-              p != NULL;
-              p = p->next)
+         for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
            {
              if (!bfd_is_abs_section (p->sec)
                  && bfd_is_abs_section (p->sec->output_section))
@@ -2066,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;
@@ -2080,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);
@@ -2120,6 +2248,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
   elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
 
   if (! ABI_64_P (output_bfd)
+      && !htab->is_vxworks
       && elf_hash_table (info)->dynamic_sections_created)
     {
       /* Make space for the trailing nop in .plt.  */
@@ -2141,55 +2270,55 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
      memory for them.  */
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
-      const char *name;
-      bfd_boolean strip = FALSE;
-
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
-      /* It's OK to base decisions on the section name, because none
-        of the dynobj section names depend upon the input files.  */
-      name = bfd_get_section_name (dynobj, s);
-
-      if (strncmp (name, ".rela", 5) == 0)
+      if (s == htab->splt
+         || s == htab->sgot
+         || s == htab->sdynbss
+         || s == htab->sgotplt)
        {
-         if (s->size == 0)
-           {
-             /* If we don't need this section, strip it from the
-                output file.  This is to handle .rela.bss and
-                .rel.plt.  We must create it in
-                create_dynamic_sections, because it must be created
-                before the linker maps input sections to output
-                sections.  The linker does that before
-                adjust_dynamic_symbol is called, and it is that
-                function which decides whether anything needs to go
-                into these sections.  */
-             strip = TRUE;
-           }
-         else
+         /* Strip this section if we don't need it; see the
+            comment below.  */
+       }
+      else if (CONST_STRNEQ (s->name, ".rela"))
+       {
+         if (s->size != 0)
            {
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
              s->reloc_count = 0;
            }
        }
-      else if (s != htab->splt && s != htab->sgot)
+      else
        {
-         /* It's not one of our sections, so don't allocate space.  */
+         /* It's not one of our sections.  */
          continue;
        }
 
-      if (strip)
+      if (s->size == 0)
        {
-         _bfd_strip_section_from_output (info, s);
+         /* If we don't need this section, strip it from the
+            output file.  This is mostly to handle .rela.bss and
+            .rela.plt.  We must create both sections in
+            create_dynamic_sections, because they must be created
+            before the linker maps input sections to output
+            sections.  The linker does that before
+            adjust_dynamic_symbol is called, and it is that
+            function which decides whether anything needs to go
+            into these sections.  */
+         s->flags |= SEC_EXCLUDE;
          continue;
        }
 
+      if ((s->flags & SEC_HAS_CONTENTS) == 0)
+       continue;
+
       /* Allocate memory for the section contents.  Zero the memory
         for the benefit of .rela.plt, which has 4 unused entries
         at the beginning, and we don't want garbage.  */
       s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
-      if (s->contents == NULL && s->size != 0)
+      if (s->contents == NULL)
        return FALSE;
     }
 
@@ -2290,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
 
@@ -2299,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);
 }
@@ -2316,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;
@@ -2351,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;
@@ -2365,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);
 
@@ -2380,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))
@@ -2412,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;
@@ -2444,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:
@@ -2525,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,
@@ -2564,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);
@@ -2632,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
@@ -2744,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;
 
@@ -2758,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)
@@ -2774,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.  */
@@ -2887,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)
@@ -2908,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))
@@ -2977,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);
@@ -3085,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))
@@ -3121,10 +3314,11 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          && !((input_section->flags & SEC_DEBUGGING) != 0
               && h->def_dynamic))
        (*_bfd_error_handler)
-         (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
+         (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
           input_bfd,
           input_section,
           (long) rel->r_offset,
+          howto->name,
           h->root.root.string);
 
       r = bfd_reloc_continue;
@@ -3343,8 +3537,34 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              {
                const char *name;
 
+               /* The Solaris native linker silently disregards overflows. 
+                  We don't, but this breaks stabs debugging info, whose
+                  relocations are only 32-bits wide.  Ignore overflows in
+                  this case and also for discarded entries.  */
+               if ((r_type == R_SPARC_32 || r_type == R_SPARC_DISP32)
+                   && (((input_section->flags & SEC_DEBUGGING) != 0
+                        && strcmp (bfd_section_name (input_bfd,
+                                                     input_section),
+                                   ".stab") == 0)
+                       || _bfd_elf_section_offset (output_bfd, info,
+                                                   input_section,
+                                                   rel->r_offset)
+                            == (bfd_vma)-1))
+                 break;
+
                if (h != NULL)
-                 name = NULL;
+                 {
+                   /* Assume this is a call protected by other code that
+                      detect the symbol is undefined.  If this is the case,
+                      we can safely ignore the overflow.  If not, the
+                      program is hosed anyway, and a little warning isn't
+                      going to help.  */
+                   if (h->root.type == bfd_link_hash_undefweak
+                       && howto->pc_relative)
+                     break;
+
+                   name = NULL;
+                 }
                else
                  {
                    name = bfd_elf_string_from_elf_section (input_bfd,
@@ -3369,6 +3589,97 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   return TRUE;
 }
 
+/* Build a VxWorks PLT entry.  PLT_INDEX is the index of the PLT entry
+   and PLT_OFFSET is the byte offset from the start of .plt.  GOT_OFFSET
+   is the offset of the associated .got.plt entry from
+   _GLOBAL_OFFSET_TABLE_.  */
+
+static void
+sparc_vxworks_build_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
+                              bfd_vma plt_offset, bfd_vma plt_index,
+                              bfd_vma got_offset)
+{
+  bfd_vma got_base;
+  const bfd_vma *plt_entry;
+  struct _bfd_sparc_elf_link_hash_table *htab;
+  bfd_byte *loc;
+  Elf_Internal_Rela rela;
+
+  htab = _bfd_sparc_elf_hash_table (info);
+  if (info->shared)
+    {
+      plt_entry = sparc_vxworks_shared_plt_entry;
+      got_base = 0;
+    }
+  else
+    {
+      plt_entry = sparc_vxworks_exec_plt_entry;
+      got_base = (htab->elf.hgot->root.u.def.value
+                 + htab->elf.hgot->root.u.def.section->output_offset
+                 + htab->elf.hgot->root.u.def.section->output_section->vma);
+    }
+
+  /* Fill in the entry in the procedure linkage table.  */
+  bfd_put_32 (output_bfd, plt_entry[0] + ((got_base + got_offset) >> 10),
+             htab->splt->contents + plt_offset);
+  bfd_put_32 (output_bfd, plt_entry[1] + ((got_base + got_offset) & 0x3ff),
+             htab->splt->contents + plt_offset + 4);
+  bfd_put_32 (output_bfd, plt_entry[2],
+             htab->splt->contents + plt_offset + 8);
+  bfd_put_32 (output_bfd, plt_entry[3],
+             htab->splt->contents + plt_offset + 12);
+  bfd_put_32 (output_bfd, plt_entry[4],
+             htab->splt->contents + plt_offset + 16);
+  bfd_put_32 (output_bfd, plt_entry[5] + (plt_index >> 10),
+             htab->splt->contents + plt_offset + 20);
+  /* PC-relative displacement for a branch to the start of
+     the PLT section.  */
+  bfd_put_32 (output_bfd, plt_entry[6] + (((-plt_offset - 24) >> 2)
+                                         & 0x003fffff),
+             htab->splt->contents + plt_offset + 24);
+  bfd_put_32 (output_bfd, plt_entry[7] + (plt_index & 0x3ff),
+             htab->splt->contents + plt_offset + 28);
+
+  /* Fill in the .got.plt entry, pointing initially at the
+     second half of the PLT entry.  */
+  BFD_ASSERT (htab->sgotplt != NULL);
+  bfd_put_32 (output_bfd,
+             htab->splt->output_section->vma
+             + htab->splt->output_offset
+             + plt_offset + 20,
+             htab->sgotplt->contents + got_offset);
+
+  /* Add relocations to .rela.plt.unloaded.  */
+  if (!info->shared)
+    {
+      loc = (htab->srelplt2->contents
+            + (2 + 3 * plt_index) * sizeof (Elf32_External_Rela));
+
+      /* Relocate the initial sethi.  */
+      rela.r_offset = (htab->splt->output_section->vma
+                      + htab->splt->output_offset
+                      + plt_offset);
+      rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_HI22);
+      rela.r_addend = got_offset;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+      loc += sizeof (Elf32_External_Rela);
+
+      /* Likewise the following or.  */
+      rela.r_offset += 4;
+      rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_LO10);
+      bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+      loc += sizeof (Elf32_External_Rela);
+
+      /* Relocate the .got.plt entry.  */
+      rela.r_offset = (htab->sgotplt->output_section->vma
+                      + htab->sgotplt->output_offset
+                      + got_offset);
+      rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_SPARC_32);
+      rela.r_addend = plt_offset + 20;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+    }
+}
+
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
 
@@ -3380,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)
     {
@@ -3390,7 +3703,7 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
       asection *srela;
       Elf_Internal_Rela rela;
       bfd_byte *loc;
-      bfd_vma r_offset;
+      bfd_vma r_offset, got_offset;
       int rela_index;
 
       /* This symbol has an entry in the PLT.  Set it up.  */
@@ -3401,23 +3714,48 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
       srela = htab->srelplt;
       BFD_ASSERT (splt != NULL && srela != NULL);
 
-      /* Fill in the entry in the procedure linkage table.  */
-      rela_index = SPARC_ELF_BUILD_PLT_ENTRY (htab, output_bfd, splt,
-                                             h->plt.offset, splt->size,
-                                             &r_offset);
-
       /* Fill in the entry in the .rela.plt section.  */
-      rela.r_offset = r_offset
-       + (splt->output_section->vma + splt->output_offset);
-      if (! ABI_64_P (output_bfd)
-         || h->plt.offset < (PLT64_LARGE_THRESHOLD * PLT64_ENTRY_SIZE))
+      if (htab->is_vxworks)
        {
+         /* Work out the index of this PLT entry.  */
+         rela_index = ((h->plt.offset - htab->plt_header_size)
+                       / htab->plt_entry_size);
+
+         /* Calculate the offset of the associated .got.plt entry.
+            The first three entries are reserved.  */
+         got_offset = (rela_index + 3) * 4;
+
+         sparc_vxworks_build_plt_entry (output_bfd, info, h->plt.offset,
+                                        rela_index, got_offset);
+
+
+         /* On VxWorks, the relocation points to the .got.plt entry,
+            not the .plt entry.  */
+         rela.r_offset = (htab->sgotplt->output_section->vma
+                          + htab->sgotplt->output_offset
+                          + got_offset);
          rela.r_addend = 0;
        }
       else
        {
-         rela.r_addend = -(h->plt.offset + 4)
-                         -(splt->output_section->vma + splt->output_offset);
+         /* Fill in the entry in the procedure linkage table.  */
+         rela_index = SPARC_ELF_BUILD_PLT_ENTRY (htab, output_bfd, splt,
+                                                 h->plt.offset, splt->size,
+                                                 &r_offset);
+
+         rela.r_offset = r_offset
+           + (splt->output_section->vma + splt->output_offset);
+         if (! ABI_64_P (output_bfd)
+             || h->plt.offset < (PLT64_LARGE_THRESHOLD * PLT64_ENTRY_SIZE))
+           {
+             rela.r_addend = 0;
+           }
+         else
+           {
+             rela.r_addend = (-(h->plt.offset + 4)
+                              - splt->output_section->vma
+                              - splt->output_offset);
+           }
        }
       rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, R_SPARC_JMP_SLOT);
 
@@ -3427,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)
        {
@@ -3495,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)
@@ -3515,13 +3843,15 @@ _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.  */
+  /* Mark some specially defined symbols as absolute.  On VxWorks,
+     _GLOBAL_OFFSET_TABLE_ is not absolute: it is relative to the
+     ".got" section.  Likewise _PROCEDURE_LINKAGE_TABLE_ and ".plt".  */
   if (strcmp (h->root.root.string, "_DYNAMIC") == 0
-      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
-      || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+      || (!htab->is_vxworks
+         && (h == htab->elf.hgot || h == htab->elf.hplt)))
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -3529,31 +3859,57 @@ _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;
+  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;
 
-  dyncon = (Elf64_External_Dyn *) sdyn->contents;
-  dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
-  for (; dyncon < dynconend; dyncon++)
+  htab = _bfd_sparc_elf_hash_table (info);
+  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_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
+      bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
 
-      switch (dyn.d_tag)
+      if (htab->is_vxworks && dyn.d_tag == DT_RELASZ)
+       {
+         /* On VxWorks, DT_RELASZ should not include the relocations
+            in .rela.plt.  */
+         if (htab->srelplt)
+           {
+             dyn.d_un.d_val -= htab->srelplt->size;
+             bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
+           }
+       }
+      else if (htab->is_vxworks && dyn.d_tag == DT_PLTGOT)
+       {
+         /* On VxWorks, DT_PLTGOT should point to the start of the GOT,
+            not to the start of the PLT.  */
+         if (htab->sgotplt)
+           {
+             dyn.d_un.d_val = (htab->sgotplt->output_section->vma
+                               + htab->sgotplt->output_offset);
+             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)
        {
-       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 =
@@ -3562,76 +3918,129 @@ sparc64_finish_dyn (bfd *output_bfd, struct bfd_link_info *info,
                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;
+         bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
        }
-
-      if (name != NULL)
+      else
        {
-         asection *s;
+         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;
+           default:          name = NULL; size = FALSE; break;
+           }
 
-         s = bfd_get_section_by_name (output_bfd, name);
-         if (s == NULL)
-           dyn.d_un.d_val = 0;
-         else
+         if (name != NULL)
            {
-             if (! size)
-               dyn.d_un.d_ptr = s->vma;
+             asection *s;
+
+             s = bfd_get_section_by_name (output_bfd, name);
+             if (s == NULL)
+               dyn.d_un.d_val = 0;
              else
-               dyn.d_un.d_val = s->size;
+               {
+                 if (! size)
+                   dyn.d_un.d_ptr = s->vma;
+                 else
+                   dyn.d_un.d_val = s->size;
+               }
+             bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
            }
-         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 ATTRIBUTE_UNUSED,
-                   bfd *dynobj, asection *sdyn,
-                   asection *splt ATTRIBUTE_UNUSED)
+/* Install the first PLT entry in a VxWorks executable and make sure that
+   .rela.plt.unloaded relocations have the correct symbol indexes.  */
+
+static void
+sparc_vxworks_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
 {
-  Elf32_External_Dyn *dyncon, *dynconend;
+  struct _bfd_sparc_elf_link_hash_table *htab;
+  Elf_Internal_Rela rela;
+  bfd_vma got_base;
+  bfd_byte *loc;
 
-  dyncon = (Elf32_External_Dyn *) sdyn->contents;
-  dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
-  for (; dyncon < dynconend; dyncon++)
-    {
-      Elf_Internal_Dyn dyn;
-      const char *name;
-      bfd_boolean size;
+  htab = _bfd_sparc_elf_hash_table (info);
 
-      bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+  /* Calculate the absolute value of _GLOBAL_OFFSET_TABLE_.  */
+  got_base = (htab->elf.hgot->root.u.def.section->output_section->vma
+             + htab->elf.hgot->root.u.def.section->output_offset
+             + htab->elf.hgot->root.u.def.value);
+
+  /* Install the initial PLT entry.  */
+  bfd_put_32 (output_bfd,
+             sparc_vxworks_exec_plt0_entry[0] + ((got_base + 8) >> 10),
+             htab->splt->contents);
+  bfd_put_32 (output_bfd,
+             sparc_vxworks_exec_plt0_entry[1] + ((got_base + 8) & 0x3ff),
+             htab->splt->contents + 4);
+  bfd_put_32 (output_bfd,
+             sparc_vxworks_exec_plt0_entry[2],
+             htab->splt->contents + 8);
+  bfd_put_32 (output_bfd,
+             sparc_vxworks_exec_plt0_entry[3],
+             htab->splt->contents + 12);
+  bfd_put_32 (output_bfd,
+             sparc_vxworks_exec_plt0_entry[4],
+             htab->splt->contents + 16);
+
+  loc = htab->srelplt2->contents;
+
+  /* Add an unloaded relocation for the initial entry's "sethi".  */
+  rela.r_offset = (htab->splt->output_section->vma
+                  + htab->splt->output_offset);
+  rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_HI22);
+  rela.r_addend = 8;
+  bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+  loc += sizeof (Elf32_External_Rela);
+
+  /* Likewise the following "or".  */
+  rela.r_offset += 4;
+  rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_LO10);
+  bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+  loc += sizeof (Elf32_External_Rela);
+
+  /* Fix up the remaining .rela.plt.unloaded relocations.  They may have
+     the wrong symbol index for _G_O_T_ or _P_L_T_ depending on the order
+     in which symbols were output.  */
+  while (loc < htab->srelplt2->contents + htab->srelplt2->size)
+    {
+      Elf_Internal_Rela rel;
+
+      /* The entry's initial "sethi" (against _G_O_T_).  */
+      bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
+      rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_HI22);
+      bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+      loc += sizeof (Elf32_External_Rela);
+
+      /* The following "or" (also against _G_O_T_).  */
+      bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
+      rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_LO10);
+      bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+      loc += sizeof (Elf32_External_Rela);
+
+      /* The .got.plt entry (against _P_L_T_).  */
+      bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
+      rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_SPARC_32);
+      bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+      loc += sizeof (Elf32_External_Rela);
+    }
+}
 
-      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;
-       default:          name = NULL; size = FALSE; break;
-       }
+/* Install the first PLT entry in a VxWorks shared object.  */
 
-      if (name != NULL)
-       {
-         asection *s;
+static void
+sparc_vxworks_finish_shared_plt (bfd *output_bfd, struct bfd_link_info *info)
+{
+  struct _bfd_sparc_elf_link_hash_table *htab;
+  unsigned int i;
 
-         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_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
-       }
-    }
-  return TRUE;
+  htab = _bfd_sparc_elf_hash_table (info);
+  for (i = 0; i < ARRAY_SIZE (sparc_vxworks_shared_plt0_entry); i++)
+    bfd_put_32 (output_bfd, sparc_vxworks_shared_plt0_entry[i],
+               htab->splt->contents + i * 4);
 }
 
 bfd_boolean
@@ -3649,36 +4058,35 @@ _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)
        {
-         if (ABI_64_P (output_bfd))
-           memset (splt->contents, 0, 4 * PLT64_ENTRY_SIZE);
+         if (htab->is_vxworks)
+           {
+             if (info->shared)
+               sparc_vxworks_finish_shared_plt (output_bfd, info);
+             else
+               sparc_vxworks_finish_exec_plt (output_bfd, info);
+           }
          else
            {
-             memset (splt->contents, 0, 4 * PLT32_ENTRY_SIZE);
-             bfd_put_32 (output_bfd, (bfd_vma) SPARC_NOP,
-                         splt->contents + splt->size - 4);
+             memset (splt->contents, 0, htab->plt_header_size);
+             if (!ABI_64_P (output_bfd))
+               bfd_put_32 (output_bfd, (bfd_vma) SPARC_NOP,
+                           splt->contents + splt->size - 4);
            }
        }
 
-      elf_section_data (splt->output_section)->this_hdr.sh_entsize =
-       (ABI_64_P (output_bfd) ? PLT64_ENTRY_SIZE : PLT32_ENTRY_SIZE);
+      elf_section_data (splt->output_section)->this_hdr.sh_entsize
+       = (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.043255 seconds and 4 git commands to generate.