* Makefile.in (TE_OBJS): Add empty definition.
[deliverable/binutils-gdb.git] / bfd / sunos.c
index bfb92bad6b79238dd3307eedc213594ea2a6eab1..807f5b1239e48447d0750bc32729b9e781a25e30 100644 (file)
-/*** bfd backend for sunos binaries */
+/* BFD backend for SunOS binaries.
+   Copyright (C) 1990, 91, 92, 93, 94, 1995 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.
-
-BFD is free software; you can redistribute it and/or modify
+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 1, or (at your option)
-any later version.
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
 
-BFD is distributed in the hope that it will be useful,
+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.
 
 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.  */
-
-/* $Id$
- *
- */
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-#define TARGET_BYTE_ORDER_BIG_P 1
+#define TARGETNAME "a.out-sunos-big"
+#define MY(OP) CAT(sunos_big_,OP)
 
-#include <ansidecl.h>
-#include "sysdep.h"
 #include "bfd.h"
-#include "libbfd.h"
-
-
-void (*bfd_error_trap)();
-
-/*SUPPRESS558*/
-/*SUPPRESS529*/
-
-
-
-
-
-/* These values are correct for the SPARC.  I dunno about anything else */
-#define PAGE_SIZE 0x02000
-#define SEGMENT_SIZE PAGE_SIZE
-#define TEXT_START_ADDR PAGE_SIZE
-#include "a.out.gnu.h"
-#include "stab.gnu.h"
-#include "ar.h"
-#include "liba.out.h"           /* BFD a.out internal data structures */
-
-#include "a.out.sun4.h"
-
-#define CTOR_TABLE_RELOC_IDX 2
-static  reloc_howto_type howto_table_ext[] = 
+#include "bfdlink.h"
+#include "libaout.h"
+
+/* Static routines defined in this file.  */
+
+static boolean sunos_read_dynamic_info PARAMS ((bfd *));
+static long sunos_get_dynamic_symtab_upper_bound PARAMS ((bfd *));
+static long sunos_canonicalize_dynamic_symtab PARAMS ((bfd *, asymbol **));
+static long sunos_get_dynamic_reloc_upper_bound PARAMS ((bfd *));
+static long sunos_canonicalize_dynamic_reloc
+  PARAMS ((bfd *, arelent **, asymbol **));
+static struct bfd_hash_entry *sunos_link_hash_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static struct bfd_link_hash_table *sunos_link_hash_table_create
+  PARAMS ((bfd *));
+static boolean sunos_add_dynamic_symbols
+  PARAMS ((bfd *, struct bfd_link_info *));
+static boolean sunos_add_one_symbol
+  PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *,
+          bfd_vma, const char *, boolean, boolean,
+          struct bfd_link_hash_entry **));
+static boolean sunos_scan_relocs
+  PARAMS ((struct bfd_link_info *, bfd *, asection *, bfd_size_type));
+static boolean sunos_scan_std_relocs
+  PARAMS ((struct bfd_link_info *, bfd *, asection *,
+          const struct reloc_std_external *, bfd_size_type));
+static boolean sunos_scan_ext_relocs
+  PARAMS ((struct bfd_link_info *, bfd *, asection *,
+          const struct reloc_ext_external *, bfd_size_type));
+static boolean sunos_link_dynamic_object
+  PARAMS ((struct bfd_link_info *, bfd *));
+static boolean sunos_write_dynamic_symbol
+  PARAMS ((bfd *, struct bfd_link_info *, struct aout_link_hash_entry *));
+static boolean sunos_check_dynamic_reloc
+  PARAMS ((struct bfd_link_info *, bfd *, asection *,
+          struct aout_link_hash_entry *, PTR, boolean *));
+static boolean sunos_finish_dynamic_link
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+#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_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
+
+/* Include the usual a.out support.  */
+#include "aoutf1.h"
+
+/* SunOS shared library support.  We store a pointer to this structure
+   in obj_aout_dynamic_info (abfd).  */
+
+struct sunos_dynamic_info
 {
-  /* type                   rs   size bsz  pcrel bitpos  abs ovrf sf name partial inplace mask*/
-{ (unsigned int) RELOC_8,      0,  0,          8,  false, 0, true,  true,0,"8",        false, 0,0x000000ff},
-{ (unsigned int) RELOC_16,     0,  1,  16, false, 0, true,  true,0,"16",       false, 0,0x0000ffff},
-{ (unsigned int) RELOC_32,     0,  2,  32, false, 0, true,  true,0,"32",       false, 0,0xffffffff},
-{ (unsigned int) RELOC_DISP8,  0,  0,  8,  true,  0, false, true,0,"DISP8",    false, 0,0x000000ff},
-{ (unsigned int) RELOC_DISP16, 0,  1,  16, true,  0, false, true,0,"DISP16",   false, 0,0x0000ffff},
-{ (unsigned int) RELOC_DISP32, 0,  2,  32, true,  0, false, true,0,"DISP32",   false, 0,0xffffffff},
-{ (unsigned int) RELOC_WDISP30,2,  2,  30, true,  0, false, true,0,"WDISP30",  false, 0,0x3fffffff},
-{ (unsigned int) RELOC_WDISP22,2,  2,  22, true,  0, false, true,0,"WDISP22",  false, 0,0x003fffff},
-{ (unsigned int) RELOC_HI22,   10, 2,  22, false, 0, false, true,0,"HI22",     false, 0,0x003fffff},
-{ (unsigned int) RELOC_22,      0, 2,  22, false, 0, false, true,0,"22",       false, 0,0x003fffff},
-{ (unsigned int) RELOC_13,     0, 2,   13, false, 0, false, true,0,"13",       false, 0,0x00001fff},
-{ (unsigned int) RELOC_LO10,   0, 2,   10, false, 0, false, true,0,"LO10",     false, 0,0x000003ff},
-{ (unsigned int) RELOC_SFA_BASE,0, 2,  32, false, 0, false, true,0,"SFA_BASE", false, 0,0xffffffff},
-{ (unsigned int) RELOC_SFA_OFF13,0,2,  32, false, 0, false, true,0,"SFA_OFF13",false, 0,0xffffffff},
-{ (unsigned int) RELOC_BASE10, 0,  2,  16, false, 0, false, true,0,"BASE10",   false, 0,0x0000ffff},
-{ (unsigned int) RELOC_BASE13, 0,  2,  13, false, 0, false, true,0,"BASE13",   false, 0,0x00001fff},
-{ (unsigned int) RELOC_BASE22, 0,  2,  0,  false, 0, false, true,0,"BASE22",   false, 0,0x00000000},
-{ (unsigned int) RELOC_PC10,   0,  2,  10, false, 0, false, true,0,"PC10",     false, 0,0x000003ff},
-{ (unsigned int) RELOC_PC22,   0,  2,  22, false, 0, false, true,0,"PC22",     false, 0,0x003fffff},
-{ (unsigned int) RELOC_JMP_TBL,0,  2,  32, false, 0, false, true,0,"JMP_TBL",  false, 0,0xffffffff},
-{ (unsigned int) RELOC_SEGOFF16,0, 2,  0,  false, 0, false, true,0,"SEGOFF16", false, 0,0x00000000},
-{ (unsigned int) RELOC_GLOB_DAT,0, 2,  0,  false, 0, false, true,0,"GLOB_DAT", false, 0,0x00000000},
-{ (unsigned int) RELOC_JMP_SLOT,0, 2,  0,  false, 0, false, true,0,"JMP_SLOT", false, 0,0x00000000},
-{ (unsigned int) RELOC_RELATIVE,0, 2,  0,  false, 0, false, true,0,"RELATIVE", false, 0,0x00000000},
-{ (unsigned int) RELOC_JUMPTARG,2, 13, 16, true,  0, false, true,0,"JUMPTARG", false, 0,0x0000ffff},
-{ (unsigned int) RELOC_CONST,  0, 13,  16, false, 0, false, true,0,"CONST",    false, 0,0x0000ffff},
-{ (unsigned int) RELOC_CONSTH, 16, 13, 16, false, 0, false, true,0,"CONSTH",   false, 0,0x0000ffff},
-};
-
-/* Convert standard reloc records to "arelent" format (incl byte swap).  */
-
-static  reloc_howto_type howto_table_std[] = {
-  /* type                   rs   size bsz  pcrel bitpos  abs ovrf sf name*/
-{ (unsigned int) 0,           0,  0,   8,  false, 0, true,  true,0,"8",        true, 0x000000ff,0x000000ff},
-{ (unsigned int) 1,           0,  1,   16, false, 0, true,  true,0,"16",       true, 0x0000ffff,0x0000ffff},
-{ (unsigned int) 2,           0,  2,   32, false, 0, true,  true,0,"32",       true, 0xffffffff,0xffffffff},
-{ (unsigned int) 3,           0,  3,   64, false, 0, true,  true,0,"64",       true, 0xdeaddead,0xdeaddead},
-{ (unsigned int) 4,           0,  0,   8,  true,  0, false, true,0,"DISP8",    true, 0x000000ff,0x000000ff},
-{ (unsigned int) 5,           0,  1,   16, true,  0, false, true,0,"DISP16",   true, 0x0000ffff,0x0000ffff},
-{ (unsigned int) 6,           0,  2,   32, true,  0, false, true,0,"DISP32",   true, 0xffffffff,0xffffffff},
-{ (unsigned int) 7,           0,  3,   64, true,  0, false, true,0,"DISP64",   true, 0xfeedface,0xfeedface},
+  /* Whether we found any dynamic information.  */
+  boolean valid;
+  /* Dynamic information.  */
+  struct internal_sun4_dynamic_link dyninfo;
+  /* Number of dynamic symbols.  */
+  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.  */
+  long dynrel_count;
+  /* Read in dynamic relocs.  This may be reloc_std_external or
+     reloc_ext_external.  */
+  PTR 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.  */
 
-bfd_error_vector_type bfd_error_vector;
-/** a.out files */
+#define HASH_ENTRY_SIZE (2 * BYTES_IN_WORD)
 
+/* 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.  */
 
-PROTO (void , sunos4_write_syms, ());
-PROTO (static boolean,sunos4_squirt_out_relocs,(bfd *abfd, asection *section));
+static boolean
+sunos_read_dynamic_info (abfd)
+     bfd *abfd;
+{
+  struct sunos_dynamic_info *info;
+  asection *dynsec;
+  file_ptr dynoff;
+  struct external_sun4_dynamic dyninfo;
+  unsigned long dynver;
+  struct external_sun4_dynamic_link linkinfo;
 
+  if (obj_aout_dynamic_info (abfd) != (PTR) NULL)
+    return true;
 
-static size_t
-reloc_size_func(abfd)
-bfd *abfd;
-{
-  switch (bfd_get_architecture (abfd)) {
-  case bfd_arch_sparc:
-  case bfd_arch_a29k:
-    return  RELOC_EXT_SIZE;
-  default:
-    return  RELOC_STD_SIZE;
-  }
-}
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
+    }
 
-static void
-DEFUN(bfd_aout_swap_exec_header_in,(abfd, raw_bytes, execp),
-      bfd *abfd AND
-      unsigned char *raw_bytes AND
-      struct exec *execp)
-{
-  struct exec_bytes *bytes = (struct exec_bytes *)raw_bytes;
-
-  /* Now fill in fields in the execp, from the bytes in the raw data.  */
-  execp->a_info   = bfd_h_getlong (abfd, bytes->a_info);
-  execp->a_text   = bfd_h_getlong (abfd, bytes->a_text);
-  execp->a_data   = bfd_h_getlong (abfd, bytes->a_data);
-  execp->a_bss    = bfd_h_getlong (abfd, bytes->a_bss);
-  execp->a_syms   = bfd_h_getlong (abfd, bytes->a_syms);
-  execp->a_entry  = bfd_h_getlong (abfd, bytes->a_entry);
-  execp->a_trsize = bfd_h_getlong (abfd, bytes->a_trsize);
-  execp->a_drsize = bfd_h_getlong (abfd, bytes->a_drsize);
-}
+  info = ((struct sunos_dynamic_info *)
+         bfd_zalloc (abfd, sizeof (struct sunos_dynamic_info)));
+  if (!info)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      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) = (PTR) 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), (PTR) &dyninfo,
+                                 (file_ptr) 0, 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 < 0 || dynoff > bfd_section_size (abfd, dynsec))
+    return true;
+
+  /* This executable appears to be dynamically linked in a way that we
+     can understand.  */
+  if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo, 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);
+
+  /* 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
+             == info->dyninfo.ld_symbols - info->dyninfo.ld_stab);
+
+  /* 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)
+             == info->dyninfo.ld_hash - info->dyninfo.ld_rel);
+
+  info->valid = true;
 
-static void
-DEFUN(bfd_aout_swap_exec_header_out,(abfd, execp, raw_bytes),
-     bfd *abfd AND
-     struct exec *execp AND 
-     unsigned char *raw_bytes)
-{
-  struct exec_bytes *bytes = (struct exec_bytes *)raw_bytes;
-
-  /* Now fill in fields in the raw data, from the fields in the exec struct. */
-  bfd_h_putlong (abfd, execp->a_info  , bytes->a_info);
-  bfd_h_putlong (abfd, execp->a_text  , bytes->a_text);
-  bfd_h_putlong (abfd, execp->a_data  , bytes->a_data);
-  bfd_h_putlong (abfd, execp->a_bss   , bytes->a_bss);
-  bfd_h_putlong (abfd, execp->a_syms  , bytes->a_syms);
-  bfd_h_putlong (abfd, execp->a_entry , bytes->a_entry);
-  bfd_h_putlong (abfd, execp->a_trsize, bytes->a_trsize);
-  bfd_h_putlong (abfd, execp->a_drsize, bytes->a_drsize);
+  return true;
 }
 
