include/elf/
[deliverable/binutils-gdb.git] / bfd / elfxx-sparc.c
index b83cd140d8fc79861940105de600877609ccecef..79f8f86d0d3092115a27d541e8cf60ffd589215f 100644 (file)
@@ -1,11 +1,11 @@
 /* SPARC-specific support for ELF
-   Copyright 2005 Free Software Foundation, Inc.
+   Copyright 2005, 2006, 2007 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"
 #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)
@@ -382,6 +386,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)
 {
@@ -485,11 +513,14 @@ struct _bfd_sparc_elf_obj_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;
+    {
+      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 bfd_elf_mkobject (abfd);
 }
 
 static void
@@ -505,27 +536,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
@@ -697,12 +715,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)
 
@@ -778,10 +837,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;
@@ -795,10 +852,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;
@@ -810,7 +865,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;
@@ -845,6 +901,14 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
       || ! 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;
 }
 
@@ -871,6 +935,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 ();
@@ -881,7 +980,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)
 {
@@ -897,10 +996,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; )
            {
@@ -930,7 +1026,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
@@ -1342,7 +1438,7 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  if (name == NULL)
                    return FALSE;
 
-                 BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+                 BFD_ASSERT (CONST_STRNEQ (name, ".rela")
                              && strcmp (bfd_get_section_name (abfd, sec),
                                         name + 5) == 0);
 
@@ -1381,13 +1477,15 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                     easily.  Oh well.  */
 
                  asection *s;
+                 void *vpp;
+
                  s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
                                                 sec, r_symndx);
                  if (s == NULL)
                    return FALSE;
 
-                 head = ((struct _bfd_sparc_elf_dyn_relocs **)
-                         &elf_section_data (s)->local_dynrel);
+                 vpp = &elf_section_data (s)->local_dynrel;
+                 head = (struct _bfd_sparc_elf_dyn_relocs **) vpp;
                }
 
              p = *head;
@@ -1418,7 +1516,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;
 
@@ -1442,35 +1542,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.  */
@@ -1626,7 +1705,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);
 
@@ -1743,29 +1821,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
@@ -1807,10 +1865,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.  */
@@ -1847,11 +1910,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
        {
@@ -1936,6 +2008,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
                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
     {
@@ -2071,10 +2161,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
        {
          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))
@@ -2138,6 +2225,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.  */
@@ -2164,12 +2252,13 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
 
       if (s == htab->splt
          || s == htab->sgot
-         || s == htab->sdynbss)
+         || s == htab->sdynbss
+         || s == htab->sgotplt)
        {
          /* 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)
            {
@@ -2307,6 +2396,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
 
@@ -2316,13 +2408,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);
 }
@@ -2368,10 +2463,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;
@@ -2383,9 +2482,6 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   Elf_Internal_Rela *relend;
   int num_relocs;
 
-  if (info->relocatable)
-    return TRUE;
-
   htab = _bfd_sparc_elf_hash_table (info);
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
@@ -2429,7 +2525,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;
@@ -2461,6 +2556,21 @@ _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_GOT10:
@@ -2542,7 +2652,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,
@@ -2649,11 +2759,7 @@ _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)
            break;
 
          if ((info->shared
@@ -2761,6 +2867,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;
 
@@ -2775,9 +2883,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)
@@ -2791,12 +2910,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.  */
@@ -2904,7 +3023,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)
@@ -2925,7 +3044,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))
@@ -2994,7 +3114,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);
@@ -3138,10 +3258,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;
@@ -3360,8 +3481,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,
@@ -3386,6 +3533,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.  */
 
@@ -3397,9 +3635,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)
     {
@@ -3407,7 +3647,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.  */
@@ -3418,23 +3658,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);
 
@@ -3444,18 +3709,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)
        {
@@ -3512,7 +3767,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)
@@ -3532,13 +3787,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;
@@ -3546,31 +3803,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 =
@@ -3579,76 +3862,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
@@ -3666,36 +4002,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.04002 seconds and 4 git commands to generate.