Add support to GDB for the Renesas rl78 architecture.
[external/binutils.git] / bfd / sunos.c
index d9235da..8ef25ed 100644 (file)
-/* BFD backend for sunos binaries */
+/* BFD backend for SunOS binaries.
+   Copyright 1990, 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2011
+   Free Software Foundation, Inc.
+   Written by Cygnus Support.
 
-/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This file is part of BFD, the Binary File Diddler.
+   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 3 of the License, or
+   (at your option) any later version.
 
-BFD 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 1, or (at your option)
-any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-BFD is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   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.  */
 
-You should have received a copy of the GNU General Public License
-along with BFD; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+#define TARGETNAME "a.out-sunos-big"
 
-/* $Id$ */
+/* Do not "beautify" the CONCAT* macro args.  Traditional C will not
+   remove whitespace added here, and thus will fail to concatenate
+   the tokens.  */
+#define MY(OP) CONCAT2 (sunos_big_,OP)
 
-#include <ansidecl.h>
-#include "sysdep.h"
 #include "bfd.h"
-#include "libbfd.h"
+#include "bfdlink.h"
+#include "libaout.h"
+
+/* ??? Where should this go?  */
+#define MACHTYPE_OK(mtype) \
+  (((mtype) == M_SPARC && bfd_lookup_arch (bfd_arch_sparc, 0) != NULL) \
+   || ((mtype) == M_SPARCLET \
+       && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \
+   || ((mtype) == M_SPARCLITE_LE \
+       && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \
+   || (((mtype) == M_UNKNOWN || (mtype) == M_68010 || (mtype) == M_68020) \
+       && bfd_lookup_arch (bfd_arch_m68k, 0) != NULL))
+
+#define MY_get_dynamic_symtab_upper_bound  sunos_get_dynamic_symtab_upper_bound
+#define MY_canonicalize_dynamic_symtab     sunos_canonicalize_dynamic_symtab
+#define MY_get_synthetic_symtab            _bfd_nodynamic_get_synthetic_symtab
+#define MY_get_dynamic_reloc_upper_bound   sunos_get_dynamic_reloc_upper_bound
+#define MY_canonicalize_dynamic_reloc      sunos_canonicalize_dynamic_reloc
+#define MY_bfd_link_hash_table_create      sunos_link_hash_table_create
+#define MY_add_dynamic_symbols             sunos_add_dynamic_symbols
+#define MY_add_one_symbol                  sunos_add_one_symbol
+#define MY_link_dynamic_object             sunos_link_dynamic_object
+#define MY_write_dynamic_symbol            sunos_write_dynamic_symbol
+#define MY_check_dynamic_reloc             sunos_check_dynamic_reloc
+#define MY_finish_dynamic_link             sunos_finish_dynamic_link
+
+static bfd_boolean sunos_add_dynamic_symbols            (bfd *, struct bfd_link_info *, struct external_nlist **, bfd_size_type *, char **);
+static bfd_boolean sunos_add_one_symbol                 (struct bfd_link_info *, bfd *, const char *, flagword, asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean, struct bfd_link_hash_entry **);
+static bfd_boolean sunos_link_dynamic_object            (struct bfd_link_info *, bfd *);
+static bfd_boolean sunos_write_dynamic_symbol           (bfd *, struct bfd_link_info *, struct aout_link_hash_entry *);
+static bfd_boolean sunos_check_dynamic_reloc            (struct bfd_link_info *, bfd *, asection *, struct aout_link_hash_entry *, void *, bfd_byte *, bfd_boolean *, bfd_vma *);
+static bfd_boolean sunos_finish_dynamic_link            (bfd *, struct bfd_link_info *);
+static struct bfd_link_hash_table *sunos_link_hash_table_create  (bfd *);
+static long        sunos_get_dynamic_symtab_upper_bound (bfd *);
+static long        sunos_canonicalize_dynamic_symtab    (bfd *, asymbol **);
+static long        sunos_get_dynamic_reloc_upper_bound  (bfd *);
+static long        sunos_canonicalize_dynamic_reloc     (bfd *, arelent **, asymbol **);
+
+/* Include the usual a.out support.  */
+#include "aoutf1.h"
+
+/* The SunOS 4.1.4 /usr/include/locale.h defines valid as a macro.  */
+#undef valid
+
+/* SunOS shared library support.  We store a pointer to this structure
+   in obj_aout_dynamic_info (abfd).  */
+
+struct sunos_dynamic_info
+{
+  /* Whether we found any dynamic information.  */
+  bfd_boolean valid;
+  /* Dynamic information.  */
+  struct internal_sun4_dynamic_link dyninfo;
+  /* Number of dynamic symbols.  */
+  unsigned long dynsym_count;
+  /* Read in nlists for dynamic symbols.  */
+  struct external_nlist *dynsym;
+  /* asymbol structures for dynamic symbols.  */
+  aout_symbol_type *canonical_dynsym;
+  /* Read in dynamic string table.  */
+  char *dynstr;
+  /* Number of dynamic relocs.  */
+  unsigned long dynrel_count;
+  /* Read in dynamic relocs.  This may be reloc_std_external or
+     reloc_ext_external.  */
+  void * dynrel;
+  /* arelent structures for dynamic relocs.  */
+  arelent *canonical_dynrel;
+};
+
+/* The hash table of dynamic symbols is composed of two word entries.
+   See include/aout/sun4.h for details.  */
 
-#include "a.out.sun4.h"
-#include "a.out.gnu.h"
-#include "stab.gnu.h"
-#include "ar.h"
-#include "liba.out.h"           /* BFD a.out internal data structures */
+#define HASH_ENTRY_SIZE (2 * BYTES_IN_WORD)
 
-void (*bfd_error_trap)();
+/* Read in the basic dynamic information.  This locates the __DYNAMIC
+   structure and uses it to find the dynamic_link structure.  It
+   creates and saves a sunos_dynamic_info structure.  If it can't find
+   __DYNAMIC, it sets the valid field of the sunos_dynamic_info
+   structure to FALSE to avoid doing this work again.  */
 
-static bfd_target *sunos4_callback ();
+static bfd_boolean
+sunos_read_dynamic_info (bfd *abfd)
+{
+  struct sunos_dynamic_info *info;
+  asection *dynsec;
+  bfd_vma dynoff;
+  struct external_sun4_dynamic dyninfo;
+  unsigned long dynver;
+  struct external_sun4_dynamic_link linkinfo;
+  bfd_size_type amt;
+
+  if (obj_aout_dynamic_info (abfd) != NULL)
+    return TRUE;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return FALSE;
+    }
+
+  amt = sizeof (struct sunos_dynamic_info);
+  info = bfd_zalloc (abfd, amt);
+  if (!info)
+    return FALSE;
+  info->valid = FALSE;
+  info->dynsym = NULL;
+  info->dynstr = NULL;
+  info->canonical_dynsym = NULL;
+  info->dynrel = NULL;
+  info->canonical_dynrel = NULL;
+  obj_aout_dynamic_info (abfd) = (void *) info;
+
+  /* This code used to look for the __DYNAMIC symbol to locate the dynamic
+     linking information.
+     However this inhibits recovering the dynamic symbols from a
+     stripped object file, so blindly assume that the dynamic linking
+     information is located at the start of the data section.
+     We could verify this assumption later by looking through the dynamic
+     symbols for the __DYNAMIC symbol.  */
+  if ((abfd->flags & DYNAMIC) == 0)
+    return TRUE;
+  if (! bfd_get_section_contents (abfd, obj_datasec (abfd), (void *) &dyninfo,
+                                 (file_ptr) 0,
+                                 (bfd_size_type) sizeof dyninfo))
+    return TRUE;
+
+  dynver = GET_WORD (abfd, dyninfo.ld_version);
+  if (dynver != 2 && dynver != 3)
+    return TRUE;
+
+  dynoff = GET_WORD (abfd, dyninfo.ld);
+
+  /* dynoff is a virtual address.  It is probably always in the .data
+     section, but this code should work even if it moves.  */
+  if (dynoff < bfd_get_section_vma (abfd, obj_datasec (abfd)))
+    dynsec = obj_textsec (abfd);
+  else
+    dynsec = obj_datasec (abfd);
+  dynoff -= bfd_get_section_vma (abfd, dynsec);
+  if (dynoff > dynsec->size)
+    return TRUE;
+
+  /* This executable appears to be dynamically linked in a way that we
+     can understand.  */
+  if (! bfd_get_section_contents (abfd, dynsec, (void *) &linkinfo,
+                                 (file_ptr) dynoff,
+                                 (bfd_size_type) sizeof linkinfo))
+    return TRUE;
+
+  /* Swap in the dynamic link information.  */
+  info->dyninfo.ld_loaded = GET_WORD (abfd, linkinfo.ld_loaded);
+  info->dyninfo.ld_need = GET_WORD (abfd, linkinfo.ld_need);
+  info->dyninfo.ld_rules = GET_WORD (abfd, linkinfo.ld_rules);
+  info->dyninfo.ld_got = GET_WORD (abfd, linkinfo.ld_got);
+  info->dyninfo.ld_plt = GET_WORD (abfd, linkinfo.ld_plt);
+  info->dyninfo.ld_rel = GET_WORD (abfd, linkinfo.ld_rel);
+  info->dyninfo.ld_hash = GET_WORD (abfd, linkinfo.ld_hash);
+  info->dyninfo.ld_stab = GET_WORD (abfd, linkinfo.ld_stab);
+  info->dyninfo.ld_stab_hash = GET_WORD (abfd, linkinfo.ld_stab_hash);
+  info->dyninfo.ld_buckets = GET_WORD (abfd, linkinfo.ld_buckets);
+  info->dyninfo.ld_symbols = GET_WORD (abfd, linkinfo.ld_symbols);
+  info->dyninfo.ld_symb_size = GET_WORD (abfd, linkinfo.ld_symb_size);
+  info->dyninfo.ld_text = GET_WORD (abfd, linkinfo.ld_text);
+  info->dyninfo.ld_plt_sz = GET_WORD (abfd, linkinfo.ld_plt_sz);
+
+  /* Reportedly the addresses need to be offset by the size of the
+     exec header in an NMAGIC file.  */
+  if (adata (abfd).magic == n_magic)
+    {
+      unsigned long exec_bytes_size = adata (abfd).exec_bytes_size;
+
+      info->dyninfo.ld_need += exec_bytes_size;
+      info->dyninfo.ld_rules += exec_bytes_size;
+      info->dyninfo.ld_rel += exec_bytes_size;
+      info->dyninfo.ld_hash += exec_bytes_size;
+      info->dyninfo.ld_stab += exec_bytes_size;
+      info->dyninfo.ld_symbols += exec_bytes_size;
+    }
 
-/*SUPPRESS558*/
-/*SUPPRESS529*/
+  /* The only way to get the size of the symbol information appears to
+     be to determine the distance between it and the string table.  */
+  info->dynsym_count = ((info->dyninfo.ld_symbols - info->dyninfo.ld_stab)
+                       / EXTERNAL_NLIST_SIZE);
+  BFD_ASSERT (info->dynsym_count * EXTERNAL_NLIST_SIZE
+             == (unsigned long) (info->dyninfo.ld_symbols
+                                 - info->dyninfo.ld_stab));
 
-bfd_target *
-sunos4_object_p (abfd)
-     bfd *abfd;
+  /* Similarly, the relocs end at the hash table.  */
+  info->dynrel_count = ((info->dyninfo.ld_hash - info->dyninfo.ld_rel)
+                       / obj_reloc_entry_size (abfd));
+  BFD_ASSERT (info->dynrel_count * obj_reloc_entry_size (abfd)
+             == (unsigned long) (info->dyninfo.ld_hash
+                                 - info->dyninfo.ld_rel));
+
+  info->valid = TRUE;
+
+  return TRUE;
+}
+
+/* Return the amount of memory required for the dynamic symbols.  */
+
+static long
+sunos_get_dynamic_symtab_upper_bound (bfd *abfd)
 {
-  unsigned char magicbuf[4];   /* Raw bytes of magic number from file */
-  unsigned long magic;         /* Swapped magic number */
+  struct sunos_dynamic_info *info;
 
-  bfd_error = system_call_error;
+  if (! sunos_read_dynamic_info (abfd))
+    return -1;
 
-  if (bfd_read ((PTR)magicbuf, 1, sizeof (magicbuf), abfd) !=
-      sizeof (magicbuf))
-    return 0;
-  magic = bfd_h_getlong (abfd, magicbuf);
+  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+  if (! info->valid)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
 
-  if (N_BADMAG (*((struct exec *) &magic))) return 0;
+  return (info->dynsym_count + 1) * sizeof (asymbol *);
+}
 
-  return some_aout_object_p (abfd, sunos4_callback);
+/* Read the external dynamic symbols.  */
+
+static bfd_boolean
+sunos_slurp_dynamic_symtab (bfd *abfd)
+{
+  struct sunos_dynamic_info *info;
+  bfd_size_type amt;
+
+  /* Get the general dynamic information.  */
+  if (obj_aout_dynamic_info (abfd) == NULL)
+    {
+      if (! sunos_read_dynamic_info (abfd))
+         return FALSE;
+    }
+
+  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+  if (! info->valid)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return FALSE;
+    }
+
+  /* Get the dynamic nlist structures.  */
+  if (info->dynsym == NULL)
+    {
+      amt = (bfd_size_type) info->dynsym_count * EXTERNAL_NLIST_SIZE;
+      info->dynsym = bfd_alloc (abfd, amt);
+      if (info->dynsym == NULL && info->dynsym_count != 0)
+       return FALSE;
+      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_stab, SEEK_SET) != 0
+         || bfd_bread ((void *) info->dynsym, amt, abfd) != amt)
+       {
+         if (info->dynsym != NULL)
+           {
+             bfd_release (abfd, info->dynsym);
+             info->dynsym = NULL;
+           }
+         return FALSE;
+       }
+    }
+
+  /* Get the dynamic strings.  */
+  if (info->dynstr == NULL)
+    {
+      amt = info->dyninfo.ld_symb_size;
+      info->dynstr = bfd_alloc (abfd, amt);
+      if (info->dynstr == NULL && info->dyninfo.ld_symb_size != 0)
+       return FALSE;
+      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_symbols, SEEK_SET) != 0
+         || bfd_bread ((void *) info->dynstr, amt, abfd) != amt)
+       {
+         if (info->dynstr != NULL)
+           {
+             bfd_release (abfd, info->dynstr);
+             info->dynstr = NULL;
+           }
+         return FALSE;
+       }
+    }
+
+  return TRUE;
 }
 