-/* Steve wants some way to frob this stuff from Saber while he's debugging
-   ld, so we have these funny shadow functions */
-/* ZMAGIC's start at 0 (making the exec part of the text section),
-  other formats start after the exec
-*/
-static unsigned int n_txtoff(ptr)
-struct exec *ptr;
-{return N_MAGIC(*ptr)== ZMAGIC ? 0: sizeof(struct exec);}
-
-static unsigned int n_datoff(ptr)
-struct exec *ptr;
-{return n_txtoff(ptr) + ptr->a_text;}
-
-static unsigned int n_treloff(ptr)
-struct exec *ptr;
-{return n_datoff(ptr) + ptr->a_data;}
-
-static unsigned int n_dreloff(ptr)
-struct exec *ptr;
-{return n_treloff(ptr) + ptr->a_trsize;}
-
-static unsigned int n_symoff(ptr)
-struct exec *ptr;
-{return n_dreloff(ptr) + ptr->a_drsize;}
-
-static unsigned int n_stroff(ptr)
-struct exec *ptr;
-{return n_symoff(ptr) + ptr->a_syms;}
-
-static
-unsigned int n_badmag(ptr)
-     struct exec *ptr;
-{
-  switch (N_MAGIC(*ptr)) {
-  case OMAGIC: case NMAGIC: case ZMAGIC: return 0;
-  default: return 1;
-  }
-}
+/* Return the amount of memory required for the dynamic symbols.  */
 
-bfd_target *
-sunos4_object_p (abfd)
+static long
+sunos_get_dynamic_symtab_upper_bound (abfd)
      bfd *abfd;
 {
-  unsigned char magicbuf[4];   /* Raw bytes of magic number from file */
-  unsigned long magic;         /* Swapped magic number */
-  unsigned char exec_bytes[EXEC_BYTES_SIZE];   /* Raw bytes of exec hdr */
-  struct exec *execp;
-  PTR rawptr;
-
-  bfd_error = system_call_error;
+  struct sunos_dynamic_info *info;
 
-  if (bfd_read ((PTR)magicbuf, 1, sizeof (magicbuf), abfd) !=
-      sizeof (magicbuf))
-    return 0;
-  magic = bfd_h_getlong (abfd, magicbuf);
+  if (! sunos_read_dynamic_info (abfd))
+    return -1;
 
-  /* Baroque syntax to mask deficiencies of the Sun compiler */
-  /* if (N_BADMAG (*((struct exec *) &magic))) return 0; */
-  if (n_badmag ((struct exec *) &magic)) return 0;
-
-  if (bfd_seek (abfd, 0L, false) < 0) return 0;
+  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+  if (! info->valid)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
 
-  if (bfd_read ((PTR) exec_bytes, 1, EXEC_BYTES_SIZE, abfd)
-      != EXEC_BYTES_SIZE) {
-    bfd_error = wrong_format;
-    return 0;
-  }
+  return (info->dynsym_count + 1) * sizeof (asymbol *);
+}
 
-  /* Use an intermediate variable for clarity */
-  rawptr = (PTR) zalloc (sizeof (struct sunexdata) + sizeof (struct exec));
+/* Read in the dynamic symbols.  */
 
-  if (rawptr == NULL) {
-    bfd_error = no_memory;
-    return 0;
-  }
+static long
+sunos_canonicalize_dynamic_symtab (abfd, storage)
+     bfd *abfd;
+     asymbol **storage;
+{
+  struct sunos_dynamic_info *info;
+  long i;
 
-  set_tdata (abfd, ((struct sunexdata *) rawptr));
-  exec_hdr (abfd) = execp =
-    (struct exec *) ((char *)rawptr + sizeof (struct sunexdata));
+  /* Get the general dynamic information.  */
+  if (obj_aout_dynamic_info (abfd) == NULL)
+    {
+      if (! sunos_read_dynamic_info (abfd))
+         return -1;
+    }
 
-  bfd_aout_swap_exec_header_in (abfd, exec_bytes, execp);
+  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+  if (! info->valid)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
 
-  /* Set the file flags */
-  abfd->flags = NO_FLAGS;
-  if (execp->a_drsize || execp->a_trsize)
-    abfd->flags |= HAS_RELOC;
-  if (execp->a_entry) 
-    abfd->flags |= EXEC_P;
-  if (execp->a_syms) 
-    abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
+  /* Get the dynamic nlist structures.  */
+  if (info->dynsym == (struct external_nlist *) NULL)
+    {
+      info->dynsym = ((struct external_nlist *)
+                     bfd_alloc (abfd,
+                                (info->dynsym_count
+                                 * EXTERNAL_NLIST_SIZE)));
+      if (info->dynsym == NULL && info->dynsym_count != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return -1;
+       }
+      if (bfd_seek (abfd, info->dyninfo.ld_stab, SEEK_SET) != 0
+         || (bfd_read ((PTR) info->dynsym, info->dynsym_count,
+                       EXTERNAL_NLIST_SIZE, abfd)
+             != info->dynsym_count * EXTERNAL_NLIST_SIZE))
+       {
+         if (info->dynsym != NULL)
+           {
+             bfd_release (abfd, info->dynsym);
+             info->dynsym = NULL;
+           }
+         return -1;
+       }
+    }
 
+  /* Get the dynamic strings.  */
+  if (info->dynstr == (char *) NULL)
+    {
+      info->dynstr = (char *) bfd_alloc (abfd, info->dyninfo.ld_symb_size);
+      if (info->dynstr == NULL && info->dyninfo.ld_symb_size != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return -1;
+       }
+      if (bfd_seek (abfd, info->dyninfo.ld_symbols, SEEK_SET) != 0
+         || (bfd_read ((PTR) info->dynstr, 1, info->dyninfo.ld_symb_size,
+                       abfd)
+             != info->dyninfo.ld_symb_size))
+       {
+         if (info->dynstr != NULL)
+           {
+             bfd_release (abfd, info->dynstr);
+             info->dynstr = NULL;
+           }
+         return -1;
+       }
+    }
 
-  if (N_MAGIC (*execp) == ZMAGIC) abfd->flags |= D_PAGED;
-  if (N_MAGIC (*execp) == NMAGIC) abfd->flags |= WP_TEXT;
+#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.  */
+  {
+    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_byte *) malloc (table_size);
+    if (table == NULL && table_size != 0)
+      abort ();
+    if (bfd_seek (abfd, info->dyninfo.ld_hash, SEEK_SET) != 0
+       || bfd_read ((PTR) table, 1, 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 */
 
-  /* Determine the architecture and machine type of the object file.  */
-  abfd->obj_arch = bfd_arch_unknown;   /* Default values */
-  abfd->obj_machine = 0;
-  switch (N_MACHTYPE (*execp)) {
+  /* Get the asymbol structures corresponding to the dynamic nlist
+     structures.  */
+  if (info->canonical_dynsym == (aout_symbol_type *) NULL)
+    {
+      info->canonical_dynsym = ((aout_symbol_type *)
+                               bfd_alloc (abfd,
+                                          (info->dynsym_count
+                                           * sizeof (aout_symbol_type))));
+      if (info->canonical_dynsym == NULL && info->dynsym_count != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return -1;
+       }
 
-  case M_UNKNOWN:
-       break;
+      if (! aout_32_translate_symbol_table (abfd, info->canonical_dynsym,
+                                           info->dynsym, info->dynsym_count,
+                                           info->dynstr,
+                                           info->dyninfo.ld_symb_size,
+                                           true))
+       {
+         if (info->canonical_dynsym != NULL)
+           {
+             bfd_release (abfd, info->canonical_dynsym);
+             info->canonical_dynsym = NULL;
+           }
+         return -1;
+       }
+    }
 
-  case M_68010:
-       abfd->obj_arch = bfd_arch_m68k;
-       abfd->obj_machine = 68010;
-       break;
+  /* Return pointers to the dynamic asymbol structures.  */
+  for (i = 0; i < info->dynsym_count; i++)
+    *storage++ = (asymbol *) (info->canonical_dynsym + i);
+  *storage = NULL;
 
-  case M_68020:
-       abfd->obj_arch = bfd_arch_m68k;
-       abfd->obj_machine = 68020;
-       break;
+  return info->dynsym_count;
+}
 
-  case M_SPARC:
-       abfd->obj_arch = bfd_arch_sparc;
-       break;
+/* Return the amount of memory required for the dynamic relocs.  */
 
-  case M_386:
-       abfd->obj_arch = bfd_arch_i386;
-       break;
+static long
+sunos_get_dynamic_reloc_upper_bound (abfd)
+     bfd *abfd;
+{
+  struct sunos_dynamic_info *info;
 
-  case M_29K:
-       abfd->obj_arch = bfd_arch_a29k;
-       break;
+  if (! sunos_read_dynamic_info (abfd))
+    return -1;
 
-  default:
-       abfd->obj_arch = bfd_arch_obscure;
-       break;
-  }
+  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+  if (! info->valid)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
 
-  bfd_get_start_address (abfd) = execp->a_entry;
-
-  /* Remember the positions of the string table and symbol table.  */
-  obj_str_filepos (abfd) = n_stroff (execp);
-  obj_sym_filepos (abfd) = n_symoff (execp);
-
-  /* create the sections.  This is raunchy, but bfd_close wants to reclaim
-     them */
-  obj_textsec (abfd) = (asection *)NULL;
-  obj_datasec (abfd) = (asection *)NULL;
-  obj_bsssec (abfd) = (asection *)NULL;
-  obj_aout_symbols(abfd) = (aout_symbol_type *)NULL;
-  (void)bfd_make_section(abfd, ".text");
-  (void)bfd_make_section(abfd, ".data");
-  (void)bfd_make_section(abfd, ".bss");
-
-  obj_datasec (abfd)->size = execp->a_data;
-  obj_bsssec (abfd)->size = execp->a_bss;
-  obj_textsec (abfd)->size = execp->a_text;
-  obj_datasec (abfd)->vma = N_DATADDR(*execp);
-  obj_bsssec (abfd)->vma = N_BSSADDR(*execp);
-  obj_textsec (abfd)->vma = N_TXTADDR(*execp);
-
-  obj_textsec (abfd)->filepos = N_TXTOFF(*execp);
-  obj_datasec (abfd)->filepos = N_DATOFF(*execp);
-
-  obj_textsec (abfd)->rel_filepos = N_TROFF(*execp);
-  obj_datasec (abfd)->rel_filepos = N_DROFF(*execp);
-
-  obj_textsec (abfd)->flags = (execp->a_trsize != 0 ?
-                               (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_HAS_CONTENTS) :
-                               (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS));
-  obj_datasec (abfd)->flags = (execp->a_drsize != 0 ?
-                               (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_HAS_CONTENTS) :
-                               (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS));
-  obj_bsssec (abfd)->flags = SEC_ALLOC;
-
-  abfd->sections = obj_textsec (abfd);
-  obj_textsec (abfd)->next = obj_datasec (abfd);
-  obj_datasec (abfd)->next = obj_bsssec (abfd);
-  return abfd->xvec;
+  return (info->dynrel_count + 1) * sizeof (arelent *);
 }
 
+/* Read in the dynamic relocs.  */
 
-boolean
-sunos4_mkobject (abfd)
+static long
+sunos_canonicalize_dynamic_reloc (abfd, storage, syms)
      bfd *abfd;
+     arelent **storage;
+     asymbol **syms;
 {
-  char *rawptr;
+  struct sunos_dynamic_info *info;
+  long i;
 
-  bfd_error = system_call_error;
+  /* Get the general dynamic information.  */
+  if (obj_aout_dynamic_info (abfd) == (PTR) NULL)
+    {
+      if (! sunos_read_dynamic_info (abfd))
+       return -1;
+    }
 
-  /* Use an intermediate variable for clarity */
-  rawptr =  zalloc (sizeof (struct sunexdata) + sizeof (struct exec));
+  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
+  if (! info->valid)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
 
-  if (rawptr == NULL) {
-    bfd_error = no_memory;
-    return false;
-  }
+  /* Get the dynamic reloc information.  */
+  if (info->dynrel == NULL)
+    {
+      info->dynrel = (PTR) bfd_alloc (abfd,
+                                     (info->dynrel_count
+                                      * obj_reloc_entry_size (abfd)));
+      if (info->dynrel == NULL && info->dynrel_count != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return -1;
+       }
+      if (bfd_seek (abfd, info->dyninfo.ld_rel, SEEK_SET) != 0
+         || (bfd_read ((PTR) info->dynrel, info->dynrel_count,
+                       obj_reloc_entry_size (abfd), abfd)
+             != info->dynrel_count * obj_reloc_entry_size (abfd)))
+       {
+         if (info->dynrel != NULL)
+           {
+             bfd_release (abfd, info->dynrel);
+             info->dynrel = NULL;
+           }
+         return -1;
+       }
+    }
+
+  /* Get the arelent structures corresponding to the dynamic reloc
+     information.  */
+  if (info->canonical_dynrel == (arelent *) NULL)
+    {
+      arelent *to;
 
-  abfd->tdata = (PTR)((struct sunexdata *) rawptr);
-  exec_hdr (abfd) = (struct exec *) (rawptr + sizeof (struct sunexdata));
+      info->canonical_dynrel = ((arelent *)
+                               bfd_alloc (abfd,
+                                          (info->dynrel_count
+                                           * sizeof (arelent))));
+      if (info->canonical_dynrel == NULL && info->dynrel_count != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return -1;
+       }
+      
+      to = info->canonical_dynrel;
 
-  /* For simplicity's sake we just make all the sections right here. */
+      if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE)
+       {
+         register 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,
+                                         info->dynsym_count);
+       }
+      else
+       {
+         register 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,
+                                         info->dynsym_count);
+       }
+    }
 