-  /* Determine the size of a relocation entry, based on the architecture */
-static void
-DEFUN(choose_reloc_size,(abfd),
-bfd *abfd)
+/* Read in the dynamic symbols.  */
+
+static long
+sunos_canonicalize_dynamic_symtab (bfd *abfd, asymbol **storage)
+{
+  struct sunos_dynamic_info *info;
+  unsigned long i;
+
+  if (! sunos_slurp_dynamic_symtab (abfd))
+    return -1;
+
+  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+
+#ifdef CHECK_DYNAMIC_HASH
+  /* Check my understanding of the dynamic hash table by making sure
+     that each symbol can be located in the hash table.  */
   {
-    switch (abfd->obj_arch) {
-    case bfd_arch_sparc:
-    case bfd_arch_a29k:
-      obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
-      break;
-    default:
-      obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
-      break;
-    }
+    bfd_size_type table_size;
+    bfd_byte *table;
+    bfd_size_type i;
+
+    if (info->dyninfo.ld_buckets > info->dynsym_count)
+      abort ();
+    table_size = info->dyninfo.ld_stab - info->dyninfo.ld_hash;
+    table = bfd_malloc (table_size);
+    if (table == NULL && table_size != 0)
+      abort ();
+    if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_hash, SEEK_SET) != 0
+       || bfd_bread ((void *) table, table_size, abfd) != table_size)
+      abort ();
+    for (i = 0; i < info->dynsym_count; i++)
+      {
+       unsigned char *name;
+       unsigned long hash;
+
+       name = ((unsigned char *) info->dynstr
+               + GET_WORD (abfd, info->dynsym[i].e_strx));
+       hash = 0;
+       while (*name != '\0')
+         hash = (hash << 1) + *name++;
+       hash &= 0x7fffffff;
+       hash %= info->dyninfo.ld_buckets;
+       while (GET_WORD (abfd, table + hash * HASH_ENTRY_SIZE) != i)
+         {
+           hash = GET_WORD (abfd,
+                            table + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD);
+           if (hash == 0 || hash >= table_size / HASH_ENTRY_SIZE)
+             abort ();
+         }
+      }
+    free (table);
   }
+#endif /* CHECK_DYNAMIC_HASH */
+
+  /* Get the asymbol structures corresponding to the dynamic nlist
+     structures.  */
+  if (info->canonical_dynsym == NULL)
+    {
+      bfd_size_type size;
+      bfd_size_type strsize = info->dyninfo.ld_symb_size;
+
+      size = (bfd_size_type) info->dynsym_count * sizeof (aout_symbol_type);
+      info->canonical_dynsym = bfd_alloc (abfd, size);
+      if (info->canonical_dynsym == NULL && info->dynsym_count != 0)
+       return -1;
+
+      if (! aout_32_translate_symbol_table (abfd, info->canonical_dynsym,
+                                           info->dynsym,
+                                           (bfd_size_type) info->dynsym_count,
+                                           info->dynstr, strsize, TRUE))
+       {
+         if (info->canonical_dynsym != NULL)
+           {
+             bfd_release (abfd, info->canonical_dynsym);
+             info->canonical_dynsym = NULL;
+           }
+         return -1;
+       }
+    }
 
-/* Set parameters about this a.out file that are machine-dependent.
-   This routine is called from some_aout_object_p just before it returns.  */
+  /* Return pointers to the dynamic asymbol structures.  */
+  for (i = 0; i < info->dynsym_count; i++)
+    *storage++ = (asymbol *) (info->canonical_dynsym + i);
+  *storage = NULL;
 
-static bfd_target *
-sunos4_callback (abfd)
-     bfd *abfd;
+  return info->dynsym_count;
+}
+
+/* Return the amount of memory required for the dynamic relocs.  */
+
+static long
+sunos_get_dynamic_reloc_upper_bound (bfd *abfd)
 {
-  struct exec *execp = exec_hdr (abfd);
+  struct sunos_dynamic_info *info;
 
-  /* The virtual memory addresses of the sections */
-  obj_datasec (abfd)->vma = N_DATADDR(*execp);
-  obj_bsssec (abfd)->vma = N_BSSADDR(*execp);
-  obj_textsec (abfd)->vma = N_TXTADDR(*execp);
+  if (! sunos_read_dynamic_info (abfd))
+    return -1;
 
-  /* The file offsets of the sections */
-  obj_textsec (abfd)->filepos = EXEC_BYTES_SIZE; /*N_TXTOFF(*execp);*/
-  obj_datasec (abfd)->filepos = N_DATOFF(*execp);
+  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+  if (! info->valid)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
 
-  /* The file offsets of the relocation info */
-  obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp);
-  obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp);
+  return (info->dynrel_count + 1) * sizeof (arelent *);
+}
 
-  /* The file offsets of the string table and symbol table.  */
-  obj_str_filepos (abfd) = N_STROFF (*execp);
-  obj_sym_filepos (abfd) = N_SYMOFF (*execp);
+/* Read in the dynamic relocs.  */
 
+static long
+sunos_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage, asymbol **syms)
+{
+  struct sunos_dynamic_info *info;
+  unsigned long i;
+  bfd_size_type size;
 
+  /* Get the general dynamic information.  */
+  if (obj_aout_dynamic_info (abfd) == NULL)
+    {
+      if (! sunos_read_dynamic_info (abfd))
+       return -1;
+    }
 
-  /* Determine the architecture and machine type of the object file.  */
-  switch (N_MACHTYPE (*exec_hdr (abfd))) {
+  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+  if (! info->valid)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
 
-  case M_UNKNOWN:
-       abfd->obj_arch = bfd_arch_unknown;
-       abfd->obj_machine = 0;
-       break;
+  /* Get the dynamic reloc information.  */
+  if (info->dynrel == NULL)
+    {
+      size = (bfd_size_type) info->dynrel_count * obj_reloc_entry_size (abfd);
+      info->dynrel = bfd_alloc (abfd, size);
+      if (info->dynrel == NULL && size != 0)
+       return -1;
+      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_rel, SEEK_SET) != 0
+         || bfd_bread ((void *) info->dynrel, size, abfd) != size)
+       {
+         if (info->dynrel != NULL)
+           {
+             bfd_release (abfd, info->dynrel);
+             info->dynrel = NULL;
+           }
+         return -1;
+       }
+    }
 
-  case M_68010:
-       abfd->obj_arch = bfd_arch_m68k;
-       abfd->obj_machine = 68010;
-       break;
+  /* Get the arelent structures corresponding to the dynamic reloc
+     information.  */
+  if (info->canonical_dynrel == NULL)
+    {
+      arelent *to;
+
+      size = (bfd_size_type) info->dynrel_count * sizeof (arelent);
+      info->canonical_dynrel = bfd_alloc (abfd, size);
+      if (info->canonical_dynrel == NULL && info->dynrel_count != 0)
+       return -1;
+
+      to = info->canonical_dynrel;
+
+      if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE)
+       {
+         struct reloc_ext_external *p;
+         struct reloc_ext_external *pend;
+
+         p = (struct reloc_ext_external *) info->dynrel;
+         pend = p + info->dynrel_count;
+         for (; p < pend; p++, to++)
+           NAME (aout, swap_ext_reloc_in) (abfd, p, to, syms,
+                                           (bfd_size_type) info->dynsym_count);
+       }
+      else
+       {
+         struct reloc_std_external *p;
+         struct reloc_std_external *pend;
+
+         p = (struct reloc_std_external *) info->dynrel;
+         pend = p + info->dynrel_count;
+         for (; p < pend; p++, to++)
+           NAME (aout, swap_std_reloc_in) (abfd, p, to, syms,
+                                           (bfd_size_type) info->dynsym_count);
+       }
+    }
 
-  case M_68020:
-       abfd->obj_arch = bfd_arch_m68k;
-       abfd->obj_machine = 68020;
-       break;
+  /* Return pointers to the dynamic arelent structures.  */
+  for (i = 0; i < info->dynrel_count; i++)
+    *storage++ = info->canonical_dynrel + i;
+  *storage = NULL;
 
-  case M_SPARC:
-       abfd->obj_arch = bfd_arch_sparc;
-       abfd->obj_machine = 0;
-       break;
+  return info->dynrel_count;
+}
+\f
+/* Code to handle linking of SunOS shared libraries.  */
 
-  case M_386:
-       abfd->obj_arch = bfd_arch_i386;
-       abfd->obj_machine = 0;
-       break;
+/* A SPARC procedure linkage table entry is 12 bytes.  The first entry
+   in the table is a jump which is filled in by the runtime linker.
+   The remaining entries are branches back to the first entry,
+   followed by an index into the relocation table encoded to look like
+   a sethi of %g0.  */
 
-  case M_29K:
-       abfd->obj_arch = bfd_arch_a29k;
-       abfd->obj_machine = 0;
-       break;
+#define SPARC_PLT_ENTRY_SIZE (12)
 
-  default:
-       abfd->obj_arch = bfd_arch_obscure;
-       abfd->obj_machine = 0;
-       break;
-  }
+static const bfd_byte sparc_plt_first_entry[SPARC_PLT_ENTRY_SIZE] =
+{
+  /* sethi %hi(0),%g1; address filled in by runtime linker.  */
+  0x3, 0, 0, 0,
+  /* jmp %g1; offset filled in by runtime linker.  */
+  0x81, 0xc0, 0x60, 0,
+  /* nop */
+  0x1, 0, 0, 0
+};
 
-  choose_reloc_size(abfd);
-  return abfd->xvec;
-}
+/* save %sp, -96, %sp */
+#define SPARC_PLT_ENTRY_WORD0 ((bfd_vma) 0x9de3bfa0)
+/* call; address filled in later.  */
+#define SPARC_PLT_ENTRY_WORD1 ((bfd_vma) 0x40000000)
+/* sethi; reloc index filled in later.  */
+#define SPARC_PLT_ENTRY_WORD2 ((bfd_vma) 0x01000000)
+
+/* This sequence is used when for the jump table entry to a defined
+   symbol in a complete executable.  It is used when linking PIC
+   compiled code which is not being put into a shared library.  */
+/* sethi <address to be filled in later>, %g1 */
+#define SPARC_PLT_PIC_WORD0 ((bfd_vma) 0x03000000)
+/* jmp %g1 + <address to be filled in later> */
+#define SPARC_PLT_PIC_WORD1 ((bfd_vma) 0x81c06000)
+/* nop */
+#define SPARC_PLT_PIC_WORD2 ((bfd_vma) 0x01000000)
+
+/* An m68k procedure linkage table entry is 8 bytes.  The first entry
+   in the table is a jump which is filled in the by the runtime
+   linker.  The remaining entries are branches back to the first
+   entry, followed by a two byte index into the relocation table.  */
+
+#define M68K_PLT_ENTRY_SIZE (8)
+
+static const bfd_byte m68k_plt_first_entry[M68K_PLT_ENTRY_SIZE] =
+{
+  /* jmps @# */
+  0x4e, 0xf9,
+  /* Filled in by runtime linker with a magic address.  */
+  0, 0, 0, 0,
+  /* Not used?  */
+  0, 0
+};
 
+/* bsrl */
+#define M68K_PLT_ENTRY_WORD0 ((bfd_vma) 0x61ff)
+/* Remaining words filled in later.  */
 
-boolean
-sunos4_mkobject (abfd)
-     bfd *abfd;
+/* An entry in the SunOS linker hash table.  */
+
+struct sunos_link_hash_entry
 {
-  char *rawptr;
+  struct aout_link_hash_entry root;
+
+  /* If this is a dynamic symbol, this is its index into the dynamic
+     symbol table.  This is initialized to -1.  As the linker looks at
+     the input files, it changes this to -2 if it will be added to the
+     dynamic symbol table.  After all the input files have been seen,
+     the linker will know whether to build a dynamic symbol table; if
+     it does build one, this becomes the index into the table.  */
+  long dynindx;
+
+  /* If this is a dynamic symbol, this is the index of the name in the
+     dynamic symbol string table.  */
+  long dynstr_index;
+
+  /* The offset into the global offset table used for this symbol.  If
+     the symbol does not require a GOT entry, this is 0.  */
+  bfd_vma got_offset;
+
+  /* The offset into the procedure linkage table used for this symbol.
+     If the symbol does not require a PLT entry, this is 0.  */
+  bfd_vma plt_offset;
+
+  /* Some linker flags.  */
+  unsigned char flags;
+  /* Symbol is referenced by a regular object.  */
+#define SUNOS_REF_REGULAR 01
+  /* Symbol is defined by a regular object.  */
+#define SUNOS_DEF_REGULAR 02
+  /* Symbol is referenced by a dynamic object.  */
+#define SUNOS_REF_DYNAMIC 04
+  /* Symbol is defined by a dynamic object.  */
+#define SUNOS_DEF_DYNAMIC 010
+  /* Symbol is a constructor symbol in a regular object.  */
+#define SUNOS_CONSTRUCTOR 020
+};
 
-  bfd_error = system_call_error;
+/* The SunOS linker hash table.  */
 
-  /* Use an intermediate variable for clarity */
-  rawptr = bfd_zalloc (abfd, sizeof (struct aoutdata) + sizeof (struct exec));
+struct sunos_link_hash_table
+{
+  struct aout_link_hash_table root;
 
-  if (rawptr == NULL) {
-    bfd_error = no_memory;
-    return false;
-  }
+  /* The object which holds the dynamic sections.  */
+  bfd *dynobj;
 
-  set_tdata (abfd, (struct aoutdata *) rawptr);
-  exec_hdr (abfd) = (struct exec *) (rawptr + sizeof (struct aoutdata));
+  /* Whether we have created the dynamic sections.  */
+  bfd_boolean dynamic_sections_created;
 
-  /* For simplicity's sake we just make all the sections right here. */
+  /* Whether we need the dynamic sections.  */
+  bfd_boolean dynamic_sections_needed;
 
-  obj_textsec (abfd) = (asection *)NULL;
-  obj_datasec (abfd) = (asection *)NULL;
-  obj_bsssec (abfd) = (asection *)NULL;
-  bfd_make_section (abfd, ".text");
-  bfd_make_section (abfd, ".data");
-  bfd_make_section (abfd, ".bss");
+  /* Whether we need the .got table.  */
+  bfd_boolean got_needed;
 
-  return true;
-}
+  /* The number of dynamic symbols.  */
+  size_t dynsymcount;
 
-/* Keep track of machine architecture and machine type for a.out's.
-   Return the machine_type for a particular arch&machine, or M_UNKNOWN
-   if that exact arch&machine can't be represented in a.out format.
+  /* The number of buckets in the hash table.  */
+  size_t bucketcount;
 
-   If the architecture is understood, machine type 0 (default) should
-   always be understood.  */
+  /* The list of dynamic objects needed by dynamic objects included in
+     the link.  */
+  struct bfd_link_needed_list *needed;
 
-static enum machine_type
-aout_machine_type (arch, machine)
-     enum bfd_architecture arch;
-     unsigned long machine;
+  /* The offset of __GLOBAL_OFFSET_TABLE_ into the .got section.  */
+  bfd_vma got_base;
+};
+
+/* Routine to create an entry in an SunOS link hash table.  */
+
+static struct bfd_hash_entry *
+sunos_link_hash_newfunc (struct bfd_hash_entry *entry,
+                        struct bfd_hash_table *table,
+                        const char *string)
 {
-  enum machine_type arch_flags;
+  struct sunos_link_hash_entry *ret = (struct sunos_link_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret ==  NULL)
+    ret = bfd_hash_allocate (table, sizeof (* ret));
+  if (ret == NULL)
+    return NULL;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct sunos_link_hash_entry *)
+        NAME (aout, link_hash_newfunc) ((struct bfd_hash_entry *) ret,
+                                        table, string));
+  if (ret != NULL)
+    {
+      /* Set local fields.  */
+      ret->dynindx = -1;
+      ret->dynstr_index = -1;
+      ret->got_offset = 0;
+      ret->plt_offset = 0;
+      ret->flags = 0;
+    }
 
-  arch_flags = M_UNKNOWN;
+  return (struct bfd_hash_entry *) ret;
+}
 