-  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");
+  /* Return pointers to the dynamic arelent structures.  */
+  for (i = 0; i < info->dynrel_count; i++)
+    *storage++ = info->canonical_dynrel + i;
+  *storage = NULL;
 
-  return true;
+  return info->dynrel_count;
 }
+\f
+/* Code to handle linking of SunOS shared libraries.  */
 
-/* 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.
+/* 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.  */
 
-   If the architecture is understood, machine type 0 (default) should
-   always be understood.  */
+#define SPARC_PLT_ENTRY_SIZE (12)
 
-static enum machine_type
-aout_machine_type (arch, machine)
-     enum bfd_architecture arch;
-     unsigned long machine;
+static const bfd_byte sparc_plt_first_entry[SPARC_PLT_ENTRY_SIZE] =
 {
-  enum machine_type arch_flags;
-
-  arch_flags = M_UNKNOWN;
-
-  switch (arch) {
-  case bfd_arch_sparc:
-       if (machine == 0)       arch_flags = M_SPARC;
-       break;
-
-  case bfd_arch_m68k:
-       switch (machine) {
-       case 0:                 arch_flags = M_UNKNOWN; 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;
-       }
-       break;
+  /* 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
+};
 
-  case bfd_arch_i386:
-       if (machine == 0)       arch_flags = M_386;
-       break;
+/* save %sp, -96, %sp */
+#define SPARC_PLT_ENTRY_WORD0 0x9de3bfa0
+/* call; address filled in later.  */
+#define SPARC_PLT_ENTRY_WORD1 0x40000000
+/* sethi; reloc index filled in later.  */
+#define SPARC_PLT_ENTRY_WORD2 0x01000000
 
-  case bfd_arch_a29k:
-       if (machine == 0)       arch_flags = M_29K;
-       break;
+/* 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.  */
 
-  default:
-       arch_flags = M_UNKNOWN;
-       break;
-  }
-  return arch_flags;
-}
+#define M68K_PLT_ENTRY_SIZE (8)
 
-boolean
-sunos4_set_arch_mach (abfd, arch, machine)
-     bfd *abfd;
-     enum bfd_architecture arch;
-     unsigned long machine;
+static const bfd_byte m68k_plt_first_entry[M68K_PLT_ENTRY_SIZE] =
 {
-  abfd->obj_arch = arch;
-  abfd->obj_machine = machine;
-  if (arch != bfd_arch_unknown &&
-      aout_machine_type (arch, machine) == M_UNKNOWN)
-    return false;              /* We can't represent this type */
-  return true;                 /* We're easy ... */
-}
+  /* jmps @# */
+  0x4e, 0xf9,
+  /* Filled in by runtime linker with a magic address.  */
+  0, 0, 0, 0,
+  /* Not used?  */
+  0, 0
+};
 
-boolean
-sunos4_write_object_contents (abfd)
-     bfd *abfd;
-{
-  size_t data_pad = 0;
-  unsigned char exec_bytes[EXEC_BYTES_SIZE];
-  struct exec *execp = exec_hdr (abfd);
-
-  execp->a_text = obj_textsec (abfd)->size;
-
-  /* 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;
-    }
-    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);
-  }
+/* bsrl */
+#define M68K_PLT_ENTRY_WORD0 (0x61ff)
+/* Remaining words filled in later.  */
 
-  N_SET_MAGIC (*execp, OMAGIC);
-  if (abfd->flags & D_PAGED) {
-    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? */
+/* An entry in the SunOS linker hash table.  */
 
-  if (abfd->flags & D_PAGED) 
-      {
-       data_pad = ((obj_datasec(abfd)->size + PAGE_SIZE -1)
-                   & (- PAGE_SIZE)) - obj_datasec(abfd)->size;
+struct sunos_link_hash_entry
+{
+  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;
+
+  /* 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 010
+  /* Symbol is defined by a dynamic object.  */
+#define SUNOS_DEF_DYNAMIC 020
+};
 
-       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;
+/* The SunOS linker hash table.  */
 
-      }
-  else {
-    execp->a_data = obj_datasec (abfd)->size;
-    execp->a_bss = obj_bsssec (abfd)->size;
-  }
+struct sunos_link_hash_table
+{
+  struct aout_link_hash_table root;
 
-  execp->a_syms = bfd_get_symcount (abfd) * sizeof (struct nlist);
-  execp->a_entry = bfd_get_start_address (abfd);
+  /* The first dynamic object found during the link.  */
+  bfd *dynobj;
 
-  execp->a_trsize = ((obj_textsec (abfd)->reloc_count) *
-                    reloc_size_func(abfd));
-                      
-  execp->a_drsize = ((obj_datasec (abfd)->reloc_count) *
-                    reloc_size_func(abfd));
+  /* The number of dynamic symbols.  */
+  size_t dynsymcount;
 
-  bfd_aout_swap_exec_header_out (abfd, execp, exec_bytes);
+  /* The number of buckets in the hash table.  */
+  size_t bucketcount;
+};
 
-  bfd_seek (abfd, 0L, false);
-  bfd_write ((PTR) exec_bytes, 1, EXEC_BYTES_SIZE, abfd);
+/* Routine to create an entry in an SunOS link hash table.  */
 
-  /* Now write out reloc info, followed by syms and strings */
+static struct bfd_hash_entry *
+sunos_link_hash_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  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 == (struct sunos_link_hash_entry *) NULL)
+    ret = ((struct sunos_link_hash_entry *)
+          bfd_hash_allocate (table, sizeof (struct sunos_link_hash_entry)));
+  if (ret == (struct sunos_link_hash_entry *) NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return (struct bfd_hash_entry *) ret;
+    }
 
-  if (bfd_get_symcount (abfd) != 0) 
+  /* 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)
     {
-      bfd_seek (abfd,
-               (long)(N_SYMOFF(*execp)), false);
+      /* Set local fields.  */
+      ret->dynindx = -1;
+      ret->dynstr_index = -1;
+      ret->flags = 0;
+    }
 
-      sunos4_write_syms (abfd);
+  return (struct bfd_hash_entry *) ret;
+}
 
-      bfd_seek (abfd,  (long)(N_TROFF(*execp)), false);
+/* Create a SunOS link hash table.  */
 
-      if (!sunos4_squirt_out_relocs (abfd, obj_textsec (abfd))) return false;
-      bfd_seek (abfd, (long)(N_DROFF(*execp)), false);
+static struct bfd_link_hash_table *
+sunos_link_hash_table_create (abfd)
+     bfd *abfd;
+{
+  struct sunos_link_hash_table *ret;
 
-      if (!sunos4_squirt_out_relocs (abfd, obj_datasec (abfd))) return false;
+  ret = ((struct sunos_link_hash_table *)
+        malloc (sizeof (struct sunos_link_hash_table)));
+  if (ret == (struct sunos_link_hash_table *) NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return (struct bfd_link_hash_table *) NULL;
     }
-  return true;
+  if (! NAME(aout,link_hash_table_init) (&ret->root, abfd,
+                                        sunos_link_hash_newfunc))
+    {
+      free (ret);
+      return (struct bfd_link_hash_table *) NULL;
+    }
+
+  ret->dynobj = NULL;
+  ret->dynsymcount = 0;
+  ret->bucketcount = 0;
+
+  return &ret->root.root;
 }
 
-/** core files */
-/** 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;
-};
+/* Look up an entry in an SunOS link hash table.  */
 
-/* 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 */
-  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.) */
-};
+#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)))
 
-/* 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;
-};
+/* Traverse a SunOS link hash table.  */
 
-bfd_target *
-sunos4_core_file_p (abfd)
-     bfd *abfd;
-{
-  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 = zalloc (core_size + sizeof (struct suncordata));
-  if (rawptr == NULL) {
-    bfd_error = no_memory;
-    return 0;
-  }
+#define sunos_link_hash_traverse(table, func, info)                    \
+  (aout_link_hash_traverse                                             \
+   (&(table)->root,                                                    \
+    (boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func),        \
+    (info)))
 
-  core = (struct core *) (rawptr + sizeof (struct suncordata));
+/* Get the SunOS link hash table from the info structure.  This is
+   just a cast.  */
 
-  if ((bfd_read ((PTR) core, 1, core_size, abfd)) != core_size) {
-    bfd_error = system_call_error;
-    free ((PTR)rawptr);
-    return 0;
-  }
+#define sunos_hash_table(p) ((struct sunos_link_hash_table *) ((p)->hash))
 
-  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 *) zalloc (sizeof (asection));
-  if (core_stacksec (abfd) == NULL) {
-loser:
-    bfd_error = no_memory;
-    free ((PTR)rawptr);
-    return 0;
-  }
-  core_datasec (abfd) = (asection *) zalloc (sizeof (asection));
-  if (core_datasec (abfd) == NULL) {
-loser1:
-    free ((PTR)core_stacksec (abfd));
-    goto loser;
-  }
-  core_regsec (abfd) = (asection *) zalloc (sizeof (asection));
-  if (core_regsec (abfd) == NULL) {
-loser2:
-    free ((PTR)core_datasec (abfd));
-    goto loser1;
-  }
-  core_reg2sec (abfd) = (asection *) zalloc (sizeof (asection));
-  if (core_reg2sec (abfd) == NULL) {
-    free ((PTR)core_regsec (abfd));
-    goto loser2;
-  }
+static boolean sunos_scan_dynamic_symbol
+  PARAMS ((struct sunos_link_hash_entry *, PTR));
 
-  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;
-}
+/* Add dynamic symbols during a link.  This is called by the a.out
+   backend linker when it encounters an object with the DYNAMIC flag
+   set.  */
 
-char *
-sunos4_core_file_failing_command (abfd)
+static boolean
+sunos_add_dynamic_symbols (abfd, info)
      bfd *abfd;
+     struct bfd_link_info *info;
 {
-  return core_hdr (abfd)->c_cmdname;
+  asection *s;
+
+  /* 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.  */
+  abfd->sections = NULL;
+
+  /* The native linker seems to just ignore dynamic objects when -r is
+     used.  */
+  if (info->relocateable)
+    return true;
+
+  /* There's no hope of using a dynamic object which does not exactly
+     match the format of the output file.  */
+  if (info->hash->creator != abfd->xvec)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
+    }
+
+  /* If this is the first dynamic object, create some new sections to
+     hold dynamic linking information.  We need to put these sections
+     somewhere, and the first dynamic object is as good a place as
+     any.  The linker script will look for these special section 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.  */
+  if (sunos_hash_table (info)->dynobj == NULL)
+    {
+      flagword flags;
+      asection *sdyn;
+
+      sunos_hash_table (info)->dynobj = abfd;
+      
+      flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+
+      /* 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 (abfd, ".dynamic");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags)
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return false;
+      sdyn = s;
+
+      /* 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.  */
+      s = bfd_make_section (abfd, ".need");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return false;
+
+      /* The .rules section holds the path to search for shared
+        objects.  The address of this section is put in the ld_rules
+        field.  */
+      s = bfd_make_section (abfd, ".rules");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return false;
+
+      /* The .got section holds the global offset table.  I don't
+        really know how this works, actually.  It seems to only be
+        used for PIC code.  The address minus four is put in the
+        ld_got field.  */
+      s = bfd_make_section (abfd, ".got");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags)
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return false;
+      s->_raw_size = BYTES_IN_WORD;
+
+      /* The .plt section holds the procedure linkage table.  The
+        address is put in the ld_plt field.  */
+      s = bfd_make_section (abfd, ".plt");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags | SEC_CODE)
+         || ! 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 (abfd, ".dynrel");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+         || ! 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 (abfd, ".hash");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+         || ! 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 (abfd, ".dynsym");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+         || ! 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 (abfd, ".dynstr");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return false;
+    }
+
+  return true;
 }
 
-int
-sunos4_core_file_failing_signal (abfd)
+/* 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 boolean
+sunos_add_one_symbol (info, abfd, name, flags, section, value, string,
+                     copy, collect, hashp)
+     struct bfd_link_info *info;
      bfd *abfd;
+     const char *name;
+     flagword flags;
+     asection *section;
+     bfd_vma value;
+     const char *string;
+     boolean copy;
+     boolean collect;
+     struct bfd_link_hash_entry **hashp;
 {
-  return core_hdr (abfd)->c_signo;
-}
+  struct sunos_link_hash_entry *h;
+  int new_flag;
 
-boolean
-sunos4_core_file_matches_executable_p  (core_bfd, exec_bfd)
-     bfd *core_bfd, *exec_bfd;
-{
-  if (core_bfd->xvec != exec_bfd->xvec) {
-    bfd_error = system_call_error;
+  h = sunos_link_hash_lookup (sunos_hash_table (info), name, true, copy,
+                             false);
+  if (h == NULL)
     return false;
-  }
-
-  return (bcmp ((char *)&core_hdr (core_bfd), (char*) &exec_hdr (exec_bfd),
-                sizeof (struct exec)) == 0) ? true : false;
-}
 
-/* 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;
-{
-  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.  */
-}
-\f
-/** exec and core file sections */
+  if (hashp != NULL)
+    *hashp = (struct bfd_link_hash_entry *) h;
 
-boolean
-sunos4_new_section_hook (abfd, newsect)
-     bfd *abfd;
-     asection *newsect;
-{
-  /* align to double at least */
-  newsect->alignment_power = 3;
+  /* 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_get_format (abfd) == bfd_object) {
-    if (obj_textsec(abfd) == NULL && !strcmp(newsect->name, ".text")) {
-      obj_textsec(abfd)= newsect;
-      return true;
+  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)
+              || (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.  */
+         h->root.root.type = bfd_link_hash_new;
+       }
     }
 
-    if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) {
-      obj_datasec(abfd) = newsect;
-      return true;
-    }
+  /* 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 (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) {
-      obj_bsssec(abfd) = newsect;
-      return true;
+  if (abfd->xvec == info->hash->creator)
+    {
+      /* 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;
+       }
     }
-  }
 
-  /* We allow more than three sections internally */
   return true;
 }
 
+/* Record an assignment made to a symbol by a linker script.  We need
+   this in case some dynamic object refers to this symbol.  */
+
 boolean
-sunos4_set_section_contents (abfd, section, location, offset, count)
-     bfd *abfd;
-     sec_ptr section;
-     unsigned char *location;
-     file_ptr offset;
-      int count;
+bfd_sunos_record_link_assignment (output_bfd, info, name)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     const char *name;
 {
-  if (abfd->output_has_begun == false)
-      {                                /* set by bfd.c handler */
-       if ((obj_textsec (abfd) == NULL) || (obj_datasec (abfd) == NULL)
-         
-           /*||
-             (obj_textsec (abfd)->size == 0) || (obj_datasec (abfd)->size=
-             0)*/
-           ) 
-           {
-             bfd_error = invalid_operation;
-             return false;
-           }
-
+  struct sunos_link_hash_entry *h;
 
-#if 0
-       if (abfd->flags & D_PAGED)
-           {
-             obj_textsec (abfd)->filepos = sizeof(struct exec);
-             obj_datasec(abfd)->filepos =  obj_textsec (abfd)->size;
-           }
-       else 
-#endif
-           {
-             obj_textsec (abfd)->filepos = sizeof(struct exec);
-             obj_datasec(abfd)->filepos = obj_textsec(abfd)->filepos  + obj_textsec (abfd)->size;
+  /* 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;
 
-           }
-      }
-  /* regardless, once we know what we're doing, we might as well get going */
-  if (section != obj_bsssec(abfd)) {
-    bfd_seek (abfd, section->filepos + offset, SEEK_SET);
+  h->flags |= SUNOS_DEF_REGULAR;
 
-    if (count) {
-      return (bfd_write ((PTR)location, 1, count, abfd) == count) ?
-       true : false;
+  if (h->dynindx == -1)
+    {
+      ++sunos_hash_table (info)->dynsymcount;
+      h->dynindx = -2;
     }
-    return false;
-  }
+
   return true;
 }
+
+/* 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.  */
+
 boolean
-sunos4_get_section_contents (abfd, section, location, offset, count)
-     bfd *abfd;
-     sec_ptr section;
-     PTR location;
-     file_ptr offset;
-     int count;
+bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
+                                srulesptr)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     asection **sdynptr;
+     asection **sneedptr;
+     asection **srulesptr;
 {
-  if (count) {
-    if (offset >= section->size) return false;
-
-    bfd_seek (abfd, section->filepos + offset, SEEK_SET);
+  bfd *dynobj;
+  size_t dynsymcount;
+  asection *s;
+  size_t bucketcount;
+  size_t hashalloc;
+  size_t i;
+  bfd *sub;
+
+  *sdynptr = NULL;
+  *sneedptr = NULL;
+  *srulesptr = NULL;
+
+  dynobj = sunos_hash_table (info)->dynobj;
+  dynsymcount = sunos_hash_table (info)->dynsymcount;
+
+  /* If there were no dynamic objects in the link, there is nothing to
+     do here.  */
+  if (dynobj == NULL)
+    return true;
+
+  /* The .dynamic section is always the same size.  */
+  s = bfd_get_section_by_name (dynobj, ".dynamic");
+  BFD_ASSERT (s != NULL);
+  s->_raw_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->_raw_size = dynsymcount * sizeof (struct external_nlist);
+  s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
+  if (s->contents == NULL && s->_raw_size != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+      
+  /* The number of buckets is just the number of symbols divided by
+     four.  The 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 worse 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_byte *) bfd_alloc (dynobj, hashalloc);
+  if (s->contents == NULL && dynsymcount > 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+  memset (s->contents, 0, hashalloc);
+  for (i = 0; i < bucketcount; i++)
+    PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE);
+  s->_raw_size = bucketcount * HASH_ENTRY_SIZE;
+
+  sunos_hash_table (info)->bucketcount = bucketcount;
+
+  /* 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)
+       {
+         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;
+       }
+    }
 
-    return (bfd_read (location, 1, count, abfd) == count) ? true:false;
-  }
-  else return true;
-}
+  /* 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,
+                           (PTR) 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->_raw_size & 7) != 0)
+    {
+      bfd_size_type add;
+      bfd_byte *contents;
 
-\f
-/* Classify stabs symbols */
+      add = 8 - (s->_raw_size & 7);
+      contents = (bfd_byte *) realloc (s->contents, s->_raw_size + add);
+      if (contents == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
+      memset (contents + s->_raw_size, 0, add);
+      s->contents = contents;
+      s->_raw_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->_raw_size != 0)
+    {
+      s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
+      if (s->contents == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
 
-#define sym_in_text_section(sym) \
-     (((sym)->n_type  & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT)
+      /* 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;
 
-#define sym_in_data_section(sym) \
-     (((sym)->n_type  & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA)
+       case bfd_arch_m68k:
+         memcpy (s->contents, m68k_plt_first_entry, M68K_PLT_ENTRY_SIZE);
+         break;
 
-#define sym_in_bss_section(sym) \
-     (((sym)->n_type  & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS)
+       default:
+         abort ();
+       }
+    }
 
-/* Symbol is undefined if type is N_UNDF|N_EXT and if it has
-   zero in the "value" field.  Nonzeroes there are fortrancommon
-   symbols.  */
-#define sym_is_undefined(sym) \
-        ((sym)->n_type == (N_UNDF | N_EXT) && (sym)->n_value == 0)
+  s = bfd_get_section_by_name (dynobj, ".dynrel");
+  if (s->_raw_size != 0)
+    {
+      s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
+      if (s->contents == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         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_byte *) bfd_alloc (dynobj, s->_raw_size);
+  if (s->contents == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
 
-/* Symbol is a global definition if N_EXT is on and if it has
-   a nonzero type field.  */
-#define sym_is_global_defn(sym) \
-        (((sym)->n_type & N_EXT) && (sym)->n_type & N_TYPE)
+  *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic");
+  *sneedptr = bfd_get_section_by_name (dynobj, ".need");
+  *srulesptr = bfd_get_section_by_name (dynobj, ".rules");
 
-/* Symbol is debugger info if any bits outside N_TYPE or N_EXT
-   are on.  */
-#define sym_is_debugger_info(sym) \
-        ((sym)->n_type & ~(N_EXT | N_TYPE))
+  return true;
+}
 
-#define sym_is_fortrancommon(sym)       \
-        (((sym)->n_type == (N_EXT)) && (sym)->n_value != 0)
+/* Scan the relocs for an input section.  */
 
-/* Symbol is absolute if it has N_ABS set */
-#define sym_is_absolute(sym) \
-              (((sym)->n_type  & N_TYPE)== N_ABS)
+static boolean
+sunos_scan_relocs (info, abfd, sec, rel_size)
+     struct bfd_link_info *info;
+     bfd *abfd;
+     asection *sec;
+     bfd_size_type rel_size;
+{
+  PTR relocs;
+  PTR free_relocs = NULL;
 
+  if (rel_size == 0)
+    return true;
 
-#define sym_is_indirect(sym) \
-              (((sym)->n_type  & N_ABS)== N_ABS)
+  if (! info->keep_memory)
+    relocs = free_relocs = malloc (rel_size);
+  else
+    {
+      aout_section_data (sec) =
+       ((struct aout_section_data_struct *)
+        bfd_alloc (abfd, sizeof (struct aout_section_data_struct)));
+      if (aout_section_data (sec) == NULL)
+       relocs = NULL;
+      else
+       relocs = aout_section_data (sec)->relocs = malloc (rel_size);
+    }
+  if (relocs == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
 
-/* Only in their own functions for ease of debugging; when sym flags have
-   stabilised these should be inlined into their (single) caller */
+  if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
+      || bfd_read (relocs, 1, rel_size, abfd) != rel_size)
+    goto error_return;
 
-static void
-translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd)
-     struct nlist *sym_pointer;
-     aout_symbol_type *cache_ptr;
-     bfd *abfd;
-{
-  switch (cache_ptr->type & N_TYPE) {
-  case N_SETA:
-  case N_SETT:
-  case N_SETD:
-  case N_SETB:
+  if (obj_reloc_entry_size (abfd) == RELOC_STD_SIZE)
     {
-      asection *section = bfd_make_section(abfd,
-                                          cache_ptr->symbol.name);
-      arelent_chain *reloc = (arelent_chain *)malloc(sizeof(arelent_chain));
-
-      switch ( (cache_ptr->type  & N_TYPE) ) {
-      case N_SETA:
-       reloc->relent.section =  (asection *)NULL;
-       cache_ptr->symbol.section = (asection *)NULL;
-       break;
-      case N_SETT:
-       reloc->relent.section = (asection *)obj_textsec(abfd);
-       cache_ptr->symbol.value -= reloc->relent.section->vma;
-       break;
-      case N_SETD:
-       reloc->relent.section = (asection *)obj_datasec(abfd);
-       cache_ptr->symbol.value -= reloc->relent.section->vma;
-       break;
-      case N_SETB:
-       reloc->relent.section = (asection *)obj_bsssec(abfd);
-       cache_ptr->symbol.value -= reloc->relent.section->vma;
-       break;
-      }
-      cache_ptr->symbol.section = reloc->relent.section;
-      reloc->relent.addend = cache_ptr->symbol.value ;
-      /* 
-        We modify the symbol to belong to a section depending upon the
-        name of the symbol - probably __CTOR__ or __DTOR__ but we don't
-        really care, and add to the size of the section to contain a
-        pointer to the symbol. Build a reloc entry to relocate to this
-        symbol attached to this section.
-        */
-
-
-      section->flags = SEC_CONSTRUCTOR;
-      section->reloc_count++;
-      section->alignment_power = 2;
-      reloc->relent.sym_ptr_ptr = (asymbol **)NULL;
-      reloc->next = section->constructor_chain;
-      section->constructor_chain = reloc;
-      reloc->relent.address = section->size;
-      section->size += sizeof(int *);
-
-      reloc->relent.howto = howto_table_ext +CTOR_TABLE_RELOC_IDX;
-      cache_ptr->symbol.flags |=  BSF_DEBUGGING ;
-      }
-    break;
-  default:
-
-    if (sym_is_debugger_info (sym_pointer)) {
-      cache_ptr->symbol.flags = BSF_DEBUGGING ;
-      /* Work out the section correct for this symbol */
-      switch (sym_pointer->n_type & N_TYPE) 
-       {
-       case N_TEXT:
-       case N_FN:
-         cache_ptr->symbol.section = obj_textsec (abfd);
-         cache_ptr->symbol.value -= obj_textsec(abfd)->vma;
-         break;
-       case N_DATA:
-         cache_ptr->symbol.value  -= obj_datasec(abfd)->vma;
-         cache_ptr->symbol.section = obj_datasec (abfd);
-         break;
-       case N_BSS :
-         cache_ptr->symbol.section = obj_bsssec (abfd);
-         cache_ptr->symbol.value -= obj_bsssec(abfd)->vma;
-         break;
-       case N_ABS:
-       default:
-         cache_ptr->symbol.section = 0;
-         break;
-       }
+      if (! sunos_scan_std_relocs (info, abfd, sec,
+                                  (struct reloc_std_external *) relocs,
+                                  rel_size))
+       goto error_return;
     }
-    else {
-      if (sym_is_fortrancommon (sym_pointer))
-       {
-         cache_ptr->symbol.flags = BSF_FORT_COMM;
-         cache_ptr->symbol.section = (asection *)NULL;
-       }
-      else {
-       if (sym_is_undefined (sym_pointer)) {
-         cache_ptr->symbol.flags = BSF_UNDEFINED;
-       }
-       else if (sym_is_global_defn (sym_pointer)) {
-         cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT;
-       }
-
-       else if (sym_is_absolute (sym_pointer)) {
-         cache_ptr->symbol.flags = BSF_ABSOLUTE;
-       }
-       else {
-         cache_ptr->symbol.flags = BSF_LOCAL;
-       }
-
-       /* In a.out, the value of a symbol is always relative to the 
-        * start of the file, if this is a data symbol we'll subtract
-        * the size of the text section to get the section relative
-        * value. If this is a bss symbol (which would be strange)
-        * we'll subtract the size of the previous two sections
-        * to find the section relative address.
-        */
-
-       if (sym_in_text_section (sym_pointer))   {
-         cache_ptr->symbol.value -= obj_textsec(abfd)->vma;
-         cache_ptr->symbol.section = obj_textsec (abfd);
-       }
-       else if (sym_in_data_section (sym_pointer)){
-         cache_ptr->symbol.value -= obj_datasec(abfd)->vma;
-         cache_ptr->symbol.section = obj_datasec (abfd);
-       }
-       else if (sym_in_bss_section(sym_pointer)) {
-         cache_ptr->symbol.section = obj_bsssec (abfd);
-         cache_ptr->symbol.value -= obj_bsssec(abfd)->vma;
-       }
-       else {
-         cache_ptr->symbol.section = (asection *)NULL;
-         cache_ptr->symbol.flags |= BSF_ABSOLUTE;
-       }
-      }
-    }
-  }
-}
-
-void
-translate_to_native_sym_flags (sym_pointer, cache_ptr_g, abfd)
-     struct nlist *sym_pointer;
-     PTR cache_ptr_g;
-     bfd *abfd;
-{
-  asymbol *cache_ptr = (asymbol *)cache_ptr_g;
-
-  /* FIXME check for wrigin bss */
-  if (bfd_get_section(cache_ptr)) {
-    if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) {
-      sym_pointer->n_type |= N_BSS;
-    }
-    else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) {
-      sym_pointer->n_type |= N_DATA;
-    }
-    else  if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) {
-      sym_pointer->n_type |= N_TEXT;
-    }
-    else {
-
-      bfd_error_vector.nonrepresentable_section(abfd, bfd_get_output_section(cache_ptr)->name);
-
+  else
+    {
+      if (! sunos_scan_ext_relocs (info, abfd, sec,
+                                  (struct reloc_ext_external *) relocs,
+                                  rel_size))
+       goto error_return;
     }
-    /* Turn the symbol from section relative to absolute again */
-    sym_pointer->n_value +=
-      cache_ptr->section->output_section->vma 
-       + cache_ptr->section->output_offset ;
-  }
-  else {
-    sym_pointer->n_type |= N_ABS;
-  }
 
-  if (cache_ptr->flags & (BSF_FORT_COMM | BSF_UNDEFINED)) {
-    sym_pointer->n_type = (N_UNDF | N_EXT);
-    return;
-  }
-
-  if (cache_ptr->flags & BSF_ABSOLUTE) {
-    sym_pointer->n_type |= N_ABS;
-  }
-
-  if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) {
-    sym_pointer->n_type |= N_EXT;
-  }
-  if (cache_ptr->flags & BSF_DEBUGGING) {
-    sym_pointer->n_type = ((aout_symbol_type *)cache_ptr)->type;
-  }
-  
-}
-\f
-/* Native-level interface to symbols. */
-
-/* We read the symbols into a buffer, which is discarded when this
-   function exits.  We read the strings into a buffer large enough to
-   hold them all plus all the cached symbol entries. */
-
-asymbol *
-sunos4_make_empty_symbol (abfd)
-bfd *abfd;
-{
-  aout_symbol_type  *new =
-    (aout_symbol_type *)zalloc (sizeof (aout_symbol_type));
-  new->symbol.the_bfd = abfd;
-
-  return &new->symbol;
-}
-
-boolean
-DEFUN(sunos4_slurp_symbol_table, (abfd),
-      bfd *abfd)
-{
-  unsigned int symbol_count;
-  size_t symbol_size;
-  size_t string_size;
-  struct nlist *syms;
-  char *strings;
-  aout_symbol_type *cached;
-
-  /* If there's no work to be done, don't do any */
-  if (obj_aout_symbols (abfd) != (aout_symbol_type *)NULL) return true;
-  symbol_size = exec_hdr(abfd)->a_syms;
-  if (symbol_size == 0) {
-    bfd_error = no_symbols;
-    return false;
-  }
-
-  bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
-  if (bfd_read ((PTR)&string_size, 4, 1, abfd) != 4)
-    return false;
-  string_size = bfd_h_getlong (abfd, (unsigned char *)&string_size);
-
-  symbol_count = symbol_size / sizeof (struct nlist);
-
-  /* Malloc (should alloca) space for native symbols, and
-     malloc space for string table and symbol cache. */
-
-  syms = (struct nlist *) zalloc (symbol_size);
-  if (syms == NULL) {
-    bfd_error = no_memory;
-    return false;
-  }
-
-  cached = (aout_symbol_type *) zalloc ((size_t)(string_size + 1 +
-                               (symbol_count * sizeof (aout_symbol_type))));
-  if (cached == NULL) {
-    bfd_error = no_memory;
-    free ((PTR)syms);
-    return false;
-  }
-
-  strings = ((char *) cached) + (symbol_count * sizeof (aout_symbol_type));
-
-  bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET);
-  if (bfd_read ((PTR)syms, 1, symbol_size, abfd) != symbol_size) {
-  bailout:
-    free ((PTR)cached);
-    free ((PTR)syms);
-    return false;
-  }
-
-  bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
-  if (bfd_read ((PTR)strings, 1, string_size, abfd) != string_size) {
-    goto bailout;
-  }
-
-  /* OK, now walk the new symtable, cacheing symbol properties */
-  {
-    register struct nlist *sym_pointer;
-    register struct nlist *sym_end = syms + symbol_count;
-    register aout_symbol_type *cache_ptr = cached;
-
-      /* run through the table and byte swap if needed */
-      for (sym_pointer = syms; sym_pointer < sym_end;  sym_pointer++) {
-        sym_pointer->n_un.n_strx =
-         bfd_h_get_x (abfd, &sym_pointer->n_un.n_strx);
-        sym_pointer->n_desc =
-         bfd_h_get_x (abfd, &sym_pointer->n_desc);
-        sym_pointer->n_value =
-         bfd_h_get_x (abfd, &sym_pointer->n_value);
-       sym_pointer->n_other = (char)
-         bfd_h_get_x(abfd, &sym_pointer->n_other);
-       sym_pointer->n_type = (char)
-         bfd_h_get_x(abfd, &sym_pointer->n_type);
-
-      }
-
-    /* Run through table and copy values */
-    for (sym_pointer = syms, cache_ptr = cached;
-        sym_pointer < sym_end; sym_pointer++, cache_ptr++) 
-      {
-       cache_ptr->symbol.the_bfd = abfd;
-       if (sym_pointer->n_un.n_strx)
-         cache_ptr->symbol.name = sym_pointer->n_un.n_strx + strings;
-       else
-         cache_ptr->symbol.name = (char *)NULL;
-       cache_ptr->symbol.value = sym_pointer->n_value;
-       cache_ptr->desc = sym_pointer->n_desc;
-       cache_ptr->other = sym_pointer->n_other;
-       cache_ptr->type = sym_pointer->n_type;
-       cache_ptr->symbol.udata = 0;
-       translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd);
-
-      }
-  }
-
-  obj_aout_symbols (abfd) =  cached;
-  bfd_get_symcount (abfd) = symbol_count;
-  free ((PTR)syms);
+  if (free_relocs != NULL)
+    free (free_relocs);
 
   return true;
+
+ error_return:
+  if (free_relocs != NULL)
+    free (free_relocs);
+  return 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.  */
 
-void
-DEFUN(sunos4_write_syms,(abfd),
-     bfd *abfd)
+static boolean
+sunos_scan_std_relocs (info, abfd, sec, relocs, rel_size)
+     struct bfd_link_info *info;
+     bfd *abfd;
+     asection *sec;
+     const struct reloc_std_external *relocs;
+     bfd_size_type rel_size;
 {
-  unsigned int count ;
-  asymbol **generic = bfd_get_outsymbols (abfd);
-
-  unsigned int stindex = sizeof(stindex); /* initial string length */
-
-  for (count = 0; count < bfd_get_symcount (abfd); count++) {
-    asymbol *g = generic[count];
-    struct nlist nsp;
-
-    if (g->name) {
-      unsigned int length = strlen(g->name) +1;
-      bfd_h_putlong  (abfd, stindex, (unsigned char *)&nsp.n_un.n_strx);
-      stindex += length;
-    }
-    else {
-      bfd_h_putlong  (abfd, 0, (unsigned char *)&nsp.n_un.n_strx);
+  bfd *dynobj;
+  asection *splt;
+  asection *srel;
+  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;
     }
 
-    if (g->the_bfd->xvec->flavour == abfd->xvec->flavour) 
-      {
-       nsp.n_desc = aout_symbol( g)->desc;
-       nsp.n_other = aout_symbol(g)->other;
-       nsp.n_type = aout_symbol(g)->type;
-      }
-    else
-      {
-       nsp.n_desc = 0;
-       nsp.n_other = 0;
-       nsp.n_type = 0;
-      }
-
-
-    nsp.n_value = g->value;
-    translate_to_native_sym_flags (&nsp, (PTR)g, abfd);
-
-
-    bfd_h_putshort (abfd, nsp.n_desc, (unsigned char *)&nsp.n_desc);
-    bfd_h_putlong  (abfd, nsp.n_value, (unsigned char *)&nsp.n_value);
-    bfd_write((PTR)&nsp,1, sizeof(nsp), abfd);
-  }
-
-
-  /* Now output the strings.  Be sure to put string length into correct
-   * byte ordering before writing it.
-   */
-  bfd_h_putlong  (abfd, stindex, (unsigned char *)&stindex);
+  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);
+  sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd);
 
-  bfd_write((PTR)&stindex, 1, sizeof(stindex), abfd);
-  
-  generic = bfd_get_outsymbols(abfd);
-  for (count = 0; count < bfd_get_symcount(abfd); count++) 
+  relend = relocs + rel_size / RELOC_STD_SIZE;
+  for (rel = relocs; rel < relend; rel++)
     {
-      asymbol *g = *(generic++);
+      int r_index;
+      struct sunos_link_hash_entry *h;
 
-      if (g->name != (char *)NULL) 
+      /* We only want relocs against external symbols.  */
+      if (abfd->xvec->header_byteorder_big_p)
        {
-         size_t length = strlen(g->name)+1;
-         bfd_write((PTR)g->name, 1, length, 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;
        }
-      if ((g->flags & BSF_FAKE)==0) {
-       g->name = itos(count);  /* smash the generic symbol */
-      }
-    }
-}
-
 
-void
-DEFUN(sunos4_reclaim_symbol_table,(abfd),
-     bfd *abfd)
-{
-  asection *section;
+      /* Get the symbol index.  */
+      if (abfd->xvec->header_byteorder_big_p)
+       {
+         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]);
+       }
 
-  if (!bfd_get_symcount (abfd)) return;
+      /* 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;
+       }
 
-  for (section = abfd->sections;
-       section != (asection *) NULL;
-       section = section->next)
-    if (section->relocation) {
-      free ((PTR)section->relocation);
-      section->relocation = NULL;
-      section->reloc_count = 0;
+      /* 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;
+
+      BFD_ASSERT ((h->flags & SUNOS_REF_REGULAR) != 0);
+      BFD_ASSERT ((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->_raw_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->_raw_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->root.root.u.def.section != splt)
+           {
+             if (splt->_raw_size == 0)
+               splt->_raw_size = M68K_PLT_ENTRY_SIZE;
+             h->root.root.u.def.section = splt;
+             h->root.root.u.def.value = splt->_raw_size;
+             splt->_raw_size += M68K_PLT_ENTRY_SIZE;
+
+             /* We will also need a dynamic reloc entry.  */
+             srel->_raw_size += RELOC_STD_SIZE;
+           }
+       }
     }
 