-  switch (arch) {
-  case bfd_arch_sparc:
-    if (machine == 0)  arch_flags = M_SPARC;
-    break;
+/* Create a SunOS link hash table.  */
 
-  case bfd_arch_m68k:
-    switch (machine) {
-    case 0:            arch_flags = M_68010; break;
-    case 68000:                arch_flags = M_UNKNOWN; break;
-    case 68010:                arch_flags = M_68010; break;
-    case 68020:                arch_flags = M_68020; break;
-    default:           arch_flags = M_UNKNOWN; break;
+static struct bfd_link_hash_table *
+sunos_link_hash_table_create (bfd *abfd)
+{
+  struct sunos_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct sunos_link_hash_table);
+
+  ret = bfd_malloc (amt);
+  if (ret ==  NULL)
+    return NULL;
+  if (!NAME (aout, link_hash_table_init) (&ret->root, abfd,
+                                         sunos_link_hash_newfunc,
+                                         sizeof (struct sunos_link_hash_entry)))
+    {
+      free (ret);
+      return NULL;
     }
-    break;
 
-  case bfd_arch_i386:
-    if (machine == 0)  arch_flags = M_386;
-    break;
+  ret->dynobj = NULL;
+  ret->dynamic_sections_created = FALSE;
+  ret->dynamic_sections_needed = FALSE;
+  ret->got_needed = FALSE;
+  ret->dynsymcount = 0;
+  ret->bucketcount = 0;
+  ret->needed = NULL;
+  ret->got_base = 0;
 
-  case bfd_arch_a29k:
-    if (machine == 0)  arch_flags = M_29K;
-    break;
+  return &ret->root.root;
+}
 
-  default:
-    arch_flags = M_UNKNOWN;
-    break;
-  }
-  return arch_flags;
+/* Look up an entry in an SunOS link hash table.  */
+
+#define sunos_link_hash_lookup(table, string, create, copy, follow) \
+  ((struct sunos_link_hash_entry *) \
+   aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\
+                         (follow)))
+
+/* Traverse a SunOS link hash table.  */
+
+#define sunos_link_hash_traverse(table, func, info)                    \
+  (aout_link_hash_traverse                                             \
+   (&(table)->root,                                                    \
+    (bfd_boolean (*) (struct aout_link_hash_entry *, void *)) (func),  \
+    (info)))
+
+/* Get the SunOS link hash table from the info structure.  This is
+   just a cast.  */
+
+#define sunos_hash_table(p) ((struct sunos_link_hash_table *) ((p)->hash))
+
+/* Create the dynamic sections needed if we are linking against a
+   dynamic object, or if we are linking PIC compiled code.  ABFD is a
+   bfd we can attach the dynamic sections to.  The linker script will
+   look for these special sections names and put them in the right
+   place in the output file.  See include/aout/sun4.h for more details
+   of the dynamic linking information.  */
+
+static bfd_boolean
+sunos_create_dynamic_sections (bfd *abfd,
+                              struct bfd_link_info *info,
+                              bfd_boolean needed)
+{
+  asection *s;
+
+  if (! sunos_hash_table (info)->dynamic_sections_created)
+    {
+      flagword flags;
+
+      sunos_hash_table (info)->dynobj = abfd;
+
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+              | SEC_LINKER_CREATED);
+
+      /* The .dynamic section holds the basic dynamic information: the
+        sun4_dynamic structure, the dynamic debugger information, and
+        the sun4_dynamic_link structure.  */
+      s = bfd_make_section_with_flags (abfd, ".dynamic", flags);
+      if (s == NULL
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return FALSE;
+
+      /* The .got section holds the global offset table.  The address
+        is put in the ld_got field.  */
+      s = bfd_make_section_with_flags (abfd, ".got", flags);
+      if (s == NULL
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return FALSE;
+
+      /* The .plt section holds the procedure linkage table.  The
+        address is put in the ld_plt field.  */
+      s = bfd_make_section_with_flags (abfd, ".plt", flags | SEC_CODE);
+      if (s == NULL
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return FALSE;
+
+      /* The .dynrel section holds the dynamic relocs.  The address is
+        put in the ld_rel field.  */
+      s = bfd_make_section_with_flags (abfd, ".dynrel", flags | SEC_READONLY);
+      if (s == NULL
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return FALSE;
+
+      /* The .hash section holds the dynamic hash table.  The address
+        is put in the ld_hash field.  */
+      s = bfd_make_section_with_flags (abfd, ".hash", flags | SEC_READONLY);
+      if (s == NULL
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return FALSE;
+
+      /* The .dynsym section holds the dynamic symbols.  The address
+        is put in the ld_stab field.  */
+      s = bfd_make_section_with_flags (abfd, ".dynsym", flags | SEC_READONLY);
+      if (s == NULL
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return FALSE;
+
+      /* The .dynstr section holds the dynamic symbol string table.
+        The address is put in the ld_symbols field.  */
+      s = bfd_make_section_with_flags (abfd, ".dynstr", flags | SEC_READONLY);
+      if (s == NULL
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return FALSE;
+
+      sunos_hash_table (info)->dynamic_sections_created = TRUE;
+    }
+
+  if ((needed && ! sunos_hash_table (info)->dynamic_sections_needed)
+      || info->shared)
+    {
+      bfd *dynobj;
+
+      dynobj = sunos_hash_table (info)->dynobj;
+
+      s = bfd_get_section_by_name (dynobj, ".got");
+      if (s->size == 0)
+       s->size = BYTES_IN_WORD;
+
+      sunos_hash_table (info)->dynamic_sections_needed = TRUE;
+      sunos_hash_table (info)->got_needed = TRUE;
+    }
+
+  return TRUE;
 }
 
-/* Write an object file in SunOS format.
-   Section contents have already been written.  We write the
-   file header, symbols, and relocation.  */
+/* Add dynamic symbols during a link.  This is called by the a.out
+   backend linker for each object it encounters.  */
 
-boolean
-sunos4_write_object_contents (abfd)
-     bfd *abfd;
+static bfd_boolean
+sunos_add_dynamic_symbols (bfd *abfd,
+                          struct bfd_link_info *info,
+                          struct external_nlist **symsp,
+                          bfd_size_type *sym_countp,
+                          char **stringsp)
 {
-  size_t data_pad = 0;
-  unsigned char exec_bytes[EXEC_BYTES_SIZE];
-  struct exec *execp = exec_hdr (abfd);
+  bfd *dynobj;
+  struct sunos_dynamic_info *dinfo;
+  unsigned long need;
 
+  /* Make sure we have all the required sections.  */
+  if (info->output_bfd->xvec == abfd->xvec)
+    {
+      if (! sunos_create_dynamic_sections (abfd, info,
+                                          ((abfd->flags & DYNAMIC) != 0
+                                           && !info->relocatable)))
+       return FALSE;
+    }
 
+  /* There is nothing else to do for a normal object.  */
+  if ((abfd->flags & DYNAMIC) == 0)
+    return TRUE;
+
+  dynobj = sunos_hash_table (info)->dynobj;
+
+  /* We do not want to include the sections in a dynamic object in the
+     output file.  We hack by simply clobbering the list of sections
+     in the BFD.  This could be handled more cleanly by, say, a new
+     section flag; the existing SEC_NEVER_LOAD flag is not the one we
+     want, because that one still implies that the section takes up
+     space in the output file.  If this is the first object we have
+     seen, we must preserve the dynamic sections we just created.  */
+  if (abfd != dynobj)
+    abfd->sections = NULL;
+  else
+    {
+      asection *s;
 
-  execp->a_text = obj_textsec (abfd)->size;
+      for (s = abfd->sections; s != NULL; s = s->next)
+       {
+         if ((s->flags & SEC_LINKER_CREATED) == 0)
+           bfd_section_list_remove (abfd, s);
+       }
+    }
 
-  /* Magic number, maestro, please!  */
-  switch (bfd_get_architecture(abfd)) {
-  case bfd_arch_m68k:
-    switch (bfd_get_machine(abfd)) {
-    case 68010:
-      N_SET_MACHTYPE(*execp, M_68010);
-      break;
-    default:
-    case 68020:
-      N_SET_MACHTYPE(*execp, M_68020);
-      break;
+  /* The native linker seems to just ignore dynamic objects when -r is
+     used.  */
+  if (info->relocatable)
+    return TRUE;
+
+  /* There's no hope of using a dynamic object which does not exactly
+     match the format of the output file.  */
+  if (info->output_bfd->xvec != abfd->xvec)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return FALSE;
     }
-    break;
-  case bfd_arch_sparc:
-    N_SET_MACHTYPE(*execp, M_SPARC);
-    break;
-  case bfd_arch_i386:
-    N_SET_MACHTYPE(*execp, M_386);
-    break;
-  case bfd_arch_a29k:
-    N_SET_MACHTYPE(*execp, M_29K);
-    break;
-  default:
-    N_SET_MACHTYPE(*execp, M_UNKNOWN);
-  }
 
-  choose_reloc_size(abfd);
-
-  N_SET_MAGIC (*execp, OMAGIC);
-  if (abfd->flags & D_PAGED) {
-    /* This is not strictly true, but will probably do for the default
-       case.  FIXME.  
-       */
-    /* Also the size has already had the sizeof the header taken into
-       account. It may be wrong for the application to have to do this
-       (though this is what sizeof_headers is for), but it's the way
-       it is, so that's the way it will stay for the moment.*/
-    execp->a_text = obj_textsec (abfd)->size ; /*+ sizeof(struct exec);*/
-    N_SET_MAGIC (*execp, ZMAGIC);
-  } else if (abfd->flags & WP_TEXT) {
-    N_SET_MAGIC (*execp, NMAGIC);
-  }
-  N_SET_FLAGS (*execp, 0x1);   /* copied from ld.c; who the hell knows? */
+  /* Make sure we have a .need and a .rules sections.  These are only
+     needed if there really is a dynamic object in the link, so they
+     are not added by sunos_create_dynamic_sections.  */
+  if (bfd_get_section_by_name (dynobj, ".need") == NULL)
+    {
+      /* The .need section holds the list of names of shared objets
+        which must be included at runtime.  The address of this
+        section is put in the ld_need field.  */
+      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                       | SEC_IN_MEMORY | SEC_READONLY);
+      asection *s = bfd_make_section_with_flags (dynobj, ".need", flags);
+      if (s == NULL
+         || ! bfd_set_section_alignment (dynobj, s, 2))
+       return FALSE;
+    }
 
-  if (abfd->flags & D_PAGED) 
-      {
-       data_pad = ((obj_datasec(abfd)->size + PAGE_SIZE -1)
-                   & (- PAGE_SIZE)) - obj_datasec(abfd)->size;
+  if (bfd_get_section_by_name (dynobj, ".rules") == NULL)
+    {
+      /* The .rules section holds the path to search for shared
+        objects.  The address of this section is put in the ld_rules
+        field.  */
+      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                       | SEC_IN_MEMORY | SEC_READONLY);
+      asection *s = bfd_make_section_with_flags (dynobj, ".rules", flags);
+      if (s == NULL
+         || ! bfd_set_section_alignment (dynobj, s, 2))
+       return FALSE;
+    }
 
-       if (data_pad > obj_bsssec(abfd)->size)
-         execp->a_bss = 0;
-       else 
-         execp->a_bss = obj_bsssec(abfd)->size - data_pad;
-       execp->a_data = obj_datasec(abfd)->size + data_pad;
+  /* Pick up the dynamic symbols and return them to the caller.  */
+  if (! sunos_slurp_dynamic_symtab (abfd))
+    return FALSE;
 
-      }
-  else {
-    execp->a_data = obj_datasec (abfd)->size;
-    execp->a_bss = obj_bsssec (abfd)->size;
-  }
+  dinfo = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+  *symsp = dinfo->dynsym;
+  *sym_countp = dinfo->dynsym_count;
+  *stringsp = dinfo->dynstr;
 
-  execp->a_syms = bfd_get_symcount (abfd) * sizeof (struct nlist);
-  execp->a_entry = bfd_get_start_address (abfd);
+  /* Record information about any other objects needed by this one.  */
+  need = dinfo->dyninfo.ld_need;
+  while (need != 0)
+    {
+      bfd_byte buf[16];
+      unsigned long name, flags;
+      unsigned short major_vno, minor_vno;
+      struct bfd_link_needed_list *needed, **pp;
+      char *namebuf, *p;
+      bfd_size_type alc;
+      bfd_byte b;
+      char *namecopy;
+
+      if (bfd_seek (abfd, (file_ptr) need, SEEK_SET) != 0
+         || bfd_bread (buf, (bfd_size_type) 16, abfd) != 16)
+       return FALSE;
+
+      /* For the format of an ld_need entry, see aout/sun4.h.  We
+        should probably define structs for this manipulation.  */
+      name = bfd_get_32 (abfd, buf);
+      flags = bfd_get_32 (abfd, buf + 4);
+      major_vno = (unsigned short) bfd_get_16 (abfd, buf + 8);
+      minor_vno = (unsigned short) bfd_get_16 (abfd, buf + 10);
+      need = bfd_get_32 (abfd, buf + 12);
+
+      alc = sizeof (struct bfd_link_needed_list);
+      needed = bfd_alloc (abfd, alc);
+      if (needed == NULL)
+       return FALSE;
+      needed->by = abfd;
+
+      /* We return the name as [-l]name[.maj][.min].  */
+      alc = 30;
+      namebuf = bfd_malloc (alc + 1);
+      if (namebuf == NULL)
+       return FALSE;
+      p = namebuf;
+
+      if ((flags & 0x80000000) != 0)
+       {
+         *p++ = '-';
+         *p++ = 'l';
+       }
+      if (bfd_seek (abfd, (file_ptr) name, SEEK_SET) != 0)
+       {
+         free (namebuf);
+         return FALSE;
+       }
+
+      do
+       {
+         if (bfd_bread (&b, (bfd_size_type) 1, abfd) != 1)
+           {
+             free (namebuf);
+             return FALSE;
+           }
+
+         if ((bfd_size_type) (p - namebuf) >= alc)
+           {
+             char *n;
+
+             alc *= 2;
+             n = bfd_realloc (namebuf, alc + 1);
+             if (n == NULL)
+               {
+                 free (namebuf);
+                 return FALSE;
+               }
+             p = n + (p - namebuf);
+             namebuf = n;
+           }
+
+         *p++ = b;
+       }
+      while (b != '\0');
+
+      if (major_vno == 0)
+       *p = '\0';
+      else
+       {
+         char majbuf[30];
+         char minbuf[30];
+
+         sprintf (majbuf, ".%d", major_vno);
+         if (minor_vno == 0)
+           minbuf[0] = '\0';
+         else
+           sprintf (minbuf, ".%d", minor_vno);
+
+         if ((p - namebuf) + strlen (majbuf) + strlen (minbuf) >= alc)
+           {
+             char *n;
+
+             alc = (p - namebuf) + strlen (majbuf) + strlen (minbuf);
+             n = bfd_realloc (namebuf, alc + 1);
+             if (n == NULL)
+               {
+                 free (namebuf);
+                 return FALSE;
+               }
+             p = n + (p - namebuf);
+             namebuf = n;
+           }
+
+         strcpy (p, majbuf);
+         strcat (p, minbuf);
+       }
+
+      namecopy = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1);
+      if (namecopy == NULL)
+       {
+         free (namebuf);
+         return FALSE;
+       }
+      strcpy (namecopy, namebuf);
+      free (namebuf);
+      needed->name = namecopy;
+
+      needed->next = NULL;
+
+      for (pp = &sunos_hash_table (info)->needed;
+          *pp != NULL;
+          pp = &(*pp)->next)
+       ;
+      *pp = needed;
+    }
+
+  return TRUE;
+}
 
+/* Function to add a single symbol to the linker hash table.  This is
+   a wrapper around _bfd_generic_link_add_one_symbol which handles the
+   tweaking needed for dynamic linking support.  */
+
+static bfd_boolean
+sunos_add_one_symbol (struct bfd_link_info *info,
+                     bfd *abfd,
+                     const char *name,
+                     flagword flags,
+                     asection *section,
+                     bfd_vma value,
+                     const char *string,
+                     bfd_boolean copy,
+                     bfd_boolean collect,
+                     struct bfd_link_hash_entry **hashp)
+{
+  struct sunos_link_hash_entry *h;
+  int new_flag;
+
+  if ((flags & (BSF_INDIRECT | BSF_WARNING | BSF_CONSTRUCTOR)) != 0
+      || ! bfd_is_und_section (section))
+    h = sunos_link_hash_lookup (sunos_hash_table (info), name, TRUE, copy,
+                               FALSE);
+  else
+    h = ((struct sunos_link_hash_entry *)
+        bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, copy, FALSE));
+  if (h == NULL)
+    return FALSE;
+
+  if (hashp != NULL)
+    *hashp = (struct bfd_link_hash_entry *) h;
+
+  /* Treat a common symbol in a dynamic object as defined in the .bss
+     section of the dynamic object.  We don't want to allocate space
+     for it in our process image.  */
+  if ((abfd->flags & DYNAMIC) != 0
+      && bfd_is_com_section (section))
+    section = obj_bsssec (abfd);
+
+  if (! bfd_is_und_section (section)
+      && h->root.root.type != bfd_link_hash_new
+      && h->root.root.type != bfd_link_hash_undefined
+      && h->root.root.type != bfd_link_hash_defweak)
+    {
+      /* We are defining the symbol, and it is already defined.  This
+        is a potential multiple definition error.  */
+      if ((abfd->flags & DYNAMIC) != 0)
+       {
+         /* The definition we are adding is from a dynamic object.
+            We do not want this new definition to override the
+            existing definition, so we pretend it is just a
+            reference.  */
+         section = bfd_und_section_ptr;
+       }
+      else if (h->root.root.type == bfd_link_hash_defined
+              && h->root.root.u.def.section->owner != NULL
+              && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
+       {
+         /* The existing definition is from a dynamic object.  We
+            want to override it with the definition we just found.
+            Clobber the existing definition.  */
+         h->root.root.type = bfd_link_hash_undefined;
+         h->root.root.u.undef.abfd = h->root.root.u.def.section->owner;
+       }
+      else if (h->root.root.type == bfd_link_hash_common
+              && (h->root.root.u.c.p->section->owner->flags & DYNAMIC) != 0)
+       {
+         /* The existing definition is from a dynamic object.  We
+            want to override it with the definition we just found.
+            Clobber the existing definition.  We can't set it to new,
+            because it is on the undefined list.  */
+         h->root.root.type = bfd_link_hash_undefined;
+         h->root.root.u.undef.abfd = h->root.root.u.c.p->section->owner;
+       }
+    }
 
+  if ((abfd->flags & DYNAMIC) != 0
+      && abfd->xvec == info->output_bfd->xvec
+      && (h->flags & SUNOS_CONSTRUCTOR) != 0)
+    /* The existing symbol is a constructor symbol, and this symbol
+       is from a dynamic object.  A constructor symbol is actually a
+       definition, although the type will be bfd_link_hash_undefined
+       at this point.  We want to ignore the definition from the
+       dynamic object.  */
+    section = bfd_und_section_ptr;
+  else if ((flags & BSF_CONSTRUCTOR) != 0
+          && (abfd->flags & DYNAMIC) == 0
+          && h->root.root.type == bfd_link_hash_defined
+          && h->root.root.u.def.section->owner != NULL
+          && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
+    /* The existing symbol is defined by a dynamic object, and this
+       is a constructor symbol.  As above, we want to force the use
+       of the constructor symbol from the regular object.  */
+    h->root.root.type = bfd_link_hash_new;
+
+  /* Do the usual procedure for adding a symbol.  */
+  if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section,
+                                         value, string, copy, collect,
+                                         hashp))
+    return FALSE;
+
+  if (abfd->xvec == info->output_bfd->xvec)
+    {
+      /* Set a flag in the hash table entry indicating the type of
+        reference or definition we just found.  Keep a count of the
+        number of dynamic symbols we find.  A dynamic symbol is one
+        which is referenced or defined by both a regular object and a
+        shared object.  */
+      if ((abfd->flags & DYNAMIC) == 0)
+       {
+         if (bfd_is_und_section (section))
+           new_flag = SUNOS_REF_REGULAR;
+         else
+           new_flag = SUNOS_DEF_REGULAR;
+       }
+      else
+       {
+         if (bfd_is_und_section (section))
+           new_flag = SUNOS_REF_DYNAMIC;
+         else
+           new_flag = SUNOS_DEF_DYNAMIC;
+       }
+      h->flags |= new_flag;
+
+      if (h->dynindx == -1
+         && (h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0)
+       {
+         ++sunos_hash_table (info)->dynsymcount;
+         h->dynindx = -2;
+       }
+
+      if ((flags & BSF_CONSTRUCTOR) != 0
+         && (abfd->flags & DYNAMIC) == 0)
+       h->flags |= SUNOS_CONSTRUCTOR;
+    }
 
+  return TRUE;
+}
 
-  execp->a_trsize = ((obj_textsec (abfd)->reloc_count) *
-                    obj_reloc_entry_size (abfd));
-                      
-  execp->a_drsize = ((obj_datasec (abfd)->reloc_count) *
-                    obj_reloc_entry_size (abfd));
+extern const bfd_target MY (vec);
 
-  bfd_aout_swap_exec_header_out (abfd, execp, exec_bytes);
+/* Return the list of objects needed by BFD.  */
 
-  bfd_seek (abfd, 0L, false);
-  bfd_write ((PTR) exec_bytes, 1, EXEC_BYTES_SIZE, abfd);
+struct bfd_link_needed_list *
+bfd_sunos_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED,
+                          struct bfd_link_info *info)
+{
+  if (info->output_bfd->xvec != &MY (vec))
+    return NULL;
+  return sunos_hash_table (info)->needed;
+}
 
-  /* Now write out reloc info, followed by syms and strings */
+/* Record an assignment made to a symbol by a linker script.  We need
+   this in case some dynamic object refers to this symbol.  */
 
-  if (bfd_get_symcount (abfd) != 0) 
+bfd_boolean
+bfd_sunos_record_link_assignment (bfd *output_bfd,
+                                 struct bfd_link_info *info,
+                                 const char *name)
+{
+  struct sunos_link_hash_entry *h;
+
+  if (output_bfd->xvec != &MY(vec))
+    return TRUE;
+
+  /* This is called after we have examined all the input objects.  If
+     the symbol does not exist, it merely means that no object refers
+     to it, and we can just ignore it at this point.  */
+  h = sunos_link_hash_lookup (sunos_hash_table (info), name,
+                             FALSE, FALSE, FALSE);
+  if (h == NULL)
+    return TRUE;
+
+  /* In a shared library, the __DYNAMIC symbol does not appear in the
+     dynamic symbol table.  */
+  if (! info->shared || strcmp (name, "__DYNAMIC") != 0)
     {
-      bfd_seek (abfd,
-               (long)(N_SYMOFF(*execp)), false);
+      h->flags |= SUNOS_DEF_REGULAR;
 
-      aout_write_syms (abfd);
+      if (h->dynindx == -1)
+       {
+         ++sunos_hash_table (info)->dynsymcount;
+         h->dynindx = -2;
+       }
+    }
 
-      bfd_seek (abfd,  (long)(N_TRELOFF(*execp)), false);
+  return TRUE;
+}
 
-      if (!aout_squirt_out_relocs (abfd, obj_textsec (abfd))) return false;
-      bfd_seek (abfd, (long)(N_DRELOFF(*execp)), false);
+/* Scan the relocs for an input section using standard relocs.  We
+   need to figure out what to do for each reloc against a dynamic
+   symbol.  If the symbol is in the .text section, an entry is made in
+   the procedure linkage table.  Note that this will do the wrong
+   thing if the symbol is actually data; I don't think the Sun 3
+   native linker handles this case correctly either.  If the symbol is
+   not in the .text section, we must preserve the reloc as a dynamic
+   reloc.  FIXME: We should also handle the PIC relocs here by
+   building global offset table entries.  */
+
+static bfd_boolean
+sunos_scan_std_relocs (struct bfd_link_info *info,
+                      bfd *abfd,
+                      asection *sec ATTRIBUTE_UNUSED,
+                      const struct reloc_std_external *relocs,
+                      bfd_size_type rel_size)
+{
+  bfd *dynobj;
+  asection *splt = NULL;
+  asection *srel = NULL;
+  struct sunos_link_hash_entry **sym_hashes;
+  const struct reloc_std_external *rel, *relend;
+
+  /* We only know how to handle m68k plt entries.  */
+  if (bfd_get_arch (abfd) != bfd_arch_m68k)
+    {
+      bfd_set_error (bfd_error_invalid_target);
+      return FALSE;
+    }
+
+  dynobj = NULL;
 
-      if (!aout_squirt_out_relocs (abfd, obj_datasec (abfd))) return false;
+  sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd);
+
+  relend = relocs + rel_size / RELOC_STD_SIZE;
+  for (rel = relocs; rel < relend; rel++)
+    {
+      int r_index;
+      struct sunos_link_hash_entry *h;
+
+      /* We only want relocs against external symbols.  */
+      if (bfd_header_big_endian (abfd))
+       {
+         if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG) == 0)
+           continue;
+       }
+      else
+       {
+         if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE) == 0)
+           continue;
+       }
+
+      /* Get the symbol index.  */
+      if (bfd_header_big_endian (abfd))
+       r_index = ((rel->r_index[0] << 16)
+                  | (rel->r_index[1] << 8)
+                  | rel->r_index[2]);
+      else
+       r_index = ((rel->r_index[2] << 16)
+                  | (rel->r_index[1] << 8)
+                  | rel->r_index[0]);
+
+      /* Get the hash table entry.  */
+      h = sym_hashes[r_index];
+      if (h == NULL)
+       /* This should not normally happen, but it will in any case
+          be caught in the relocation phase.  */
+       continue;
+
+      /* At this point common symbols have already been allocated, so
+        we don't have to worry about them.  We need to consider that
+        we may have already seen this symbol and marked it undefined;
+        if the symbol is really undefined, then SUNOS_DEF_DYNAMIC
+        will be zero.  */
+      if (h->root.root.type != bfd_link_hash_defined
+         && h->root.root.type != bfd_link_hash_defweak
+         && h->root.root.type != bfd_link_hash_undefined)
+       continue;
+
+      if ((h->flags & SUNOS_DEF_DYNAMIC) == 0
+         || (h->flags & SUNOS_DEF_REGULAR) != 0)
+       continue;
+
+      if (dynobj == NULL)
+       {
+         asection *sgot;
+
+         if (! sunos_create_dynamic_sections (abfd, info, FALSE))
+           return FALSE;
+         dynobj = sunos_hash_table (info)->dynobj;
+         splt = bfd_get_section_by_name (dynobj, ".plt");
+         srel = bfd_get_section_by_name (dynobj, ".dynrel");
+         BFD_ASSERT (splt != NULL && srel != NULL);
+
+         sgot = bfd_get_section_by_name (dynobj, ".got");
+         BFD_ASSERT (sgot != NULL);
+         if (sgot->size == 0)
+           sgot->size = BYTES_IN_WORD;
+         sunos_hash_table (info)->got_needed = TRUE;
+       }
+
+      BFD_ASSERT ((h->flags & SUNOS_REF_REGULAR) != 0);
+      BFD_ASSERT (h->plt_offset != 0
+                 || ((h->root.root.type == bfd_link_hash_defined
+                      || h->root.root.type == bfd_link_hash_defweak)
+                     ? (h->root.root.u.def.section->owner->flags
+                        & DYNAMIC) != 0
+                     : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0));
+
+      /* This reloc is against a symbol defined only by a dynamic
+        object.  */
+      if (h->root.root.type == bfd_link_hash_undefined)
+       /* Presumably this symbol was marked as being undefined by
+          an earlier reloc.  */
+       srel->size += RELOC_STD_SIZE;
+      else if ((h->root.root.u.def.section->flags & SEC_CODE) == 0)
+       {
+         bfd *sub;
+
+         /* This reloc is not in the .text section.  It must be
+            copied into the dynamic relocs.  We mark the symbol as
+            being undefined.  */
+         srel->size += RELOC_STD_SIZE;
+         sub = h->root.root.u.def.section->owner;
+         h->root.root.type = bfd_link_hash_undefined;
+         h->root.root.u.undef.abfd = sub;
+       }
+      else
+       {
+         /* This symbol is in the .text section.  We must give it an
+            entry in the procedure linkage table, if we have not
+            already done so.  We change the definition of the symbol
+            to the .plt section; this will cause relocs against it to
+            be handled correctly.  */
+         if (h->plt_offset == 0)
+           {
+             if (splt->size == 0)
+               splt->size = M68K_PLT_ENTRY_SIZE;
+             h->plt_offset = splt->size;
+
+             if ((h->flags & SUNOS_DEF_REGULAR) == 0)
+               {
+                 h->root.root.u.def.section = splt;
+                 h->root.root.u.def.value = splt->size;
+               }
+
+             splt->size += M68K_PLT_ENTRY_SIZE;
+
+             /* We may also need a dynamic reloc entry.  */
+             if ((h->flags & SUNOS_DEF_REGULAR) == 0)
+               srel->size += RELOC_STD_SIZE;
+           }
+       }
     }