-  bfd_get_symcount (abfd) = 0;
-  free ((PTR)obj_aout_symbols (abfd));
-  obj_aout_symbols (abfd) = (aout_symbol_type *)NULL;
-}
-\f
-unsigned int
-sunos4_get_symtab_upper_bound (abfd)
-     bfd *abfd;
-{
-  if (!sunos4_slurp_symbol_table (abfd)) return 0;
-
-  return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *));
-}
-
-unsigned int
-sunos4_get_symtab (abfd, location)
-     bfd *abfd;
-     asymbol **location;
-{
-  unsigned int counter = 0;
-  aout_symbol_type *symbase;
-
-  if (!sunos4_slurp_symbol_table (abfd)) return 0;
-
-  for (symbase = obj_aout_symbols(abfd); counter++ < bfd_get_symcount (abfd);)
-    *(location++) = (asymbol *)( symbase++);
-  *location++ =0;
-  return bfd_get_symcount(abfd);
-}
-
-\f
-/* Obsolete procedural interface; better to look at the cache directly */
-
-/* User should have checked the file flags; perhaps we should return
-   BFD_NO_MORE_SYMBOLS if there are none? */
-
-int
-sunos4_get_symcount_upper_bound (abfd)
-     bfd *abfd;
-{
-  /* In case we're doing an output file or something...?  */
-  if (bfd_get_symcount (abfd)) return bfd_get_symcount (abfd);
-
-  return (exec_hdr (abfd)->a_syms) / (sizeof (struct nlist));
-}
-
-symindex
-sunos4_get_first_symbol (ignore_abfd)
-     bfd * ignore_abfd;
-{
-  return 0;
-}
-
-symindex
-sunos4_get_next_symbol (abfd, oidx)
-     bfd *abfd;
-     symindex oidx;
-{
-  if (oidx == BFD_NO_MORE_SYMBOLS) return BFD_NO_MORE_SYMBOLS;
-  return ++oidx >= bfd_get_symcount (abfd) ? BFD_NO_MORE_SYMBOLS : oidx;
-}
-
-CONST char *
-sunos4_symbol_name (abfd, idx)
-     bfd *abfd;
-     symindex idx;
-{
-  return (obj_aout_symbols (abfd) + idx)->symbol.name;
-}
-
-long
-sunos4_symbol_value (abfd, idx)
-     bfd *abfd;
-     symindex idx;
-{
-  return (obj_aout_symbols (abfd) + idx)->symbol.value;
-}
-
-symclass
-sunos4_classify_symbol (abfd, idx)
-     bfd *abfd;
-     symindex idx;
-{
-  aout_symbol_type *sym = obj_aout_symbols (abfd) + idx;
-
-  if ((sym->symbol.flags & BSF_FORT_COMM) != 0)   return bfd_symclass_fcommon;
-  if ((sym->symbol.flags & BSF_GLOBAL) != 0)    return bfd_symclass_global;
-  if ((sym->symbol.flags & BSF_DEBUGGING) != 0)  return bfd_symclass_debugger;
-  if ((sym->symbol.flags & BSF_UNDEFINED) != 0) return bfd_symclass_undefined;
-
-  return bfd_symclass_unknown;
+  return true;
 }
 
-boolean
-sunos4_symbol_hasclass (abfd, idx, class)
-     bfd *abfd;
-     symindex idx;
-     symclass class;
-{
-  aout_symbol_type *sym = obj_aout_symbols (abfd) + idx;
-  switch (class) {
-  case bfd_symclass_fcommon:
-    return (sym->symbol.flags & BSF_FORT_COMM) ? true :false;
-  case bfd_symclass_global:
-    return (sym->symbol.flags & BSF_GLOBAL) ? true:false;
-  case bfd_symclass_debugger:
-    return (sym->symbol.flags & BSF_DEBUGGING) ? true:false;;
-  case bfd_symclass_undefined:
-    return (sym->symbol.flags & BSF_UNDEFINED) ? true:false;;
-  default: return false;
-  }
-}
-\f
-/* Standard reloc stuff */
-/* Output standard relocation information to a file in target byte order. */
+/* 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.  FIXME:
+   We should also handle the PIC relocs here by building global offset
+   table entries.  */
 
-void
-swap_std_reloc_out (abfd, p, natptr, count)
+static boolean
+sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
+     struct bfd_link_info *info;
      bfd *abfd;
-     arelent **p;              /* Generic relocation struct */
-     struct reloc_std_bytes *natptr;
-     unsigned int count;
+     asection *sec;
+     const struct reloc_ext_external *relocs;
+     bfd_size_type rel_size;
 {
-  int r_index;
-  int r_extern;
-  unsigned int r_length;
-  int r_pcrel;
-  int r_baserel, r_jmptable, r_relative;
-  unsigned int r_addend;
-  unsigned int idx;
-  for (idx = 0; idx < count; idx++, p++, natptr++) 
+  bfd *dynobj;
+  asection *splt;
+  asection *srel;
+  struct sunos_link_hash_entry **sym_hashes;
+  const struct reloc_ext_external *rel, *relend;
+
+  /* We only know how to handle SPARC plt entries.  */
+  if (bfd_get_arch (abfd) != bfd_arch_sparc)
     {
-      arelent *g = *p;
-      bfd_h_putlong (abfd, g->address, natptr->r_address);
-
-      r_length = g->howto->size; /* Size as a power of two */
-      r_pcrel  = (int) g->howto->pc_relative;  /* Relative to PC? */
-      /* r_baserel, r_jmptable, r_relative???  FIXME-soon */
-      r_baserel = 0;
-      r_jmptable = 0;
-      r_relative = 0;
+      bfd_set_error (bfd_error_invalid_target);
+      return false;
+    }
 
-      r_addend = g->addend;    /* Start here, see how it goes */
+  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);
+  sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd);
 
-      /* name was clobbered by sunos4_write_syms to be symbol index */
+  relend = relocs + rel_size / RELOC_EXT_SIZE;
+  for (rel = relocs; rel < relend; rel++)
+    {
+      int r_index;
+      int r_type;
+      struct sunos_link_hash_entry *h;
 
-      if (g->sym_ptr_ptr != NULL) 
+      /* We only want relocs against external symbols.  */
+      if (abfd->xvec->header_byteorder_big_p)
        {
-         if ((*(g->sym_ptr_ptr))->section) {
-           /* put the section offset into the addend for output */
-           r_addend += (*(g->sym_ptr_ptr))->section->vma;
-         }
+         if ((rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG) == 0)
+           continue;
+       }
+      else
+       {
+         if ((rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE) == 0)
+           continue;
+       }
 
-         r_index = stoi((*(g->sym_ptr_ptr))->name);
-         r_extern = 1;
+      /* Get the symbol index and reloc type.  */
+      if (abfd->xvec->header_byteorder_big_p)
+       {
+         r_index   =  ((rel->r_index[0] << 16)
+                       | (rel->r_index[1] << 8)
+                       | rel->r_index[2]);
+         r_type   = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
+                     >> RELOC_EXT_BITS_TYPE_SH_BIG);
        }
-      else {
-       r_extern = 0;
-       if (g->section == NULL) {
-         BFD_ASSERT(0);
-         r_index = N_ABS | N_EXT;
+      else
+       {
+         r_index   = ((rel->r_index[2] << 16)
+                      | (rel->r_index[1] << 8)
+                      | rel->r_index[0]);
+         r_type   = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
+                     >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
        }
-       else  if(g->section->output_section == obj_textsec(abfd)) {
-         r_index = N_TEXT | N_EXT;
-         r_addend += g->section->output_section->vma;
+
+      /* 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;
        }
-       else if (g->section->output_section == obj_datasec(abfd)) {
-         r_index = N_DATA | N_EXT;
-         r_addend += g->section->output_section->vma;
+
+      /* 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 symbols 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;
+
+      BFD_ASSERT ((h->flags & SUNOS_REF_REGULAR) != 0);
+      BFD_ASSERT ((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->_raw_size += RELOC_EXT_SIZE;
        }
-       else if (g->section->output_section == obj_bsssec(abfd)) {
-         r_index = N_BSS | N_EXT ;
-         r_addend += g->section->output_section->vma;
+      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->_raw_size += RELOC_EXT_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 {
-         BFD_ASSERT(0);
+      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->root.root.u.def.section != splt)
+           {
+             if (splt->_raw_size == 0)
+               splt->_raw_size = SPARC_PLT_ENTRY_SIZE;
+             h->root.root.u.def.section = splt;
+             h->root.root.u.def.value = splt->_raw_size;
+             splt->_raw_size += SPARC_PLT_ENTRY_SIZE;
+
+             /* We will also need a dynamic reloc entry.  */
+             srel->_raw_size += RELOC_EXT_SIZE;
+           }
        }
-      }
-
-      /* now the fun stuff */
-      if (abfd->xvec->header_byteorder_big_p != false) {
-       natptr->r_index[0] = r_index >> 16;
-       natptr->r_index[1] = r_index >> 8;
-       natptr->r_index[2] = r_index;
-       natptr->r_bits[0] =
-         (r_extern?    RELOC_STD_BITS_EXTERN_BIG: 0)
-           | (r_pcrel?     RELOC_STD_BITS_PCREL_BIG: 0)
-             | (r_baserel?   RELOC_STD_BITS_BASEREL_BIG: 0)
-               | (r_jmptable?  RELOC_STD_BITS_JMPTABLE_BIG: 0)
-                 | (r_relative?  RELOC_STD_BITS_RELATIVE_BIG: 0)
-                   | (r_length <<  RELOC_STD_BITS_LENGTH_SH_BIG);
-      } else {
-       natptr->r_index[2] = r_index >> 16;
-       natptr->r_index[1] = r_index >> 8;
-       natptr->r_index[0] = r_index;
-       natptr->r_bits[0] =
-         (r_extern?    RELOC_STD_BITS_EXTERN_LITTLE: 0)
-           | (r_pcrel?     RELOC_STD_BITS_PCREL_LITTLE: 0)
-             | (r_baserel?   RELOC_STD_BITS_BASEREL_LITTLE: 0)
-               | (r_jmptable?  RELOC_STD_BITS_JMPTABLE_LITTLE: 0)
-                 | (r_relative?  RELOC_STD_BITS_RELATIVE_LITTLE: 0)
-                   | (r_length <<  RELOC_STD_BITS_LENGTH_SH_LITTLE);
-      }
-
-
     }
-}
 
+  return true;
+}
 
-/* Extended stuff */
-/* Output extended relocation information to a file in target byte order. */
+/* 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.  */
 