-  return true;
+
+  return TRUE;
 }
-\f
-/* core files */
-
-#define CORE_MAGIC 0x080456
-#define CORE_NAMELEN 16
-
-/* The core structure is taken from the Sun documentation.
-   Unfortunately, they don't document the FPA structure, or at least I
-   can't find it easily.  Fortunately the core header contains its own
-   length.  So this shouldn't cause problems, except for c_ucode, which
-   so far we don't use but is easy to find with a little arithmetic. */
-
-/* But the reg structure can be gotten from the SPARC processor handbook.
-   This really should be in a GNU include file though so that gdb can use
-   the same info. */
-struct regs {
-  int r_psr;
-  int r_pc;
-  int r_npc;
-  int r_y;
-  int r_g1;
-  int r_g2;
-  int r_g3;
-  int r_g4;
-  int r_g5;
-  int r_g6;
-  int r_g7;
-  int r_o0;
-  int r_o1;
-  int r_o2;
-  int r_o3;
-  int r_o4;
-  int r_o5;
-  int r_o6;
-  int r_o7;
-};
 
-/* Taken from Sun documentation: */
-
-/* FIXME:  It's worse than we expect.  This struct contains TWO substructs
-   neither of whose size we know, WITH STUFF IN BETWEEN THEM!  We can't
-   even portably access the stuff in between!  */
-
-struct core {
-  int c_magic;                 /* Corefile magic number */
-  int c_len;                   /* Sizeof (struct core) */
-  struct regs c_regs;          /* General purpose registers -- MACHDEP SIZE */
-  struct exec c_aouthdr;       /* A.out header */
-  int c_signo;                 /* Killing signal, if any */
-  int c_tsize;                 /* Text size (bytes) */
-  int c_dsize;                 /* Data size (bytes) */
-  int c_ssize;                 /* Stack size (bytes) */
-  char c_cmdname[CORE_NAMELEN + 1]; /* Command name */
-  double fp_stuff[1];          /* external FPU state (size unknown by us) */
-               /* The type "double" is critical here, for alignment.
-                  SunOS declares a struct here, but the struct's alignment
-                  is double since it contains doubles.  */
-  int c_ucode;                 /* Exception no. from u_code */
-               /* (this member is not accessible by name since we don't
-                   portably know the size of fp_stuff.) */
-};
+/* Scan the relocs for an input section using extended relocs.  We
+   need to figure out what to do for each reloc against a dynamic
+   symbol.  If the reloc is a WDISP30, and the symbol is in the .text
+   section, an entry is made in the procedure linkage table.
+   Otherwise, we must preserve the reloc as a dynamic reloc.  */
+
+static bfd_boolean
+sunos_scan_ext_relocs (struct bfd_link_info *info,
+                      bfd *abfd,
+                      asection *sec ATTRIBUTE_UNUSED,
+                      const struct reloc_ext_external *relocs,
+                      bfd_size_type rel_size)
+{
+  bfd *dynobj;
+  struct sunos_link_hash_entry **sym_hashes;
+  const struct reloc_ext_external *rel, *relend;
+  asection *splt = NULL;
+  asection *sgot = NULL;
+  asection *srel = NULL;
+  bfd_size_type amt;
+
+  /* We only know how to handle SPARC plt entries.  */
+  if (bfd_get_arch (abfd) != bfd_arch_sparc)
+    {
+      bfd_set_error (bfd_error_invalid_target);
+      return FALSE;
+    }
 
-/* Supposedly the user stack grows downward from the bottom of kernel memory.
-   Presuming that this remains true, this definition will work. */
-#define USRSTACK (-(128*1024*1024))
-
-PROTO (static void, swapcore, (bfd *abfd, struct core *core));
-
-/* need this cast b/c ptr is really void * */
-#define core_hdr(bfd) (((struct suncordata *) (bfd->tdata))->hdr)
-#define core_datasec(bfd) (((struct suncordata *) ((bfd)->tdata))->data_section)
-#define core_stacksec(bfd) (((struct suncordata*)((bfd)->tdata))->stack_section)
-#define core_regsec(bfd) (((struct suncordata *) ((bfd)->tdata))->reg_section)
-#define core_reg2sec(bfd) (((struct suncordata *) ((bfd)->tdata))->reg2_section)
-
-/* These are stored in the bfd's tdata */
-struct suncordata {
-  struct core *hdr;             /* core file header */
-  asection *data_section;
-  asection *stack_section;
-  asection *reg_section;
-  asection *reg2_section;
-};
+  dynobj = NULL;
 
-bfd_target *
-sunos4_core_file_p (abfd)
-     bfd *abfd;
+  sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd);
+
+  relend = relocs + rel_size / RELOC_EXT_SIZE;
+  for (rel = relocs; rel < relend; rel++)
+    {
+      unsigned int r_index;
+      int r_extern;
+      int r_type;
+      struct sunos_link_hash_entry *h = NULL;
+
+      /* Swap in the reloc information.  */
+      if (bfd_header_big_endian (abfd))
+       {
+         r_index = ((rel->r_index[0] << 16)
+                    | (rel->r_index[1] << 8)
+                    | rel->r_index[2]);
+         r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
+         r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
+                   >> RELOC_EXT_BITS_TYPE_SH_BIG);
+       }
+      else
+       {
+         r_index = ((rel->r_index[2] << 16)
+                    | (rel->r_index[1] << 8)
+                    | rel->r_index[0]);
+         r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
+         r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
+                   >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
+       }
+
+      if (r_extern)
+       {
+         h = sym_hashes[r_index];
+         if (h == NULL)
+           {
+             /* This should not normally happen, but it will in any
+                case be caught in the relocation phase.  */
+             continue;
+           }
+       }
+
+      /* If this is a base relative reloc, we need to make an entry in
+        the .got section.  */
+      if (r_type == RELOC_BASE10
+         || r_type == RELOC_BASE13
+         || r_type == RELOC_BASE22)
+       {
+         if (dynobj == NULL)
+           {
+             if (! sunos_create_dynamic_sections (abfd, info, FALSE))
+               return FALSE;
+             dynobj = sunos_hash_table (info)->dynobj;
+             splt = bfd_get_section_by_name (dynobj, ".plt");
+             sgot = bfd_get_section_by_name (dynobj, ".got");
+             srel = bfd_get_section_by_name (dynobj, ".dynrel");
+             BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
+
+             /* Make sure we have an initial entry in the .got table.  */
+             if (sgot->size == 0)
+               sgot->size = BYTES_IN_WORD;
+             sunos_hash_table (info)->got_needed = TRUE;
+           }
+
+         if (r_extern)
+           {
+             if (h->got_offset != 0)
+               continue;
+
+             h->got_offset = sgot->size;
+           }
+         else
+           {
+             if (r_index >= bfd_get_symcount (abfd))
+               /* This is abnormal, but should be caught in the
+                  relocation phase.  */
+               continue;
+
+             if (adata (abfd).local_got_offsets == NULL)
+               {
+                 amt = bfd_get_symcount (abfd);
+                 amt *= sizeof (bfd_vma);
+                 adata (abfd).local_got_offsets = bfd_zalloc (abfd, amt);
+                 if (adata (abfd).local_got_offsets == NULL)
+                   return FALSE;
+               }
+
+             if (adata (abfd).local_got_offsets[r_index] != 0)
+               continue;
+
+             adata (abfd).local_got_offsets[r_index] = sgot->size;
+           }
+
+         sgot->size += BYTES_IN_WORD;
+
+         /* If we are making a shared library, or if the symbol is
+            defined by a dynamic object, we will need a dynamic reloc
+            entry.  */
+         if (info->shared
+             || (h != NULL
+                 && (h->flags & SUNOS_DEF_DYNAMIC) != 0
+                 && (h->flags & SUNOS_DEF_REGULAR) == 0))
+           srel->size += RELOC_EXT_SIZE;
+
+         continue;
+       }
+
+      /* Otherwise, we are only interested in relocs against symbols
+        defined in dynamic objects but not in regular objects.  We
+        only need to consider relocs against external symbols.  */
+      if (! r_extern)
+       {
+         /* But, if we are creating a shared library, we need to
+            generate an absolute reloc.  */
+         if (info->shared)
+           {
+             if (dynobj == NULL)
+               {
+                 if (! sunos_create_dynamic_sections (abfd, info, TRUE))
+                   return FALSE;
+                 dynobj = sunos_hash_table (info)->dynobj;
+                 splt = bfd_get_section_by_name (dynobj, ".plt");
+                 sgot = bfd_get_section_by_name (dynobj, ".got");
+                 srel = bfd_get_section_by_name (dynobj, ".dynrel");
+                 BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
+               }
+
+             srel->size += RELOC_EXT_SIZE;
+           }
+
+         continue;
+       }
+
+      /* At this point common symbols have already been allocated, so
+        we don't have to worry about them.  We need to consider that
+        we may have already seen this symbol and marked it undefined;
+        if the symbol is really undefined, then SUNOS_DEF_DYNAMIC
+        will be zero.  */
+      if (h->root.root.type != bfd_link_hash_defined
+         && h->root.root.type != bfd_link_hash_defweak
+         && h->root.root.type != bfd_link_hash_undefined)
+       continue;
+
+      if (r_type != RELOC_JMP_TBL
+         && ! info->shared
+         && ((h->flags & SUNOS_DEF_DYNAMIC) == 0
+             || (h->flags & SUNOS_DEF_REGULAR) != 0))
+       continue;
+
+      if (r_type == RELOC_JMP_TBL
+         && ! info->shared
+         && (h->flags & SUNOS_DEF_DYNAMIC) == 0
+         && (h->flags & SUNOS_DEF_REGULAR) == 0)
+       {
+         /* This symbol is apparently undefined.  Don't do anything
+            here; just let the relocation routine report an undefined
+            symbol.  */
+         continue;
+       }
+
+      if (strcmp (h->root.root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
+       continue;
+
+      if (dynobj == NULL)
+       {
+         if (! sunos_create_dynamic_sections (abfd, info, FALSE))
+           return FALSE;
+         dynobj = sunos_hash_table (info)->dynobj;
+         splt = bfd_get_section_by_name (dynobj, ".plt");
+         sgot = bfd_get_section_by_name (dynobj, ".got");
+         srel = bfd_get_section_by_name (dynobj, ".dynrel");
+         BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
+
+         /* Make sure we have an initial entry in the .got table.  */
+         if (sgot->size == 0)
+           sgot->size = BYTES_IN_WORD;
+         sunos_hash_table (info)->got_needed = TRUE;
+       }
+
+      BFD_ASSERT (r_type == RELOC_JMP_TBL
+                 || info->shared
+                 || (h->flags & SUNOS_REF_REGULAR) != 0);
+      BFD_ASSERT (r_type == RELOC_JMP_TBL
+                 || info->shared
+                 || h->plt_offset != 0
+                 || ((h->root.root.type == bfd_link_hash_defined
+                      || h->root.root.type == bfd_link_hash_defweak)
+                     ? (h->root.root.u.def.section->owner->flags
+                        & DYNAMIC) != 0
+                     : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0));
+
+      /* This reloc is against a symbol defined only by a dynamic
+        object, or it is a jump table reloc from PIC compiled code.  */
+
+      if (r_type != RELOC_JMP_TBL
+         && h->root.root.type == bfd_link_hash_undefined)
+       /* Presumably this symbol was marked as being undefined by
+          an earlier reloc.  */
+       srel->size += RELOC_EXT_SIZE;
+
+      else if (r_type != RELOC_JMP_TBL
+              && (h->root.root.u.def.section->flags & SEC_CODE) == 0)
+       {
+         bfd *sub;
+
+         /* This reloc is not in the .text section.  It must be
+            copied into the dynamic relocs.  We mark the symbol as
+            being undefined.  */
+         srel->size += RELOC_EXT_SIZE;
+         if ((h->flags & SUNOS_DEF_REGULAR) == 0)
+           {
+             sub = h->root.root.u.def.section->owner;
+             h->root.root.type = bfd_link_hash_undefined;
+             h->root.root.u.undef.abfd = sub;
+           }
+       }
+      else
+       {
+         /* This symbol is in the .text section.  We must give it an
+            entry in the procedure linkage table, if we have not
+            already done so.  We change the definition of the symbol
+            to the .plt section; this will cause relocs against it to
+            be handled correctly.  */
+         if (h->plt_offset == 0)
+           {
+             if (splt->size == 0)
+               splt->size = SPARC_PLT_ENTRY_SIZE;
+             h->plt_offset = splt->size;
+
+             if ((h->flags & SUNOS_DEF_REGULAR) == 0)
+               {
+                 if (h->root.root.type == bfd_link_hash_undefined)
+                   h->root.root.type = bfd_link_hash_defined;
+                 h->root.root.u.def.section = splt;
+                 h->root.root.u.def.value = splt->size;
+               }
+
+             splt->size += SPARC_PLT_ENTRY_SIZE;
+
+             /* We will also need a dynamic reloc entry, unless this
+                is a JMP_TBL reloc produced by linking PIC compiled
+                code, and we are not making a shared library.  */
+             if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
+               srel->size += RELOC_EXT_SIZE;
+           }
+
+         /* If we are creating a shared library, we need to copy over
+            any reloc other than a jump table reloc.  */
+         if (info->shared && r_type != RELOC_JMP_TBL)
+           srel->size += RELOC_EXT_SIZE;
+       }
+    }
+
+  return TRUE;
+}
+
+/* Scan the relocs for an input section.  */
+
+static bfd_boolean
+sunos_scan_relocs (struct bfd_link_info *info,
+                  bfd *abfd,
+                  asection *sec,
+                  bfd_size_type rel_size)
 {
-  unsigned char longbuf[4];    /* Raw bytes of various header fields */
-  int core_size;
-  int core_mag;
-  struct core *core;
-  char *rawptr;
-
-  bfd_error = system_call_error;
-
-  if (bfd_read ((PTR)longbuf, 1, sizeof (longbuf), abfd) !=
-        sizeof (longbuf))
-    return 0;
-  core_mag = bfd_h_getlong (abfd, longbuf);
-
-  if (core_mag != CORE_MAGIC) return 0;
-
-  /* SunOS core headers can vary in length; second word is size; */
-  if (bfd_read ((PTR)longbuf, 1, sizeof (longbuf), abfd) !=
-        sizeof (longbuf))
-    return 0;
-  core_size = bfd_h_getlong (abfd, longbuf);
-  /* Sanity check */
-  if (core_size > 20000)
-    return 0;
-
-  if (bfd_seek (abfd, 0L, false) < 0) return 0;
-
-  rawptr = bfd_zalloc (abfd, core_size + sizeof (struct suncordata));
-  if (rawptr == NULL) {
-    bfd_error = no_memory;
-    return 0;
-  }
+  void * relocs;
+  void * free_relocs = NULL;
 
-  core = (struct core *) (rawptr + sizeof (struct suncordata));
+  if (rel_size == 0)
+    return TRUE;
 
-  if ((bfd_read ((PTR) core, 1, core_size, abfd)) != core_size) {
-    bfd_error = system_call_error;
-    bfd_release (abfd, rawptr);
-    return 0;
-  }
+  if (! info->keep_memory)
+    relocs = free_relocs = bfd_malloc (rel_size);
+  else
+    {
+      struct aout_section_data_struct *n;
+      bfd_size_type amt = sizeof (struct aout_section_data_struct);
+
+      n = bfd_alloc (abfd, amt);
+      if (n == NULL)
+       relocs = NULL;
+      else
+       {
+         set_aout_section_data (sec, n);
+         relocs = bfd_malloc (rel_size);
+         aout_section_data (sec)->relocs = relocs;
+       }
+    }
+  if (relocs == NULL)
+    return FALSE;
 
-  swapcore (abfd, core);
-  set_tdata (abfd, ((struct suncordata *) rawptr));
-  core_hdr (abfd) = core;
-
-  /* create the sections.  This is raunchy, but bfd_close wants to reclaim
-     them */
-  core_stacksec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection));
-  if (core_stacksec (abfd) == NULL) {
-loser:
-    bfd_error = no_memory;
-    bfd_release (abfd, rawptr);
-    return 0;
-  }
-  core_datasec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection));
-  if (core_datasec (abfd) == NULL) {
-loser1:
-    bfd_release (abfd, core_stacksec (abfd));
-    goto loser;
-  }
-  core_regsec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection));
-  if (core_regsec (abfd) == NULL) {
-loser2:
-    bfd_release (abfd, core_datasec (abfd));
-    goto loser1;
-  }
-  core_reg2sec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection));
-  if (core_reg2sec (abfd) == NULL) {
-    bfd_release (abfd, core_regsec (abfd));
-    goto loser2;
-  }
+  if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
+      || bfd_bread (relocs, rel_size, abfd) != rel_size)
+    goto error_return;
+
+  if (obj_reloc_entry_size (abfd) == RELOC_STD_SIZE)
+    {
+      if (! sunos_scan_std_relocs (info, abfd, sec,
+                                  (struct reloc_std_external *) relocs,
+                                  rel_size))
+       goto error_return;
+    }
+  else
+    {
+      if (! sunos_scan_ext_relocs (info, abfd, sec,
+                                  (struct reloc_ext_external *) relocs,
+                                  rel_size))
+       goto error_return;
+    }
+
+  if (free_relocs != NULL)
+    free (free_relocs);
 