-void
-swap_ext_reloc_out (abfd, p, natptr, count)
-     bfd *abfd;
-     arelent **p;              /* Generic relocation struct */
-     register struct reloc_ext_bytes *natptr;
-     unsigned int count;
+static boolean
+sunos_scan_dynamic_symbol (h, data)
+     struct sunos_link_hash_entry *h;
+     PTR data;
 {
-
-  int r_index;
-  int r_extern;
-  unsigned int r_type;
-  unsigned int r_addend;
-  unsigned int idx;
-  for (idx = 0; idx < count; idx++, p++, natptr++) {
-    arelent *g = *p;
-
-    bfd_h_putlong (abfd, g->address, natptr->r_address);
-
-    /* Find a type in the output format which matches the input howto - 
-       at the moment we assume input format == output format FIXME!! */
-    r_type = (enum reloc_type) g->howto->type;
-
-    r_addend = g->addend;      /* Start here, see how it goes */
-
-    /* name was clobbered by sunos4_write_syms to be symbol index*/
-
-    if (g->sym_ptr_ptr != NULL) 
-      {
-       if ((*(g->sym_ptr_ptr))->section) {
-         /* put the section offset into the addend for output */
-         r_addend += (*(g->sym_ptr_ptr))->section->vma;
+  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.  */
+  if ((h->flags & SUNOS_DEF_REGULAR) == 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;
        }
-
-       r_index = stoi((*(g->sym_ptr_ptr))->name);
-       r_extern = 1;
-      }
-    else {
-      r_extern = 0;
-      if (g->section == NULL) {
-       BFD_ASSERT(0);
-       r_index = N_ABS | N_EXT;
-      }
-      else  if(g->section->output_section == obj_textsec(abfd)) {
-       r_index = N_TEXT | N_EXT;
-       r_addend += g->section->output_section->vma;
-      }
-      else if (g->section->output_section == obj_datasec(abfd)) {
-       r_index = N_DATA | N_EXT;
-       r_addend += g->section->output_section->vma;
-      }
-      else if (g->section->output_section == obj_bsssec(abfd)) {
-       r_index = N_BSS | N_EXT ;
-       r_addend += g->section->output_section->vma;
-      }
-      else {
-       BFD_ASSERT(0);
-      }
     }
 
-    /* now the fun stuff */
-    if (abfd->xvec->header_byteorder_big_p != false) {
-      natptr->r_index[0] = r_index >> 16;
-      natptr->r_index[1] = r_index >> 8;
-      natptr->r_index[2] = r_index;
-      natptr->r_bits[0] =
-       (r_extern? RELOC_EXT_BITS_EXTERN_BIG: 0)
-         || (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
-    } else {
-      natptr->r_index[2] = r_index >> 16;
-      natptr->r_index[1] = r_index >> 8;
-      natptr->r_index[0] = r_index;
-      natptr->r_bits[0] =
-       (r_extern? RELOC_EXT_BITS_EXTERN_LITTLE: 0)
-         || (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
+  /* 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);
+
+      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 (sunos_hash_table (info)->dynobj,
+                                  ".dynstr");
+      BFD_ASSERT (s != NULL);
+      if (s->contents == NULL)
+       contents = (bfd_byte *) malloc (len + 1);
+      else
+       contents = (bfd_byte *) realloc (s->contents, s->_raw_size + len + 1);
+      if (contents == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
+      s->contents = contents;
+
+      h->dynstr_index = s->_raw_size;
+      strcpy (contents + s->_raw_size, h->root.root.root.string);
+      s->_raw_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;
+
+      dynobj = sunos_hash_table (info)->dynobj;
+      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->_raw_size / HASH_ENTRY_SIZE,
+                   s->contents + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD);
+         PUT_WORD (dynobj, h->dynindx, s->contents + s->_raw_size);
+         PUT_WORD (dynobj, next, s->contents + s->_raw_size + BYTES_IN_WORD);
+         s->_raw_size += HASH_ENTRY_SIZE;
+       }
     }
 
-    bfd_h_putlong (abfd, r_addend, natptr->r_addend);
-  }
+  return true;
 }
-#define MOVE_ADDRESS(ad)                                                       \
-  if (r_extern) {                                                      \
-    cache_ptr->sym_ptr_ptr = symbols + r_index;                                \
-    cache_ptr->section = (asection *)NULL;                             \
-      cache_ptr->addend = ad;                                          \
-  } else {                                                             \
-    cache_ptr->sym_ptr_ptr = (asymbol **)NULL;                         \
-    switch (r_index) {                                                 \
-    case N_TEXT:                                                       \
-    case N_TEXT | N_EXT:                                               \
-      cache_ptr->section = obj_textsec(abfd);                          \
-      cache_ptr->addend = ad  - su->textsec->vma;                      \
-      break;                                                           \
-    case N_DATA:                                                       \
-    case N_DATA | N_EXT:                                               \
-      cache_ptr->section = obj_datasec(abfd);                          \
-      cache_ptr->addend = ad - su->datasec->vma;                       \
-      break;                                                           \
-    case N_BSS:                                                                \
-    case N_BSS | N_EXT:                                                        \
-      cache_ptr->section = obj_bsssec(abfd);                           \
-      cache_ptr->addend = ad - su->bsssec->vma;                                \
-      break;                                                           \
-    case N_ABS:                                                                \
-    case N_ABS | N_EXT:                                                        \
-      BFD_ASSERT(1);                                                   \
-      break;                                                           \
-    default:                                                           \
-      BFD_ASSERT(1);                                                   \
-      break;                                                           \
-    }                                                                  \
-  }                                                                    \
-
-void
-swap_ext_reloc_in (abfd, bytes, cache_ptr, symbols)
-     bfd *abfd;
-     struct reloc_ext_bytes *bytes;
-     arelent *cache_ptr;
-     asymbol **symbols;
-{
-  int r_index;
-  int r_extern;
-  unsigned int r_type;
-  struct sunexdata *su = (struct sunexdata *)(abfd->tdata);
-
-  cache_ptr->address = bfd_h_getlong (abfd, bytes->r_address);
-
-  /* now the fun stuff */
-  if (abfd->xvec->header_byteorder_big_p != false) {
-    r_index =  (bytes->r_index[0] << 16)
-            | (bytes->r_index[1] << 8)
-            |  bytes->r_index[2];
-    r_extern = (0 != (bytes->r_bits[0] & RELOC_EXT_BITS_EXTERN_BIG));
-    r_type   =       (bytes->r_bits[0] & RELOC_EXT_BITS_TYPE_BIG)
-                                     >> RELOC_EXT_BITS_TYPE_SH_BIG;
-  } else {
-    r_index =  (bytes->r_index[2] << 16)
-            | (bytes->r_index[1] << 8)
-            |  bytes->r_index[0];
-    r_extern = (0 != (bytes->r_bits[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
-    r_type   =       (bytes->r_bits[0] & RELOC_EXT_BITS_TYPE_LITTLE)
-                                     >> RELOC_EXT_BITS_TYPE_SH_LITTLE;
-  }
 
-  cache_ptr->howto =  howto_table_ext + r_type;
-  MOVE_ADDRESS(bfd_h_getlong(abfd,bytes->r_addend));
-                                                                        
-}
+/* 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.  */
 
-void
-swap_std_reloc_in (abfd, bytes, cache_ptr, symbols)
+/*ARGSUSED*/
+static boolean
+sunos_link_dynamic_object (info, abfd)
+     struct bfd_link_info *info;
      bfd *abfd;
- struct reloc_std_bytes *bytes;
-     arelent *cache_ptr;
-     asymbol **symbols;
 {
-  int r_index;
-  int r_extern;
-  unsigned int r_length;
-  int r_pcrel;
-  int r_baserel, r_jmptable, r_relative;
-  struct sunexdata *su = (struct sunexdata *)(abfd->tdata);
-  cache_ptr->address = bfd_h_getlong (abfd, bytes->r_address);
-
-  /* now the fun stuff */
-  if (abfd->xvec->header_byteorder_big_p != false) {
-    r_index =  (bytes->r_index[0] << 16)
-      | (bytes->r_index[1] << 8)
-       |  bytes->r_index[2];
-    r_extern  = (0 != (bytes->r_bits[0] & RELOC_STD_BITS_EXTERN_BIG));
-    r_pcrel   = (0 != (bytes->r_bits[0] & RELOC_STD_BITS_PCREL_BIG));
-    r_baserel = (0 != (bytes->r_bits[0] & RELOC_STD_BITS_BASEREL_BIG));
-    r_jmptable= (0 != (bytes->r_bits[0] & RELOC_STD_BITS_JMPTABLE_BIG));
-    r_relative= (0 != (bytes->r_bits[0] & RELOC_STD_BITS_RELATIVE_BIG));
-    r_length  =       (bytes->r_bits[0] & RELOC_STD_BITS_LENGTH_BIG) 
-      >> RELOC_STD_BITS_LENGTH_SH_BIG;
-  } else {
-    r_index =  (bytes->r_index[2] << 16)
-      | (bytes->r_index[1] << 8)
-       |  bytes->r_index[0];
-    r_extern  = (0 != (bytes->r_bits[0] & RELOC_STD_BITS_EXTERN_LITTLE));
-    r_pcrel   = (0 != (bytes->r_bits[0] & RELOC_STD_BITS_PCREL_LITTLE));
-    r_baserel = (0 != (bytes->r_bits[0] & RELOC_STD_BITS_BASEREL_LITTLE));
-    r_jmptable= (0 != (bytes->r_bits[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
-    r_relative= (0 != (bytes->r_bits[0] & RELOC_STD_BITS_RELATIVE_LITTLE));
-    r_length  =       (bytes->r_bits[0] & RELOC_STD_BITS_LENGTH_LITTLE) 
-      >> RELOC_STD_BITS_LENGTH_SH_LITTLE;
-  }
-
-  cache_ptr->howto =  howto_table_std + r_length + 4 * r_pcrel;
-  /* FIXME-soon:  Roll baserel, jmptable, relative bits into howto setting */
-
-  MOVE_ADDRESS(0);
+  return true;
 }
 
-/* Reloc hackery */
 
-boolean
-sunos4_slurp_reloc_table (abfd, asect, symbols)
-     bfd *abfd;
-     sec_ptr asect;
-     asymbol **symbols;
+/* Write out a dynamic symbol.  This is called by the final traversal
+   over the symbol table.  */
+
+static boolean
+sunos_write_dynamic_symbol (output_bfd, info, harg)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     struct aout_link_hash_entry *harg;
 {
-  unsigned int count;
-  size_t reloc_size;
-  PTR relocs;
-  arelent *reloc_cache;
-  size_t each_size;
+  struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg;
+  boolean plt;
+  int type;
+  bfd_vma val;
+  asection *s;
+  struct external_nlist *outsym;
+
+  if (h->dynindx < 0)
+    return true;
+
+  plt = false;
+  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 (strcmp (sec->name, ".plt") == 0)
+         {
+           plt = true;
+           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;
+    }
 
-  if (asect->relocation) 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));
 
-  if (asect->flags & SEC_CONSTRUCTOR) return true;
+  bfd_h_put_8 (output_bfd, type, outsym->e_type);
+  bfd_h_put_8 (output_bfd, 0, outsym->e_other);
 
-  if (asect == obj_datasec (abfd)) {
-    reloc_size = exec_hdr(abfd)->a_drsize;
-    goto doit;
-  }
+  /* 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.  */
+  bfd_h_put_16 (output_bfd, 0, outsym->e_desc);
 
-  if (asect == obj_textsec (abfd)) {
-    reloc_size = exec_hdr(abfd)->a_trsize;
-    goto doit;
-  }
+  PUT_WORD (output_bfd, h->dynstr_index, outsym->e_strx);
+  PUT_WORD (output_bfd, val, outsym->e_value);
 
-  bfd_error = invalid_operation;
-  return false;
+  /* If this symbol is in the procedure linkage table, fill in the
+     table entry.  */
+  if (plt)
+    {
+      bfd_byte *p;
+      asection *s;
+      bfd_vma r_address;
 
- doit:
-  bfd_seek (abfd, asect->rel_filepos, SEEK_SET);
-  each_size = reloc_size_func(abfd);
+      p = h->root.root.u.def.section->contents + h->root.root.u.def.value;
 
-  count = reloc_size / each_size;
+      s = bfd_get_section_by_name (sunos_hash_table (info)->dynobj, ".dynrel");
+      BFD_ASSERT (s != NULL);
 
-  relocs =  (PTR) malloc (reloc_size);
-  if (!relocs) {
-    bfd_error = no_memory;
-    return false;
-  }
-  reloc_cache = (arelent *) zalloc ((size_t)(count * sizeof (arelent)));
-  if (reloc_cache == (arelent *)NULL) {
-    free (relocs);
-    bfd_error = no_memory;
-    return false;
-  }
+      r_address = (h->root.root.u.def.section->output_section->vma
+                  + h->root.root.u.def.section->output_offset
+                  + h->root.root.u.def.value);
 
-  if (bfd_read ( relocs, 1, reloc_size, abfd) != reloc_size) {
-    bfd_error = system_call_error;
-    free (reloc_cache);
-    free (relocs);
-    return false;
-  }
+      switch (bfd_get_arch (output_bfd))
+       {
+       case bfd_arch_sparc:
+         bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD0, p);
+         bfd_put_32 (output_bfd,
+                     (SPARC_PLT_ENTRY_WORD1
+                      + (((- (h->root.root.u.def.value + 4) >> 2)
+                          & 0x3fffffff))),
+                     p + 4);
+         bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD2 + s->reloc_count,
+                     p + 8);
+         break;
 
-  if (each_size == RELOC_EXT_SIZE)
-    {
-      register struct reloc_ext_bytes *rptr = (struct reloc_ext_bytes *) relocs;
-      unsigned int counter = 0;
-      arelent *cache_ptr = reloc_cache;
+       case bfd_arch_m68k:
+         bfd_put_16 (output_bfd, M68K_PLT_ENTRY_WORD0, p);
+         bfd_put_32 (output_bfd, (- (h->root.root.u.def.value + 2)), p + 2);
+         bfd_put_16 (output_bfd, s->reloc_count, p + 6);
+         r_address += 2;
+         break;
 
-      for (; counter < count; counter++, rptr++, cache_ptr++) {
-       swap_ext_reloc_in(abfd, rptr, cache_ptr, symbols);
-      }
-    }
-  else {
-    register struct reloc_std_bytes *rptr = (struct reloc_std_bytes *) relocs;
-    unsigned int counter = 0;
-    arelent *cache_ptr = reloc_cache;
+       default:
+         abort ();
+       }
+
+      /* We also need to add a jump table reloc.  */
+      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 (output_bfd->xvec->header_byteorder_big_p)
+           {
+             srel->r_index[0] = h->dynindx >> 16;
+             srel->r_index[1] = h->dynindx >> 8;
+             srel->r_index[2] = h->dynindx;
+             srel->r_type[0] = (RELOC_STD_BITS_EXTERN_BIG
+                                | RELOC_STD_BITS_JMPTABLE_BIG);
+           }
+         else
+           {
+             srel->r_index[2] = h->dynindx >> 16;
+             srel->r_index[1] = h->dynindx >> 8;
+             srel->r_index[0] = 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 (output_bfd->xvec->header_byteorder_big_p)
+           {
+             erel->r_index[0] = h->dynindx >> 16;
+             erel->r_index[1] = h->dynindx >> 8;
+             erel->r_index[2] = h->dynindx;
+             erel->r_type[0] = (RELOC_EXT_BITS_EXTERN_BIG
+                                | (22 << RELOC_EXT_BITS_TYPE_SH_BIG));
+           }
+         else
+           {
+             erel->r_index[2] = h->dynindx >> 16;
+             erel->r_index[1] = h->dynindx >> 8;
+             erel->r_index[0] = h->dynindx;
+             erel->r_type[0] = (RELOC_EXT_BITS_EXTERN_LITTLE
+                                | (22 << RELOC_EXT_BITS_TYPE_SH_LITTLE));
+           }
+         PUT_WORD (output_bfd, (bfd_vma) 0, erel->r_addend);
+       }
 
-    for (; counter < count; counter++, rptr++, cache_ptr++) {
-       swap_std_reloc_in(abfd, rptr, cache_ptr, symbols);
+      ++s->reloc_count;
     }
 
-  }
-  free (relocs);
-  asect->relocation = reloc_cache;
-  asect->reloc_count = count;
   return true;
 }
 
+/* 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.  */
 
-
-/* Write out a relocation section into an object file.  */
-
+/*ARGSUSED*/
 static boolean
-sunos4_squirt_out_relocs (abfd, section)
-     bfd *abfd;
-     asection *section;
+sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, skip)
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     asection *input_section;
+     struct aout_link_hash_entry *harg;
+     PTR reloc;
+     boolean *skip;
 {
-  arelent **generic;
-  unsigned char *native;
-  size_t each_size;
+  struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg;
+  bfd *dynobj;
+  asection *srel;
+  bfd_byte *p;
 
-  unsigned int count = section->reloc_count;
-  size_t natsize;
+  *skip = false;
 
-  if (count == 0) return true;
+  dynobj = sunos_hash_table (info)->dynobj;
 
-  each_size = reloc_size_func(abfd);
-  natsize = each_size * count;
-  native = (unsigned char *) zalloc (natsize);
-  if (!native) {
-    bfd_error = no_memory;
-    return false;
-  }
+  if (dynobj == 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;
+
+  /* It looks this is a reloc we are supposed to copy.  */
+
+  srel = bfd_get_section_by_name (dynobj, ".dynrel");
+  BFD_ASSERT (srel != NULL);
 
-  generic = section->orelocation;
+  p = srel->contents + srel->reloc_count * obj_reloc_entry_size (dynobj);
 
-  if (each_size == RELOC_EXT_SIZE) 
+  /* Copy the reloc over.  */
+  memcpy (p, reloc, obj_reloc_entry_size (dynobj));
+
+  /* Adjust the address and symbol index.  */
+  if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE)
     {
-      swap_ext_reloc_out (abfd,
-                         generic,
-                         (struct reloc_ext_bytes *)native,
-                         count);
+      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 (dynobj->xvec->header_byteorder_big_p)
+       {
+         srel->r_index[0] = h->dynindx >> 16;
+         srel->r_index[1] = h->dynindx >> 8;
+         srel->r_index[2] = h->dynindx;
+       }
+      else
+       {
+         srel->r_index[2] = h->dynindx >> 16;
+         srel->r_index[1] = h->dynindx >> 8;
+         srel->r_index[0] = h->dynindx;
+       }
     }
-  else 
+  else
     {
-      swap_std_reloc_out(abfd, generic, native, count);
+      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 (dynobj->xvec->header_byteorder_big_p)
+       {
+         erel->r_index[0] = h->dynindx >> 16;
+         erel->r_index[1] = h->dynindx >> 8;
+         erel->r_index[2] = h->dynindx;
+       }
+      else
+       {
+         erel->r_index[2] = h->dynindx >> 16;
+         erel->r_index[1] = h->dynindx >> 8;
+         erel->r_index[0] = h->dynindx;
+       }
     }
 
-  if ( bfd_write ((PTR) native, 1, natsize, abfd) != natsize) {
-    free(native);
-    return false;
-  }
-  free (native);
+  ++srel->reloc_count;
+
+  *skip = true;
 
   return true;
 }
 
-/* This is stupid.  This function should be a boolean predicate */
-unsigned int
-sunos4_canonicalize_reloc (abfd, section, relptr, symbols)
-     bfd *abfd;
-     sec_ptr section;
-     arelent **relptr;
-     asymbol **symbols;
-{
-  arelent *tblptr = section->relocation;
-  unsigned int count;
-
-  if (!(tblptr || sunos4_slurp_reloc_table (abfd, section, symbols)))
-    return 0;
+/* Finish up the dynamic linking information.  */
 
-  if (section->flags & SEC_CONSTRUCTOR) {
-    arelent_chain *chain = section->constructor_chain;
-    for (count = 0; count < section->reloc_count; count ++) {
-      *relptr ++ = &chain->relent;
-      chain = chain->next;
-    }
-  }
-  else {
-    tblptr = section->relocation;
-    if (!tblptr) return 0;
-
-    for (count = 0; count++ < section->reloc_count;) 
-      {
-       *relptr++ = tblptr++;
-      }
-  }
-  *relptr = 0;
-
-  return section->reloc_count;
-}
-
-unsigned int
-sunos4_get_reloc_upper_bound (abfd, asect)
+static boolean
+sunos_finish_dynamic_link (abfd, info)
      bfd *abfd;
-     sec_ptr asect;
+     struct bfd_link_info *info;
 {
-  if (bfd_get_format (abfd) != bfd_object) {
-    bfd_error = invalid_operation;
-    return 0;
-  }
-  if (asect->flags & SEC_CONSTRUCTOR) {
-    return (sizeof (arelent *) * (asect->reloc_count+1));
-  }
-
-
-  if (asect == obj_datasec (abfd))
-    return (sizeof (arelent *) *
-            ((exec_hdr(abfd)->a_drsize / reloc_size_func(abfd))
-             +1));
-
-  if (asect == obj_textsec (abfd))
-    return (sizeof (arelent *) *
-            ((exec_hdr(abfd)->a_trsize / reloc_size_func(abfd))
-             +1));
-
-  bfd_error = invalid_operation;
-  return 0;
-}
+  bfd *dynobj;
+  asection *o;
+  asection *s;
+  asection *sdyn;
+  struct external_sun4_dynamic esd;
+  struct external_sun4_dynamic_link esdl;
+
+  dynobj = sunos_hash_table (info)->dynobj;
+  if (dynobj == NULL)
+    return true;
+
+  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");
+  BFD_ASSERT (s != NULL);
+  if (s->_raw_size != 0)
+    {
+      file_ptr filepos;
+      bfd_byte *p;
 
-void
-sunos4_reclaim_reloc (ignore_abfd, section)
-     bfd *ignore_abfd;
-     sec_ptr section;
-{
-  if (section->relocation) {
-    free (section->relocation);
-    section->relocation = NULL;
-    section->reloc_count = 0;
+      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;
+       }
     }
-}
-\f
 
-alent *
-sunos4_get_lineno(ignore_abfd, ignore_symbol)
-bfd *ignore_abfd;
-PTR ignore_symbol;
-{
-return (alent *)NULL;
-}
+  /* The first entry in the .got section is the address of the dynamic
+     information.  */
+  s = bfd_get_section_by_name (dynobj, ".got");
+  BFD_ASSERT (s != NULL);
+  PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset,
+           s->contents);
 
-void 
-sunos4_print_symbol(ignore_abfd, file,  symbol, how)
-bfd *ignore_abfd;
-FILE *file;
-asymbol *symbol;
-bfd_print_symbol_enum_type how;
-{
-  switch (how) {
-  case bfd_print_symbol_name_enum:
-    fprintf(file,"%s", symbol->name);
-    break;
-  case bfd_print_symbol_type_enum:
-    fprintf(file,"%4x %2x %2x",(unsigned)(aout_symbol(symbol)->desc & 0xffff),
-           (unsigned)(   aout_symbol(symbol)->other  & 0xff),
-           (unsigned)(aout_symbol(symbol)->type));
-    break;
-  case bfd_print_symbol_all_enum:
+  for (o = dynobj->sections; o != NULL; o = o->next)
     {
-   CONST char *section_name = symbol->section == (asection *)NULL ?
-       "*abs" : symbol->section->name;
-
-      bfd_print_symbol_vandf((PTR)file,symbol);
-
-      fprintf(file," %-5s %04x %02x %02x %s",
-             section_name,
-             (unsigned)(aout_symbol(symbol)->desc & 0xffff),
-             (unsigned)(aout_symbol(symbol)->other  & 0xff),
-             (unsigned)(aout_symbol(symbol)->type  & 0xff),
-             symbol->name);
-    }
-    break;
-  }
-}
-/* Once we know all the stuff that could be consed, we know how to clean
-   it up.  So why don't we? */
-
-boolean
-sunos4_close_and_cleanup (abfd)
-     bfd *abfd;
-{
-  if (!bfd_read_p (abfd))
-    switch (abfd->format) {
-    case bfd_archive:
-      if (!_bfd_write_archive_contents (abfd)) return false; break;
-    case bfd_object:
-      if (!sunos4_write_object_contents (abfd))  return false; break;
-    default: bfd_error = invalid_operation; return false;
+      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, o->output_offset,
+                                         o->_raw_size))
+           return false;
+       }
     }
 
-#define cleaner(ptr) if (abfd->ptr) free (abfd->ptr)
-  cleaner (tdata);
+  /* 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,
+                                 sdyn->output_offset, sizeof esd))
+    return false;
 
-  if (abfd->my_archive)
-    cleaner (filename);
 
-#undef cleaner
-  return true;
-}
+  PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded);
+
+  s = bfd_get_section_by_name (dynobj, ".need");
+  BFD_ASSERT (s != NULL);
+  if (s->_raw_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");
+  BFD_ASSERT (s != NULL);
+  if (s->_raw_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->_raw_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->_raw_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->_raw_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)->_raw_size, 0x2000),
+           esdl.ld_text);
+  
+  if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl,
+                                 (sdyn->output_offset
+                                  + sizeof esd
+                                  + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE),
+                                 sizeof esdl))
+    return false;
 
-/* 
- provided a bfd, a section and an offset into the section, calculate
- and return the name of the source file and the line nearest to the
- wanted location.
-*/
-boolean
-DEFUN(sunos4_find_nearest_line,(abfd,
-                               section,
-                               symbols,
-                               offset,
-                               filename_ptr,
-                               functionname_ptr,
-                               line_ptr),
-      bfd *abfd AND
-      asection *section AND
-      asymbol **symbols AND
-      bfd_vma offset AND
-      CONST char **filename_ptr AND
-      CONST char **functionname_ptr AND
-      unsigned int *line_ptr)
-{
-  /* Run down the file looking for the filename, function and linenumber */
-  asymbol **p;
-  static  char buffer[100];
-  bfd_vma high_line_vma = ~0;
-  bfd_vma low_func_vma = 0;
-  asymbol *func = 0;
-  *filename_ptr = abfd->filename;
-  *functionname_ptr = 0;
-  *line_ptr = 0;
-  if (symbols != (asymbol **)NULL) {
-    for (p = symbols; *p; p++) {
-      aout_symbol_type  *q = (aout_symbol_type *)(*p);
-      switch (q->type){
-      case N_SO:
-       *filename_ptr = q->symbol.name;
-       if (obj_textsec(abfd) != section) {
-         return true;
-       }
-       break;
-      case N_SLINE:
-
-      case N_DSLINE:
-      case N_BSLINE:
-       /* We'll keep this if it resolves nearer than the one we have already */
-       if (q->symbol.value >= offset &&
-           q->symbol.value < high_line_vma) {
-         *line_ptr = q->desc;
-         high_line_vma = q->symbol.value;
-       }
-       break;
-      case N_FUN:
-       {
-         /* We'll keep this if it is nearer than the one we have already */
-         if (q->symbol.value >= low_func_vma &&
-             q->symbol.value <= offset) {
-           low_func_vma = q->symbol.value;
-           func = (asymbol *)q;
-         }
-         if (*line_ptr && func) {
-           CONST char *function = func->name;
-           char *p;
-           strncpy(buffer, function, sizeof(buffer)-1);
-           buffer[sizeof(buffer)-1] = 0;
-           /* Have to remove : stuff */
-           p = strchr(buffer,':');
-           if (p != NULL) {*p = NULL; }
-           *functionname_ptr = buffer;
-           return true;
+  abfd->flags |= DYNAMIC;
 
-         }
-       }
-       break;
-      }
-    }
-  }
-  
   return true;
-
 }
-
-bfd_target aout_big_vec =
-{
-  "a.out-generic-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 */
-  0,                           /* valid reloc types */
-  ' ',                         /* ar_pad_char */
-  16,                          /* ar_max_namelen */
-  sunos4_close_and_cleanup,    /* _close_and_cleanup */
-  sunos4_set_section_contents, /* bfd_set_section_contents */
-  sunos4_get_section_contents, /* bfd_get_section_contents */
-  sunos4_new_section_hook,     /* new_section_hook */
-  sunos4_core_file_failing_command, /* _core_file_failing_command */
-  sunos4_core_file_failing_signal, /* _core_file_failing_signal */
-  sunos4_core_file_matches_executable_p, /* _core_file_matches_ex...p */
-
-  bfd_slurp_bsd_armap,         /* bfd_slurp_armap */
-  bfd_true,                    /* bfd_slurp_extended_name_table */
-  bfd_bsd_truncate_arname,     /* bfd_truncate_arname */
-
-  sunos4_get_symtab_upper_bound, /* get_symtab_upper_bound */
-  sunos4_get_symtab,           /* canonicalize_symtab */
-  sunos4_reclaim_symbol_table, /* bfd_reclaim_symbol_table */
-  sunos4_get_reloc_upper_bound,        /* get_reloc_upper_bound */
-  sunos4_canonicalize_reloc,   /* bfd_canonicalize_reloc */
-  sunos4_reclaim_reloc,                /* bfd_reclaim_reloc */
-  sunos4_get_symcount_upper_bound, /* bfd_get_symcount_upper_bound */
-  sunos4_get_first_symbol,     /* bfd_get_first_symbol */
-  sunos4_get_next_symbol,      /* bfd_get_next_symbol */
-  sunos4_classify_symbol,      /* bfd_classify_symbol */
-  sunos4_symbol_hasclass,      /* bfd_symbol_hasclass */
-  sunos4_symbol_name,          /* bfd_symbol_name */
-  sunos4_symbol_value,         /* bfd_symbol_value */
-
-  _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_check_format */
-     bfd_generic_archive_p, sunos4_core_file_p},
-  {bfd_false, sunos4_mkobject, /* bfd_zxset_format */
-     _bfd_generic_mkarchive, bfd_false},
-  sunos4_make_empty_symbol,
-  sunos4_print_symbol,
-  sunos4_get_lineno,
-  sunos4_set_arch_mach,
-  bsd_write_armap,
-  bfd_generic_openr_next_archived_file,
-  sunos4_find_nearest_line,    /* bfd_find_nearest_line */
-  bfd_generic_stat_arch_elt /* bfd_stat_arch_elt */
-  };
-
-bfd_target aout_little_vec =
-{
-  "a.out-generic-little",              /* 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 */
-  0,                           /* valid reloc types */
-  ' ',                         /* ar_pad_char */
-  16,                          /* ar_max_namelen */
-  sunos4_close_and_cleanup,    /* _close_and_cleanup */
-  sunos4_set_section_contents, /* bfd_set_section_contents */
-  sunos4_get_section_contents, /* bfd_get_section_contents */
-  sunos4_new_section_hook,     /* new_section_hook */
-  sunos4_core_file_failing_command, /* _core_file_failing_command */
-  sunos4_core_file_failing_signal, /* _core_file_failing_signal */
-  sunos4_core_file_matches_executable_p, /* _core_file_matches_ex...p */
-
-  bfd_slurp_bsd_armap,         /* bfd_slurp_armap */
-  bfd_true,                    /* bfd_slurp_extended_name_table */
-  bfd_bsd_truncate_arname,     /* bfd_truncate_arname */
-
-  sunos4_get_symtab_upper_bound, /* get_symtab_upper_bound */
-  sunos4_get_symtab,           /* canonicalize_symtab */
-  sunos4_reclaim_symbol_table, /* bfd_reclaim_symbol_table */
-  sunos4_get_reloc_upper_bound,        /* get_reloc_upper_bound */
-  sunos4_canonicalize_reloc,   /* bfd_canonicalize_reloc */
-  sunos4_reclaim_reloc,                /* bfd_reclaim_reloc */
-  sunos4_get_symcount_upper_bound, /* bfd_get_symcount_upper_bound */
-  sunos4_get_first_symbol,     /* bfd_get_first_symbol */
-  sunos4_get_next_symbol,      /* bfd_get_next_symbol */
-  sunos4_classify_symbol,      /* bfd_classify_symbol */
-  sunos4_symbol_hasclass,      /* bfd_symbol_hasclass */
-  sunos4_symbol_name,          /* bfd_symbol_name */
-  sunos4_symbol_value,         /* bfd_symbol_value */
-
-  _do_getllong, _do_putllong, _do_getlshort, _do_putlshort, /* data */
-  _do_getllong, _do_putllong, _do_getlshort, _do_putlshort, /* hdrs */
-
-  {_bfd_dummy_target, sunos4_object_p, /* bfd_check_format */
-     bfd_generic_archive_p, sunos4_core_file_p},
-  {bfd_false, sunos4_mkobject, /* bfd_zxset_format */
-     _bfd_generic_mkarchive, bfd_false},
-  sunos4_make_empty_symbol,
-  sunos4_print_symbol,
-  sunos4_get_lineno,
-  sunos4_set_arch_mach,
-  bsd_write_armap,
-  bfd_generic_openr_next_archived_file,
-  sunos4_find_nearest_line,    /* bfd_find_nearest_line */
-  bfd_generic_stat_arch_elt /* bfd_stat_arch_elt */
-  };
-
This page took 0.059203 seconds and 4 git commands to generate.