-  core_stacksec (abfd)->name = ".stack";
-  core_datasec (abfd)->name = ".data";
-  core_regsec (abfd)->name = ".reg";
-  core_reg2sec (abfd)->name = ".reg2";
-
-  core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD;
-  core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD;
-  core_regsec (abfd)->flags = SEC_ALLOC;
-  core_reg2sec (abfd)->flags = SEC_ALLOC;
-
-  core_stacksec (abfd)->size = core->c_ssize;
-  core_datasec (abfd)->size = core->c_dsize;
-  core_regsec (abfd)->size = (sizeof core->c_regs);
-  /* Float regs take up end of struct, except c_ucode.  */
-  core_reg2sec (abfd)->size = core_size - (sizeof core->c_ucode) -
-                             (file_ptr)(((struct core *)0)->fp_stuff);
-
-  core_stacksec (abfd)->vma = (USRSTACK - core->c_ssize);
-  core_datasec (abfd)->vma = N_DATADDR(core->c_aouthdr);
-  core_regsec (abfd)->vma = -1;
-  core_reg2sec (abfd)->vma = -1;
-
-  core_stacksec (abfd)->filepos = core->c_len + core->c_dsize;
-  core_datasec (abfd)->filepos = core->c_len;
-                        /* In file header: */
-  core_regsec (abfd)->filepos = (file_ptr)(&((struct core *)0)->c_regs);
-  core_reg2sec (abfd)->filepos = (file_ptr)(((struct core *)0)->fp_stuff);
-
-  /* Align to word at least */
-  core_stacksec (abfd)->alignment_power = 2;
-  core_datasec (abfd)->alignment_power = 2;
-  core_regsec (abfd)->alignment_power = 2;
-  core_reg2sec (abfd)->alignment_power = 2;
-
-  abfd->sections = core_stacksec (abfd);
-  core_stacksec (abfd)->next = core_datasec (abfd);
-  core_datasec (abfd)->next = core_regsec (abfd);
-  core_regsec (abfd)->next = core_reg2sec (abfd);
-
-  abfd->section_count = 4;
-
-  return abfd->xvec;
+  return TRUE;
+
+ error_return:
+  if (free_relocs != NULL)
+    free (free_relocs);
+  return FALSE;
 }
 
-char *
-sunos4_core_file_failing_command (abfd)
-     bfd *abfd;
+/* Build the hash table of dynamic symbols, and to mark as written all
+   symbols from dynamic objects which we do not plan to write out.  */
+
+static bfd_boolean
+sunos_scan_dynamic_symbol (struct sunos_link_hash_entry *h, void * data)
 {
-  return core_hdr (abfd)->c_cmdname;
+  struct bfd_link_info *info = (struct bfd_link_info *) data;
+
+  /* Set the written flag for symbols we do not want to write out as
+     part of the regular symbol table.  This is all symbols which are
+     not defined in a regular object file.  For some reason symbols
+     which are referenced by a regular object and defined by a dynamic
+     object do not seem to show up in the regular symbol table.  It is
+     possible for a symbol to have only SUNOS_REF_REGULAR set here, it
+     is an undefined symbol which was turned into a common symbol
+     because it was found in an archive object which was not included
+     in the link.  */
+  if ((h->flags & SUNOS_DEF_REGULAR) == 0
+      && (h->flags & SUNOS_DEF_DYNAMIC) != 0
+      && strcmp (h->root.root.root.string, "__DYNAMIC") != 0)
+    h->root.written = TRUE;
+
+  /* If this symbol is defined by a dynamic object and referenced by a
+     regular object, see whether we gave it a reasonable value while
+     scanning the relocs.  */
+  if ((h->flags & SUNOS_DEF_REGULAR) == 0
+      && (h->flags & SUNOS_DEF_DYNAMIC) != 0
+      && (h->flags & SUNOS_REF_REGULAR) != 0)
+    {
+      if ((h->root.root.type == bfd_link_hash_defined
+          || h->root.root.type == bfd_link_hash_defweak)
+         && ((h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
+         && h->root.root.u.def.section->output_section == NULL)
+       {
+         bfd *sub;
+
+         /* This symbol is currently defined in a dynamic section
+            which is not being put into the output file.  This
+            implies that there is no reloc against the symbol.  I'm
+            not sure why this case would ever occur.  In any case, we
+            change the symbol to be undefined.  */
+         sub = h->root.root.u.def.section->owner;
+         h->root.root.type = bfd_link_hash_undefined;
+         h->root.root.u.undef.abfd = sub;
+       }
+    }
+
+  /* If this symbol is defined or referenced by a regular file, add it
+     to the dynamic symbols.  */
+  if ((h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0)
+    {
+      asection *s;
+      size_t len;
+      bfd_byte *contents;
+      unsigned char *name;
+      unsigned long hash;
+      bfd *dynobj;
+
+      BFD_ASSERT (h->dynindx == -2);
+
+      dynobj = sunos_hash_table (info)->dynobj;
+
+      h->dynindx = sunos_hash_table (info)->dynsymcount;
+      ++sunos_hash_table (info)->dynsymcount;
+
+      len = strlen (h->root.root.root.string);
+
+      /* We don't bother to construct a BFD hash table for the strings
+        which are the names of the dynamic symbols.  Using a hash
+        table for the regular symbols is beneficial, because the
+        regular symbols includes the debugging symbols, which have
+        long names and are often duplicated in several object files.
+        There are no debugging symbols in the dynamic symbols.  */
+      s = bfd_get_section_by_name (dynobj, ".dynstr");
+      BFD_ASSERT (s != NULL);
+      contents = bfd_realloc (s->contents, s->size + len + 1);
+      if (contents == NULL)
+       return FALSE;
+      s->contents = contents;
+
+      h->dynstr_index = s->size;
+      strcpy ((char *) contents + s->size, h->root.root.root.string);
+      s->size += len + 1;
+
+      /* Add it to the dynamic hash table.  */
+      name = (unsigned char *) h->root.root.root.string;
+      hash = 0;
+      while (*name != '\0')
+       hash = (hash << 1) + *name++;
+      hash &= 0x7fffffff;
+      hash %= sunos_hash_table (info)->bucketcount;
+
+      s = bfd_get_section_by_name (dynobj, ".hash");
+      BFD_ASSERT (s != NULL);
+
+      if (GET_SWORD (dynobj, s->contents + hash * HASH_ENTRY_SIZE) == -1)
+       PUT_WORD (dynobj, h->dynindx, s->contents + hash * HASH_ENTRY_SIZE);
+      else
+       {
+         bfd_vma next;
+
+         next = GET_WORD (dynobj,
+                          (s->contents
+                           + hash * HASH_ENTRY_SIZE
+                           + BYTES_IN_WORD));
+         PUT_WORD (dynobj, s->size / HASH_ENTRY_SIZE,
+                   s->contents + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD);
+         PUT_WORD (dynobj, h->dynindx, s->contents + s->size);
+         PUT_WORD (dynobj, next, s->contents + s->size + BYTES_IN_WORD);
+         s->size += HASH_ENTRY_SIZE;
+       }
+    }
+
+  return TRUE;
 }
 
-int
-sunos4_core_file_failing_signal (abfd)
-     bfd *abfd;
+/* Set up the sizes and contents of the dynamic sections created in
+   sunos_add_dynamic_symbols.  This is called by the SunOS linker
+   emulation before_allocation routine.  We must set the sizes of the
+   sections before the linker sets the addresses of the various
+   sections.  This unfortunately requires reading all the relocs so
+   that we can work out which ones need to become dynamic relocs.  If
+   info->keep_memory is TRUE, we keep the relocs in memory; otherwise,
+   we discard them, and will read them again later.  */
+
+bfd_boolean
+bfd_sunos_size_dynamic_sections (bfd *output_bfd,
+                                struct bfd_link_info *info,
+                                asection **sdynptr,
+                                asection **sneedptr,
+                                asection **srulesptr)
 {
-  return core_hdr (abfd)->c_signo;
+  bfd *dynobj;
+  bfd_size_type dynsymcount;
+  struct sunos_link_hash_entry *h;
+  asection *s;
+  size_t bucketcount;
+  bfd_size_type hashalloc;
+  size_t i;
+  bfd *sub;
+
+  *sdynptr = NULL;
+  *sneedptr = NULL;
+  *srulesptr = NULL;
+
+  if (info->relocatable)
+    return TRUE;
+
+  if (output_bfd->xvec != &MY(vec))
+    return TRUE;
+
+  /* Look through all the input BFD's and read their relocs.  It would
+     be better if we didn't have to do this, but there is no other way
+     to determine the number of dynamic relocs we need, and, more
+     importantly, there is no other way to know which symbols should
+     get an entry in the procedure linkage table.  */
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    {
+      if ((sub->flags & DYNAMIC) == 0
+         && sub->xvec == output_bfd->xvec)
+       {
+         if (! sunos_scan_relocs (info, sub, obj_textsec (sub),
+                                  exec_hdr (sub)->a_trsize)
+             || ! sunos_scan_relocs (info, sub, obj_datasec (sub),
+                                     exec_hdr (sub)->a_drsize))
+           return FALSE;
+       }
+    }
+
+  dynobj = sunos_hash_table (info)->dynobj;
+  dynsymcount = sunos_hash_table (info)->dynsymcount;
+
+  /* If there were no dynamic objects in the link, and we don't need
+     to build a global offset table, there is nothing to do here.  */
+  if (! sunos_hash_table (info)->dynamic_sections_needed
+      && ! sunos_hash_table (info)->got_needed)
+    return TRUE;
+
+  /* If __GLOBAL_OFFSET_TABLE_ was mentioned, define it.  */
+  h = sunos_link_hash_lookup (sunos_hash_table (info),
+                             "__GLOBAL_OFFSET_TABLE_", FALSE, FALSE, FALSE);
+  if (h != NULL && (h->flags & SUNOS_REF_REGULAR) != 0)
+    {
+      h->flags |= SUNOS_DEF_REGULAR;
+      if (h->dynindx == -1)
+       {
+         ++sunos_hash_table (info)->dynsymcount;
+         h->dynindx = -2;
+       }
+      h->root.root.type = bfd_link_hash_defined;
+      h->root.root.u.def.section = bfd_get_section_by_name (dynobj, ".got");
+
+      /* If the .got section is more than 0x1000 bytes, we set
+        __GLOBAL_OFFSET_TABLE_ to be 0x1000 bytes into the section,
+        so that 13 bit relocations have a greater chance of working.  */
+      s = bfd_get_section_by_name (dynobj, ".got");
+      BFD_ASSERT (s != NULL);
+      if (s->size >= 0x1000)
+       h->root.root.u.def.value = 0x1000;
+      else
+       h->root.root.u.def.value = 0;
+
+      sunos_hash_table (info)->got_base = h->root.root.u.def.value;
+    }
+
+  /* If there are any shared objects in the link, then we need to set
+     up the dynamic linking information.  */
+  if (sunos_hash_table (info)->dynamic_sections_needed)
+    {
+      *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic");
+
+      /* The .dynamic section is always the same size.  */
+      s = *sdynptr;
+      BFD_ASSERT (s != NULL);
+      s->size = (sizeof (struct external_sun4_dynamic)
+                     + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE
+                     + sizeof (struct external_sun4_dynamic_link));
+
+      /* Set the size of the .dynsym and .hash sections.  We counted
+        the number of dynamic symbols as we read the input files.  We
+        will build the dynamic symbol table (.dynsym) and the hash
+        table (.hash) when we build the final symbol table, because
+        until then we do not know the correct value to give the
+        symbols.  We build the dynamic symbol string table (.dynstr)
+        in a traversal of the symbol table using
+        sunos_scan_dynamic_symbol.  */
+      s = bfd_get_section_by_name (dynobj, ".dynsym");
+      BFD_ASSERT (s != NULL);
+      s->size = dynsymcount * sizeof (struct external_nlist);
+      s->contents = bfd_alloc (output_bfd, s->size);
+      if (s->contents == NULL && s->size != 0)
+       return FALSE;
+
+      /* The number of buckets is just the number of symbols divided
+        by four.  To compute the final size of the hash table, we
+        must actually compute the hash table.  Normally we need
+        exactly as many entries in the hash table as there are
+        dynamic symbols, but if some of the buckets are not used we
+        will need additional entries.  In the worst case, every
+        symbol will hash to the same bucket, and we will need
+        BUCKETCOUNT - 1 extra entries.  */
+      if (dynsymcount >= 4)
+       bucketcount = dynsymcount / 4;
+      else if (dynsymcount > 0)
+       bucketcount = dynsymcount;
+      else
+       bucketcount = 1;
+      s = bfd_get_section_by_name (dynobj, ".hash");
+      BFD_ASSERT (s != NULL);
+      hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE;
+      s->contents = bfd_zalloc (dynobj, hashalloc);
+      if (s->contents == NULL && dynsymcount > 0)
+       return FALSE;
+      for (i = 0; i < bucketcount; i++)
+       PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE);
+      s->size = bucketcount * HASH_ENTRY_SIZE;
+
+      sunos_hash_table (info)->bucketcount = bucketcount;
+
+      /* Scan all the symbols, place them in the dynamic symbol table,
+        and build the dynamic hash table.  We reuse dynsymcount as a
+        counter for the number of symbols we have added so far.  */
+      sunos_hash_table (info)->dynsymcount = 0;
+      sunos_link_hash_traverse (sunos_hash_table (info),
+                               sunos_scan_dynamic_symbol,
+                               (void *) info);
+      BFD_ASSERT (sunos_hash_table (info)->dynsymcount == dynsymcount);
+
+      /* The SunOS native linker seems to align the total size of the
+        symbol strings to a multiple of 8.  I don't know if this is
+        important, but it can't hurt much.  */
+      s = bfd_get_section_by_name (dynobj, ".dynstr");
+      BFD_ASSERT (s != NULL);
+      if ((s->size & 7) != 0)
+       {
+         bfd_size_type add;
+         bfd_byte *contents;
+
+         add = 8 - (s->size & 7);
+         contents = bfd_realloc (s->contents, s->size + add);
+         if (contents == NULL)
+           return FALSE;
+         memset (contents + s->size, 0, (size_t) add);
+         s->contents = contents;
+         s->size += add;
+       }
+    }
+
+  /* Now that we have worked out the sizes of the procedure linkage
+     table and the dynamic relocs, allocate storage for them.  */
+  s = bfd_get_section_by_name (dynobj, ".plt");
+  BFD_ASSERT (s != NULL);
+  if (s->size != 0)
+    {
+      s->contents = bfd_alloc (dynobj, s->size);
+      if (s->contents == NULL)
+       return FALSE;
+
+      /* Fill in the first entry in the table.  */
+      switch (bfd_get_arch (dynobj))
+       {
+       case bfd_arch_sparc:
+         memcpy (s->contents, sparc_plt_first_entry, SPARC_PLT_ENTRY_SIZE);
+         break;
+
+       case bfd_arch_m68k:
+         memcpy (s->contents, m68k_plt_first_entry, M68K_PLT_ENTRY_SIZE);
+         break;
+
+       default:
+         abort ();
+       }
+    }
+
+  s = bfd_get_section_by_name (dynobj, ".dynrel");
+  if (s->size != 0)
+    {
+      s->contents = bfd_alloc (dynobj, s->size);
+      if (s->contents == NULL)
+       return FALSE;
+    }
+  /* We use the reloc_count field to keep track of how many of the
+     relocs we have output so far.  */
+  s->reloc_count = 0;
+
+  /* Make space for the global offset table.  */
+  s = bfd_get_section_by_name (dynobj, ".got");
+  s->contents = bfd_alloc (dynobj, s->size);
+  if (s->contents == NULL)
+    return FALSE;
+
+  *sneedptr = bfd_get_section_by_name (dynobj, ".need");
+  *srulesptr = bfd_get_section_by_name (dynobj, ".rules");
+
+  return TRUE;
 }
 
-boolean
-sunos4_core_file_matches_executable_p  (core_bfd, exec_bfd)
-     bfd *core_bfd, *exec_bfd;
+/* Link a dynamic object.  We actually don't have anything to do at
+   this point.  This entry point exists to prevent the regular linker
+   code from doing anything with the object.  */
+
+static bfd_boolean
+sunos_link_dynamic_object (struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                          bfd *abfd ATTRIBUTE_UNUSED)
 {
-  if (core_bfd->xvec != exec_bfd->xvec) {
-    bfd_error = system_call_error;
-    return false;
-  }
+  return TRUE;
+}
+
+/* Write out a dynamic symbol.  This is called by the final traversal
+   over the symbol table.  */
 
-  return (bcmp ((char *)&core_hdr (core_bfd), (char*) &exec_hdr (exec_bfd),
-                sizeof (struct exec)) == 0) ? true : false;
+static bfd_boolean
+sunos_write_dynamic_symbol (bfd *output_bfd,
+                           struct bfd_link_info *info,
+                           struct aout_link_hash_entry *harg)
+{
+  struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg;
+  int type;
+  bfd_vma val;
+  asection *s;
+  struct external_nlist *outsym;
+
+  /* If this symbol is in the procedure linkage table, fill in the
+     table entry.  */
+  if (h->plt_offset != 0)
+    {
+      bfd *dynobj;
+      asection *splt;
+      bfd_byte *p;
+      bfd_vma r_address;
+
+      dynobj = sunos_hash_table (info)->dynobj;
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      p = splt->contents + h->plt_offset;
+
+      s = bfd_get_section_by_name (dynobj, ".dynrel");
+
+      r_address = (splt->output_section->vma
+                  + splt->output_offset
+                  + h->plt_offset);
+
+      switch (bfd_get_arch (output_bfd))
+       {
+       case bfd_arch_sparc:
+         if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
+           {
+             bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD0, p);
+             bfd_put_32 (output_bfd,
+                         (SPARC_PLT_ENTRY_WORD1
+                          + (((- (h->plt_offset + 4) >> 2)
+                              & 0x3fffffff))),
+                         p + 4);
+             bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD2 + s->reloc_count,
+                         p + 8);
+           }
+         else
+           {
+             val = (h->root.root.u.def.section->output_section->vma
+                    + h->root.root.u.def.section->output_offset
+                    + h->root.root.u.def.value);
+             bfd_put_32 (output_bfd,
+                         SPARC_PLT_PIC_WORD0 + ((val >> 10) & 0x3fffff),
+                         p);
+             bfd_put_32 (output_bfd,
+                         SPARC_PLT_PIC_WORD1 + (val & 0x3ff),
+                         p + 4);
+             bfd_put_32 (output_bfd, SPARC_PLT_PIC_WORD2, p + 8);
+           }
+         break;
+
+       case bfd_arch_m68k:
+         if (! info->shared && (h->flags & SUNOS_DEF_REGULAR) != 0)
+           abort ();
+         bfd_put_16 (output_bfd, M68K_PLT_ENTRY_WORD0, p);
+         bfd_put_32 (output_bfd, (- (h->plt_offset + 2)), p + 2);
+         bfd_put_16 (output_bfd, (bfd_vma) s->reloc_count, p + 6);
+         r_address += 2;
+         break;
+
+       default:
+         abort ();
+       }
+
+      /* We also need to add a jump table reloc, unless this is the
+        result of a JMP_TBL reloc from PIC compiled code.  */
+      if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
+       {
+         BFD_ASSERT (h->dynindx >= 0);
+         BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
+                     < s->size);
+         p = s->contents + s->reloc_count * obj_reloc_entry_size (output_bfd);
+         if (obj_reloc_entry_size (output_bfd) == RELOC_STD_SIZE)
+           {
+             struct reloc_std_external *srel;
+
+             srel = (struct reloc_std_external *) p;
+             PUT_WORD (output_bfd, r_address, srel->r_address);
+             if (bfd_header_big_endian (output_bfd))
+               {
+                 srel->r_index[0] = (bfd_byte) (h->dynindx >> 16);
+                 srel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
+                 srel->r_index[2] = (bfd_byte) (h->dynindx);
+                 srel->r_type[0] = (RELOC_STD_BITS_EXTERN_BIG
+                                    | RELOC_STD_BITS_JMPTABLE_BIG);
+               }
+             else
+               {
+                 srel->r_index[2] = (bfd_byte) (h->dynindx >> 16);
+                 srel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
+                 srel->r_index[0] = (bfd_byte)h->dynindx;
+                 srel->r_type[0] = (RELOC_STD_BITS_EXTERN_LITTLE
+                                    | RELOC_STD_BITS_JMPTABLE_LITTLE);
+               }
+           }
+         else
+           {
+             struct reloc_ext_external *erel;
+
+             erel = (struct reloc_ext_external *) p;
+             PUT_WORD (output_bfd, r_address, erel->r_address);
+             if (bfd_header_big_endian (output_bfd))
+               {
+                 erel->r_index[0] = (bfd_byte) (h->dynindx >> 16);
+                 erel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
+                 erel->r_index[2] = (bfd_byte)h->dynindx;
+                 erel->r_type[0] =
+                   (RELOC_EXT_BITS_EXTERN_BIG
+                    | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_BIG));
+               }
+             else
+               {
+                 erel->r_index[2] = (bfd_byte) (h->dynindx >> 16);
+                 erel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
+                 erel->r_index[0] = (bfd_byte)h->dynindx;
+                 erel->r_type[0] =
+                   (RELOC_EXT_BITS_EXTERN_LITTLE
+                    | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_LITTLE));
+               }
+             PUT_WORD (output_bfd, (bfd_vma) 0, erel->r_addend);
+           }
+
+         ++s->reloc_count;
+       }
+    }
+
+  /* If this is not a dynamic symbol, we don't have to do anything
+     else.  We only check this after handling the PLT entry, because
+     we can have a PLT entry for a nondynamic symbol when linking PIC
+     compiled code from a regular object.  */
+  if (h->dynindx < 0)
+    return TRUE;
+
+  switch (h->root.root.type)
+    {
+    default:
+    case bfd_link_hash_new:
+      abort ();
+      /* Avoid variable not initialized warnings.  */
+      return TRUE;
+    case bfd_link_hash_undefined:
+      type = N_UNDF | N_EXT;
+      val = 0;
+      break;
+    case bfd_link_hash_defined:
+    case bfd_link_hash_defweak:
+      {
+       asection *sec;
+       asection *output_section;
+
+       sec = h->root.root.u.def.section;
+       output_section = sec->output_section;
+       BFD_ASSERT (bfd_is_abs_section (output_section)
+                   || output_section->owner == output_bfd);
+       if (h->plt_offset != 0
+           && (h->flags & SUNOS_DEF_REGULAR) == 0)
+         {
+           type = N_UNDF | N_EXT;
+           val = 0;
+         }
+       else
+         {
+           if (output_section == obj_textsec (output_bfd))
+             type = (h->root.root.type == bfd_link_hash_defined
+                     ? N_TEXT
+                     : N_WEAKT);
+           else if (output_section == obj_datasec (output_bfd))
+             type = (h->root.root.type == bfd_link_hash_defined
+                     ? N_DATA
+                     : N_WEAKD);
+           else if (output_section == obj_bsssec (output_bfd))
+             type = (h->root.root.type == bfd_link_hash_defined
+                     ? N_BSS
+                     : N_WEAKB);
+           else
+             type = (h->root.root.type == bfd_link_hash_defined
+                     ? N_ABS
+                     : N_WEAKA);
+           type |= N_EXT;
+           val = (h->root.root.u.def.value
+                  + output_section->vma
+                  + sec->output_offset);
+         }
+      }
+      break;
+    case bfd_link_hash_common:
+      type = N_UNDF | N_EXT;
+      val = h->root.root.u.c.size;
+      break;
+    case bfd_link_hash_undefweak:
+      type = N_WEAKU;
+      val = 0;
+      break;
+    case bfd_link_hash_indirect:
+    case bfd_link_hash_warning:
+      /* FIXME: Ignore these for now.  The circumstances under which
+        they should be written out are not clear to me.  */
+      return TRUE;
+    }
+
+  s = bfd_get_section_by_name (sunos_hash_table (info)->dynobj, ".dynsym");
+  BFD_ASSERT (s != NULL);
+  outsym = ((struct external_nlist *)
+           (s->contents + h->dynindx * EXTERNAL_NLIST_SIZE));
+
+  H_PUT_8 (output_bfd, type, outsym->e_type);
+  H_PUT_8 (output_bfd, 0, outsym->e_other);
+
+  /* FIXME: The native linker doesn't use 0 for desc.  It seems to use
+     one less than the desc value in the shared library, although that
+     seems unlikely.  */
+  H_PUT_16 (output_bfd, 0, outsym->e_desc);
+
+  PUT_WORD (output_bfd, h->dynstr_index, outsym->e_strx);
+  PUT_WORD (output_bfd, val, outsym->e_value);
+
+  return TRUE;
 }
 
-/* byte-swap core structure */
-/* FIXME, this needs more work to swap IN a core struct from raw bytes */
-static void
-swapcore (abfd, core)
-     bfd *abfd;
-     struct core *core;
+/* This is called for each reloc against an external symbol.  If this
+   is a reloc which are are going to copy as a dynamic reloc, then
+   copy it over, and tell the caller to not bother processing this
+   reloc.  */
+
+static bfd_boolean
+sunos_check_dynamic_reloc (struct bfd_link_info *info,
+                          bfd *input_bfd,
+                          asection *input_section,
+                          struct aout_link_hash_entry *harg,
+                          void * reloc,
+                          bfd_byte *contents ATTRIBUTE_UNUSED,
+                          bfd_boolean *skip,
+                          bfd_vma *relocationp)
 {
-  unsigned char exec_bytes[EXEC_BYTES_SIZE];
-
-  core->c_magic = bfd_h_getlong (abfd, (unsigned char *)&core->c_magic);
-  core->c_len   = bfd_h_getlong (abfd, (unsigned char *)&core->c_len  );
-  /* Leave integer registers in target byte order.  */
-  bcopy ((char *)&(core->c_aouthdr), (char *)exec_bytes, EXEC_BYTES_SIZE);
-  bfd_aout_swap_exec_header_in (abfd, exec_bytes, &core->c_aouthdr);
-  core->c_signo = bfd_h_getlong (abfd, (unsigned char *)&core->c_signo);
-  core->c_tsize = bfd_h_getlong (abfd, (unsigned char *)&core->c_tsize);
-  core->c_dsize = bfd_h_getlong (abfd, (unsigned char *)&core->c_dsize);
-  core->c_ssize = bfd_h_getlong (abfd, (unsigned char *)&core->c_ssize);
-  /* Leave FP registers in target byte order.  */
-  /* Leave "c_ucode" unswapped for now, since we can't find it easily.  */
+  struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg;
+  bfd *dynobj;
+  bfd_boolean baserel;
+  bfd_boolean jmptbl;
+  bfd_boolean pcrel;
+  asection *s;
+  bfd_byte *p;
+  long indx;
+
+  *skip = FALSE;
+
+  dynobj = sunos_hash_table (info)->dynobj;
+
+  if (h != NULL
+      && h->plt_offset != 0
+      && (info->shared
+         || (h->flags & SUNOS_DEF_REGULAR) == 0))
+    {
+      asection *splt;
+
+      /* Redirect the relocation to the PLT entry.  */
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      *relocationp = (splt->output_section->vma
+                     + splt->output_offset
+                     + h->plt_offset);
+    }
+
+  if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
+    {
+      struct reloc_std_external *srel;
+
+      srel = (struct reloc_std_external *) reloc;
+      if (bfd_header_big_endian (input_bfd))
+       {
+         baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
+         jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
+         pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
+       }
+      else
+       {
+         baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
+         jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
+         pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
+       }
+    }
+  else
+    {
+      struct reloc_ext_external *erel;
+      int r_type;
+
+      erel = (struct reloc_ext_external *) reloc;
+      if (bfd_header_big_endian (input_bfd))
+       r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
+                 >> RELOC_EXT_BITS_TYPE_SH_BIG);
+      else
+       r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
+                 >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
+      baserel = (r_type == RELOC_BASE10
+                || r_type == RELOC_BASE13
+                || r_type == RELOC_BASE22);
+      jmptbl = r_type == RELOC_JMP_TBL;
+      pcrel = (r_type == RELOC_DISP8
+              || r_type == RELOC_DISP16
+              || r_type == RELOC_DISP32
+              || r_type == RELOC_WDISP30
+              || r_type == RELOC_WDISP22);
+      /* We don't consider the PC10 and PC22 types to be PC relative,
+        because they are pcrel_offset.  */
+    }
+
+  if (baserel)
+    {
+      bfd_vma *got_offsetp;
+      asection *sgot;
+
+      if (h != NULL)
+       got_offsetp = &h->got_offset;
+      else if (adata (input_bfd).local_got_offsets == NULL)
+       got_offsetp = NULL;
+      else
+       {
+         struct reloc_std_external *srel;
+         int r_index;
+
+         srel = (struct reloc_std_external *) reloc;
+         if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
+           {
+             if (bfd_header_big_endian (input_bfd))
+               r_index = ((srel->r_index[0] << 16)
+                          | (srel->r_index[1] << 8)
+                          | srel->r_index[2]);
+             else
+               r_index = ((srel->r_index[2] << 16)
+                          | (srel->r_index[1] << 8)
+                          | srel->r_index[0]);
+           }
+         else
+           {
+             struct reloc_ext_external *erel;
+
+             erel = (struct reloc_ext_external *) reloc;
+             if (bfd_header_big_endian (input_bfd))
+               r_index = ((erel->r_index[0] << 16)
+                          | (erel->r_index[1] << 8)
+                          | erel->r_index[2]);
+             else
+               r_index = ((erel->r_index[2] << 16)
+                          | (erel->r_index[1] << 8)
+                          | erel->r_index[0]);
+           }
+
+         got_offsetp = adata (input_bfd).local_got_offsets + r_index;
+       }
+
+      BFD_ASSERT (got_offsetp != NULL && *got_offsetp != 0);
+
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+
+      /* We set the least significant bit to indicate whether we have
+        already initialized the GOT entry.  */
+      if ((*got_offsetp & 1) == 0)
+       {
+         if (h == NULL
+             || (! info->shared
+                 && ((h->flags & SUNOS_DEF_DYNAMIC) == 0
+                     || (h->flags & SUNOS_DEF_REGULAR) != 0)))
+           PUT_WORD (dynobj, *relocationp, sgot->contents + *got_offsetp);
+         else
+           PUT_WORD (dynobj, 0, sgot->contents + *got_offsetp);
+
+         if (info->shared
+             || (h != NULL
+                 && (h->flags & SUNOS_DEF_DYNAMIC) != 0
+                 && (h->flags & SUNOS_DEF_REGULAR) == 0))
+           {
+             /* We need to create a GLOB_DAT or 32 reloc to tell the
+                dynamic linker to fill in this entry in the table.  */
+
+             s = bfd_get_section_by_name (dynobj, ".dynrel");
+             BFD_ASSERT (s != NULL);
+             BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
+                         < s->size);
+
+             p = (s->contents
+                  + s->reloc_count * obj_reloc_entry_size (dynobj));
+
+             if (h != NULL)
+               indx = h->dynindx;
+             else
+               indx = 0;
+
+             if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE)
+               {
+                 struct reloc_std_external *srel;
+
+                 srel = (struct reloc_std_external *) p;
+                 PUT_WORD (dynobj,
+                           (*got_offsetp
+                            + sgot->output_section->vma
+                            + sgot->output_offset),
+                           srel->r_address);
+                 if (bfd_header_big_endian (dynobj))
+                   {
+                     srel->r_index[0] = (bfd_byte) (indx >> 16);
+                     srel->r_index[1] = (bfd_byte) (indx >> 8);
+                     srel->r_index[2] = (bfd_byte)indx;
+                     if (h == NULL)
+                       srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_BIG;
+                     else
+                       srel->r_type[0] =
+                         (RELOC_STD_BITS_EXTERN_BIG
+                          | RELOC_STD_BITS_BASEREL_BIG
+                          | RELOC_STD_BITS_RELATIVE_BIG
+                          | (2 << RELOC_STD_BITS_LENGTH_SH_BIG));
+                   }
+                 else
+                   {
+                     srel->r_index[2] = (bfd_byte) (indx >> 16);
+                     srel->r_index[1] = (bfd_byte) (indx >> 8);
+                     srel->r_index[0] = (bfd_byte)indx;
+                     if (h == NULL)
+                       srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_LITTLE;
+                     else
+                       srel->r_type[0] =
+                         (RELOC_STD_BITS_EXTERN_LITTLE
+                          | RELOC_STD_BITS_BASEREL_LITTLE
+                          | RELOC_STD_BITS_RELATIVE_LITTLE
+                          | (2 << RELOC_STD_BITS_LENGTH_SH_LITTLE));
+                   }
+               }
+             else
+               {
+                 struct reloc_ext_external *erel;
+
+                 erel = (struct reloc_ext_external *) p;
+                 PUT_WORD (dynobj,
+                           (*got_offsetp
+                            + sgot->output_section->vma
+                            + sgot->output_offset),
+                           erel->r_address);
+                 if (bfd_header_big_endian (dynobj))
+                   {
+                     erel->r_index[0] = (bfd_byte) (indx >> 16);
+                     erel->r_index[1] = (bfd_byte) (indx >> 8);
+                     erel->r_index[2] = (bfd_byte)indx;
+                     if (h == NULL)
+                       erel->r_type[0] =
+                         RELOC_32 << RELOC_EXT_BITS_TYPE_SH_BIG;
+                     else
+                       erel->r_type[0] =
+                         (RELOC_EXT_BITS_EXTERN_BIG
+                          | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_BIG));
+                   }
+                 else
+                   {
+                     erel->r_index[2] = (bfd_byte) (indx >> 16);
+                     erel->r_index[1] = (bfd_byte) (indx >> 8);
+                     erel->r_index[0] = (bfd_byte)indx;
+                     if (h == NULL)
+                       erel->r_type[0] =
+                         RELOC_32 << RELOC_EXT_BITS_TYPE_SH_LITTLE;
+                     else
+                       erel->r_type[0] =
+                         (RELOC_EXT_BITS_EXTERN_LITTLE
+                          | (RELOC_GLOB_DAT
+                             << RELOC_EXT_BITS_TYPE_SH_LITTLE));
+                   }
+                 PUT_WORD (dynobj, 0, erel->r_addend);
+               }
+
+             ++s->reloc_count;
+           }
+
+         *got_offsetp |= 1;
+       }
+
+      *relocationp = (sgot->vma
+                     + (*got_offsetp &~ (bfd_vma) 1)
+                     - sunos_hash_table (info)->got_base);
+
+      /* There is nothing else to do for a base relative reloc.  */
+      return TRUE;
+    }
+
+  if (! sunos_hash_table (info)->dynamic_sections_needed)
+    return TRUE;
+  if (! info->shared)
+    {
+      if (h == NULL
+         || h->dynindx == -1
+         || h->root.root.type != bfd_link_hash_undefined
+         || (h->flags & SUNOS_DEF_REGULAR) != 0
+         || (h->flags & SUNOS_DEF_DYNAMIC) == 0
+         || (h->root.root.u.undef.abfd->flags & DYNAMIC) == 0)
+       return TRUE;
+    }
+  else
+    {
+      if (h != NULL
+         && (h->dynindx == -1
+             || jmptbl
+             || strcmp (h->root.root.root.string,
+                        "__GLOBAL_OFFSET_TABLE_") == 0))
+       return TRUE;
+    }
+
+  /* It looks like this is a reloc we are supposed to copy.  */
+
+  s = bfd_get_section_by_name (dynobj, ".dynrel");
+  BFD_ASSERT (s != NULL);
+  BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->size);
+
+  p = s->contents + s->reloc_count * obj_reloc_entry_size (dynobj);
+
+  /* Copy the reloc over.  */
+  memcpy (p, reloc, obj_reloc_entry_size (dynobj));
+
+  if (h != NULL)
+    indx = h->dynindx;
+  else
+    indx = 0;
+
+  /* Adjust the address and symbol index.  */
+  if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE)
+    {
+      struct reloc_std_external *srel;
+
+      srel = (struct reloc_std_external *) p;
+      PUT_WORD (dynobj,
+               (GET_WORD (dynobj, srel->r_address)
+                + input_section->output_section->vma
+                + input_section->output_offset),
+               srel->r_address);
+      if (bfd_header_big_endian (dynobj))
+       {
+         srel->r_index[0] = (bfd_byte) (indx >> 16);
+         srel->r_index[1] = (bfd_byte) (indx >> 8);
+         srel->r_index[2] = (bfd_byte)indx;
+       }
+      else
+       {
+         srel->r_index[2] = (bfd_byte) (indx >> 16);
+         srel->r_index[1] = (bfd_byte) (indx >> 8);
+         srel->r_index[0] = (bfd_byte)indx;
+       }
+      /* FIXME: We may have to change the addend for a PC relative
+        reloc.  */
+    }
+  else
+    {
+      struct reloc_ext_external *erel;
+
+      erel = (struct reloc_ext_external *) p;
+      PUT_WORD (dynobj,
+               (GET_WORD (dynobj, erel->r_address)
+                + input_section->output_section->vma
+                + input_section->output_offset),
+               erel->r_address);
+      if (bfd_header_big_endian (dynobj))
+       {
+         erel->r_index[0] = (bfd_byte) (indx >> 16);
+         erel->r_index[1] = (bfd_byte) (indx >> 8);
+         erel->r_index[2] = (bfd_byte)indx;
+       }
+      else
+       {
+         erel->r_index[2] = (bfd_byte) (indx >> 16);
+         erel->r_index[1] = (bfd_byte) (indx >> 8);
+         erel->r_index[0] = (bfd_byte)indx;
+       }
+      if (pcrel && h != NULL)
+       {
+         /* Adjust the addend for the change in address.  */
+         PUT_WORD (dynobj,
+                   (GET_WORD (dynobj, erel->r_addend)
+                    - (input_section->output_section->vma
+                       + input_section->output_offset
+                       - input_section->vma)),
+                   erel->r_addend);
+       }
+    }
+
+  ++s->reloc_count;
+
+  if (h != NULL)
+    *skip = TRUE;
+
+  return TRUE;
 }
-\f
-/* We use BFD generic archive files.  */
-#define        aout_openr_next_archived_file   bfd_generic_openr_next_archived_file
-#define        aout_generic_stat_arch_elt      bfd_generic_stat_arch_elt
-#define        aout_slurp_armap                bfd_slurp_bsd_armap
-#define        aout_slurp_extended_name_table  bfd_true
-#define        aout_write_armap                bsd_write_armap
-#define        aout_truncate_arname            bfd_bsd_truncate_arname
-
-/* We use our own core file format.  */
-#define        aout_core_file_failing_command  sunos4_core_file_failing_command
-#define        aout_core_file_failing_signal   sunos4_core_file_failing_signal
-#define        aout_core_file_matches_executable_p     \
-                                       sunos4_core_file_matches_executable_p
-
-/* We implement these routines ourselves, rather than using the generic
-   a.out versions.  */
-#define        aout_write_object_contents      sunos4_write_object_contents
-
-bfd_target sunos_big_vec =
+
+/* Finish up the dynamic linking information.  */
+
+static bfd_boolean
+sunos_finish_dynamic_link (bfd *abfd, struct bfd_link_info *info)
 {
-  "a.out-sunos-big",           /* name */
-  bfd_target_aout_flavour_enum,
-  true,                                /* target byte order */
-  true,                                /* target headers byte order */
-  (HAS_RELOC | EXEC_P |                /* object flags */
-   HAS_LINENO | HAS_DEBUG |
-   HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
-  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
-  ' ',                         /* ar_pad_char */
-  16,                          /* ar_max_namelen */
-  _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* data */
-  _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* hdrs */
-
-    {_bfd_dummy_target, sunos4_object_p,
-       bfd_generic_archive_p, sunos4_core_file_p},
-    {bfd_false, sunos4_mkobject,
-       _bfd_generic_mkarchive, bfd_false},
-    {bfd_false, sunos4_write_object_contents,  /* bfd_write_contents */
-       _bfd_write_archive_contents, bfd_false},
-
-  JUMP_TABLE(aout)
-};
+  bfd *dynobj;
+  asection *o;
+  asection *s;
+  asection *sdyn;
+
+  if (! sunos_hash_table (info)->dynamic_sections_needed
+      && ! sunos_hash_table (info)->got_needed)
+    return TRUE;
+
+  dynobj = sunos_hash_table (info)->dynobj;
+
+  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+  BFD_ASSERT (sdyn != NULL);
+
+  /* Finish up the .need section.  The linker emulation code filled it
+     in, but with offsets from the start of the section instead of
+     real addresses.  Now that we know the section location, we can
+     fill in the final values.  */
+  s = bfd_get_section_by_name (dynobj, ".need");
+  if (s != NULL && s->size != 0)
+    {
+      file_ptr filepos;
+      bfd_byte *p;
+
+      filepos = s->output_section->filepos + s->output_offset;
+      p = s->contents;
+      while (1)
+       {
+         bfd_vma val;
+
+         PUT_WORD (dynobj, GET_WORD (dynobj, p) + filepos, p);
+         val = GET_WORD (dynobj, p + 12);
+         if (val == 0)
+           break;
+         PUT_WORD (dynobj, val + filepos, p + 12);
+         p += 16;
+       }
+    }
+
+  /* The first entry in the .got section is the address of the
+     dynamic information, unless this is a shared library.  */
+  s = bfd_get_section_by_name (dynobj, ".got");
+  BFD_ASSERT (s != NULL);
+  if (info->shared || sdyn->size == 0)
+    PUT_WORD (dynobj, 0, s->contents);
+  else
+    PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset,
+             s->contents);
+
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    {
+      if ((o->flags & SEC_HAS_CONTENTS) != 0
+         && o->contents != NULL)
+       {
+         BFD_ASSERT (o->output_section != NULL
+                     && o->output_section->owner == abfd);
+         if (! bfd_set_section_contents (abfd, o->output_section,
+                                         o->contents,
+                                         (file_ptr) o->output_offset,
+                                         o->size))
+           return FALSE;
+       }
+    }
+
+  if (sdyn->size > 0)
+    {
+      struct external_sun4_dynamic esd;
+      struct external_sun4_dynamic_link esdl;
+      file_ptr pos;
+
+      /* Finish up the dynamic link information.  */
+      PUT_WORD (dynobj, (bfd_vma) 3, esd.ld_version);
+      PUT_WORD (dynobj,
+               sdyn->output_section->vma + sdyn->output_offset + sizeof esd,
+               esd.ldd);
+      PUT_WORD (dynobj,
+               (sdyn->output_section->vma
+                + sdyn->output_offset
+                + sizeof esd
+                + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE),
+               esd.ld);
+
+      if (! bfd_set_section_contents (abfd, sdyn->output_section, &esd,
+                                     (file_ptr) sdyn->output_offset,
+                                     (bfd_size_type) sizeof esd))
+       return FALSE;
+
+      PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded);
+
+      s = bfd_get_section_by_name (dynobj, ".need");
+      if (s == NULL || s->size == 0)
+       PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_need);
+      else
+       PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+                 esdl.ld_need);
+
+      s = bfd_get_section_by_name (dynobj, ".rules");
+      if (s == NULL || s->size == 0)
+       PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_rules);
+      else
+       PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+                 esdl.ld_rules);
+
+      s = bfd_get_section_by_name (dynobj, ".got");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->vma + s->output_offset,
+               esdl.ld_got);
+
+      s = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->vma + s->output_offset,
+               esdl.ld_plt);
+      PUT_WORD (dynobj, s->size, esdl.ld_plt_sz);
+
+      s = bfd_get_section_by_name (dynobj, ".dynrel");
+      BFD_ASSERT (s != NULL);
+      BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
+                 == s->size);
+      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+               esdl.ld_rel);
+
+      s = bfd_get_section_by_name (dynobj, ".hash");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+               esdl.ld_hash);
+
+      s = bfd_get_section_by_name (dynobj, ".dynsym");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+               esdl.ld_stab);
+
+      PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_stab_hash);
+
+      PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount,
+               esdl.ld_buckets);
+
+      s = bfd_get_section_by_name (dynobj, ".dynstr");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+               esdl.ld_symbols);
+      PUT_WORD (dynobj, s->size, esdl.ld_symb_size);
+
+      /* The size of the text area is the size of the .text section
+        rounded up to a page boundary.  FIXME: Should the page size be
+        conditional on something?  */
+      PUT_WORD (dynobj,
+               BFD_ALIGN (obj_textsec (abfd)->size, 0x2000),
+               esdl.ld_text);
+
+      pos = sdyn->output_offset;
+      pos += sizeof esd + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE;
+      if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl,
+                                     pos, (bfd_size_type) sizeof esdl))
+       return FALSE;
+
+      abfd->flags |= DYNAMIC;
+    }
+
+  return TRUE;
+}