* Many files: Changes to avoid gcc warnings: Add ATTRIBUTE_UNUSED
[deliverable/binutils-gdb.git] / bfd / aoutx.h
index 03665907a4239ae1c8ee292ef36decaf75e91ba9..66b414f098b6ff795033981e28e5dbcdcbad9033 100644 (file)
@@ -1,5 +1,6 @@
 /* BFD semi-generic back-end for a.out binaries.
-   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+   Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -16,7 +17,7 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /*
 SECTION
@@ -65,7 +66,6 @@ DESCRIPTION
 
        from @file{sunos.c}:
 
-|      #define ARCH 32
 |      #define TARGET_NAME "a.out-sunos-big"
 |      #define VECNAME    sunos_big_vec
 |      #include "aoutf1.h"
@@ -118,14 +118,11 @@ DESCRIPTION
    (Just want to make these explicit, so the conditions tested in this
    file make sense if you're more familiar with a.out than with BFD.)  */
 
-#define KEEPIT flags
-#define KEEPITTYPE int
+#define KEEPIT udata.i
 
-#include <assert.h>
-#include <string.h>            /* For strchr and friends */
+#include <ctype.h>
 #include "bfd.h"
-#include <sysdep.h>
-#include <ansidecl.h>
+#include "sysdep.h"
 #include "bfdlink.h"
 
 #include "libaout.h"
@@ -134,11 +131,14 @@ DESCRIPTION
 #include "aout/stab_gnu.h"
 #include "aout/ar.h"
 
-static boolean translate_symbol_table PARAMS ((bfd *, aout_symbol_type *,
-                                              struct external_nlist *,
-                                              bfd_size_type, char *,
-                                              bfd_size_type,
-                                              boolean dynamic));
+static boolean aout_get_external_symbols PARAMS ((bfd *));
+static boolean translate_from_native_sym_flags
+  PARAMS ((bfd *, aout_symbol_type *));
+static boolean translate_to_native_sym_flags
+  PARAMS ((bfd *, asymbol *, struct external_nlist *));
+static void adjust_o_magic PARAMS ((bfd *, struct internal_exec *));
+static void adjust_z_magic PARAMS ((bfd *, struct internal_exec *));
+static void adjust_n_magic PARAMS ((bfd *, struct internal_exec *));
 
 /*
 SUBSECTION
@@ -154,7 +154,28 @@ DESCRIPTION
        addend.
 
 */
+#ifndef CTOR_TABLE_RELOC_HOWTO
 #define CTOR_TABLE_RELOC_IDX 2
+#define CTOR_TABLE_RELOC_HOWTO(BFD) ((obj_reloc_entry_size(BFD) == RELOC_EXT_SIZE \
+            ? howto_table_ext : howto_table_std) \
+           + CTOR_TABLE_RELOC_IDX)
+#endif
+
+#ifndef MY_swap_std_reloc_in
+#define MY_swap_std_reloc_in NAME(aout,swap_std_reloc_in)
+#endif
+
+#ifndef MY_swap_std_reloc_out
+#define MY_swap_std_reloc_out NAME(aout,swap_std_reloc_out)
+#endif
+
+#ifndef MY_final_link_relocate
+#define MY_final_link_relocate _bfd_final_link_relocate
+#endif
+
+#ifndef MY_relocate_contents
+#define MY_relocate_contents _bfd_relocate_contents
+#endif
 
 #define howto_table_ext NAME(aout,ext_howto_table)
 #define howto_table_std NAME(aout,std_howto_table)
@@ -176,16 +197,20 @@ reloc_howto_type howto_table_ext[] =
   HOWTO(RELOC_LO10,   0,  2,   10, false, 0, complain_overflow_dont,0,"LO10",     false, 0,0x000003ff, false),
   HOWTO(RELOC_SFA_BASE,0, 2,   32, false, 0, complain_overflow_bitfield,0,"SFA_BASE", false, 0,0xffffffff, false),
   HOWTO(RELOC_SFA_OFF13,0,2,   32, false, 0, complain_overflow_bitfield,0,"SFA_OFF13",false, 0,0xffffffff, false),
-  HOWTO(RELOC_BASE10, 0,  2,   16, false, 0, complain_overflow_bitfield,0,"BASE10",   false, 0,0x0000ffff, false),
-  HOWTO(RELOC_BASE13, 0,  2,   13, false, 0, complain_overflow_bitfield,0,"BASE13",   false, 0,0x00001fff, false),
-  HOWTO(RELOC_BASE22, 0,  2,   0,  false, 0, complain_overflow_bitfield,0,"BASE22",   false, 0,0x00000000, false),
-  HOWTO(RELOC_PC10,   0,  2,   10, false, 0, complain_overflow_bitfield,0,"PC10",      false, 0,0x000003ff, false),
-  HOWTO(RELOC_PC22,   0,  2,   22, false, 0, complain_overflow_bitfield,0,"PC22",      false, 0,0x003fffff, false),
-  HOWTO(RELOC_JMP_TBL,0,  2,   32, false, 0, complain_overflow_bitfield,0,"JMP_TBL",   false, 0,0xffffffff, false),
+  HOWTO(RELOC_BASE10, 0,  2,   10, false, 0, complain_overflow_dont,0,"BASE10",   false, 0,0x000003ff, false),
+  HOWTO(RELOC_BASE13, 0,  2,   13, false, 0, complain_overflow_signed,0,"BASE13",   false, 0,0x00001fff, false),
+  HOWTO(RELOC_BASE22, 10, 2,   22, false, 0, complain_overflow_bitfield,0,"BASE22",   false, 0,0x003fffff, false),
+  HOWTO(RELOC_PC10,   0,  2,   10, true,  0, complain_overflow_dont,0,"PC10",  false, 0,0x000003ff, true),
+  HOWTO(RELOC_PC22,   10,  2,  22, true,  0, complain_overflow_signed,0,"PC22", false, 0,0x003fffff, true),
+  HOWTO(RELOC_JMP_TBL,2,  2,   30, true,  0, complain_overflow_signed,0,"JMP_TBL",     false, 0,0x3fffffff, false),
   HOWTO(RELOC_SEGOFF16,0, 2,   0,  false, 0, complain_overflow_bitfield,0,"SEGOFF16",  false, 0,0x00000000, false),
   HOWTO(RELOC_GLOB_DAT,0, 2,   0,  false, 0, complain_overflow_bitfield,0,"GLOB_DAT",  false, 0,0x00000000, false),
   HOWTO(RELOC_JMP_SLOT,0, 2,   0,  false, 0, complain_overflow_bitfield,0,"JMP_SLOT",  false, 0,0x00000000, false),
   HOWTO(RELOC_RELATIVE,0, 2,   0,  false, 0, complain_overflow_bitfield,0,"RELATIVE",  false, 0,0x00000000, false),
+  HOWTO(0,  0, 0,    0,  false, 0, complain_overflow_dont, 0, "R_SPARC_NONE",    false,0,0x00000000,true),
+  HOWTO(0,  0, 0,    0,  false, 0, complain_overflow_dont, 0, "R_SPARC_NONE",    false,0,0x00000000,true),
+#define RELOC_SPARC_REV32 RELOC_WDISP19
+  HOWTO(RELOC_SPARC_REV32,    0,  2,   32, false, 0, complain_overflow_dont,0,"R_SPARC_REV32",       false, 0,0xffffffff, false),
 };
 
 /* Convert standard reloc records to "arelent" format (incl byte swap).  */
@@ -200,17 +225,47 @@ HOWTO( 4,        0,  0,   8,  true,  0, complain_overflow_signed,  0,"DISP8",     tru
 HOWTO( 5,             0,  1,   16, true,  0, complain_overflow_signed,  0,"DISP16",    true, 0x0000ffff,0x0000ffff, false),
 HOWTO( 6,             0,  2,   32, true,  0, complain_overflow_signed,  0,"DISP32",    true, 0xffffffff,0xffffffff, false),
 HOWTO( 7,             0,  4,   64, true,  0, complain_overflow_signed,  0,"DISP64",    true, 0xfeedface,0xfeedface, false),
-{ -1 },
+HOWTO( 8,             0,  2,    0, false, 0, complain_overflow_bitfield,0,"GOT_REL",   false,         0,0x00000000, false),
 HOWTO( 9,             0,  1,   16, false, 0, complain_overflow_bitfield,0,"BASE16",    false,0xffffffff,0xffffffff, false),
 HOWTO(10,             0,  2,   32, false, 0, complain_overflow_bitfield,0,"BASE32",    false,0xffffffff,0xffffffff, false),
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+  HOWTO(16,           0,  2,    0, false, 0, complain_overflow_bitfield,0,"JMP_TABLE", false,         0,0x00000000, false),
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+  HOWTO(32,           0,  2,    0, false, 0, complain_overflow_bitfield,0,"RELATIVE",  false,         0,0x00000000, false),
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+{ -1, 0, 0, 0, false, 0, complain_overflow_dont, NULL, NULL, false, 0, 0, false },
+  HOWTO(40,           0,  2,    0, false, 0, complain_overflow_bitfield,0,"BASEREL",   false,         0,0x00000000, false),
 };
 
 #define TABLE_SIZE(TABLE)      (sizeof(TABLE)/sizeof(TABLE[0]))
 
-CONST struct reloc_howto_struct *
-DEFUN(NAME(aout,reloc_type_lookup),(abfd,code),
-      bfd *abfd AND
-      bfd_reloc_code_real_type code)
+reloc_howto_type *
+NAME(aout,reloc_type_lookup) (abfd,code)
+     bfd *abfd;
+     bfd_reloc_code_real_type code;
 {
 #define EXT(i,j)       case i: return &howto_table_ext[j]
 #define STD(i,j)       case i: return &howto_table_std[j]
@@ -221,6 +276,9 @@ DEFUN(NAME(aout,reloc_type_lookup),(abfd,code),
       case 32:
        code = BFD_RELOC_32;
        break;
+      case 64:
+       code = BFD_RELOC_64;
+       break;
       }
   if (ext)
     switch (code)
@@ -230,7 +288,16 @@ DEFUN(NAME(aout,reloc_type_lookup),(abfd,code),
        EXT (BFD_RELOC_LO10, 11);
        EXT (BFD_RELOC_32_PCREL_S2, 6);
        EXT (BFD_RELOC_SPARC_WDISP22, 7);
-      default: return (CONST struct reloc_howto_struct *) 0;
+       EXT (BFD_RELOC_SPARC13, 10);
+       EXT (BFD_RELOC_SPARC_GOT10, 14);
+       EXT (BFD_RELOC_SPARC_BASE13, 15);
+       EXT (BFD_RELOC_SPARC_GOT13, 15);
+       EXT (BFD_RELOC_SPARC_GOT22, 16);
+       EXT (BFD_RELOC_SPARC_PC10, 17);
+       EXT (BFD_RELOC_SPARC_PC22, 18);
+       EXT (BFD_RELOC_SPARC_WPLT30, 19);
+       EXT (BFD_RELOC_SPARC_REV32, 26);
+      default: return (reloc_howto_type *) NULL;
       }
   else
     /* std relocs */
@@ -243,7 +310,7 @@ DEFUN(NAME(aout,reloc_type_lookup),(abfd,code),
        STD (BFD_RELOC_32_PCREL, 6);
        STD (BFD_RELOC_16_BASEREL, 9);
        STD (BFD_RELOC_32_BASEREL, 10);
-      default: return (CONST struct reloc_howto_struct *) 0;
+      default: return (reloc_howto_type *) NULL;
       }
 }
 
@@ -276,10 +343,10 @@ DESCRIPTION
 
 #ifndef NAME_swap_exec_header_in
 void
-DEFUN(NAME(aout,swap_exec_header_in),(abfd, raw_bytes, execp),
-      bfd *abfd AND
-      struct external_exec *raw_bytes AND
-      struct internal_exec *execp)
+NAME(aout,swap_exec_header_in) (abfd, raw_bytes, execp)
+     bfd *abfd;
+     struct external_exec *raw_bytes;
+     struct internal_exec *execp;
 {
   struct external_exec *bytes = (struct external_exec *)raw_bytes;
 
@@ -287,7 +354,7 @@ DEFUN(NAME(aout,swap_exec_header_in),(abfd, raw_bytes, execp),
      configuration (IE for i960), so ensure that all such uninitialized
      fields are zero'd out.  There are places where two of these structs
      are memcmp'd, and thus the contents do matter. */
-  memset (execp, 0, sizeof (struct internal_exec));
+  memset ((PTR) execp, 0, sizeof (struct internal_exec));
   /* Now fill in fields in the execp, from the bytes in the raw data.  */
   execp->a_info   = bfd_h_get_32 (abfd, bytes->e_info);
   execp->a_text   = GET_WORD (abfd, bytes->e_text);
@@ -316,10 +383,10 @@ DESCRIPTION
        @var{execp} into the buffer @var{raw_bytes} ready for writing to disk.
 */
 void
-DEFUN(NAME(aout,swap_exec_header_out),(abfd, execp, raw_bytes),
-     bfd *abfd AND
-     struct internal_exec *execp AND
-     struct external_exec *raw_bytes)
+NAME(aout,swap_exec_header_out) (abfd, execp, raw_bytes)
+     bfd *abfd;
+     struct internal_exec *execp;
+     struct external_exec *raw_bytes;
 {
   struct external_exec *bytes = (struct external_exec *)raw_bytes;
 
@@ -334,16 +401,32 @@ DEFUN(NAME(aout,swap_exec_header_out),(abfd, execp, raw_bytes),
   PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize);
 }
 
+/* Make all the section for an a.out file.  */
 
+boolean
+NAME(aout,make_sections) (abfd)
+     bfd *abfd;
+{
+  if (obj_textsec (abfd) == (asection *) NULL
+      && bfd_make_section (abfd, ".text") == (asection *) NULL)
+    return false;
+  if (obj_datasec (abfd) == (asection *) NULL
+      && bfd_make_section (abfd, ".data") == (asection *) NULL)
+    return false;
+  if (obj_bsssec (abfd) == (asection *) NULL
+      && bfd_make_section (abfd, ".bss") == (asection *) NULL)
+    return false;
+  return true;
+}
 
 /*
 FUNCTION
        aout_@var{size}_some_aout_object_p
 
 SYNOPSIS
-       bfd_target *aout_@var{size}_some_aout_object_p
+       const bfd_target *aout_@var{size}_some_aout_object_p
         (bfd *abfd,
-         bfd_target *(*callback_to_real_object_p)());
+         const bfd_target *(*callback_to_real_object_p)());
 
 DESCRIPTION
        Some a.out variant thinks that the file open in @var{abfd}
@@ -353,20 +436,18 @@ DESCRIPTION
        handle any last-minute setup.
 */
 
-bfd_target *
-DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
-      bfd *abfd AND
-      struct internal_exec *execp AND
-      bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *)))
+const bfd_target *
+NAME(aout,some_aout_object_p) (abfd, execp, callback_to_real_object_p)
+     bfd *abfd;
+     struct internal_exec *execp;
+     const bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *));
 {
   struct aout_data_struct *rawptr, *oldrawptr;
-  bfd_target *result;
+  const bfd_target *result;
 
   rawptr = (struct aout_data_struct  *) bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
-  if (rawptr == NULL) {
-    bfd_error = no_memory;
+  if (rawptr == NULL)
     return 0;
-  }
 
   oldrawptr = abfd->tdata.aout_data;
   abfd->tdata.aout_data = rawptr;
@@ -383,7 +464,7 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
   execp = abfd->tdata.aout_data->a.hdr;
 
   /* Set the file flags */
-  abfd->flags = NO_FLAGS;
+  abfd->flags = BFD_NO_FLAGS;
   if (execp->a_drsize || execp->a_trsize)
     abfd->flags |= HAS_RELOC;
   /* Setting of EXEC_P has been deferred to the bottom of this function */
@@ -394,16 +475,29 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
 
   if (N_MAGIC (*execp) == ZMAGIC)
     {
-      abfd->flags |= D_PAGED|WP_TEXT;
-      adata(abfd).magic = z_magic;
+      abfd->flags |= D_PAGED | WP_TEXT;
+      adata (abfd).magic = z_magic;
+    }
+  else if (N_MAGIC (*execp) == QMAGIC)
+    {
+      abfd->flags |= D_PAGED | WP_TEXT;
+      adata (abfd).magic = z_magic;
+      adata (abfd).subformat = q_magic_format;
     }
   else if (N_MAGIC (*execp) == NMAGIC)
     {
       abfd->flags |= WP_TEXT;
-      adata(abfd).magic = n_magic;
+      adata (abfd).magic = n_magic;
     }
+  else if (N_MAGIC (*execp) == OMAGIC
+          || N_MAGIC (*execp) == BMAGIC)
+    adata (abfd).magic = o_magic;
   else
-    adata(abfd).magic = o_magic;
+    {
+      /* Should have been checked with N_BADMAG before this routine
+        was called.  */
+      abort ();
+    }
 
   bfd_get_start_address (abfd) = execp->a_entry;
 
@@ -416,35 +510,26 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
   /* The default symbol entry size is that of traditional Unix. */
   obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE;
 
+#ifdef USE_MMAP
+  bfd_init_window (&obj_aout_sym_window (abfd));
+  bfd_init_window (&obj_aout_string_window (abfd));
+#endif
   obj_aout_external_syms (abfd) = NULL;
   obj_aout_external_strings (abfd) = NULL;
   obj_aout_sym_hashes (abfd) = NULL;
 
-  /* Create the sections.  This is raunchy, but bfd_close wants to reclaim
-     them.  */
-
-  obj_textsec (abfd) = bfd_make_section_old_way (abfd, ".text");
-  obj_datasec (abfd) = bfd_make_section_old_way (abfd, ".data");
-  obj_bsssec (abfd) = bfd_make_section_old_way (abfd, ".bss");
-
-#if 0
-  (void)bfd_make_section (abfd, ".text");
-  (void)bfd_make_section (abfd, ".data");
-  (void)bfd_make_section (abfd, ".bss");
-#endif
+  if (! NAME(aout,make_sections) (abfd))
+    return NULL;
 
   obj_datasec (abfd)->_raw_size = execp->a_data;
   obj_bsssec (abfd)->_raw_size = execp->a_bss;
 
-  /* If this object is dynamically linked, we assume that both
-     sections have relocs.  This does no real harm, even though it may
-     not be true.  */
   obj_textsec (abfd)->flags =
-    (execp->a_trsize != 0 || (abfd->flags & DYNAMIC) != 0
+    (execp->a_trsize != 0
      ? (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC)
      : (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS));
   obj_datasec (abfd)->flags =
-    (execp->a_drsize != 0 || (abfd->flags & DYNAMIC) != 0
+    (execp->a_drsize != 0
      ? (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC)
      : (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS));
   obj_bsssec (abfd)->flags = SEC_ALLOC;
@@ -452,7 +537,7 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
 #ifdef THIS_IS_ONLY_DOCUMENTATION
   /* The common code can't fill in these things because they depend
      on either the start address of the text segment, the rounding
-     up of virtual addersses between segments, or the starting file
+     up of virtual addresses between segments, or the starting file
      position of the text segment -- all of which varies among different
      versions of a.out.  */
 
@@ -490,7 +575,7 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
     break;
   }
 
-  adata(abfd)->page_size = PAGE_SIZE;
+  adata(abfd)->page_size = TARGET_PAGE_SIZE;
   adata(abfd)->segment_size = SEGMENT_SIZE;
   adata(abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
 
@@ -512,13 +597,41 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
      guess at whether the file is executable.  If the entry point
      is within the text segment, assume it is.  (This makes files
      executable even if their entry point address is 0, as long as
-     their text starts at zero.)
+     their text starts at zero.).
+
+     This test had to be changed to deal with systems where the text segment
+     runs at a different location than the default.  The problem is that the
+     entry address can appear to be outside the text segment, thus causing an
+     erroneous conclusion that the file isn't executable.
 
-     At some point we should probably break down and stat the file and
-     declare it executable if (one of) its 'x' bits are on...  */
-  if ((execp->a_entry >= obj_textsec(abfd)->vma) &&
-      (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size))
+     To fix this, we now accept any non-zero entry point as an indication of
+     executability.  This will work most of the time, since only the linker
+     sets the entry point, and that is likely to be non-zero for most systems. */
+
+  if (execp->a_entry != 0
+      || (execp->a_entry >= obj_textsec(abfd)->vma
+         && execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size))
     abfd->flags |= EXEC_P;
+#ifdef STAT_FOR_EXEC
+  else
+    {
+      struct stat stat_buf;
+
+      /* The original heuristic doesn't work in some important cases.
+        The a.out file has no information about the text start
+        address.  For files (like kernels) linked to non-standard
+        addresses (ld -Ttext nnn) the entry point may not be between
+        the default text start (obj_textsec(abfd)->vma) and
+        (obj_textsec(abfd)->vma) + text size.  This is not just a mach
+        issue.  Many kernels are loaded at non standard addresses.  */
+      if (abfd->iostream != NULL
+         && (abfd->flags & BFD_IN_MEMORY) == 0
+         && (fstat(fileno((FILE *) (abfd->iostream)), &stat_buf) == 0)
+         && ((stat_buf.st_mode & 0111) != 0))
+       abfd->flags |= EXEC_P;
+    }
+#endif /* STAT_FOR_EXEC */
+
   if (result)
     {
 #if 0 /* These should be set correctly anyways.  */
@@ -547,35 +660,25 @@ DESCRIPTION
 */
 
 boolean
-DEFUN(NAME(aout,mkobject),(abfd),
-     bfd *abfd)
+NAME(aout,mkobject) (abfd)
+     bfd *abfd;
 {
   struct aout_data_struct  *rawptr;
 
-  bfd_error = system_call_error;
+  bfd_set_error (bfd_error_system_call);
 
   /* Use an intermediate variable for clarity */
   rawptr = (struct aout_data_struct *)bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
 
-  if (rawptr == NULL) {
-    bfd_error = no_memory;
+  if (rawptr == NULL)
     return false;
-  }
 
   abfd->tdata.aout_data = rawptr;
   exec_hdr (abfd) = &(rawptr->e);
 
-  /* For simplicity's sake we just make all the sections right here. */
-
   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");
-  bfd_make_section (abfd, BFD_ABS_SECTION_NAME);
-  bfd_make_section (abfd, BFD_UND_SECTION_NAME);
-  bfd_make_section (abfd, BFD_COM_SECTION_NAME);
 
   return true;
 }
@@ -601,26 +704,35 @@ DESCRIPTION
 */
 
 enum machine_type
-DEFUN(NAME(aout,machine_type),(arch, machine),
-      enum bfd_architecture arch AND
-      unsigned long machine)
+NAME(aout,machine_type) (arch, machine, unknown)
+     enum bfd_architecture arch;
+     unsigned long machine;
+     boolean *unknown;
 {
   enum machine_type arch_flags;
 
   arch_flags = M_UNKNOWN;
+  *unknown = true;
 
   switch (arch) {
   case bfd_arch_sparc:
-    if (machine == 0)  arch_flags = M_SPARC;
+    if (machine == 0
+       || machine == bfd_mach_sparc
+       || machine == bfd_mach_sparc_sparclite
+       || machine == bfd_mach_sparc_sparclite_le
+       || machine == bfd_mach_sparc_v9)
+      arch_flags = M_SPARC;
+    else if (machine == bfd_mach_sparc_sparclet)
+      arch_flags = M_SPARCLET;
     break;
 
   case bfd_arch_m68k:
     switch (machine) {
-    case 0:            arch_flags = M_68010; break;
-    case 68000:                arch_flags = M_UNKNOWN; break;
-    case 68010:                arch_flags = M_68010; break;
-    case 68020:                arch_flags = M_68020; break;
-    default:           arch_flags = M_UNKNOWN; break;
+    case 0:              arch_flags = M_68010; break;
+    case bfd_mach_m68000: arch_flags = M_UNKNOWN; *unknown = false; break;
+    case bfd_mach_m68010: arch_flags = M_68010; break;
+    case bfd_mach_m68020: arch_flags = M_68020; break;
+    default:             arch_flags = M_UNKNOWN; break;
     }
     break;
 
@@ -632,21 +744,59 @@ DEFUN(NAME(aout,machine_type),(arch, machine),
     if (machine == 0)  arch_flags = M_29K;
     break;
 
+  case bfd_arch_arm:
+    if (machine == 0)  arch_flags = M_ARM;
+    break;
+    
   case bfd_arch_mips:
     switch (machine) {
     case 0:
-    case 2000:
-    case 3000:          arch_flags = M_MIPS1; break;
-    case 4000:
-    case 4400:
-    case 6000:          arch_flags = M_MIPS2; break;
-    default:            arch_flags = M_UNKNOWN; break;
+    case bfd_mach_mips3000:
+    case bfd_mach_mips3900:
+      arch_flags = M_MIPS1;
+      break;
+    case bfd_mach_mips6000:
+      arch_flags = M_MIPS2;
+      break;
+    case bfd_mach_mips4000:
+    case bfd_mach_mips4010:
+    case bfd_mach_mips4100:
+    case bfd_mach_mips4300:
+    case bfd_mach_mips4400:
+    case bfd_mach_mips4600:
+    case bfd_mach_mips4650:
+    case bfd_mach_mips8000:
+    case bfd_mach_mips10000:
+    case bfd_mach_mips16:
+      /* FIXME: These should be MIPS3 or MIPS4.  */
+      arch_flags = M_MIPS2;
+      break;
+    default:
+      arch_flags = M_UNKNOWN;
+      break;
+    }
+    break;
+
+  case bfd_arch_ns32k:
+    switch (machine) {
+    case 0:                    arch_flags = M_NS32532; break;
+    case 32032:                arch_flags = M_NS32032; break;
+    case 32532:                arch_flags = M_NS32532; break;
+    default:           arch_flags = M_UNKNOWN; break;
     }
     break;
 
+  case bfd_arch_vax:
+    *unknown = false;
+    break;
+
   default:
     arch_flags = M_UNKNOWN;
   }
+
+  if (arch_flags != M_UNKNOWN)
+    *unknown = false;
+
   return arch_flags;
 }
 
@@ -668,17 +818,22 @@ DESCRIPTION
 */
 
 boolean
-DEFUN(NAME(aout,set_arch_mach),(abfd, arch, machine),
-      bfd *abfd AND
-      enum bfd_architecture arch AND
-      unsigned long machine)
+NAME(aout,set_arch_mach) (abfd, arch, machine)
+     bfd *abfd;
+     enum bfd_architecture arch;
+     unsigned long machine;
 {
   if (! bfd_default_set_arch_mach (abfd, arch, machine))
     return false;
 
-  if (arch != bfd_arch_unknown &&
-      NAME(aout,machine_type) (arch, machine) == M_UNKNOWN)
-    return false;              /* We can't represent this type */
+  if (arch != bfd_arch_unknown)
+    {
+      boolean unknown;
+
+      NAME(aout,machine_type) (arch, machine, &unknown);
+      if (unknown)
+       return false;
+    }
 
   /* Determine the size of a relocation entry */
   switch (arch) {
@@ -706,6 +861,11 @@ adjust_o_magic (abfd, execp)
 
   /* Text.  */
   obj_textsec(abfd)->filepos = pos;
+  if (!obj_textsec(abfd)->user_set_vma)
+    obj_textsec(abfd)->vma = vma;
+  else
+    vma = obj_textsec(abfd)->vma;
+
   pos += obj_textsec(abfd)->_raw_size;
   vma += obj_textsec(abfd)->_raw_size;
 
@@ -720,6 +880,8 @@ adjust_o_magic (abfd, execp)
       vma += pad;
       obj_datasec(abfd)->vma = vma;
     }
+  else
+    vma = obj_datasec(abfd)->vma;
   obj_datasec(abfd)->filepos = pos;
   pos += obj_datasec(abfd)->_raw_size;
   vma += obj_datasec(abfd)->_raw_size;
@@ -735,6 +897,18 @@ adjust_o_magic (abfd, execp)
       vma += pad;
       obj_bsssec(abfd)->vma = vma;
     }
+  else
+    {
+      /* The VMA of the .bss section is set by the the VMA of the
+         .data section plus the size of the .data section.  We may
+         need to add padding bytes to make this true.  */
+      pad = obj_bsssec (abfd)->vma - vma;
+      if (pad > 0)
+       {
+         obj_datasec (abfd)->_raw_size += pad;
+         pos += pad;
+       }
+    }
   obj_bsssec(abfd)->filepos = pos;
 
   /* Fix up the exec header.  */
@@ -757,23 +931,51 @@ adjust_z_magic (abfd, execp)
   abdp = aout_backend_info (abfd);
 
   /* Text.  */
-  ztih = abdp && abdp->text_includes_header;
+  ztih = (abdp != NULL
+         && (abdp->text_includes_header
+             || obj_aout_subformat (abfd) == q_magic_format));
   obj_textsec(abfd)->filepos = (ztih
                                ? adata(abfd).exec_bytes_size
-                               : adata(abfd).page_size);
+                               : adata(abfd).zmagic_disk_block_size);
   if (! obj_textsec(abfd)->user_set_vma)
-    /* ?? Do we really need to check for relocs here?  */
-    obj_textsec(abfd)->vma = ((abfd->flags & HAS_RELOC)
-                             ? 0
-                             : (ztih
-                                ? (abdp->default_text_vma
-                                   + adata(abfd).exec_bytes_size)
-                                : abdp->default_text_vma));
-  /* Could take strange alignment of text section into account here?  */
-  
+    {
+      /* ?? Do we really need to check for relocs here?  */
+      obj_textsec(abfd)->vma = ((abfd->flags & HAS_RELOC)
+                               ? 0
+                               : (ztih
+                                  ? (abdp->default_text_vma
+                                     + adata(abfd).exec_bytes_size)
+                                  : abdp->default_text_vma));
+      text_pad = 0;
+    }
+  else
+    {
+      /* The .text section is being loaded at an unusual address.  We
+         may need to pad it such that the .data section starts at a page
+         boundary.  */
+      if (ztih)
+       text_pad = ((obj_textsec (abfd)->filepos - obj_textsec (abfd)->vma)
+                   & (adata (abfd).page_size - 1));
+      else
+       text_pad = ((- obj_textsec (abfd)->vma)
+                   & (adata (abfd).page_size - 1));
+    }
+
   /* Find start of data.  */
-  text_end = obj_textsec(abfd)->filepos + obj_textsec(abfd)->_raw_size;
-  text_pad = BFD_ALIGN (text_end, adata(abfd).page_size) - text_end;
+  if (ztih)
+    {
+      text_end = obj_textsec (abfd)->filepos + obj_textsec (abfd)->_raw_size;
+      text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
+    }
+  else
+    {
+      /* Note that if page_size == zmagic_disk_block_size, then
+        filepos == page_size, and this case is the same as the ztih
+        case.  */
+      text_end = obj_textsec (abfd)->_raw_size;
+      text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
+      text_end += obj_textsec (abfd)->filepos;
+    }
   obj_textsec(abfd)->_raw_size += text_pad;
   text_end += text_pad;
 
@@ -798,7 +1000,10 @@ adjust_z_magic (abfd, execp)
   execp->a_text = obj_textsec(abfd)->_raw_size;
   if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted)))
     execp->a_text += adata(abfd).exec_bytes_size;
-  N_SET_MAGIC (*execp, ZMAGIC);
+  if (obj_aout_subformat (abfd) == q_magic_format)
+    N_SET_MAGIC (*execp, QMAGIC);
+  else
+    N_SET_MAGIC (*execp, ZMAGIC);
 
   /* Spec says data section should be rounded up to page boundary.  */
   obj_datasec(abfd)->_raw_size
@@ -871,17 +1076,18 @@ adjust_n_magic (abfd, execp)
 }
 
 boolean
-DEFUN (NAME(aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
-       bfd *abfd AND bfd_size_type *text_size AND file_ptr *text_end)
+NAME(aout,adjust_sizes_and_vmas) (abfd, text_size, text_end)
+     bfd *abfd;
+     bfd_size_type *text_size;
+     file_ptr *text_end ATTRIBUTE_UNUSED;
 {
   struct internal_exec *execp = exec_hdr (abfd);
 
-  if ((obj_textsec (abfd) == NULL) || (obj_datasec (abfd) == NULL))
-    {
-      bfd_error = invalid_operation;
-      return false;
-    }
-  if (adata(abfd).magic != undecided_magic) return true;
+  if (! NAME(aout,make_sections) (abfd))
+    return false;
+
+  if (adata(abfd).magic != undecided_magic)
+    return true;
 
   obj_textsec(abfd)->_raw_size =
     align_power(obj_textsec(abfd)->_raw_size,
@@ -891,7 +1097,7 @@ DEFUN (NAME(aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
   /* Rule (heuristic) for when to pad to a new page.  Note that there
      are (at least) two ways demand-paged (ZMAGIC) files have been
      handled.  Most Berkeley-based systems start the text segment at
-     (PAGE_SIZE).  However, newer versions of SUNOS start the text
+     (TARGET_PAGE_SIZE).  However, newer versions of SUNOS start the text
      segment right after the exec header; the latter is counted in the
      text segment size, and is paged in by the kernel with the rest of
      the text. */
@@ -906,7 +1112,6 @@ DEFUN (NAME(aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
 
   if (abfd->flags & D_PAGED)
     /* Whether or not WP_TEXT is set -- let D_PAGED override.  */
-    /* @@ What about QMAGIC?  */
     adata(abfd).magic = z_magic;
   else if (abfd->flags & WP_TEXT)
     adata(abfd).magic = n_magic;
@@ -975,9 +1180,9 @@ DESCRIPTION
        request.
 */
 boolean
-DEFUN(NAME(aout,new_section_hook),(abfd, newsect),
-       bfd *abfd AND
-       asection *newsect)
+NAME(aout,new_section_hook) (abfd, newsect)
+     bfd *abfd;
+     asection *newsect;
 {
   /* align to double at least */
   newsect->alignment_power = bfd_get_arch_info(abfd)->section_align_power;
@@ -987,19 +1192,19 @@ DEFUN(NAME(aout,new_section_hook),(abfd, newsect),
   {
     if (obj_textsec(abfd) == NULL && !strcmp(newsect->name, ".text")) {
        obj_textsec(abfd)= newsect;
-       newsect->target_index = N_TEXT | N_EXT;
+       newsect->target_index = N_TEXT;
        return true;
       }
 
     if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) {
        obj_datasec(abfd) = newsect;
-       newsect->target_index = N_DATA | N_EXT;
+       newsect->target_index = N_DATA;
        return true;
       }
 
     if (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) {
        obj_bsssec(abfd) = newsect;
-       newsect->target_index = N_BSS | N_EXT;
+       newsect->target_index = N_BSS;
        return true;
       }
 
@@ -1010,145 +1215,310 @@ DEFUN(NAME(aout,new_section_hook),(abfd, newsect),
 }
 
 boolean
-DEFUN(NAME(aout,set_section_contents),(abfd, section, location, offset, count),
-      bfd *abfd AND
-      sec_ptr section AND
-      PTR location AND
-      file_ptr offset AND
-      bfd_size_type count)
+NAME(aout,set_section_contents) (abfd, section, location, offset, count)
+     bfd *abfd;
+     sec_ptr section;
+     PTR location;
+     file_ptr offset;
+     bfd_size_type count;
 {
   file_ptr text_end;
   bfd_size_type text_size;
 
-  if (abfd->output_has_begun == false)
-      {
-       if (NAME(aout,adjust_sizes_and_vmas) (abfd,
-                                             &text_size,
-                                             &text_end) == false)
-         return false;
-      }
+  if (! abfd->output_has_begun)
+    {
+      if (! NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
+       return false;
+    }
 
-  /* 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);
+  if (section == obj_bsssec (abfd))
+    {
+      bfd_set_error (bfd_error_no_contents);
+      return false;
+    }
+
+  if (section != obj_textsec (abfd)
+      && section != obj_datasec (abfd))
+    {
+      (*_bfd_error_handler)
+       (_("%s: can not represent section `%s' in a.out object file format"),
+        bfd_get_filename (abfd), bfd_get_section_name (abfd, section));
+      bfd_set_error (bfd_error_nonrepresentable_section);
+      return false;
+    }
+
+  if (count != 0)
+    {
+      if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
+         || bfd_write (location, 1, count, abfd) != count)
+       return false;
+    }
 
-       if (count) {
-         return (bfd_write ((PTR)location, 1, count, abfd) == count) ?
-           true : false;
-       }
-       return true;
-      }
   return true;
 }
 \f
-/* Classify stabs symbols */
+/* Read the external symbols from an a.out file.  */
+
+static boolean
+aout_get_external_symbols (abfd)
+     bfd *abfd;
+{
+  if (obj_aout_external_syms (abfd) == (struct external_nlist *) NULL)
+    {
+      bfd_size_type count;
+      struct external_nlist *syms;
 
-#define sym_in_text_section(sym) \
-  (((sym)->type  & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT)
+      count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE;
 
-#define sym_in_data_section(sym) \
-  (((sym)->type  & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA)
+#ifdef USE_MMAP
+      if (bfd_get_file_window (abfd,
+                              obj_sym_filepos (abfd), exec_hdr (abfd)->a_syms,
+                              &obj_aout_sym_window (abfd), true) == false)
+       return false;
+      syms = (struct external_nlist *) obj_aout_sym_window (abfd).data;
+#else
+      /* We allocate using malloc to make the values easy to free
+        later on.  If we put them on the objalloc it might not be
+        possible to free them.  */
+      syms = ((struct external_nlist *)
+             bfd_malloc ((size_t) count * EXTERNAL_NLIST_SIZE));
+      if (syms == (struct external_nlist *) NULL && count != 0)
+       return false;
 
-#define sym_in_bss_section(sym) \
-  (((sym)->type  & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS)
+      if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
+         || (bfd_read (syms, 1, exec_hdr (abfd)->a_syms, abfd)
+             != exec_hdr (abfd)->a_syms))
+       {
+         free (syms);
+         return false;
+       }
+#endif
 
-/* 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)->type == (N_UNDF | N_EXT) && (sym)->symbol.value == 0)
+      obj_aout_external_syms (abfd) = syms;
+      obj_aout_external_sym_count (abfd) = count;
+    }
+      
+  if (obj_aout_external_strings (abfd) == NULL
+      && exec_hdr (abfd)->a_syms != 0)
+    {
+      unsigned char string_chars[BYTES_IN_WORD];
+      bfd_size_type stringsize;
+      char *strings;
+
+      /* Get the size of the strings.  */
+      if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
+         || (bfd_read ((PTR) string_chars, BYTES_IN_WORD, 1, abfd)
+             != BYTES_IN_WORD))
+       return false;
+      stringsize = GET_WORD (abfd, string_chars);
 
-/* 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)->type & N_EXT) && (sym)->type & N_TYPE)
+#ifdef USE_MMAP
+      if (bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize,
+                              &obj_aout_string_window (abfd), true) == false)
+       return false;
+      strings = (char *) obj_aout_string_window (abfd).data;
+#else
+      strings = (char *) bfd_malloc ((size_t) stringsize + 1);
+      if (strings == NULL)
+       return false;
 
-/* Symbol is debugger info if any bits outside N_TYPE or N_EXT
-  are on.  */
-#define sym_is_debugger_info(sym) \
-  (((sym)->type & ~(N_EXT | N_TYPE)) || (sym)->type == N_FN)
+      /* Skip space for the string count in the buffer for convenience
+        when using indexes.  */
+      if (bfd_read (strings + BYTES_IN_WORD, 1, stringsize - BYTES_IN_WORD,
+                   abfd)
+         != stringsize - BYTES_IN_WORD)
+       {
+         free (strings);
+         return false;
+       }
+#endif
 
-#define sym_is_fortrancommon(sym)       \
-  (((sym)->type == (N_EXT)) && (sym)->symbol.value != 0)
+      /* Ensure that a zero index yields an empty string.  */
+      strings[0] = '\0';
 
-/* Symbol is absolute if it has N_ABS set */
-#define sym_is_absolute(sym) \
-  (((sym)->type  & N_TYPE)== N_ABS)
+      strings[stringsize - 1] = 0;
 
+      obj_aout_external_strings (abfd) = strings;
+      obj_aout_external_string_size (abfd) = stringsize;
+    }
 
-#define sym_is_indirect(sym) \
-  (((sym)->type & N_ABS)== N_ABS)
+  return true;
+}
 
-/* Only in their own functions for ease of debugging; when sym flags have
-  stabilised these should be inlined into their (single) caller */
+/* Translate an a.out symbol into a BFD symbol.  The desc, other, type
+   and symbol->value fields of CACHE_PTR will be set from the a.out
+   nlist structure.  This function is responsible for setting
+   symbol->flags and symbol->section, and adjusting symbol->value.  */
 
-static void
-DEFUN (translate_from_native_sym_flags, (sym_pointer, cache_ptr, abfd),
-       struct external_nlist *sym_pointer AND
-       aout_symbol_type * cache_ptr AND
-       bfd * abfd)
+static boolean
+translate_from_native_sym_flags (abfd, cache_ptr)
+     bfd *abfd;
+     aout_symbol_type *cache_ptr;
 {
-  cache_ptr->symbol.section = 0;
-  switch (cache_ptr->type & N_TYPE)
+  flagword visible;
+
+  if ((cache_ptr->type & N_STAB) != 0
+      || cache_ptr->type == N_FN)
+    {
+      asection *sec;
+
+      /* This is a debugging symbol.  */
+
+      cache_ptr->symbol.flags = BSF_DEBUGGING;
+
+      /* Work out the symbol section.  */
+      switch (cache_ptr->type & N_TYPE)
+       {
+       case N_TEXT:
+       case N_FN:
+         sec = obj_textsec (abfd);
+         break;
+       case N_DATA:
+         sec = obj_datasec (abfd);
+         break;
+       case N_BSS:
+         sec = obj_bsssec (abfd);
+         break;
+       default:
+       case N_ABS:
+         sec = bfd_abs_section_ptr;
+         break;
+       }
+
+      cache_ptr->symbol.section = sec;
+      cache_ptr->symbol.value -= sec->vma;
+
+      return true;
+    }
+
+  /* Get the default visibility.  This does not apply to all types, so
+     we just hold it in a local variable to use if wanted.  */
+  if ((cache_ptr->type & N_EXT) == 0)
+    visible = BSF_LOCAL;
+  else
+    visible = BSF_GLOBAL;
+
+  switch (cache_ptr->type)
     {
+    default:
+    case N_ABS: case N_ABS | N_EXT:
+      cache_ptr->symbol.section = bfd_abs_section_ptr;
+      cache_ptr->symbol.flags = visible;
+      break;
+
+    case N_UNDF | N_EXT:
+      if (cache_ptr->symbol.value != 0)
+       {
+         /* This is a common symbol.  */
+         cache_ptr->symbol.flags = BSF_GLOBAL;
+         cache_ptr->symbol.section = bfd_com_section_ptr;
+       }
+      else
+       {
+         cache_ptr->symbol.flags = 0;
+         cache_ptr->symbol.section = bfd_und_section_ptr;
+       }
+      break;
+
+    case N_TEXT: case N_TEXT | N_EXT:
+      cache_ptr->symbol.section = obj_textsec (abfd);
+      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+      cache_ptr->symbol.flags = visible;
+      break;
+
+      /* N_SETV symbols used to represent set vectors placed in the
+        data section.  They are no longer generated.  Theoretically,
+        it was possible to extract the entries and combine them with
+        new ones, although I don't know if that was ever actually
+        done.  Unless that feature is restored, treat them as data
+        symbols.  */
+    case N_SETV: case N_SETV | N_EXT:
+    case N_DATA: case N_DATA | N_EXT:
+      cache_ptr->symbol.section = obj_datasec (abfd);
+      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+      cache_ptr->symbol.flags = visible;
+      break;
+
+    case N_BSS: case N_BSS | N_EXT:
+      cache_ptr->symbol.section = obj_bsssec (abfd);
+      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+      cache_ptr->symbol.flags = visible;
+      break;
+
     case N_SETA: case N_SETA | N_EXT:
     case N_SETT: case N_SETT | N_EXT:
     case N_SETD: case N_SETD | N_EXT:
     case N_SETB: case N_SETB | N_EXT:
       {
-       char *copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1);
+       /* This code is no longer needed.  It used to be used to make
+           the linker handle set symbols, but they are now handled in
+           the add_symbols routine instead.  */
+#if 0
        asection *section;
+       arelent_chain *reloc;
        asection *into_section;
 
-       arelent_chain *reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain));
-       strcpy (copy, cache_ptr->symbol.name);
+       /* This is a set symbol.  The name of the symbol is the name
+          of the set (e.g., __CTOR_LIST__).  The value of the symbol
+          is the value to add to the set.  We create a section with
+          the same name as the symbol, and add a reloc to insert the
+          appropriate value into the section.
+
+          This action is actually obsolete; it used to make the
+          linker do the right thing, but the linker no longer uses
+          this function.  */
+
+       section = bfd_get_section_by_name (abfd, cache_ptr->symbol.name);
+       if (section == NULL)
+         {
+           char *copy;
+
+           copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1);
+           if (copy == NULL)
+             return false;
+
+           strcpy (copy, cache_ptr->symbol.name);
+           section = bfd_make_section (abfd, copy);
+           if (section == NULL)
+             return false;
+         }
 
-       /* Make sure that this bfd has a section with the right contructor
-          name */
-       section = bfd_get_section_by_name (abfd, copy);
-       if (!section)
-         section = bfd_make_section (abfd, copy);
+       reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain));
+       if (reloc == NULL)
+         return false;
 
-       /* Build a relocation entry for the constructor */
-       switch ((cache_ptr->type & N_TYPE))
+       /* Build a relocation entry for the constructor */
+       switch (cache_ptr->type & N_TYPE)
          {
-         case N_SETA: case N_SETA | N_EXT:
-           into_section = &bfd_abs_section;
+         case N_SETA:
+           into_section = bfd_abs_section_ptr;
            cache_ptr->type = N_ABS;
            break;
-         case N_SETT: case N_SETT | N_EXT:
-           into_section = (asection *) obj_textsec (abfd);
+         case N_SETT:
+           into_section = obj_textsec (abfd);
            cache_ptr->type = N_TEXT;
            break;
-         case N_SETD: case N_SETD | N_EXT:
-           into_section = (asection *) obj_datasec (abfd);
+         case N_SETD:
+           into_section = obj_datasec (abfd);
            cache_ptr->type = N_DATA;
            break;
-         case N_SETB: case N_SETB | N_EXT:
-           into_section = (asection *) obj_bsssec (abfd);
+         case N_SETB:
+           into_section = obj_bsssec (abfd);
            cache_ptr->type = N_BSS;
            break;
-         default:
-           abort ();
          }
 
-       /* Build a relocation pointing into the constuctor section
-          pointing at the symbol in the set vector specified */
-
+       /* Build a relocation pointing into the constructor section
+          pointing at the symbol in the set vector specified.  */
        reloc->relent.addend = cache_ptr->symbol.value;
-       cache_ptr->symbol.section = into_section->symbol->section;
+       cache_ptr->symbol.section = into_section;
        reloc->relent.sym_ptr_ptr = into_section->symbol_ptr_ptr;
 
-
-       /* 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;
-
+       /* We modify the symbol to belong to a section depending upon
+          the name of the symbol, 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 | SEC_RELOC;
 
        section->reloc_count++;
        section->alignment_power = 2;
@@ -1156,219 +1526,180 @@ DEFUN (translate_from_native_sym_flags, (sym_pointer, cache_ptr, abfd),
        reloc->next = section->constructor_chain;
        section->constructor_chain = reloc;
        reloc->relent.address = section->_raw_size;
-       section->_raw_size += sizeof (int *);
+       section->_raw_size += BYTES_IN_WORD;
+
+       reloc->relent.howto = CTOR_TABLE_RELOC_HOWTO(abfd);
+
+#endif /* 0 */
+
+       switch (cache_ptr->type & N_TYPE)
+         {
+         case N_SETA:
+           cache_ptr->symbol.section = bfd_abs_section_ptr;
+           break;
+         case N_SETT:
+           cache_ptr->symbol.section = obj_textsec (abfd);
+           break;
+         case N_SETD:
+           cache_ptr->symbol.section = obj_datasec (abfd);
+           break;
+         case N_SETB:
+           cache_ptr->symbol.section = obj_bsssec (abfd);
+           break;
+         }
 
-       reloc->relent.howto
-         = (obj_reloc_entry_size(abfd) == RELOC_EXT_SIZE
-            ? howto_table_ext : howto_table_std)
-           + CTOR_TABLE_RELOC_IDX;
        cache_ptr->symbol.flags |= BSF_CONSTRUCTOR;
       }
       break;
-    default:
-      if (cache_ptr->type == N_WARNING)
-       {
-         /* This symbol is the text of a warning message, the next symbol
-            is the symbol to associate the warning with */
-         cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING;
-
-         /* @@ Stuffing pointers into integers is a no-no.
-            We can usually get away with it if the integer is
-            large enough though.  */
-         if (sizeof (cache_ptr + 1) > sizeof (bfd_vma))
-           abort ();
-         cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1));
-
-          /* We don't use a warning symbol's section, but we need
-            it to be nonzero for the sanity check below, so
-            pick one arbitrarily.  */
-         cache_ptr->symbol.section = &bfd_abs_section;
-
-         /* We furgle with the next symbol in place.
-            We don't want it to be undefined, we'll trample the type */
-         (sym_pointer + 1)->e_type[0] = 0xff;
-         break;
-       }
-      if ((cache_ptr->type | N_EXT) == (N_INDR | N_EXT))
-       {
-         /* Two symbols in a row for an INDR message. The first symbol
-            contains the name we will match, the second symbol contains
-            the name the first name is translated into. It is supplied to
-            us undefined. This is good, since we want to pull in any files
-            which define it */
-         cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT;
-
-         /* @@ Stuffing pointers into integers is a no-no.
-            We can usually get away with it if the integer is
-            large enough though.  */
-         if (sizeof (cache_ptr + 1) > sizeof (bfd_vma))
-           abort ();
-
-         cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1));
-         cache_ptr->symbol.section = &bfd_ind_section;
-       }
 
-      else if (sym_is_debugger_info (cache_ptr))
-       {
-         cache_ptr->symbol.flags = BSF_DEBUGGING;
-         /* Work out the section correct for this symbol */
-         switch (cache_ptr->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;
-           default:
-           case N_ABS:
-             cache_ptr->symbol.section = &bfd_abs_section;
-             break;
-           }
-       }
-      else
-       {
+    case N_WARNING:
+      /* This symbol is the text of a warning message.  The next
+        symbol is the symbol to associate the warning with.  If a
+        reference is made to that symbol, a warning is issued.  */
+      cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING;
+      cache_ptr->symbol.section = bfd_abs_section_ptr;
+      break;
 
-         if (sym_is_fortrancommon (cache_ptr))
-           {
-             cache_ptr->symbol.flags = 0;
-             cache_ptr->symbol.section = &bfd_com_section;
-           }
-         else
-           {
+    case N_INDR: case N_INDR | N_EXT:
+      /* An indirect symbol.  This consists of two symbols in a row.
+        The first symbol is the name of the indirection.  The second
+        symbol is the name of the target.  A reference to the first
+        symbol becomes a reference to the second.  */
+      cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT | visible;
+      cache_ptr->symbol.section = bfd_ind_section_ptr;
+      break;
 
+    case N_WEAKU:
+      cache_ptr->symbol.section = bfd_und_section_ptr;
+      cache_ptr->symbol.flags = BSF_WEAK;
+      break;
 
-           }
+    case N_WEAKA:
+      cache_ptr->symbol.section = bfd_abs_section_ptr;
+      cache_ptr->symbol.flags = BSF_WEAK;
+      break;
 
-         /* 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.
-          */
+    case N_WEAKT:
+      cache_ptr->symbol.section = obj_textsec (abfd);
+      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+      cache_ptr->symbol.flags = BSF_WEAK;
+      break;
 
-         if (sym_in_text_section (cache_ptr))
-           {
-             cache_ptr->symbol.value -= obj_textsec (abfd)->vma;
-             cache_ptr->symbol.section = obj_textsec (abfd);
-           }
-         else if (sym_in_data_section (cache_ptr))
-           {
-             cache_ptr->symbol.value -= obj_datasec (abfd)->vma;
-             cache_ptr->symbol.section = obj_datasec (abfd);
-           }
-         else if (sym_in_bss_section (cache_ptr))
-           {
-             cache_ptr->symbol.section = obj_bsssec (abfd);
-             cache_ptr->symbol.value -= obj_bsssec (abfd)->vma;
-           }
-         else if (sym_is_undefined (cache_ptr))
-           {
-             cache_ptr->symbol.flags = 0;
-             cache_ptr->symbol.section = &bfd_und_section;
-           }
-         else if (sym_is_absolute (cache_ptr))
-           {
-             cache_ptr->symbol.section = &bfd_abs_section;
-           }
+    case N_WEAKD:
+      cache_ptr->symbol.section = obj_datasec (abfd);
+      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+      cache_ptr->symbol.flags = BSF_WEAK;
+      break;
 
-         if (sym_is_global_defn (cache_ptr))
-           {
-             cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT;
-           }
-         else if (! sym_is_undefined (cache_ptr))
-           {
-             cache_ptr->symbol.flags = BSF_LOCAL;
-           }
-       }
+    case N_WEAKB:
+      cache_ptr->symbol.section = obj_bsssec (abfd);
+      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
+      cache_ptr->symbol.flags = BSF_WEAK;
+      break;
     }
-  if (cache_ptr->symbol.section == 0)
-    abort ();
-}
 
+  return true;
+}
 
+/* Set the fields of SYM_POINTER according to CACHE_PTR.  */
 
 static boolean
-DEFUN(translate_to_native_sym_flags,(sym_pointer, cache_ptr, abfd),
-     struct external_nlist *sym_pointer AND
-     asymbol *cache_ptr AND
-     bfd *abfd)
+translate_to_native_sym_flags (abfd, cache_ptr, sym_pointer)
+     bfd *abfd;
+     asymbol *cache_ptr;
+     struct external_nlist *sym_pointer;
 {
   bfd_vma value = cache_ptr->value;
+  asection *sec;
+  bfd_vma off;
 
-  /* mask out any existing type bits in case copying from one section
-     to another */
+  /* Mask out any existing type bits in case copying from one section
+     to another */
   sym_pointer->e_type[0] &= ~N_TYPE;
 
-  /* We attempt to order these tests by decreasing frequency of success,
-     according to tcov when linking the linker.  */
-  if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) {
-    sym_pointer->e_type[0] |= N_ABS;
-  }
-  else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) {
+  sec = bfd_get_section (cache_ptr);
+  off = 0;
+
+  if (sec == NULL)
+    {
+      /* This case occurs, e.g., for the *DEBUG* section of a COFF
+        file.  */
+      (*_bfd_error_handler)
+       (_("%s: can not represent section for symbol `%s' in a.out object file format"),
+        bfd_get_filename (abfd), 
+        cache_ptr->name != NULL ? cache_ptr->name : _("*unknown*"));
+      bfd_set_error (bfd_error_nonrepresentable_section);
+      return false;
+    }
+
+  if (sec->output_section != NULL)
+    {
+      off = sec->output_offset;
+      sec = sec->output_section;
+    }
+
+  if (bfd_is_abs_section (sec))
+    sym_pointer->e_type[0] |= N_ABS;
+  else if (sec == obj_textsec (abfd))
     sym_pointer->e_type[0] |= N_TEXT;
-  }
-  else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) {
+  else if (sec == obj_datasec (abfd))
     sym_pointer->e_type[0] |= N_DATA;
-  }
-  else if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) {
+  else if (sec == obj_bsssec (abfd))
     sym_pointer->e_type[0] |= N_BSS;
-  }
-  else if (bfd_get_output_section(cache_ptr) == &bfd_und_section) {
-    sym_pointer->e_type[0] = (N_UNDF | N_EXT);
-  }
-  else if (bfd_get_output_section(cache_ptr) == &bfd_ind_section) {
+  else if (bfd_is_und_section (sec))
+    sym_pointer->e_type[0] = N_UNDF | N_EXT;
+  else if (bfd_is_ind_section (sec))
     sym_pointer->e_type[0] = N_INDR;
-  }
-  else if (bfd_get_output_section(cache_ptr) == NULL) {
-    /* Protect the bfd_is_com_section call.
-       This case occurs, e.g., for the *DEBUG* section of a COFF file.  */
-    bfd_error = bfd_error_nonrepresentable_section;
-    return false;
-  }
-  else if (bfd_is_com_section (bfd_get_output_section (cache_ptr))) {
-    sym_pointer->e_type[0] = (N_UNDF | N_EXT);
-  }
-  else {
-    bfd_error = bfd_error_nonrepresentable_section;
-    return false;
-  }
+  else if (bfd_is_com_section (sec))
+    sym_pointer->e_type[0] = N_UNDF | N_EXT;
+  else
+    {
+      (*_bfd_error_handler)
+       (_("%s: can not represent section `%s' in a.out object file format"),
+        bfd_get_filename (abfd), bfd_get_section_name (abfd, sec));
+      bfd_set_error (bfd_error_nonrepresentable_section);
+      return false;
+    }
 
   /* Turn the symbol from section relative to absolute again */
+  value += sec->vma + off;
 
-  value +=  cache_ptr->section->output_section->vma  + cache_ptr->section->output_offset ;
-
-
-  if (cache_ptr->flags & (BSF_WARNING)) {
+  if ((cache_ptr->flags & BSF_WARNING) != 0)
     sym_pointer->e_type[0] = N_WARNING;
-    (sym_pointer+1)->e_type[0] = 1;
-  }
 
-  if (cache_ptr->flags & BSF_DEBUGGING) {
-    sym_pointer->e_type[0] = ((aout_symbol_type *)cache_ptr)->type;
-  }
-  else if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) {
+  if ((cache_ptr->flags & BSF_DEBUGGING) != 0)
+    sym_pointer->e_type[0] = ((aout_symbol_type *) cache_ptr)->type;
+  else if ((cache_ptr->flags & BSF_GLOBAL) != 0)
     sym_pointer->e_type[0] |= N_EXT;
-  }
-  if (cache_ptr->flags & BSF_CONSTRUCTOR) {
-    int type = ((aout_symbol_type *)cache_ptr)->type;
-    switch (type)
-      {
-      case N_ABS:      type = N_SETA; break;
-      case N_TEXT:     type = N_SETT; break;
-      case N_DATA:     type = N_SETD; break;
-      case N_BSS:      type = N_SETB; break;
-      }
-    sym_pointer->e_type[0] = type;
-  }
+
+  if ((cache_ptr->flags & BSF_CONSTRUCTOR) != 0)
+    {
+      int type = ((aout_symbol_type *) cache_ptr)->type;
+      switch (type)
+       {
+       case N_ABS:     type = N_SETA; break;
+       case N_TEXT:    type = N_SETT; break;
+       case N_DATA:    type = N_SETD; break;
+       case N_BSS:     type = N_SETB; break;
+       }
+      sym_pointer->e_type[0] = type;
+    }
+
+  if ((cache_ptr->flags & BSF_WEAK) != 0)
+    {
+      int type;
+
+      switch (sym_pointer->e_type[0] & N_TYPE)
+       {
+       default:
+       case N_ABS:     type = N_WEAKA; break;
+       case N_TEXT:    type = N_WEAKT; break;
+       case N_DATA:    type = N_WEAKD; break;
+       case N_BSS:     type = N_WEAKB; break;
+       case N_UNDF:    type = N_WEAKU; break;
+       }
+      sym_pointer->e_type[0] = type;
+    }
 
   PUT_WORD(abfd, value, sym_pointer->e_value);
 
@@ -1377,13 +1708,14 @@ DEFUN(translate_to_native_sym_flags,(sym_pointer, cache_ptr, abfd),
 \f
 /* Native-level interface to symbols. */
 
-
 asymbol *
-DEFUN(NAME(aout,make_empty_symbol),(abfd),
-      bfd *abfd)
+NAME(aout,make_empty_symbol) (abfd)
+     bfd *abfd;
 {
   aout_symbol_type  *new =
     (aout_symbol_type *)bfd_zalloc (abfd, sizeof (aout_symbol_type));
+  if (!new)
+    return NULL;
   new->symbol.the_bfd = abfd;
 
   return &new->symbol;
@@ -1391,8 +1723,8 @@ DEFUN(NAME(aout,make_empty_symbol),(abfd),
 
 /* Translate a set of internal symbols into external symbols.  */
 
-static boolean
-translate_symbol_table (abfd, in, ext, count, str, strsize, dynamic)
+boolean
+NAME(aout,translate_symbol_table) (abfd, in, ext, count, str, strsize, dynamic)
      bfd *abfd;
      aout_symbol_type *in;
      struct external_nlist *ext;
@@ -1410,7 +1742,15 @@ translate_symbol_table (abfd, in, ext, count, str, strsize, dynamic)
 
       x = GET_WORD (abfd, ext->e_strx);
       in->symbol.the_bfd = abfd;
-      if (x < strsize)
+
+      /* For the normal symbols, the zero index points at the number
+        of bytes in the string table but is to be interpreted as the
+        null string.  For the dynamic symbols, the number of bytes in
+        the string table is stored in the __DYNAMIC structure and the
+        zero index points at an actual string.  */
+      if (x == 0 && ! dynamic)
+       in->symbol.name = "";
+      else if (x < strsize)
        in->symbol.name = str + x;
       else
        return false;
@@ -1419,9 +1759,10 @@ translate_symbol_table (abfd, in, ext, count, str, strsize, dynamic)
       in->desc = bfd_h_get_16 (abfd, ext->e_desc);
       in->other = bfd_h_get_8 (abfd, ext->e_other);
       in->type = bfd_h_get_8 (abfd,  ext->e_type);
-      in->symbol.udata = 0;
+      in->symbol.udata.p = NULL;
 
-      translate_from_native_sym_flags (ext, in, abfd);
+      if (! translate_from_native_sym_flags (abfd, in))
+       return false;
 
       if (dynamic)
        in->symbol.flags |= BSF_DYNAMIC;
@@ -1435,500 +1776,153 @@ translate_symbol_table (abfd, in, ext, count, str, strsize, dynamic)
    hold them all plus all the cached symbol entries. */
 
 boolean
-DEFUN(NAME(aout,slurp_symbol_table),(abfd),
-      bfd *abfd)
+NAME(aout,slurp_symbol_table) (abfd)
+     bfd *abfd;
 {
-  bfd_size_type symbol_size;
-  bfd_size_type string_size;
-  unsigned char string_chars[BYTES_IN_WORD];
-  struct external_nlist *syms;
-  char *strings;
+  struct external_nlist *old_external_syms;
   aout_symbol_type *cached;
-  bfd_size_type dynsym_count = 0;
-  struct external_nlist *dynsyms = NULL;
-  char *dynstrs = NULL;
-  bfd_size_type dynstr_size;
+  size_t cached_size;
 
   /* 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_chars, BYTES_IN_WORD, 1, abfd) != BYTES_IN_WORD)
-    return false;
-  string_size = GET_WORD (abfd, string_chars);
+  if (obj_aout_symbols (abfd) != (aout_symbol_type *) NULL)
+    return true;
 
-  /* If this is a dynamic object, see if we can get the dynamic symbol
-     table.  */
-  if ((bfd_get_file_flags (abfd) & DYNAMIC) != 0
-      && aout_backend_info (abfd)->read_dynamic_symbols)
-    {
-      dynsym_count = ((*aout_backend_info (abfd)->read_dynamic_symbols)
-                     (abfd, &dynsyms, &dynstrs, &dynstr_size));
-      if (dynsym_count == (bfd_size_type) -1)
-       return false;
-    }
+  old_external_syms = obj_aout_external_syms (abfd);
 
-  strings = (char *) bfd_alloc (abfd, string_size + 1);
-  cached = ((aout_symbol_type *)
-           bfd_zalloc (abfd,
-                       ((bfd_get_symcount (abfd) + dynsym_count)
-                        * sizeof (aout_symbol_type))));
+  if (! aout_get_external_symbols (abfd))
+    return false;
 
-  /* Don't allocate on the obstack, so we can free it easily.  */
-  syms = (struct external_nlist *) bfd_xmalloc(symbol_size);
-  bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET);
-  if (bfd_read ((PTR)syms, 1, symbol_size, abfd) != symbol_size)
+  cached_size = (obj_aout_external_sym_count (abfd)
+                * sizeof (aout_symbol_type));
+  cached = (aout_symbol_type *) bfd_malloc (cached_size);
+  if (cached == NULL && cached_size != 0)
+    return false;
+  if (cached_size != 0)
+    memset (cached, 0, cached_size);
+
+  /* Convert from external symbol information to internal.  */
+  if (! (NAME(aout,translate_symbol_table)
+        (abfd, cached,
+         obj_aout_external_syms (abfd),
+         obj_aout_external_sym_count (abfd),
+         obj_aout_external_strings (abfd),
+         obj_aout_external_string_size (abfd),
+         false)))
     {
-    bailout:
-      if (syms)
-       free (syms);
-      if (cached)
-       bfd_release (abfd, cached);
-      if (strings)
-       bfd_release (abfd, strings);
+      free (cached);
       return false;
     }
 
-  bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
-  if (bfd_read ((PTR)strings, 1, string_size, abfd) != string_size)
-    {
-      goto bailout;
-    }
-  strings[string_size] = 0; /* Just in case. */
+  bfd_get_symcount (abfd) = obj_aout_external_sym_count (abfd);
 
-  /* OK, now walk the new symtable, cacheing symbol properties */
-  if (! translate_symbol_table (abfd, cached, syms, bfd_get_symcount (abfd),
-                               strings, string_size, false))
-    goto bailout;
-  if (dynsym_count > 0)
-    {
-      if (! translate_symbol_table (abfd, cached + bfd_get_symcount (abfd),
-                                   dynsyms, dynsym_count, dynstrs,
-                                   dynstr_size, true))
-       goto bailout;
+  obj_aout_symbols (abfd) = cached;
 
-      bfd_get_symcount (abfd) += dynsym_count;
+  /* It is very likely that anybody who calls this function will not
+     want the external symbol information, so if it was allocated
+     because of our call to aout_get_external_symbols, we free it up
+     right away to save space.  */
+  if (old_external_syms == (struct external_nlist *) NULL
+      && obj_aout_external_syms (abfd) != (struct external_nlist *) NULL)
+    {
+#ifdef USE_MMAP
+      bfd_free_window (&obj_aout_sym_window (abfd));
+#else
+      free (obj_aout_external_syms (abfd));
+#endif
+      obj_aout_external_syms (abfd) = NULL;
     }
 
-  obj_aout_symbols (abfd) =  cached;
-  free((PTR)syms);
-
   return true;
 }
-
 \f
-/* Possible improvements:
-   + look for strings matching trailing substrings of other strings
-   + better data structures?  balanced trees?
-   + smaller per-string or per-symbol data?  re-use some of the symbol's
-     data fields?
-   + also look at reducing memory use elsewhere -- maybe if we didn't have to
-     construct the entire symbol table at once, we could get by with smaller
-     amounts of VM?  (What effect does that have on the string table
-     reductions?)
-   + rip this out of here, put it into its own file in bfd or libiberty, so
-     coff and elf can use it too.  I'll work on this soon, but have more
-     pressing tasks right now.
-
-   A hash table might(?) be more efficient for handling exactly the cases that
-   are handled now, but for trailing substring matches, I think we want to
-   examine the `nearest' values (reverse-)lexically, not merely impose a strict
-   order, nor look only for exact-match or not-match.  I don't think a hash
-   table would be very useful for that, and I don't feel like fleshing out two
-   completely different implementations.  [raeburn:930419.0331EDT] */
-
-struct stringtab_entry {
-  /* Hash value for this string.  Only useful so long as we aren't doing
-     substring matches.  */
-  unsigned int hash;
-
-  /* Next node to look at, depending on whether the hash value of the string
-     being searched for is less than or greater than the hash value of the
-     current node.  For now, `equal to' is lumped in with `greater than', for
-     space efficiency.  It's not a common enough case to warrant another field
-     to be used for all nodes.  */
-  struct stringtab_entry *less;
-  struct stringtab_entry *greater;
-
-  /* The string itself.  */
-  CONST char *string;
-
-  /* The index allocated for this string.  */
-  bfd_size_type index;
-
-#ifdef GATHER_STATISTICS
-  /* How many references have there been to this string?  (Not currently used;
-     could be dumped out for anaylsis, if anyone's interested.)  */
-  unsigned long count;
-#endif
-
-  /* Next node in linked list, in suggested output order.  */
-  struct stringtab_entry *next_to_output;
-};
-
-struct stringtab_data {
-  /* Tree of string table entries.  */
-  struct stringtab_entry *strings;
-
-  /* Fudge factor used to center top node of tree.  */
-  int hash_zero;
-
-  /* Next index value to issue.  */
-  bfd_size_type index;
-
-  /* Index used for empty strings.  Cached here because checking for them
-     is really easy, and we can avoid searching the tree.  */
-  bfd_size_type empty_string_index;
-
-  /* These fields indicate the two ends of a singly-linked list that indicates
-     the order strings should be written out in.  Use this order, and no
-     seeking will need to be done, so output efficiency should be maximized. */
-  struct stringtab_entry **end;
-  struct stringtab_entry *output_order;
-
-#ifdef GATHER_STATISTICS
-  /* Number of strings which duplicate strings already in the table.  */
-  unsigned long duplicates;
-
-  /* Number of bytes saved by not having to write all the duplicate strings. */
-  unsigned long bytes_saved;
-
-  /* Number of zero-length strings.  Currently, these all turn into
-     references to the null byte at the end of the first string.  In some
-     cases (possibly not all?  explore this...), it should be possible to
-     simply write out a zero index value.  */
-  unsigned long empty_strings;
-
-  /* Number of times the hash values matched but the strings were different.
-     Note that this includes the number of times the other string(s) occurs, so
-     there may only be two strings hashing to the same value, even if this
-     number is very large.  */
-  unsigned long bad_hash_matches;
-
-  /* Null strings aren't counted in this one.
-     This will probably only be nonzero if we've got an input file
-     which was produced by `ld -r' (i.e., it's already been processed
-     through this code).  Under some operating systems, native tools
-     may make all empty strings have the same index; but the pointer
-     check won't catch those, because to get to that stage we'd already
-     have to compute the checksum, which requires reading the string,
-     so we short-circuit that case with empty_string_index above.  */
-  unsigned long pointer_matches;
-
-  /* Number of comparisons done.  I figure with the algorithms in use below,
-     the average number of comparisons done (per symbol) should be roughly
-     log-base-2 of the number of unique strings.  */
-  unsigned long n_compares;
-#endif
-};
+/* We use a hash table when writing out symbols so that we only write
+   out a particular string once.  This helps particularly when the
+   linker writes out stabs debugging entries, because each different
+   contributing object file tends to have many duplicate stabs
+   strings.
 
-/* Some utility functions for the string table code.  */
+   This hash table code breaks dbx on SunOS 4.1.3, so we don't do it
+   if BFD_TRADITIONAL_FORMAT is set.  */
 
-/* For speed, only hash on the first this many bytes of strings.
-   This number was chosen by profiling ld linking itself, with -g.  */
-#define HASHMAXLEN 25
-
-#define HASH_CHAR(c) (sum ^= sum >> 20, sum ^= sum << 7, sum += (c))
-
-static INLINE unsigned int
-hash (string, len)
-     unsigned char *string;
-     register unsigned int len;
-{
-  register unsigned int sum = 0;
-
-  if (len > HASHMAXLEN)
-    {
-      HASH_CHAR (len);
-      len = HASHMAXLEN;
-    }
-
-  while (len--)
-    {
-      HASH_CHAR (*string++);
-    }
-  return sum;
-}
-
-static INLINE void
-stringtab_init (tab)
-     struct stringtab_data *tab;
-{
-  tab->strings = 0;
-  tab->output_order = 0;
-  tab->hash_zero = 0;
-  tab->end = &tab->output_order;
-
-  /* Initial string table length includes size of length field.  */
-  tab->index = BYTES_IN_WORD;
-  tab->empty_string_index = -1;
-#ifdef GATHER_STATISTICS
-  tab->duplicates = 0;
-  tab->empty_strings = 0;
-  tab->bad_hash_matches = 0;
-  tab->pointer_matches = 0;
-  tab->bytes_saved = 0;
-  tab->n_compares = 0;
-#endif
-}
-
-static INLINE int
-compare (entry, str, hash)
-     struct stringtab_entry *entry;
-     CONST char *str;
-     unsigned int hash;
-{
-  return hash - entry->hash;
-}
+static bfd_size_type add_to_stringtab
+  PARAMS ((bfd *, struct bfd_strtab_hash *, const char *, boolean));
+static boolean emit_stringtab PARAMS ((bfd *, struct bfd_strtab_hash *));
 
-#ifdef GATHER_STATISTICS
-/* Don't want to have to link in math library with all bfd applications...  */
-static INLINE double
-log2 (num)
-     int num;
-{
-  double d = num;
-  int n = 0;
-  while (d >= 2.0)
-    n++, d /= 2.0;
-  return ((d > 1.41) ? 0.5 : 0) + n;
-}
-#endif
+/* Get the index of a string in a strtab, adding it if it is not
+   already present.  */
 
-/* Main string table routines.  */
-/* Returns index in string table.  Whether or not this actually adds an
-   entry into the string table should be irrelevant -- it just has to
-   return a valid index.  */
-static bfd_size_type
-add_to_stringtab (abfd, str, tab)
+static INLINE bfd_size_type
+add_to_stringtab (abfd, tab, str, copy)
      bfd *abfd;
-     CONST char *str;
-     struct stringtab_data *tab;
+     struct bfd_strtab_hash *tab;
+     const char *str;
+     boolean copy;
 {
-  struct stringtab_entry **ep;
-  register struct stringtab_entry *entry;
-  unsigned int hashval, len;
+  boolean hash;
+  bfd_size_type index;
 
-  if (str[0] == 0)
-    {
-      bfd_size_type index;
-      CONST bfd_size_type minus_one = -1;
+  /* An index of 0 always means the empty string.  */
+  if (str == 0 || *str == '\0')
+    return 0;
 
-#ifdef GATHER_STATISTICS
-      tab->empty_strings++;
-#endif
-      index = tab->empty_string_index;
-      if (index != minus_one)
-       {
-       got_empty:
-#ifdef GATHER_STATISTICS
-         tab->bytes_saved++;
-         tab->duplicates++;
-#endif
-         return index;
-       }
+  /* Don't hash if BFD_TRADITIONAL_FORMAT is set, because SunOS dbx
+     doesn't understand a hashed string table.  */
+  hash = true;
+  if ((abfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
+    hash = false;
 
-      /* Need to find it.  */
-      entry = tab->strings;
-      if (entry)
-       {
-         index = entry->index + strlen (entry->string);
-         tab->empty_string_index = index;
-         goto got_empty;
-       }
-      len = 0;
-    }
-  else
-    len = strlen (str);
-
-  /* The hash_zero value is chosen such that the first symbol gets a value of
-     zero.  With a balanced tree, this wouldn't be very useful, but without it,
-     we might get a more even split at the top level, instead of skewing it
-     badly should hash("/usr/lib/crt0.o") (or whatever) be far from zero. */
-  hashval = hash (str, len) ^ tab->hash_zero;
-  ep = &tab->strings;
-  if (!*ep)
-    {
-      tab->hash_zero = hashval;
-      hashval = 0;
-      goto add_it;
-    }
+  index = _bfd_stringtab_add (tab, str, hash, copy);
 
-  while (*ep)
+  if (index != (bfd_size_type) -1)
     {
-      register int cmp;
-
-      entry = *ep;
-#ifdef GATHER_STATISTICS
-      tab->n_compares++;
-#endif
-      cmp = compare (entry, str, hashval);
-      /* The not-equal cases are more frequent, so check them first.  */
-      if (cmp > 0)
-       ep = &entry->greater;
-      else if (cmp < 0)
-       ep = &entry->less;
-      else
-       {
-         if (entry->string == str)
-           {
-#ifdef GATHER_STATISTICS
-             tab->pointer_matches++;
-#endif
-             goto match;
-           }
-         /* Compare the first bytes to save a function call if they
-            don't match.  */
-         if (entry->string[0] == str[0] && !strcmp (entry->string, str))
-           {
-           match:
-#ifdef GATHER_STATISTICS
-             entry->count++;
-             tab->bytes_saved += len + 1;
-             tab->duplicates++;
-#endif
-             /* If we're in the linker, and the new string is from a new
-                input file which might have already had these reductions
-                run over it, we want to keep the new string pointer.  I
-                don't think we're likely to see any (or nearly as many,
-                at least) cases where a later string is in the same location
-                as an earlier one rather than this one.  */
-             entry->string = str;
-             return entry->index;
-           }
-#ifdef GATHER_STATISTICS
-         tab->bad_hash_matches++;
-#endif
-         ep = &entry->greater;
-       }
+      /* Add BYTES_IN_WORD to the return value to account for the
+        space taken up by the string table size.  */
+      index += BYTES_IN_WORD;
     }
 
-  /* If we get here, nothing that's in the table already matched.
-     EP points to the `next' field at the end of the chain; stick a
-     new entry on here.  */
- add_it:
-  entry = (struct stringtab_entry *)
-    bfd_alloc_by_size_t (abfd, sizeof (struct stringtab_entry));
-
-  entry->less = entry->greater = 0;
-  entry->hash = hashval;
-  entry->index = tab->index;
-  entry->string = str;
-  entry->next_to_output = 0;
-#ifdef GATHER_STATISTICS
-  entry->count = 1;
-#endif
-
-  assert (*tab->end == 0);
-  *(tab->end) = entry;
-  tab->end = &entry->next_to_output;
-  assert (*tab->end == 0);
-
-  {
-    tab->index += len + 1;
-    if (len == 0)
-      tab->empty_string_index = entry->index;
-  }
-  assert (*ep == 0);
-  *ep = entry;
-  return entry->index;
+  return index;
 }
 
-static void
-emit_strtab (abfd, tab)
-     bfd *abfd;
-     struct stringtab_data *tab;
-{
-  struct stringtab_entry *entry;
-#ifdef GATHER_STATISTICS
-  int count = 0;
-#endif
-
-  /* Be sure to put string length into correct byte ordering before writing
-     it out.  */
-  char buffer[BYTES_IN_WORD];
-
-  PUT_WORD (abfd, tab->index, (unsigned char *) buffer);
-  bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd);
-
-  for (entry = tab->output_order; entry; entry = entry->next_to_output)
-    {
-      bfd_write ((PTR) entry->string, 1, strlen (entry->string) + 1, abfd);
-#ifdef GATHER_STATISTICS
-      count++;
-#endif
-    }
+/* Write out a strtab.  ABFD is already at the right location in the
+   file.  */
 
-#ifdef GATHER_STATISTICS
-  /* Short form only, for now.
-     To do:  Specify output file.  Conditionalize on environment?  Detailed
-     analysis if desired.  */
-  {
-    int n_syms = bfd_get_symcount (abfd);
-
-    fprintf (stderr, "String table data for output file:\n");
-    fprintf (stderr, "  %8d symbols output\n", n_syms);
-    fprintf (stderr, "  %8d duplicate strings\n", tab->duplicates);
-    fprintf (stderr, "  %8d empty strings\n", tab->empty_strings);
-    fprintf (stderr, "  %8d unique strings output\n", count);
-    fprintf (stderr, "  %8d pointer matches\n", tab->pointer_matches);
-    fprintf (stderr, "  %8d bytes saved\n", tab->bytes_saved);
-    fprintf (stderr, "  %8d bad hash matches\n", tab->bad_hash_matches);
-    fprintf (stderr, "  %8d hash-val comparisons\n", tab->n_compares);
-    if (n_syms)
-      {
-       double n_compares = tab->n_compares;
-       double avg_compares = n_compares / n_syms;
-       /* The second value here should usually be near one.  */
-       fprintf (stderr,
-                "\t    average %f comparisons per symbol (%f * log2 nstrings)\n",
-                avg_compares, avg_compares / log2 (count));
-      }
-  }
-#endif
+static boolean
+emit_stringtab (abfd, tab)
+     register bfd *abfd;
+     struct bfd_strtab_hash *tab;
+{
+  bfd_byte buffer[BYTES_IN_WORD];
 
-/* Old code:
-  unsigned int count;
-  generic = bfd_get_outsymbols(abfd);
-  for (count = 0; count < bfd_get_symcount(abfd); count++)
-    {
-      asymbol *g = *(generic++);
+  /* The string table starts with the size.  */
+  PUT_WORD (abfd, _bfd_stringtab_size (tab) + BYTES_IN_WORD, buffer);
+  if (bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd) != BYTES_IN_WORD)
+    return false;
 
-      if (g->name)
-       {
-         size_t length = strlen(g->name)+1;
-         bfd_write((PTR)g->name, 1, length, abfd);
-       }
-      g->KEEPIT = (KEEPITTYPE) count;
-    } */
+  return _bfd_stringtab_emit (abfd, tab);
 }
-
+\f
 boolean
-DEFUN(NAME(aout,write_syms),(abfd),
-      bfd *abfd)
+NAME(aout,write_syms) (abfd)
+     bfd *abfd;
 {
   unsigned int count ;
   asymbol **generic = bfd_get_outsymbols (abfd);
-  struct stringtab_data strtab;
+  struct bfd_strtab_hash *strtab;
 
-  stringtab_init (&strtab);
+  strtab = _bfd_stringtab_init ();
+  if (strtab == NULL)
+    return false;
 
   for (count = 0; count < bfd_get_symcount (abfd); count++)
     {
       asymbol *g = generic[count];
+      bfd_size_type indx;
       struct external_nlist nsp;
 
-      if (g->name)
-       PUT_WORD (abfd, add_to_stringtab (abfd, g->name, &strtab),
-                 (unsigned char *) nsp.e_strx);
-      else
-       PUT_WORD (abfd, 0, (unsigned char *)nsp.e_strx);
+      indx = add_to_stringtab (abfd, strtab, g->name, false);
+      if (indx == (bfd_size_type) -1)
+       goto error_return;
+      PUT_WORD (abfd, indx, (bfd_byte *) nsp.e_strx);
 
       if (bfd_asymbol_flavour(g) == abfd->xvec->flavour)
        {
@@ -1943,33 +1937,41 @@ DEFUN(NAME(aout,write_syms),(abfd),
          bfd_h_put_8(abfd, 0, nsp.e_type);
        }
 
-      if (! translate_to_native_sym_flags (&nsp, g, abfd))
-       return false;
+      if (! translate_to_native_sym_flags (abfd, g, &nsp))
+       goto error_return;
 
       if (bfd_write((PTR)&nsp,1,EXTERNAL_NLIST_SIZE, abfd)
          != EXTERNAL_NLIST_SIZE)
-       return false;
+       goto error_return;
 
-      /* NB: `KEEPIT' currently overlays `flags', so set this only
+      /* NB: `KEEPIT' currently overlays `udata.p', so set this only
         here, at the end.  */
       g->KEEPIT = count;
     }
 
-  emit_strtab (abfd, &strtab);
+  if (! emit_stringtab (abfd, strtab))
+    goto error_return;
+
+  _bfd_stringtab_free (strtab);
 
   return true;
+
+error_return:
+  _bfd_stringtab_free (strtab);
+  return false;
 }
 
 \f
-unsigned int
-DEFUN(NAME(aout,get_symtab),(abfd, location),
-      bfd *abfd AND
-      asymbol **location)
+long
+NAME(aout,get_symtab) (abfd, location)
+     bfd *abfd;
+     asymbol **location;
 {
     unsigned int counter = 0;
     aout_symbol_type *symbase;
 
-    if (!NAME(aout,slurp_symbol_table)(abfd)) return 0;
+    if (!NAME(aout,slurp_symbol_table)(abfd))
+      return -1;
 
     for (symbase = obj_aout_symbols(abfd); counter++ < bfd_get_symcount (abfd);)
       *(location++) = (asymbol *)( symbase++);
@@ -1981,11 +1983,14 @@ DEFUN(NAME(aout,get_symtab),(abfd, location),
 /* Standard reloc stuff */
 /* Output standard relocation information to a file in target byte order. */
 
+extern void  NAME(aout,swap_std_reloc_out)
+  PARAMS ((bfd *, arelent *, struct reloc_std_external *));
+
 void
-DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
-      bfd *abfd AND
-      arelent *g AND
-      struct reloc_std_external *natptr)
+NAME(aout,swap_std_reloc_out) (abfd, g, natptr)
+     bfd *abfd;
+     arelent *g;
+     struct reloc_std_external *natptr;
 {
   int r_index;
   asymbol *sym = *(g->sym_ptr_ptr);
@@ -2001,9 +2006,8 @@ DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
   r_pcrel  = (int) g->howto->pc_relative; /* Relative to PC? */
   /* XXX This relies on relocs coming from a.out files.  */
   r_baserel = (g->howto->type & 8) != 0;
-  /* r_jmptable, r_relative???  FIXME-soon */
-  r_jmptable = 0;
-  r_relative = 0;
+  r_jmptable = (g->howto->type & 16) != 0;
+  r_relative = (g->howto->type & 32) != 0;
 
 #if 0
   /* For a standard reloc, the addend is in the object file.  */
@@ -2022,21 +2026,21 @@ DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
 
 
   if (bfd_is_com_section (output_section)
-      || output_section == &bfd_abs_section
-      || output_section == &bfd_und_section)
+      || bfd_is_abs_section (output_section)
+      || bfd_is_und_section (output_section))
     {
-      if (bfd_abs_section.symbol == sym)
+      if (bfd_abs_section_ptr->symbol == sym)
       {
        /* Whoops, looked like an abs symbol, but is really an offset
           from the abs section */
-       r_index = 0;
+       r_index = N_ABS;
        r_extern = 0;
        }
       else
       {
        /* Fill in symbol */
        r_extern = 1;
-       r_index =  stoi((*(g->sym_ptr_ptr))->KEEPIT);
+       r_index = (*(g->sym_ptr_ptr))->KEEPIT;
 
       }
     }
@@ -2048,7 +2052,7 @@ DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
     }
 
   /* now the fun stuff */
-  if (abfd->xvec->header_byteorder_big_p != false) {
+  if (bfd_header_big_endian (abfd)) {
       natptr->r_index[0] = r_index >> 16;
       natptr->r_index[1] = r_index >> 8;
       natptr->r_index[2] = r_index;
@@ -2077,11 +2081,14 @@ DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
 /* Extended stuff */
 /* Output extended relocation information to a file in target byte order. */
 
+extern void NAME(aout,swap_ext_reloc_out)
+  PARAMS ((bfd *, arelent *, struct reloc_ext_external *));
+
 void
-DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
-      bfd *abfd AND
-      arelent *g AND
-      register struct reloc_ext_external *natptr)
+NAME(aout,swap_ext_reloc_out) (abfd, g, natptr)
+     bfd *abfd;
+     arelent *g;
+     register struct reloc_ext_external *natptr;
 {
   int r_index;
   int r_extern;
@@ -2094,7 +2101,9 @@ DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
 
   r_type = (unsigned int) g->howto->type;
 
-  r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
+  r_addend = g->addend;
+  if ((sym->flags & BSF_SECTION_SYM) != 0)
+    r_addend += (*(g->sym_ptr_ptr))->section->output_section->vma;
 
   /* If this relocation is relative to a symbol then set the
      r_index to the symbols index, and the r_extern bit.
@@ -2103,32 +2112,29 @@ DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
      from the abs section, or as a symbol which has an abs value.
      check for that here.  */
 
-  if (bfd_is_com_section (output_section)
-      || output_section == &bfd_abs_section
-      || output_section == &bfd_und_section)
-  {
-    if (bfd_abs_section.symbol == sym)
+  if (bfd_is_abs_section (bfd_get_section (sym)))
     {
-      /* Whoops, looked like an abs symbol, but is really an offset
-        from the abs section */
-      r_index = 0;
       r_extern = 0;
-     }
-    else
+      r_index = N_ABS;
+    }
+  else if ((sym->flags & BSF_SECTION_SYM) == 0)
     {
-      r_extern = 1;
-      r_index =  stoi((*(g->sym_ptr_ptr))->KEEPIT);
+      if (bfd_is_und_section (bfd_get_section (sym))
+         || (sym->flags & BSF_GLOBAL) != 0)
+       r_extern = 1;
+      else
+       r_extern = 0;
+      r_index = (*(g->sym_ptr_ptr))->KEEPIT;
     }
-  }
   else
-  {
-    /* Just an ordinary section */
-    r_extern = 0;
-    r_index  = output_section->target_index;
-  }
+    {
+      /* Just an ordinary section */
+      r_extern = 0;
+      r_index = output_section->target_index;
+    }
 
   /* now the fun stuff */
-  if (abfd->xvec->header_byteorder_big_p != false) {
+  if (bfd_header_big_endian (abfd)) {
     natptr->r_index[0] = r_index >> 16;
     natptr->r_index[1] = r_index >> 8;
     natptr->r_index[2] = r_index;
@@ -2183,20 +2189,21 @@ DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
     default:                                                           \
     case N_ABS:                                                                \
     case N_ABS | N_EXT:                                                        \
-     cache_ptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;  \
+     cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;     \
       cache_ptr->addend = ad;                                          \
       break;                                                           \
     }                                                                  \
   }                                                                    \
 
 void
-DEFUN(NAME(aout,swap_ext_reloc_in), (abfd, bytes, cache_ptr, symbols),
-      bfd *abfd AND
-      struct reloc_ext_external *bytes AND
-      arelent *cache_ptr AND
-      asymbol **symbols)
+NAME(aout,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
+     bfd *abfd;
+     struct reloc_ext_external *bytes;
+     arelent *cache_ptr;
+     asymbol **symbols;
+     bfd_size_type symcount;
 {
-  int r_index;
+  unsigned int r_index;
   int r_extern;
   unsigned int r_type;
   struct aoutdata *su = &(abfd->tdata.aout_data->a);
@@ -2204,7 +2211,7 @@ DEFUN(NAME(aout,swap_ext_reloc_in), (abfd, bytes, cache_ptr, symbols),
   cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
 
   /* now the fun stuff */
-  if (abfd->xvec->header_byteorder_big_p != false) {
+  if (bfd_header_big_endian (abfd)) {
     r_index =  (bytes->r_index[0] << 16)
             | (bytes->r_index[1] << 8)
             |  bytes->r_index[2];
@@ -2221,28 +2228,46 @@ DEFUN(NAME(aout,swap_ext_reloc_in), (abfd, bytes, cache_ptr, symbols),
   }
 
   cache_ptr->howto =  howto_table_ext + r_type;
+
+  /* Base relative relocs are always against the symbol table,
+     regardless of the setting of r_extern.  r_extern just reflects
+     whether the symbol the reloc is against is local or global.  */
+  if (r_type == RELOC_BASE10
+      || r_type == RELOC_BASE13
+      || r_type == RELOC_BASE22)
+    r_extern = 1;
+
+  if (r_extern && r_index > symcount)
+    {
+      /* We could arrange to return an error, but it might be useful
+         to see the file even if it is bad.  */
+      r_extern = 0;
+      r_index = N_ABS;
+    }
+
   MOVE_ADDRESS(GET_SWORD(abfd, bytes->r_addend));
 }
 
 void
-DEFUN(NAME(aout,swap_std_reloc_in), (abfd, bytes, cache_ptr, symbols),
-  bfd *abfd AND
-  struct reloc_std_external *bytes AND
-  arelent *cache_ptr AND
-  asymbol **symbols)
+NAME(aout,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
+     bfd *abfd;
+     struct reloc_std_external *bytes;
+     arelent *cache_ptr;
+     asymbol **symbols;
+     bfd_size_type symcount;
 {
-  int r_index;
+  unsigned int r_index;
   int r_extern;
   unsigned int r_length;
   int r_pcrel;
   int r_baserel, r_jmptable, r_relative;
   struct aoutdata  *su = &(abfd->tdata.aout_data->a);
-  int howto_idx;
+  unsigned int howto_idx;
 
   cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address);
 
   /* now the fun stuff */
-  if (abfd->xvec->header_byteorder_big_p != false) {
+  if (bfd_header_big_endian (abfd)) {
     r_index =  (bytes->r_index[0] << 16)
       | (bytes->r_index[1] << 8)
        |  bytes->r_index[2];
@@ -2266,86 +2291,86 @@ DEFUN(NAME(aout,swap_std_reloc_in), (abfd, bytes, cache_ptr, symbols),
                        >> RELOC_STD_BITS_LENGTH_SH_LITTLE;
   }
 
-  howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel;
+  howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel
+             + 16 * r_jmptable + 32 * r_relative;
   BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
   cache_ptr->howto =  howto_table_std + howto_idx;
-  BFD_ASSERT (cache_ptr->howto->type != -1);
-  BFD_ASSERT (r_jmptable == 0);
-  BFD_ASSERT (r_relative == 0);
-  /* FIXME-soon:  Roll jmptable, relative bits into howto setting */
+  BFD_ASSERT (cache_ptr->howto->type != (unsigned int) -1);
+
+  /* Base relative relocs are always against the symbol table,
+     regardless of the setting of r_extern.  r_extern just reflects
+     whether the symbol the reloc is against is local or global.  */
+  if (r_baserel)
+    r_extern = 1;
+
+  if (r_extern && r_index > symcount)
+    {
+      /* We could arrange to return an error, but it might be useful
+         to see the file even if it is bad.  */
+      r_extern = 0;
+      r_index = N_ABS;
+    }
 
   MOVE_ADDRESS(0);
 }
 
-/* Reloc hackery */
+/* Read and swap the relocs for a section.  */
 
 boolean
-DEFUN(NAME(aout,slurp_reloc_table),(abfd, asect, symbols),
-      bfd *abfd AND
-      sec_ptr asect AND
-      asymbol **symbols)
+NAME(aout,slurp_reloc_table) (abfd, asect, symbols)
+     bfd *abfd;
+     sec_ptr asect;
+     asymbol **symbols;
 {
   unsigned int count;
   bfd_size_type reloc_size;
   PTR relocs;
-  bfd_size_type dynrel_count = 0;
-  PTR dynrels = NULL;
   arelent *reloc_cache;
   size_t each_size;
   unsigned int counter = 0;
   arelent *cache_ptr;
 
-  if (asect->relocation) return true;
+  if (asect->relocation)
+    return true;
 
-  if (asect->flags & SEC_CONSTRUCTOR) return true;
+  if (asect->flags & SEC_CONSTRUCTOR)
+    return true;
 
   if (asect == obj_datasec (abfd))
     reloc_size = exec_hdr(abfd)->a_drsize;
   else if (asect == obj_textsec (abfd))
     reloc_size = exec_hdr(abfd)->a_trsize;
+  else if (asect == obj_bsssec (abfd))
+    reloc_size = 0;
   else
     {
-      bfd_error = invalid_operation;
+      bfd_set_error (bfd_error_invalid_operation);
       return false;
     }
 
-  if ((bfd_get_file_flags (abfd) & DYNAMIC) != 0
-      && aout_backend_info (abfd)->read_dynamic_relocs)
-    {
-      dynrel_count = ((*aout_backend_info (abfd)->read_dynamic_relocs)
-                     (abfd, &dynrels));
-      if (dynrel_count == (bfd_size_type) -1)
-       return false;
-    }
+  if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
+    return false;
 
-  bfd_seek (abfd, asect->rel_filepos, SEEK_SET);
   each_size = obj_reloc_entry_size (abfd);
 
   count = reloc_size / each_size;
 
-  reloc_cache = ((arelent *)
-                bfd_zalloc (abfd,
-                            (size_t) ((count + dynrel_count)
-                                      * sizeof (arelent))));
-  if (!reloc_cache)
-    {
-    nomem:
-      bfd_error = no_memory;
-      return false;
-    }
+  reloc_cache = (arelent *) bfd_malloc ((size_t) (count * sizeof (arelent)));
+  if (reloc_cache == NULL && count != 0)
+    return false;
+  memset (reloc_cache, 0, count * sizeof (arelent));
 
-  relocs = (PTR) bfd_alloc (abfd, reloc_size);
-  if (!relocs)
+  relocs = bfd_malloc ((size_t) reloc_size);
+  if (relocs == NULL && reloc_size != 0)
     {
-      bfd_release (abfd, reloc_cache);
-      goto nomem;
+      free (reloc_cache);
+      return false;
     }
 
   if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size)
     {
-      bfd_release (abfd, relocs);
-      bfd_release (abfd, reloc_cache);
-      bfd_error = system_call_error;
+      free (relocs);
+      free (reloc_cache);
       return false;
     }
 
@@ -2356,72 +2381,33 @@ DEFUN(NAME(aout,slurp_reloc_table),(abfd, asect, symbols),
        (struct reloc_ext_external *) relocs;
 
       for (; counter < count; counter++, rptr++, cache_ptr++)
-       NAME(aout,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols);
+       NAME(aout,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols,
+                                     bfd_get_symcount (abfd));
     }
   else
     {
-      register struct reloc_std_external *rptr
-       (struct reloc_std_external *) relocs;
+      register struct reloc_std_external *rptr =
+       (struct reloc_std_external *) relocs;
 
       for (; counter < count; counter++, rptr++, cache_ptr++)
-       NAME(aout,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols);
+       MY_swap_std_reloc_in (abfd, rptr, cache_ptr, symbols,
+                             bfd_get_symcount (abfd));
     }
 
-  if (dynrel_count > 0)
-    {
-      asymbol **dynsyms;
-
-      /* The dynamic symbols are at the end of the symbol table.  */
-      for (dynsyms = symbols;
-          *dynsyms != NULL && ((*dynsyms)->flags & BSF_DYNAMIC) == 0;
-          ++dynsyms)
-       ;
-
-      /* Swap in the dynamic relocs.  These relocs may be for either
-        section, so we must discard ones we don't want.  */
-      counter = 0;
-      if (each_size == RELOC_EXT_SIZE)
-       {
-         register struct reloc_ext_external *rptr
-           = (struct reloc_ext_external *) dynrels;
-
-         for (; counter < dynrel_count; counter++, rptr++, cache_ptr++)
-           {
-             NAME(aout,swap_ext_reloc_in) (abfd, rptr, cache_ptr, dynsyms);
-             cache_ptr->address -= bfd_get_section_vma (abfd, asect);
-             if (cache_ptr->address >= bfd_section_size (abfd, asect))
-               --cache_ptr;
-           }
-       }
-      else
-       {
-         register struct reloc_std_external *rptr
-           = (struct reloc_std_external *) dynrels;
-
-         for (; counter < dynrel_count; counter++, rptr++, cache_ptr++)
-           {
-             NAME(aout,swap_std_reloc_in) (abfd, rptr, cache_ptr, dynsyms);
-             cache_ptr->address -= bfd_get_section_vma (abfd, asect);
-             if (cache_ptr->address >= bfd_section_size (abfd, asect))
-               --cache_ptr;
-           }
-       }
-    }
+  free (relocs);
 
-  bfd_release (abfd,relocs);
   asect->relocation = reloc_cache;
   asect->reloc_count = cache_ptr - reloc_cache;
+
   return true;
 }
 
-
-
 /* Write out a relocation section into an object file.  */
 
 boolean
-DEFUN(NAME(aout,squirt_out_relocs),(abfd, section),
-      bfd *abfd AND
-      asection *section)
+NAME(aout,squirt_out_relocs) (abfd, section)
+     bfd *abfd;
+     asection *section;
 {
   arelent **generic;
   unsigned char *native, *natptr;
@@ -2430,15 +2416,14 @@ DEFUN(NAME(aout,squirt_out_relocs),(abfd, section),
   unsigned int count = section->reloc_count;
   size_t natsize;
 
-  if (count == 0) return true;
+  if (count == 0 || section->orelocation == NULL)
+    return true;
 
   each_size = obj_reloc_entry_size (abfd);
   natsize = each_size * count;
   native = (unsigned char *) bfd_zalloc (abfd, natsize);
-  if (!native) {
-    bfd_error = no_memory;
+  if (!native)
     return false;
-  }
 
   generic = section->orelocation;
 
@@ -2454,7 +2439,7 @@ DEFUN(NAME(aout,squirt_out_relocs),(abfd, section),
       for (natptr = native;
           count != 0;
           --count, natptr += each_size, ++generic)
-       NAME(aout,swap_std_reloc_out)(abfd, *generic, (struct reloc_std_external *)natptr);
+       MY_swap_std_reloc_out(abfd, *generic, (struct reloc_std_external *)natptr);
     }
 
   if ( bfd_write ((PTR) native, 1, natsize, abfd) != natsize) {
@@ -2467,18 +2452,24 @@ DEFUN(NAME(aout,squirt_out_relocs),(abfd, section),
 }
 
 /* This is stupid.  This function should be a boolean predicate */
-unsigned int
-DEFUN(NAME(aout,canonicalize_reloc),(abfd, section, relptr, symbols),
-      bfd *abfd AND
-      sec_ptr section AND
-      arelent **relptr AND
-      asymbol **symbols)
+long
+NAME(aout,canonicalize_reloc) (abfd, section, relptr, symbols)
+     bfd *abfd;
+     sec_ptr section;
+     arelent **relptr;
+     asymbol **symbols;
 {
   arelent *tblptr = section->relocation;
   unsigned int count;
 
+  if (section == obj_bsssec (abfd))
+    {
+      *relptr = NULL;
+      return 0;
+    }
+
   if (!(tblptr || NAME(aout,slurp_reloc_table)(abfd, section, symbols)))
-    return 0;
+    return -1;
 
   if (section->flags & SEC_CONSTRUCTOR) {
     arelent_chain *chain = section->constructor_chain;
@@ -2489,7 +2480,6 @@ DEFUN(NAME(aout,canonicalize_reloc),(abfd, section, relptr, symbols),
   }
   else {
     tblptr = section->relocation;
-    if (!tblptr) return 0;
 
     for (count = 0; count++ < section->reloc_count;)
       {
@@ -2501,78 +2491,72 @@ DEFUN(NAME(aout,canonicalize_reloc),(abfd, section, relptr, symbols),
   return section->reloc_count;
 }
 
-unsigned int
-DEFUN(NAME(aout,get_reloc_upper_bound),(abfd, asect),
-     bfd *abfd AND
-     sec_ptr asect)
+long
+NAME(aout,get_reloc_upper_bound) (abfd, asect)
+     bfd *abfd;
+     sec_ptr asect;
 {
-  bfd_size_type dynrel_count = 0;
-
   if (bfd_get_format (abfd) != bfd_object) {
-    bfd_error = invalid_operation;
-    return 0;
+    bfd_set_error (bfd_error_invalid_operation);
+    return -1;
   }
   if (asect->flags & SEC_CONSTRUCTOR) {
     return (sizeof (arelent *) * (asect->reloc_count+1));
   }
 
-  if ((bfd_get_file_flags (abfd) & DYNAMIC) != 0
-      && aout_backend_info (abfd)->read_dynamic_relocs)
-    {
-      PTR dynrels;
-
-      dynrel_count = ((*aout_backend_info (abfd)->read_dynamic_relocs)
-                     (abfd, &dynrels));
-      if (dynrel_count == (bfd_size_type) -1)
-       return 0;
-    }
-
   if (asect == obj_datasec (abfd))
-    return (sizeof (arelent *) *
-           ((exec_hdr(abfd)->a_drsize / obj_reloc_entry_size (abfd))
-            + dynrel_count + 1));
+    return (sizeof (arelent *)
+           ((exec_hdr(abfd)->a_drsize / obj_reloc_entry_size (abfd))
+              + 1));
 
   if (asect == obj_textsec (abfd))
-    return (sizeof (arelent *) *
-           ((exec_hdr(abfd)->a_trsize / obj_reloc_entry_size (abfd))
-            + dynrel_count + 1));
+    return (sizeof (arelent *)
+           * ((exec_hdr(abfd)->a_trsize / obj_reloc_entry_size (abfd))
+              + 1));
+
+  if (asect == obj_bsssec (abfd))
+    return sizeof (arelent *);
+
+  if (asect == obj_bsssec (abfd))
+    return 0;
 
-  bfd_error = invalid_operation;
-  return 0;
+  bfd_set_error (bfd_error_invalid_operation);
+  return -1;
 }
 
 \f
- unsigned int
-DEFUN(NAME(aout,get_symtab_upper_bound),(abfd),
-     bfd *abfd)
+long
+NAME(aout,get_symtab_upper_bound) (abfd)
+     bfd *abfd;
 {
-  if (!NAME(aout,slurp_symbol_table)(abfd)) return 0;
+  if (!NAME(aout,slurp_symbol_table)(abfd))
+    return -1;
 
   return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *));
 }
 
 /*ARGSUSED*/
  alent *
-DEFUN(NAME(aout,get_lineno),(ignore_abfd, ignore_symbol),
-      bfd *ignore_abfd AND
-      asymbol *ignore_symbol)
+NAME(aout,get_lineno) (ignore_abfd, ignore_symbol)
+     bfd *ignore_abfd ATTRIBUTE_UNUSED;
+     asymbol *ignore_symbol ATTRIBUTE_UNUSED;
 {
-return (alent *)NULL;
+  return (alent *)NULL;
 }
 
 /*ARGSUSED*/
 void
-DEFUN(NAME(aout,get_symbol_info),(ignore_abfd, symbol, ret),
-      bfd *ignore_abfd AND
-      asymbol *symbol AND
-      symbol_info *ret)
+NAME(aout,get_symbol_info) (ignore_abfd, symbol, ret)
+     bfd *ignore_abfd ATTRIBUTE_UNUSED;
+     asymbol *symbol;
+     symbol_info *ret;
 {
   bfd_symbol_info (symbol, ret);
 
   if (ret->type == '?')
     {
       int type_code = aout_symbol(symbol)->type & 0xff;
-      CONST char *stab_name = aout_stab_name(type_code);
+      const char *stab_name = bfd_get_stab_name (type_code);
       static char buf[10];
 
       if (stab_name == NULL)
@@ -2581,6 +2565,7 @@ DEFUN(NAME(aout,get_symbol_info),(ignore_abfd, symbol, ret),
          stab_name = buf;
        }
       ret->type = '-';
+      ret->stab_type = type_code;
       ret->stab_other = (unsigned)(aout_symbol(symbol)->other & 0xff);
       ret->stab_desc = (unsigned)(aout_symbol(symbol)->desc & 0xffff);
       ret->stab_name = stab_name;
@@ -2589,11 +2574,11 @@ DEFUN(NAME(aout,get_symbol_info),(ignore_abfd, symbol, ret),
 
 /*ARGSUSED*/
 void
-DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how),
-      bfd *ignore_abfd AND
-      PTR afile AND
-      asymbol *symbol AND
-      bfd_print_symbol_type how)
+NAME(aout,print_symbol) (ignore_abfd, afile, symbol, how)
+     bfd *ignore_abfd ATTRIBUTE_UNUSED;
+     PTR afile;
+     asymbol *symbol;
+     bfd_print_symbol_type how;
 {
   FILE *file = (FILE *)afile;
 
@@ -2626,6 +2611,78 @@ DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how),
   }
 }
 
+/* If we don't have to allocate more than 1MB to hold the generic
+   symbols, we use the generic minisymbol methord: it's faster, since
+   it only translates the symbols once, not multiple times.  */
+#define MINISYM_THRESHOLD (1000000 / sizeof (asymbol))
+
+/* Read minisymbols.  For minisymbols, we use the unmodified a.out
+   symbols.  The minisymbol_to_symbol function translates these into
+   BFD asymbol structures.  */
+
+long
+NAME(aout,read_minisymbols) (abfd, dynamic, minisymsp, sizep)
+     bfd *abfd;
+     boolean dynamic;
+     PTR *minisymsp;
+     unsigned int *sizep;
+{
+  if (dynamic)
+    {
+      /* We could handle the dynamic symbols here as well, but it's
+         easier to hand them off.  */
+      return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep);
+    }
+
+  if (! aout_get_external_symbols (abfd))
+    return -1;
+
+  if (obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD)
+    return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep);
+
+  *minisymsp = (PTR) obj_aout_external_syms (abfd);
+
+  /* By passing the external symbols back from this routine, we are
+     giving up control over the memory block.  Clear
+     obj_aout_external_syms, so that we do not try to free it
+     ourselves.  */
+  obj_aout_external_syms (abfd) = NULL;
+
+  *sizep = EXTERNAL_NLIST_SIZE;
+  return obj_aout_external_sym_count (abfd);
+}
+
+/* Convert a minisymbol to a BFD asymbol.  A minisymbol is just an
+   unmodified a.out symbol.  The SYM argument is a structure returned
+   by bfd_make_empty_symbol, which we fill in here.  */
+
+asymbol *
+NAME(aout,minisymbol_to_symbol) (abfd, dynamic, minisym, sym)
+     bfd *abfd;
+     boolean dynamic;
+     const PTR minisym;
+     asymbol *sym;
+{
+  if (dynamic
+      || obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD)
+    return _bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym);
+
+  memset (sym, 0, sizeof (aout_symbol_type));
+
+  /* We call translate_symbol_table to translate a single symbol.  */
+  if (! (NAME(aout,translate_symbol_table)
+        (abfd,
+         (aout_symbol_type *) sym,
+         (struct external_nlist *) minisym,
+         (bfd_size_type) 1,
+         obj_aout_external_strings (abfd),
+         obj_aout_external_string_size (abfd),
+         false)))
+    return NULL;
+
+  return sym;
+}
+
 /*
  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
@@ -2633,32 +2690,29 @@ DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how),
 */
 
 boolean
-DEFUN(NAME(aout,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)
+NAME(aout,find_nearest_line)
+     (abfd, section, symbols, offset, filename_ptr, functionname_ptr, line_ptr)
+     bfd *abfd;
+     asection *section;
+     asymbol **symbols;
+     bfd_vma offset;
+     CONST char **filename_ptr;
+     CONST char **functionname_ptr;
+     unsigned int *line_ptr;
 {
   /* Run down the file looking for the filename, function and linenumber */
   asymbol **p;
-  static  char buffer[100];
-  static  char filename_buffer[200];
   CONST char *directory_name = NULL;
   CONST char *main_file_name = NULL;
   CONST char *current_file_name = NULL;
   CONST char *line_file_name = NULL; /* Value of current_file_name at line number. */
-  bfd_vma high_line_vma = ~0;
+  CONST char *line_directory_name = NULL; /* Value of directory_name at line number. */
+  bfd_vma low_line_vma = 0;
   bfd_vma low_func_vma = 0;
   asymbol *func = 0;
+  size_t filelen, funclen;
+  char *buf;
+
   *filename_ptr = abfd->filename;
   *functionname_ptr = 0;
   *line_ptr = 0;
@@ -2667,7 +2721,49 @@ DEFUN(NAME(aout,find_nearest_line),(abfd,
       aout_symbol_type  *q = (aout_symbol_type *)(*p);
     next:
       switch (q->type){
+      case N_TEXT:
+       /* If this looks like a file name symbol, and it comes after
+           the line number we have found so far, but before the
+           offset, then we have probably not found the right line
+           number.  */
+       if (q->symbol.value <= offset
+           && ((q->symbol.value > low_line_vma
+                && (line_file_name != NULL
+                    || *line_ptr != 0))
+               || (q->symbol.value > low_func_vma
+                   && func != NULL)))
+         {
+           const char *symname;
+
+           symname = q->symbol.name;
+           if (strcmp (symname + strlen (symname) - 2, ".o") == 0)
+             {
+               if (q->symbol.value > low_line_vma)
+                 {
+                   *line_ptr = 0;
+                   line_file_name = NULL;
+                 }
+               if (q->symbol.value > low_func_vma)
+                 func = NULL;
+             }
+         }
+       break;
+
       case N_SO:
+       /* If this symbol is less than the offset, but greater than
+           the line number we have found so far, then we have not
+           found the right line number.  */
+       if (q->symbol.value <= offset)
+         {
+           if (q->symbol.value > low_line_vma)
+             {
+               *line_ptr = 0;
+               line_file_name = NULL;
+             }
+           if (q->symbol.value > low_func_vma)
+             func = NULL;
+         }
+
        main_file_name = current_file_name = q->symbol.name;
        /* Look ahead to next symbol to check if that too is an N_SO. */
        p++;
@@ -2691,13 +2787,16 @@ DEFUN(NAME(aout,find_nearest_line),(abfd,
 
       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;
-         line_file_name = current_file_name;
-       }
+       /* We'll keep this if it resolves nearer than the one we have
+           already.  */
+       if (q->symbol.value >= low_line_vma
+           && q->symbol.value <= offset)
+         {
+           *line_ptr = q->desc;
+           low_line_vma = q->symbol.value;
+           line_file_name = current_file_name;
+           line_directory_name = directory_name;
+         }
        break;
       case N_FUN:
        {
@@ -2707,18 +2806,8 @@ DEFUN(NAME(aout,find_nearest_line),(abfd,
            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 = '\0'; }
-           *functionname_ptr = buffer;
+         else if (q->symbol.value > offset)
            goto done;
-
-         }
        }
        break;
       }
@@ -2726,57 +2815,117 @@ DEFUN(NAME(aout,find_nearest_line),(abfd,
   }
 
  done:
-  if (*line_ptr)
-    main_file_name = line_file_name;
-  if (main_file_name) {
+  if (*line_ptr != 0)
+    {
+      main_file_name = line_file_name;
+      directory_name = line_directory_name;
+    }
+
+  if (main_file_name == NULL
+      || main_file_name[0] == '/'
+      || directory_name == NULL)
+    filelen = 0;
+  else
+    filelen = strlen (directory_name) + strlen (main_file_name);
+  if (func == NULL)
+    funclen = 0;
+  else
+    funclen = strlen (bfd_asymbol_name (func));
+
+  if (adata (abfd).line_buf != NULL)
+    free (adata (abfd).line_buf);
+  if (filelen + funclen == 0)
+    adata (abfd).line_buf = buf = NULL;
+  else
+    {
+      buf = (char *) bfd_malloc (filelen + funclen + 3);
+      adata (abfd).line_buf = buf;
+      if (buf == NULL)
+       return false;
+    }
+
+  if (main_file_name != NULL)
+    {
       if (main_file_name[0] == '/' || directory_name == NULL)
-         *filename_ptr = main_file_name;
-      else {
-         sprintf(filename_buffer, "%.140s%.50s",
-                 directory_name, main_file_name);
-         *filename_ptr = filename_buffer;
-      }
-  }
-  return true;
+       *filename_ptr = main_file_name;
+      else
+       {
+         sprintf (buf, "%s%s", directory_name, main_file_name);
+         *filename_ptr = buf;
+         buf += filelen + 1;
+       }
+    }
+
+  if (func)
+    {
+      const char *function = func->name;
+      char *p;
+
+      /* The caller expects a symbol name.  We actually have a
+        function name, without the leading underscore.  Put the
+        underscore back in, so that the caller gets a symbol name.  */
+      if (bfd_get_symbol_leading_char (abfd) == '\0')
+       strcpy (buf, function);
+      else
+       {
+         buf[0] = bfd_get_symbol_leading_char (abfd);
+         strcpy (buf + 1, function);
+       }
+      /* Have to remove : stuff */
+      p = strchr (buf, ':');
+      if (p != NULL)
+       *p = '\0';
+      *functionname_ptr = buf;
+    }
 
+  return true;
 }
 
 /*ARGSUSED*/
 int
-DEFUN(NAME(aout,sizeof_headers),(abfd, execable),
-      bfd *abfd AND
-      boolean execable)
+NAME(aout,sizeof_headers) (abfd, execable)
+     bfd *abfd;
+     boolean execable ATTRIBUTE_UNUSED;
 {
   return adata(abfd).exec_bytes_size;
 }
-\f
-/* a.out link code.  */
 
-/* a.out linker hash table entries.  */
+/* Free all information we have cached for this BFD.  We can always
+   read it again later if we need it.  */
 
-struct aout_link_hash_entry
+boolean
+NAME(aout,bfd_free_cached_info) (abfd)
+     bfd *abfd;
 {
-  struct bfd_link_hash_entry root;
-  /* Symbol index in output file.  */
-  int indx;
-};
+  asection *o;
+
+  if (bfd_get_format (abfd) != bfd_object)
+    return true;
 
-/* a.out linker hash table.  */
+#define BFCI_FREE(x) if (x != NULL) { free (x); x = NULL; }
+  BFCI_FREE (obj_aout_symbols (abfd));
+#ifdef USE_MMAP
+  obj_aout_external_syms (abfd) = 0;
+  bfd_free_window (&obj_aout_sym_window (abfd));
+  bfd_free_window (&obj_aout_string_window (abfd));
+  obj_aout_external_strings (abfd) = 0;
+#else
+  BFCI_FREE (obj_aout_external_syms (abfd));
+  BFCI_FREE (obj_aout_external_strings (abfd));
+#endif
+  for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+    BFCI_FREE (o->relocation);
+#undef BFCI_FREE
 
-struct aout_link_hash_table
-{
-  struct bfd_link_hash_table root;
-};
+  return true;
+}
+\f
+/* a.out link code.  */
 
-static struct bfd_hash_entry *aout_link_hash_newfunc
-  PARAMS ((struct bfd_hash_entry *entry,
-          struct bfd_hash_table *table,
-          const char *string));
 static boolean aout_link_add_object_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean aout_link_check_archive_element
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
-static boolean aout_link_get_symbols PARAMS ((bfd *));
 static boolean aout_link_free_symbols PARAMS ((bfd *));
 static boolean aout_link_check_ar_symbols
   PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
@@ -2785,8 +2934,8 @@ static boolean aout_link_add_symbols
 
 /* Routine to create an entry in an a.out link hash table.  */
 
-static struct bfd_hash_entry *
-aout_link_hash_newfunc (entry, table, string)
+struct bfd_hash_entry *
+NAME(aout,link_hash_newfunc) (entry, table, string)
      struct bfd_hash_entry *entry;
      struct bfd_hash_table *table;
      const char *string;
@@ -2798,18 +2947,36 @@ aout_link_hash_newfunc (entry, table, string)
   if (ret == (struct aout_link_hash_entry *) NULL)
     ret = ((struct aout_link_hash_entry *)
           bfd_hash_allocate (table, sizeof (struct aout_link_hash_entry)));
+  if (ret == (struct aout_link_hash_entry *) NULL)
+    return (struct bfd_hash_entry *) ret;
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct aout_link_hash_entry *)
         _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
                                 table, string));
-
-  /* Set local fields.  */
-  ret->indx = -1;
+  if (ret)
+    {
+      /* Set local fields.  */
+      ret->written = false;
+      ret->indx = -1;
+    }
 
   return (struct bfd_hash_entry *) ret;
 }
 
+/* Initialize an a.out link hash table.  */
+
+boolean
+NAME(aout,link_hash_table_init) (table, abfd, newfunc)
+     struct aout_link_hash_table *table;
+     bfd *abfd;
+     struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+                                               struct bfd_hash_table *,
+                                               const char *));
+{
+  return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
+}
+
 /* Create an a.out link hash table.  */
 
 struct bfd_link_hash_table *
@@ -2819,9 +2986,11 @@ NAME(aout,link_hash_table_create) (abfd)
   struct aout_link_hash_table *ret;
 
   ret = ((struct aout_link_hash_table *)
-        bfd_xmalloc (sizeof (struct aout_link_hash_table)));
-  if (! _bfd_link_hash_table_init (&ret->root, abfd,
-                                  aout_link_hash_newfunc))
+        bfd_alloc (abfd, sizeof (struct aout_link_hash_table)));
+  if (ret == NULL)
+    return (struct bfd_link_hash_table *) NULL;
+  if (! NAME(aout,link_hash_table_init) (ret, abfd,
+                                        NAME(aout,link_hash_newfunc)))
     {
       free (ret);
       return (struct bfd_link_hash_table *) NULL;
@@ -2829,25 +2998,6 @@ NAME(aout,link_hash_table_create) (abfd)
   return &ret->root;
 }
 
-/* Look up an entry in an a.out link hash table.  */
-
-#define aout_link_hash_lookup(table, string, create, copy, follow) \
-  ((struct aout_link_hash_entry *) \
-   bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow)))
-
-/* Traverse an a.out link hash table.  */
-
-#define aout_link_hash_traverse(table, func, info)                     \
-  (bfd_link_hash_traverse                                              \
-   (&(table)->root,                                                    \
-    (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \
-    (info)))
-
-/* Get the a.out link hash table from the info structure.  This is
-   just a cast.  */
-
-#define aout_hash_table(p) ((struct aout_link_hash_table *) ((p)->hash))
-
 /* Given an a.out BFD, add symbols to the global hash table as
    appropriate.  */
 
@@ -2864,7 +3014,7 @@ NAME(aout,link_add_symbols) (abfd, info)
       return _bfd_generic_link_add_archive_symbols
        (abfd, info, aout_link_check_archive_element);
     default:
-      bfd_error = wrong_format;
+      bfd_set_error (bfd_error_wrong_format);
       return false;
     }
 }
@@ -2876,7 +3026,7 @@ aout_link_add_object_symbols (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
-  if (! aout_link_get_symbols (abfd))
+  if (! aout_get_external_symbols (abfd))
     return false;
   if (! aout_link_add_symbols (abfd, info))
     return false;
@@ -2899,7 +3049,7 @@ aout_link_check_archive_element (abfd, info, pneeded)
      struct bfd_link_info *info;
      boolean *pneeded;
 {
-  if (! aout_link_get_symbols (abfd))
+  if (! aout_get_external_symbols (abfd))
     return false;
 
   if (! aout_link_check_ar_symbols (abfd, info, pneeded))
@@ -2911,11 +3061,7 @@ aout_link_check_archive_element (abfd, info, pneeded)
        return false;
     }
 
-  /* We keep around the symbols even if we aren't going to use this
-     object file, because we may want to reread it.  This doesn't
-     waste too much memory, because it isn't all that common to read
-     an archive element but not need it.  */
-  if (! info->keep_memory)
+  if (! info->keep_memory || ! *pneeded)
     {
       if (! aout_link_free_symbols (abfd))
        return false;
@@ -2924,59 +3070,6 @@ aout_link_check_archive_element (abfd, info, pneeded)
   return true;
 }
 
-/* Read the internal symbols from an a.out file.  */
-
-static boolean
-aout_link_get_symbols (abfd)
-     bfd *abfd;
-{
-  bfd_size_type count;
-  struct external_nlist *syms;
-  unsigned char string_chars[BYTES_IN_WORD];
-  bfd_size_type stringsize;
-  char *strings;
-
-  if (obj_aout_external_syms (abfd) != (struct external_nlist *) NULL)
-    {
-      /* We already have them.  */
-      return true;
-    }
-
-  count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE;
-
-  /* We allocate using bfd_xmalloc to make the values easy to free
-     later on.  If we put them on the obstack it might not be possible
-     to free them.  */
-  syms = ((struct external_nlist *)
-         bfd_xmalloc ((size_t) count * EXTERNAL_NLIST_SIZE));
-
-  if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
-      || (bfd_read ((PTR) syms, 1, exec_hdr (abfd)->a_syms, abfd)
-         != exec_hdr (abfd)->a_syms))
-    return false;
-
-  /* Get the size of the strings.  */
-  if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
-      || (bfd_read ((PTR) string_chars, BYTES_IN_WORD, 1, abfd)
-         != BYTES_IN_WORD))
-    return false;
-  stringsize = GET_WORD (abfd, string_chars);
-  strings = (char *) bfd_xmalloc ((size_t) stringsize);
-
-  /* Skip space for the string count in the buffer for convenience
-     when using indexes.  */
-  if (bfd_read (strings + BYTES_IN_WORD, 1, stringsize - BYTES_IN_WORD, abfd)
-      != stringsize - BYTES_IN_WORD)
-    return false;
-
-  /* Save the data.  */
-  obj_aout_external_syms (abfd) = syms;
-  obj_aout_external_sym_count (abfd) = count;
-  obj_aout_external_strings (abfd) = strings;
-
-  return true;
-}
-
 /* Free up the internal symbols read from an a.out file.  */
 
 static boolean
@@ -2985,12 +3078,20 @@ aout_link_free_symbols (abfd)
 {
   if (obj_aout_external_syms (abfd) != (struct external_nlist *) NULL)
     {
+#ifdef USE_MMAP
+      bfd_free_window (&obj_aout_sym_window (abfd));
+#else
       free ((PTR) obj_aout_external_syms (abfd));
+#endif
       obj_aout_external_syms (abfd) = (struct external_nlist *) NULL;
     }
   if (obj_aout_external_strings (abfd) != (char *) NULL)
     {
+#ifdef USE_MMAP
+      bfd_free_window (&obj_aout_string_window (abfd));
+#else
       free ((PTR) obj_aout_external_strings (abfd));
+#endif
       obj_aout_external_strings (abfd) = (char *) NULL;
     }
   return true;
@@ -3025,9 +3126,22 @@ aout_link_check_ar_symbols (abfd, info, pneeded)
       const char *name;
       struct bfd_link_hash_entry *h;
 
-      /* Ignore symbols that are not externally visible.  */
-      if ((type & N_EXT) == 0)
-       continue;
+      /* Ignore symbols that are not externally visible.  This is an
+        optimization only, as we check the type more thoroughly
+        below.  */
+      if (((type & N_EXT) == 0
+          || (type & N_STAB) != 0
+          || type == N_FN)
+         && type != N_WEAKA
+         && type != N_WEAKT
+         && type != N_WEAKD
+         && type != N_WEAKB)
+       {
+         if (type == N_WARNING
+             || type == N_INDR)
+           ++p;
+         continue;
+       }
 
       name = strings + GET_WORD (abfd, p->e_strx);
       h = bfd_link_hash_lookup (info->hash, name, false, false, true);
@@ -3037,9 +3151,17 @@ aout_link_check_ar_symbols (abfd, info, pneeded)
       if (h == (struct bfd_link_hash_entry *) NULL
          || (h->type != bfd_link_hash_undefined
              && h->type != bfd_link_hash_common))
-       continue;
+       {
+         if (type == (N_INDR | N_EXT))
+           ++p;
+         continue;
+       }
 
-      if ((type & (N_TEXT | N_DATA | N_BSS)) != 0)
+      if (type == (N_TEXT | N_EXT)
+         || type == (N_DATA | N_EXT)
+         || type == (N_BSS | N_EXT)
+         || type == (N_ABS | N_EXT)
+         || type == (N_INDR | N_EXT))
        {
          /* This object file defines this symbol.  We must link it
             in.  This is true regardless of whether the current
@@ -3049,14 +3171,20 @@ aout_link_check_ar_symbols (abfd, info, pneeded)
                 int a;
             and this object file from the archive includes
                 int a = 5;
-            In such a case we must include this object file.  */
+            In such a case we must include this object file.
+
+            FIXME: The SunOS 4.1.3 linker will pull in the archive
+            element if the symbol is defined in the .data section,
+            but not if it is defined in the .text section.  That
+            seems a bit crazy to me, and I haven't implemented it.
+            However, it might be correct.  */
          if (! (*info->callbacks->add_archive_element) (info, abfd, name))
            return false;
          *pneeded = true;
          return true;
        }
 
-      if (type == (N_EXT | N_UNDF))
+      if (type == (N_UNDF | N_EXT))
        {
          bfd_vma value;
 
@@ -3068,6 +3196,7 @@ aout_link_check_ar_symbols (abfd, info, pneeded)
              if (h->type == bfd_link_hash_undefined)
                {
                  bfd *symbfd;
+                 unsigned int power;
 
                  symbfd = h->u.undef.abfd;
                  if (symbfd == (bfd *) NULL)
@@ -3086,9 +3215,25 @@ aout_link_check_ar_symbols (abfd, info, pneeded)
                  /* Turn the current link symbol into a common
                     symbol.  It is already on the undefs list.  */
                  h->type = bfd_link_hash_common;
+                 h->u.c.p = ((struct bfd_link_hash_common_entry *)
+                             bfd_hash_allocate (&info->hash->table,
+                                 sizeof (struct bfd_link_hash_common_entry)));
+                 if (h->u.c.p == NULL)
+                   return false;
+
                  h->u.c.size = value;
-                 h->u.c.section = bfd_make_section_old_way (symbfd,
-                                                            "COMMON");
+
+                 /* FIXME: This isn't quite right.  The maximum
+                    alignment of a common symbol should be set by the
+                    architecture of the output file, not of the input
+                    file.  */
+                 power = bfd_log2 (value);
+                 if (power > bfd_get_arch_info (abfd)->section_align_power)
+                   power = bfd_get_arch_info (abfd)->section_align_power;
+                 h->u.c.p->alignment_power = power;
+
+                 h->u.c.p->section = bfd_make_section_old_way (symbfd,
+                                                               "COMMON");
                }
              else
                {
@@ -3099,6 +3244,23 @@ aout_link_check_ar_symbols (abfd, info, pneeded)
                }
            }
        }
+
+      if (type == N_WEAKA
+         || type == N_WEAKT
+         || type == N_WEAKD
+         || type == N_WEAKB)
+       {
+         /* This symbol is weak but defined.  We must pull it in if
+            the current link symbol is undefined, but we don't want
+            it if the current link symbol is common.  */
+         if (h->type == bfd_link_hash_undefined)
+           {
+             if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+               return false;
+             *pneeded = true;
+             return true;
+           }
+       }
     }
 
   /* We do not need this object file.  */
@@ -3112,6 +3274,12 @@ aout_link_add_symbols (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
+  boolean (*add_one_symbol) PARAMS ((struct bfd_link_info *, bfd *,
+                                    const char *, flagword, asection *,
+                                    bfd_vma, const char *, boolean,
+                                    boolean,
+                                    struct bfd_link_hash_entry **));
+  struct external_nlist *syms;
   bfd_size_type sym_count;
   char *strings;
   boolean copy;
@@ -3119,6 +3287,7 @@ aout_link_add_symbols (abfd, info)
   register struct external_nlist *p;
   struct external_nlist *pend;
 
+  syms = obj_aout_external_syms (abfd);
   sym_count = obj_aout_external_sym_count (abfd);
   strings = obj_aout_external_strings (abfd);
   if (info->keep_memory)
@@ -3126,6 +3295,13 @@ aout_link_add_symbols (abfd, info)
   else
     copy = true;
 
+  if (aout_backend_info (abfd)->add_dynamic_symbols != NULL)
+    {
+      if (! ((*aout_backend_info (abfd)->add_dynamic_symbols)
+            (abfd, info, &syms, &sym_count, &strings)))
+       return false;
+    }
+
   /* We keep a list of the linker hash table entries that correspond
      to particular symbols.  We could just look them up in the hash
      table, but keeping the list is more efficient.  Perhaps this
@@ -3134,9 +3310,15 @@ aout_link_add_symbols (abfd, info)
              bfd_alloc (abfd,
                         ((size_t) sym_count
                          * sizeof (struct aout_link_hash_entry *))));
+  if (sym_hash == NULL && sym_count != 0)
+    return false;
   obj_aout_sym_hashes (abfd) = sym_hash;
 
-  p = obj_aout_external_syms (abfd);
+  add_one_symbol = aout_backend_info (abfd)->add_one_symbol;
+  if (add_one_symbol == NULL)
+    add_one_symbol = _bfd_generic_link_add_one_symbol;
+
+  p = syms;
   pend = p + sym_count;
   for (; p < pend; p++, sym_hash++)
     {
@@ -3155,29 +3337,6 @@ aout_link_add_symbols (abfd, info)
       if ((type & N_STAB) != 0)
        continue;
 
-      /* Ignore symbols that are not external.  */
-      if ((type & N_EXT) == 0
-         && type != N_WARNING
-         && type != N_SETA
-         && type != N_SETT
-         && type != N_SETD
-         && type != N_SETB)
-       {
-         /* If this is an N_INDR symbol we must skip the next entry,
-            which is the symbol to indirect to (actually, an N_INDR
-            symbol without N_EXT set is pretty useless).  */
-         if (type == N_INDR)
-           {
-             ++p;
-             ++sym_hash;
-           }
-         continue;
-       }
-
-      /* Ignore N_FN symbols (these appear to have N_EXT set).  */
-      if (type == N_FN)
-       continue;
-
       name = strings + GET_WORD (abfd, p->e_strx);
       value = GET_WORD (abfd, p->e_value);
       flags = BSF_GLOBAL;
@@ -3186,20 +3345,44 @@ aout_link_add_symbols (abfd, info)
        {
        default:
          abort ();
+
+       case N_UNDF:
+       case N_ABS:
+       case N_TEXT:
+       case N_DATA:
+       case N_BSS:
+       case N_FN_SEQ:
+       case N_COMM:
+       case N_SETV:
+       case N_FN:
+         /* Ignore symbols that are not externally visible.  */
+         continue;
+       case N_INDR:
+         /* Ignore local indirect symbol.  */
+         ++p;
+         ++sym_hash;
+         continue;
+
        case N_UNDF | N_EXT:
-         if (value != 0)
-           section = &bfd_com_section;
+         if (value == 0)
+           {
+             section = bfd_und_section_ptr;
+             flags = 0;
+           }
          else
-           section = &bfd_und_section;
+           section = bfd_com_section_ptr;
          break;
        case N_ABS | N_EXT:
-         section = &bfd_abs_section;
+         section = bfd_abs_section_ptr;
          break;
        case N_TEXT | N_EXT:
          section = obj_textsec (abfd);
          value -= bfd_get_section_vma (abfd, section);
          break;
        case N_DATA | N_EXT:
+       case N_SETV | N_EXT:
+         /* Treat N_SETV symbols as N_DATA symbol; see comment in
+            translate_from_native_sym_flags.  */
          section = obj_datasec (abfd);
          value -= bfd_get_section_vma (abfd, section);
          break;
@@ -3213,14 +3396,14 @@ aout_link_add_symbols (abfd, info)
          BFD_ASSERT (p + 1 < pend);
          ++p;
          string = strings + GET_WORD (abfd, p->e_strx);
-         section = &bfd_ind_section;
+         section = bfd_ind_section_ptr;
          flags |= BSF_INDIRECT;
          break;
        case N_COMM | N_EXT:
-         section = &bfd_com_section;
+         section = bfd_com_section_ptr;
          break;
        case N_SETA: case N_SETA | N_EXT:
-         section = &bfd_abs_section;
+         section = bfd_abs_section_ptr;
          flags |= BSF_CONSTRUCTOR;
          break;
        case N_SETT: case N_SETT | N_EXT:
@@ -3245,22 +3428,96 @@ aout_link_add_symbols (abfd, info)
          ++p;
          string = name;
          name = strings + GET_WORD (abfd, p->e_strx);
-         section = &bfd_und_section;
+         section = bfd_und_section_ptr;
          flags |= BSF_WARNING;
          break;
+       case N_WEAKU:
+         section = bfd_und_section_ptr;
+         flags = BSF_WEAK;
+         break;
+       case N_WEAKA:
+         section = bfd_abs_section_ptr;
+         flags = BSF_WEAK;
+         break;
+       case N_WEAKT:
+         section = obj_textsec (abfd);
+         value -= bfd_get_section_vma (abfd, section);
+         flags = BSF_WEAK;
+         break;
+       case N_WEAKD:
+         section = obj_datasec (abfd);
+         value -= bfd_get_section_vma (abfd, section);
+         flags = BSF_WEAK;
+         break;
+       case N_WEAKB:
+         section = obj_bsssec (abfd);
+         value -= bfd_get_section_vma (abfd, section);
+         flags = BSF_WEAK;
+         break;
        }
 
-      if (! (_bfd_generic_link_add_one_symbol
+      if (! ((*add_one_symbol)
             (info, abfd, name, flags, section, value, string, copy, false,
-             ARCH_SIZE, (struct bfd_link_hash_entry **) sym_hash)))
+             (struct bfd_link_hash_entry **) sym_hash)))
        return false;
 
+      /* Restrict the maximum alignment of a common symbol based on
+        the architecture, since a.out has no way to represent
+        alignment requirements of a section in a .o file.  FIXME:
+        This isn't quite right: it should use the architecture of the
+        output file, not the input files.  */
+      if ((*sym_hash)->root.type == bfd_link_hash_common
+         && ((*sym_hash)->root.u.c.p->alignment_power >
+             bfd_get_arch_info (abfd)->section_align_power))
+       (*sym_hash)->root.u.c.p->alignment_power =
+         bfd_get_arch_info (abfd)->section_align_power;
+
+      /* If this is a set symbol, and we are not building sets, then
+        it is possible for the hash entry to not have been set.  In
+        such a case, treat the symbol as not globally defined.  */
+      if ((*sym_hash)->root.type == bfd_link_hash_new)
+       {
+         BFD_ASSERT ((flags & BSF_CONSTRUCTOR) != 0);
+         *sym_hash = NULL;
+       }
+
       if (type == (N_INDR | N_EXT) || type == N_WARNING)
        ++sym_hash;
     }
 
   return true;
 }
+\f
+/* A hash table used for header files with N_BINCL entries.  */
+
+struct aout_link_includes_table
+{
+  struct bfd_hash_table root;
+};
+
+/* A linked list of totals that we have found for a particular header
+   file.  */
+
+struct aout_link_includes_totals
+{
+  struct aout_link_includes_totals *next;
+  bfd_vma total;
+};
+
+/* An entry in the header file hash table.  */
+
+struct aout_link_includes_entry
+{
+  struct bfd_hash_entry root;
+  /* List of totals we have found for this file.  */
+  struct aout_link_includes_totals *totals;
+};
+
+/* Look up an entry in an the header file hash table.  */
+
+#define aout_link_includes_lookup(table, string, create, copy) \
+  ((struct aout_link_includes_entry *) \
+   bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
 
 /* During the final link step we need to pass around a bunch of
    information, so we do it in an instance of this structure.  */
@@ -3276,29 +3533,76 @@ struct aout_final_link_info
   /* File position of symbols.  */
   file_ptr symoff;
   /* String table.  */
-  struct stringtab_data strtab;
+  struct bfd_strtab_hash *strtab;
+  /* Header file hash table.  */
+  struct aout_link_includes_table includes;
+  /* A buffer large enough to hold the contents of any section.  */
+  bfd_byte *contents;
+  /* A buffer large enough to hold the relocs of any section.  */
+  PTR relocs;
+  /* A buffer large enough to hold the symbol map of any input BFD.  */
+  int *symbol_map;
+  /* A buffer large enough to hold output symbols of any input BFD.  */
+  struct external_nlist *output_syms;
 };
 
+static struct bfd_hash_entry *aout_link_includes_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
 static boolean aout_link_input_bfd
   PARAMS ((struct aout_final_link_info *, bfd *input_bfd));
 static boolean aout_link_write_symbols
-  PARAMS ((struct aout_final_link_info *, bfd *input_bfd, int *symbol_map));
+  PARAMS ((struct aout_final_link_info *, bfd *input_bfd));
 static boolean aout_link_write_other_symbol
   PARAMS ((struct aout_link_hash_entry *, PTR));
 static boolean aout_link_input_section
   PARAMS ((struct aout_final_link_info *, bfd *input_bfd,
           asection *input_section, file_ptr *reloff_ptr,
-          bfd_size_type rel_size, int *symbol_map));
+          bfd_size_type rel_size));
 static boolean aout_link_input_section_std
   PARAMS ((struct aout_final_link_info *, bfd *input_bfd,
           asection *input_section, struct reloc_std_external *,
-          bfd_size_type rel_size, bfd_byte *contents, int *symbol_map));
+          bfd_size_type rel_size, bfd_byte *contents));
 static boolean aout_link_input_section_ext
   PARAMS ((struct aout_final_link_info *, bfd *input_bfd,
           asection *input_section, struct reloc_ext_external *,
-          bfd_size_type rel_size, bfd_byte *contents, int *symbol_map));
+          bfd_size_type rel_size, bfd_byte *contents));
 static INLINE asection *aout_reloc_index_to_section
   PARAMS ((bfd *, int));
+static boolean aout_link_reloc_link_order
+  PARAMS ((struct aout_final_link_info *, asection *,
+          struct bfd_link_order *));
+
+/* The function to create a new entry in the header file hash table.  */
+
+static struct bfd_hash_entry *
+aout_link_includes_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  struct aout_link_includes_entry *ret =
+    (struct aout_link_includes_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == (struct aout_link_includes_entry *) NULL)
+    ret = ((struct aout_link_includes_entry *)
+          bfd_hash_allocate (table,
+                             sizeof (struct aout_link_includes_entry)));
+  if (ret == (struct aout_link_includes_entry *) NULL)
+    return (struct bfd_hash_entry *) ret;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct aout_link_includes_entry *)
+        bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+  if (ret)
+    {
+      /* Set local fields.  */
+      ret->totals = NULL;
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
 
 /* Do the final link step.  This is called on the output BFD.  The
    INFO structure should point to a list of BFDs linked through the
@@ -3314,30 +3618,48 @@ NAME(aout,final_link) (abfd, info, callback)
      void (*callback) PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *));
 {
   struct aout_final_link_info aout_info;
+  boolean includes_hash_initialized = false;
   register bfd *sub;
+  bfd_size_type trsize, drsize;
+  size_t max_contents_size;
+  size_t max_relocs_size;
+  size_t max_sym_count;
   bfd_size_type text_size;
   file_ptr text_end;
   register struct bfd_link_order *p;
   asection *o;
+  boolean have_link_order_relocs;
+
+  if (info->shared)
+    abfd->flags |= DYNAMIC;
 
   aout_info.info = info;
   aout_info.output_bfd = abfd;
-
-  if (! info->relocateable)
+  aout_info.contents = NULL;
+  aout_info.relocs = NULL;
+  aout_info.symbol_map = NULL;
+  aout_info.output_syms = NULL;
+
+  if (! bfd_hash_table_init_n (&aout_info.includes.root,
+                              aout_link_includes_newfunc,
+                              251))
+    goto error_return;
+  includes_hash_initialized = true;
+
+  /* Figure out the largest section size.  Also, if generating
+     relocateable output, count the relocs.  */
+  trsize = 0;
+  drsize = 0;
+  max_contents_size = 0;
+  max_relocs_size = 0;
+  max_sym_count = 0;
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
     {
-      exec_hdr (abfd)->a_trsize = 0;
-      exec_hdr (abfd)->a_drsize = 0;
-    }
-  else
-    {
-      bfd_size_type trsize, drsize;
+      size_t sz;
 
-      /* Count up the relocation sizes.  */
-      trsize = 0;
-      drsize = 0;
-      for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
+      if (info->relocateable)
        {
-         if (bfd_get_flavour (abfd) == bfd_target_aout_flavour)
+         if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
            {
              trsize += exec_hdr (sub)->a_trsize;
              drsize += exec_hdr (sub)->a_drsize;
@@ -3348,20 +3670,59 @@ NAME(aout,final_link) (abfd, info, callback)
                 and call get_reloc_upper_bound and canonicalize_reloc to
                 work out the number of relocs needed, and then multiply
                 by the reloc size.  */
-             abort ();
+             (*_bfd_error_handler)
+               (_("%s: relocateable link from %s to %s not supported"),
+                bfd_get_filename (abfd),
+                sub->xvec->name, abfd->xvec->name);
+             bfd_set_error (bfd_error_invalid_operation);
+             goto error_return;
            }
        }
-      exec_hdr (abfd)->a_trsize = trsize;
-      exec_hdr (abfd)->a_drsize = drsize;
+
+      if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
+       {
+         sz = bfd_section_size (sub, obj_textsec (sub));
+         if (sz > max_contents_size)
+           max_contents_size = sz;
+         sz = bfd_section_size (sub, obj_datasec (sub));
+         if (sz > max_contents_size)
+           max_contents_size = sz;
+
+         sz = exec_hdr (sub)->a_trsize;
+         if (sz > max_relocs_size)
+           max_relocs_size = sz;
+         sz = exec_hdr (sub)->a_drsize;
+         if (sz > max_relocs_size)
+           max_relocs_size = sz;
+
+         sz = obj_aout_external_sym_count (sub);
+         if (sz > max_sym_count)
+           max_sym_count = sz;
+       }
+    }
+
+  if (info->relocateable)
+    {
+      if (obj_textsec (abfd) != (asection *) NULL)
+       trsize += (_bfd_count_link_order_relocs (obj_textsec (abfd)
+                                                ->link_order_head)
+                  * obj_reloc_entry_size (abfd));
+      if (obj_datasec (abfd) != (asection *) NULL)
+       drsize += (_bfd_count_link_order_relocs (obj_datasec (abfd)
+                                                ->link_order_head)
+                  * obj_reloc_entry_size (abfd));
     }
 
+  exec_hdr (abfd)->a_trsize = trsize;
+  exec_hdr (abfd)->a_drsize = drsize;
+
   exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd);
 
   /* Adjust the section sizes and vmas according to the magic number.
      This sets a_text, a_data and a_bss in the exec_hdr and sets the
      filepos for each section.  */
   if (! NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
-    return false;
+    goto error_return;
 
   /* The relocation and symbol file positions differ among a.out
      targets.  We are passed a callback routine from the backend
@@ -3381,7 +3742,35 @@ NAME(aout,final_link) (abfd, info, callback)
   obj_aout_external_sym_count (abfd) = 0;
 
   /* We accumulate the string table as we write out the symbols.  */
-  stringtab_init (&aout_info.strtab);
+  aout_info.strtab = _bfd_stringtab_init ();
+  if (aout_info.strtab == NULL)
+    goto error_return;
+
+  /* Allocate buffers to hold section contents and relocs.  */
+  aout_info.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+  aout_info.relocs = (PTR) bfd_malloc (max_relocs_size);
+  aout_info.symbol_map = (int *) bfd_malloc (max_sym_count * sizeof (int *));
+  aout_info.output_syms = ((struct external_nlist *)
+                          bfd_malloc ((max_sym_count + 1)
+                                      * sizeof (struct external_nlist)));
+  if ((aout_info.contents == NULL && max_contents_size != 0)
+      || (aout_info.relocs == NULL && max_relocs_size != 0)
+      || (aout_info.symbol_map == NULL && max_sym_count != 0)
+      || aout_info.output_syms == NULL)
+    goto error_return;
+
+  /* If we have a symbol named __DYNAMIC, force it out now.  This is
+     required by SunOS.  Doing this here rather than in sunos.c is a
+     hack, but it's easier than exporting everything which would be
+     needed.  */
+  {
+    struct aout_link_hash_entry *h;
+
+    h = aout_link_hash_lookup (aout_hash_table (info), "__DYNAMIC",
+                              false, false, false);
+    if (h != NULL)
+      aout_link_write_other_symbol (h, &aout_info);
+  }
 
   /* The most time efficient way to do the link would be to read all
      the input object files into memory and then sort out the
@@ -3407,19 +3796,26 @@ NAME(aout,final_link) (abfd, info, callback)
   for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
     sub->output_has_begun = false;
 
+  /* Mark all sections which are to be included in the link.  This
+     will normally be every section.  We need to do this so that we
+     can identify any sections which the linker has decided to not
+     include.  */
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      for (p = o->link_order_head; p != NULL; p = p->next)
+       {
+         if (p->type == bfd_indirect_link_order)
+           p->u.indirect.section->linker_mark = true;
+       }
+    }
+
+  have_link_order_relocs = false;
   for (o = abfd->sections; o != (asection *) NULL; o = o->next)
     {
       for (p = o->link_order_head;
           p != (struct bfd_link_order *) NULL;
           p = p->next)
        {
-         /* If we might be using the C based alloca function, we need
-            to dump the memory allocated by aout_link_input_bfd.  */
-#ifndef __GNUC__
-#ifndef alloca
-         (void) alloca (0);
-#endif
-#endif
          if (p->type == bfd_indirect_link_order
              && (bfd_get_flavour (p->u.indirect.section->owner)
                  == bfd_target_aout_flavour))
@@ -3430,14 +3826,20 @@ NAME(aout,final_link) (abfd, info, callback)
              if (! input_bfd->output_has_begun)
                {
                  if (! aout_link_input_bfd (&aout_info, input_bfd))
-                   return false;
+                   goto error_return;
                  input_bfd->output_has_begun = true;
                }
            }
+         else if (p->type == bfd_section_reloc_link_order
+                  || p->type == bfd_symbol_reloc_link_order)
+           {
+             /* These are handled below.  */
+             have_link_order_relocs = true;
+           }
          else
            {
              if (! _bfd_default_link_order (abfd, info, o, p))
-               return false;
+               goto error_return;
            }
        }
     }
@@ -3447,6 +3849,61 @@ NAME(aout,final_link) (abfd, info, callback)
                           aout_link_write_other_symbol,
                           (PTR) &aout_info);
 
+  /* Now handle any relocs we were asked to create by the linker.
+     These did not come from any input file.  We must do these after
+     we have written out all the symbols, so that we know the symbol
+     indices to use.  */
+  if (have_link_order_relocs)
+    {
+      for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+       {
+         for (p = o->link_order_head;
+              p != (struct bfd_link_order *) NULL;
+              p = p->next)
+           {
+             if (p->type == bfd_section_reloc_link_order
+                 || p->type == bfd_symbol_reloc_link_order)
+               {
+                 if (! aout_link_reloc_link_order (&aout_info, o, p))
+                   goto error_return;
+               }
+           }
+       }
+    }
+
+  if (aout_info.contents != NULL)
+    {
+      free (aout_info.contents);
+      aout_info.contents = NULL;
+    }
+  if (aout_info.relocs != NULL)
+    {
+      free (aout_info.relocs);
+      aout_info.relocs = NULL;
+    }
+  if (aout_info.symbol_map != NULL)
+    {
+      free (aout_info.symbol_map);
+      aout_info.symbol_map = NULL;
+    }
+  if (aout_info.output_syms != NULL)
+    {
+      free (aout_info.output_syms);
+      aout_info.output_syms = NULL;
+    }
+  if (includes_hash_initialized)
+    {
+      bfd_hash_table_free (&aout_info.includes.root);
+      includes_hash_initialized = false;
+    }
+
+  /* Finish up any dynamic linking we may be doing.  */
+  if (aout_backend_info (abfd)->finish_dynamic_link != NULL)
+    {
+      if (! (*aout_backend_info (abfd)->finish_dynamic_link) (abfd, info))
+       goto error_return;
+    }
+
   /* Update the header information.  */
   abfd->symcount = obj_aout_external_sym_count (abfd);
   exec_hdr (abfd)->a_syms = abfd->symcount * EXTERNAL_NLIST_SIZE;
@@ -3456,12 +3913,42 @@ NAME(aout,final_link) (abfd, info, callback)
   obj_datasec (abfd)->reloc_count =
     exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd);
 
-  /* Write out the string table.  */
-  if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0)
-    return false;
-  emit_strtab (abfd, &aout_info.strtab);
+  /* Write out the string table, unless there are no symbols.  */
+  if (abfd->symcount > 0)
+    {
+      if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
+         || ! emit_stringtab (abfd, aout_info.strtab))
+       goto error_return;
+    }
+  else if (obj_textsec (abfd)->reloc_count == 0
+          && obj_datasec (abfd)->reloc_count == 0)
+    {
+      bfd_byte b;
+
+      b = 0;
+      if (bfd_seek (abfd,
+                   (obj_datasec (abfd)->filepos
+                    + exec_hdr (abfd)->a_data
+                    - 1),
+                   SEEK_SET) != 0
+         || bfd_write (&b, 1, 1, abfd) != 1)
+       goto error_return;
+    }
 
   return true;
+
+ error_return:
+  if (aout_info.contents != NULL)
+    free (aout_info.contents);
+  if (aout_info.relocs != NULL)
+    free (aout_info.relocs);
+  if (aout_info.symbol_map != NULL)
+    free (aout_info.symbol_map);
+  if (aout_info.output_syms != NULL)
+    free (aout_info.output_syms);
+  if (includes_hash_initialized)
+    bfd_hash_table_free (&aout_info.includes.root);
+  return false;
 }
 
 /* Link an a.out input BFD into the output file.  */
@@ -3472,34 +3959,49 @@ aout_link_input_bfd (finfo, input_bfd)
      bfd *input_bfd;
 {
   bfd_size_type sym_count;
-  int *symbol_map;
 
   BFD_ASSERT (bfd_get_format (input_bfd) == bfd_object);
 
+  /* If this is a dynamic object, it may need special handling.  */
+  if ((input_bfd->flags & DYNAMIC) != 0
+      && aout_backend_info (input_bfd)->link_dynamic_object != NULL)
+    {
+      return ((*aout_backend_info (input_bfd)->link_dynamic_object)
+             (finfo->info, input_bfd));
+    }
+
   /* Get the symbols.  We probably have them already, unless
      finfo->info->keep_memory is false.  */
-  if (! aout_link_get_symbols (input_bfd))
+  if (! aout_get_external_symbols (input_bfd))
     return false;
 
   sym_count = obj_aout_external_sym_count (input_bfd);
-  symbol_map = (int *) alloca ((size_t) sym_count * sizeof (int));
 
-  /* Write out the symbols and get a map of the new indices.  */
-  if (! aout_link_write_symbols (finfo, input_bfd, symbol_map))
+  /* Write out the symbols and get a map of the new indices.  The map
+     is placed into finfo->symbol_map.  */
+  if (! aout_link_write_symbols (finfo, input_bfd))
     return false;
 
-  /* Relocate and write out the sections.  */
-  if (! aout_link_input_section (finfo, input_bfd,
-                                obj_textsec (input_bfd),
-                                &finfo->treloff,
-                                exec_hdr (input_bfd)->a_trsize,
-                                symbol_map)
-      || ! aout_link_input_section (finfo, input_bfd,
-                                   obj_datasec (input_bfd),
-                                   &finfo->dreloff,
-                                   exec_hdr (input_bfd)->a_drsize,
-                                   symbol_map))
-    return false;
+  /* Relocate and write out the sections.  These functions use the
+     symbol map created by aout_link_write_symbols.  The linker_mark
+     field will be set if these sections are to be included in the
+     link, which will normally be the case.  */
+  if (obj_textsec (input_bfd)->linker_mark)
+    {
+      if (! aout_link_input_section (finfo, input_bfd,
+                                    obj_textsec (input_bfd),
+                                    &finfo->treloff,
+                                    exec_hdr (input_bfd)->a_trsize))
+       return false;
+    }
+  if (obj_datasec (input_bfd)->linker_mark)
+    {
+      if (! aout_link_input_section (finfo, input_bfd,
+                                    obj_datasec (input_bfd),
+                                    &finfo->dreloff,
+                                    exec_hdr (input_bfd)->a_drsize))
+       return false;
+    }
 
   /* If we are not keeping memory, we don't need the symbols any
      longer.  We still need them if we are keeping memory, because the
@@ -3517,32 +4019,30 @@ aout_link_input_bfd (finfo, input_bfd)
    symbol indices into a symbol_map.  */
 
 static boolean
-aout_link_write_symbols (finfo, input_bfd, symbol_map)
+aout_link_write_symbols (finfo, input_bfd)
      struct aout_final_link_info *finfo;
      bfd *input_bfd;
-     int *symbol_map;
 {
   bfd *output_bfd;
   bfd_size_type sym_count;
   char *strings;
   enum bfd_link_strip strip;
   enum bfd_link_discard discard;
-  struct external_nlist *output_syms;
   struct external_nlist *outsym;
+  bfd_size_type strtab_index;
   register struct external_nlist *sym;
   struct external_nlist *sym_end;
   struct aout_link_hash_entry **sym_hash;
+  int *symbol_map;
   boolean pass;
-  boolean skip_indirect;
+  boolean skip_next;
 
   output_bfd = finfo->output_bfd;
   sym_count = obj_aout_external_sym_count (input_bfd);
   strings = obj_aout_external_strings (input_bfd);
   strip = finfo->info->strip;
   discard = finfo->info->discard;
-  output_syms = ((struct external_nlist *)
-                alloca ((size_t) (sym_count + 1) * EXTERNAL_NLIST_SIZE));
-  outsym = output_syms;
+  outsym = finfo->output_syms;
 
   /* First write out a symbol for this object file, unless we are
      discarding such symbols.  */
@@ -3555,35 +4055,54 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
       bfd_h_put_8 (output_bfd, N_TEXT, outsym->e_type);
       bfd_h_put_8 (output_bfd, 0, outsym->e_other);
       bfd_h_put_16 (output_bfd, (bfd_vma) 0, outsym->e_desc);
+      strtab_index = add_to_stringtab (output_bfd, finfo->strtab,
+                                      input_bfd->filename, false);
+      if (strtab_index == (bfd_size_type) -1)
+       return false;
+      PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
       PUT_WORD (output_bfd,
-               add_to_stringtab (output_bfd, input_bfd->filename,
-                                 &finfo->strtab),
-               outsym->e_strx);
-      PUT_WORD (output_bfd,
-               bfd_get_section_vma (input_bfd, obj_textsec (input_bfd)),
+               (bfd_get_section_vma (output_bfd,
+                                     obj_textsec (input_bfd)->output_section)
+                + obj_textsec (input_bfd)->output_offset),
                outsym->e_value);
       ++obj_aout_external_sym_count (output_bfd);
       ++outsym;
     }
 
   pass = false;
-  skip_indirect = false;
+  skip_next = false;
   sym = obj_aout_external_syms (input_bfd);
   sym_end = sym + sym_count;
   sym_hash = obj_aout_sym_hashes (input_bfd);
+  symbol_map = finfo->symbol_map;
+  memset (symbol_map, 0, sym_count * sizeof *symbol_map);
   for (; sym < sym_end; sym++, sym_hash++, symbol_map++)
     {
       const char *name;
       int type;
+      struct aout_link_hash_entry *h;
       boolean skip;
       asection *symsec;
       bfd_vma val = 0;
+      boolean copy;
+
+      /* We set *symbol_map to 0 above for all symbols.  If it has
+         already been set to -1 for this symbol, it means that we are
+         discarding it because it appears in a duplicate header file.
+         See the N_BINCL code below.  */
+      if (*symbol_map == -1)
+       continue;
 
+      /* Initialize *symbol_map to -1, which means that the symbol was
+         not copied into the output file.  We will change it later if
+         we do copy the symbol over.  */
       *symbol_map = -1;
 
       type = bfd_h_get_8 (input_bfd, sym->e_type);
       name = strings + GET_WORD (input_bfd, sym->e_strx);
 
+      h = NULL;
+
       if (pass)
        {
          /* Pass this symbol through.  It is the target of an
@@ -3591,17 +4110,16 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
          val = GET_WORD (input_bfd, sym->e_value);
          pass = false;
        }
-      else if (skip_indirect)
+      else if (skip_next)
        {
          /* Skip this symbol, which is the target of an indirect
             symbol that we have changed to no longer be an indirect
             symbol.  */
-         skip_indirect = false;
+         skip_next = false;
          continue;
        }
       else
        {
-         struct aout_link_hash_entry *h;
          struct aout_link_hash_entry *hresolve;
 
          /* We have saved the hash table entry for this symbol, if
@@ -3610,6 +4128,11 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
             external symbol. */
          h = *sym_hash;
 
+         /* Use the name from the hash table, in case the symbol was
+             wrapped.  */
+         if (h != NULL)
+           name = h->root.root.string;
+
          /* If this is an indirect or warning symbol, then change
             hresolve to the base symbol.  We also change *sym_hash so
             that the relocation routines relocate against the real
@@ -3620,7 +4143,8 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
                  || h->root.type == bfd_link_hash_warning))
            {
              hresolve = (struct aout_link_hash_entry *) h->root.u.i.link;
-             while (hresolve->root.type == bfd_link_hash_indirect)
+             while (hresolve->root.type == bfd_link_hash_indirect
+                    || hresolve->root.type == bfd_link_hash_warning)
                hresolve = ((struct aout_link_hash_entry *)
                            hresolve->root.u.i.link);
              *sym_hash = hresolve;
@@ -3628,8 +4152,12 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
 
          /* If the symbol has already been written out, skip it.  */
          if (h != (struct aout_link_hash_entry *) NULL
-             && h->root.written)
+             && h->root.type != bfd_link_hash_warning
+             && h->written)
            {
+             if ((type & N_TYPE) == N_INDR
+                 || type == N_WARNING)
+               skip_next = true;
              *symbol_map = h->indx;
              continue;
            }
@@ -3656,22 +4184,27 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
          if (skip)
            {
              if (h != (struct aout_link_hash_entry *) NULL)
-               h->root.written = true;
+               h->written = true;
              continue;
            }
 
          /* Get the value of the symbol.  */
-         if ((type & N_TYPE) == N_TEXT)
+         if ((type & N_TYPE) == N_TEXT
+             || type == N_WEAKT)
            symsec = obj_textsec (input_bfd);
-         else if ((type & N_TYPE) == N_DATA)
+         else if ((type & N_TYPE) == N_DATA
+                  || type == N_WEAKD)
            symsec = obj_datasec (input_bfd);
-         else if ((type & N_TYPE) == N_BSS)
+         else if ((type & N_TYPE) == N_BSS
+                  || type == N_WEAKB)
            symsec = obj_bsssec (input_bfd);
-         else if ((type & N_TYPE) == N_ABS)
-           symsec = &bfd_abs_section;
+         else if ((type & N_TYPE) == N_ABS
+                  || type == N_WEAKA)
+           symsec = bfd_abs_section_ptr;
          else if (((type & N_TYPE) == N_INDR
                    && (hresolve == (struct aout_link_hash_entry *) NULL
                        || (hresolve->root.type != bfd_link_hash_defined
+                           && hresolve->root.type != bfd_link_hash_defweak
                            && hresolve->root.type != bfd_link_hash_common)))
                   || type == N_WARNING)
            {
@@ -3696,23 +4229,45 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
                 a case we do not want to output the next symbol,
                 which is the target of the indirection.  */
              if ((type & N_TYPE) == N_INDR)
-               skip_indirect = true;
+               skip_next = true;
+
+             symsec = NULL;
 
              /* We need to get the value from the hash table.  We use
                 hresolve so that if we have defined an indirect
                 symbol we output the final definition.  */
              if (h == (struct aout_link_hash_entry *) NULL)
-               val = 0;
-             else if (hresolve->root.type == bfd_link_hash_defined)
+               {
+                 switch (type & N_TYPE)
+                   {
+                   case N_SETT:
+                     symsec = obj_textsec (input_bfd);
+                     break;
+                   case N_SETD:
+                     symsec = obj_datasec (input_bfd);
+                     break;
+                   case N_SETB:
+                     symsec = obj_bsssec (input_bfd);
+                     break;
+                   case N_SETA:
+                     symsec = bfd_abs_section_ptr;
+                     break;
+                   default:
+                     val = 0;
+                     break;
+                   }
+               }
+             else if (hresolve->root.type == bfd_link_hash_defined
+                      || hresolve->root.type == bfd_link_hash_defweak)
                {
                  asection *input_section;
                  asection *output_section;
 
-                 /* This case means a common symbol which was turned
-                    into a defined symbol.  */
+                 /* This case usually means a common symbol which was
+                    turned into a defined symbol.  */
                  input_section = hresolve->root.u.def.section;
                  output_section = input_section->output_section;
-                 BFD_ASSERT (output_section == &bfd_abs_section
+                 BFD_ASSERT (bfd_is_abs_section (output_section)
                              || output_section->owner == output_bfd);
                  val = (hresolve->root.u.def.value
                         + bfd_get_section_vma (output_bfd, output_section)
@@ -3730,20 +4285,31 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
                  type &=~ N_TYPE;
 
                  if (output_section == obj_textsec (output_bfd))
-                   type |= N_TEXT;
+                   type |= (hresolve->root.type == bfd_link_hash_defined
+                            ? N_TEXT
+                            : N_WEAKT);
                  else if (output_section == obj_datasec (output_bfd))
-                   type |= N_DATA;
+                   type |= (hresolve->root.type == bfd_link_hash_defined
+                            ? N_DATA
+                            : N_WEAKD);
                  else if (output_section == obj_bsssec (output_bfd))
-                   type |= N_BSS;
+                   type |= (hresolve->root.type == bfd_link_hash_defined
+                            ? N_BSS
+                            : N_WEAKB);
                  else
-                   type |= N_ABS;
+                   type |= (hresolve->root.type == bfd_link_hash_defined
+                            ? N_ABS
+                            : N_WEAKA);
                }
              else if (hresolve->root.type == bfd_link_hash_common)
                val = hresolve->root.u.c.size;
+             else if (hresolve->root.type == bfd_link_hash_undefweak)
+               {
+                 val = 0;
+                 type = N_WEAKU;
+               }
              else
                val = 0;
-
-             symsec = NULL;
            }
          if (symsec != (asection *) NULL)
            val = (symsec->output_section->vma
@@ -3755,20 +4321,21 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
             it is a local symbol see if we should discard it.  */
          if (h != (struct aout_link_hash_entry *) NULL)
            {
-             h->root.written = true;
+             h->written = true;
              h->indx = obj_aout_external_sym_count (output_bfd);
            }
-         else
+         else if ((type & N_TYPE) != N_SETT
+                  && (type & N_TYPE) != N_SETD
+                  && (type & N_TYPE) != N_SETB
+                  && (type & N_TYPE) != N_SETA)
            {
              switch (discard)
                {
                case discard_none:
                  break;
                case discard_l:
-                 if (*name == *finfo->info->lprefix
-                     && (finfo->info->lprefix_len == 1
-                         || strncmp (name, finfo->info->lprefix,
-                                     finfo->info->lprefix_len) == 0))
+                 if ((type & N_STAB) == 0
+                     && bfd_is_local_label_name (input_bfd, name))
                    skip = true;
                  break;
                case discard_all:
@@ -3781,6 +4348,112 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
                  continue;
                }
            }
+
+         /* An N_BINCL symbol indicates the start of the stabs
+            entries for a header file.  We need to scan ahead to the
+            next N_EINCL symbol, ignoring nesting, adding up all the
+            characters in the symbol names, not including the file
+            numbers in types (the first number after an open
+            parenthesis).  */
+         if (type == N_BINCL)
+           {
+             struct external_nlist *incl_sym;
+             int nest;
+             struct aout_link_includes_entry *incl_entry;
+             struct aout_link_includes_totals *t;
+
+             val = 0;
+             nest = 0;
+             for (incl_sym = sym + 1; incl_sym < sym_end; incl_sym++)
+               {
+                 int incl_type;
+
+                 incl_type = bfd_h_get_8 (input_bfd, incl_sym->e_type);
+                 if (incl_type == N_EINCL)
+                   {
+                     if (nest == 0)
+                       break;
+                     --nest;
+                   }
+                 else if (incl_type == N_BINCL)
+                   ++nest;
+                 else if (nest == 0)
+                   {
+                     const char *s;
+
+                     s = strings + GET_WORD (input_bfd, incl_sym->e_strx);
+                     for (; *s != '\0'; s++)
+                       {
+                         val += *s;
+                         if (*s == '(')
+                           {
+                             /* Skip the file number.  */
+                             ++s;
+                             while (isdigit ((unsigned char) *s))
+                               ++s;
+                             --s;
+                           }
+                       }
+                   }
+               }
+
+             /* If we have already included a header file with the
+                 same value, then replace this one with an N_EXCL
+                 symbol.  */
+             copy = ! finfo->info->keep_memory;
+             incl_entry = aout_link_includes_lookup (&finfo->includes,
+                                                     name, true, copy);
+             if (incl_entry == NULL)
+               return false;
+             for (t = incl_entry->totals; t != NULL; t = t->next)
+               if (t->total == val)
+                 break;
+             if (t == NULL)
+               {
+                 /* This is the first time we have seen this header
+                     file with this set of stabs strings.  */
+                 t = ((struct aout_link_includes_totals *)
+                      bfd_hash_allocate (&finfo->includes.root,
+                                         sizeof *t));
+                 if (t == NULL)
+                   return false;
+                 t->total = val;
+                 t->next = incl_entry->totals;
+                 incl_entry->totals = t;
+               }
+             else
+               {
+                 int *incl_map;
+
+                 /* This is a duplicate header file.  We must change
+                     it to be an N_EXCL entry, and mark all the
+                     included symbols to prevent outputting them.  */
+                 type = N_EXCL;
+
+                 nest = 0;
+                 for (incl_sym = sym + 1, incl_map = symbol_map + 1;
+                      incl_sym < sym_end;
+                      incl_sym++, incl_map++)
+                   {
+                     int incl_type;
+
+                     incl_type = bfd_h_get_8 (input_bfd, incl_sym->e_type);
+                     if (incl_type == N_EINCL)
+                       {
+                         if (nest == 0)
+                           {
+                             *incl_map = -1;
+                             break;
+                           }
+                         --nest;
+                       }
+                     else if (incl_type == N_BINCL)
+                       ++nest;
+                     else if (nest == 0)
+                       *incl_map = -1;
+                   }
+               }
+           }
        }
 
       /* Copy this symbol into the list of symbols we are going to
@@ -3790,9 +4463,22 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
                   outsym->e_other);
       bfd_h_put_16 (output_bfd, bfd_h_get_16 (input_bfd, sym->e_desc),
                    outsym->e_desc);
-      PUT_WORD (output_bfd,
-               add_to_stringtab (output_bfd, name, &finfo->strtab),
-               outsym->e_strx);
+      copy = false;
+      if (! finfo->info->keep_memory)
+       {
+         /* name points into a string table which we are going to
+            free.  If there is a hash table entry, use that string.
+            Otherwise, copy name into memory.  */
+         if (h != (struct aout_link_hash_entry *) NULL)
+           name = h->root.root.string;
+         else
+           copy = true;
+       }
+      strtab_index = add_to_stringtab (output_bfd, finfo->strtab,
+                                      name, copy);
+      if (strtab_index == (bfd_size_type) -1)
+       return false;
+      PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
       PUT_WORD (output_bfd, val, outsym->e_value);
       *symbol_map = obj_aout_external_sym_count (output_bfd);
       ++obj_aout_external_sym_count (output_bfd);
@@ -3800,14 +4486,15 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
     }
 
   /* Write out the output symbols we have just constructed.  */
-  if (outsym > output_syms)
+  if (outsym > finfo->output_syms)
     {
       bfd_size_type outsym_count;
 
       if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0)
        return false;
-      outsym_count = outsym - output_syms;
-      if (bfd_write ((PTR) output_syms, (bfd_size_type) EXTERNAL_NLIST_SIZE,
+      outsym_count = outsym - finfo->output_syms;
+      if (bfd_write ((PTR) finfo->output_syms,
+                    (bfd_size_type) EXTERNAL_NLIST_SIZE,
                     (bfd_size_type) outsym_count, output_bfd)
          != outsym_count * EXTERNAL_NLIST_SIZE)
        return false;
@@ -3830,47 +4517,76 @@ aout_link_write_other_symbol (h, data)
   int type;
   bfd_vma val;
   struct external_nlist outsym;
+  bfd_size_type indx;
+
+  output_bfd = finfo->output_bfd;
+
+  if (aout_backend_info (output_bfd)->write_dynamic_symbol != NULL)
+    {
+      if (! ((*aout_backend_info (output_bfd)->write_dynamic_symbol)
+            (output_bfd, finfo->info, h)))
+       {
+         /* FIXME: No way to handle errors.  */
+         abort ();
+       }
+    }
 
-  if (h->root.written)
+  if (h->written)
     return true;
 
-  output_bfd = finfo->output_bfd;
+  h->written = true;
+
+  /* An indx of -2 means the symbol must be written.  */
+  if (h->indx != -2
+      && (finfo->info->strip == strip_all
+         || (finfo->info->strip == strip_some
+             && bfd_hash_lookup (finfo->info->keep_hash, h->root.root.string,
+                                 false, false) == NULL)))
+    return true;
 
   switch (h->root.type)
     {
     default:
-    case bfd_link_hash_new:
       abort ();
       /* Avoid variable not initialized warnings.  */
       return true;
+    case bfd_link_hash_new:
+      /* This can happen for set symbols when sets are not being
+         built.  */
+      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;
 
-       sec = h->root.u.def.section;
-       BFD_ASSERT (sec == &bfd_abs_section
+       sec = h->root.u.def.section->output_section;
+       BFD_ASSERT (bfd_is_abs_section (sec)
                    || sec->owner == output_bfd);
        if (sec == obj_textsec (output_bfd))
-         type = N_TEXT | N_EXT;
+         type = h->root.type == bfd_link_hash_defined ? N_TEXT : N_WEAKT;
        else if (sec == obj_datasec (output_bfd))
-         type = N_DATA | N_EXT;
+         type = h->root.type == bfd_link_hash_defined ? N_DATA : N_WEAKD;
        else if (sec == obj_bsssec (output_bfd))
-         type = N_BSS | N_EXT;
+         type = h->root.type == bfd_link_hash_defined ? N_BSS : N_WEAKB;
        else
-         type = N_ABS | N_EXT;
+         type = h->root.type == bfd_link_hash_defined ? N_ABS : N_WEAKA;
+       type |= N_EXT;
        val = (h->root.u.def.value
-              + sec->output_section->vma
-              + sec->output_offset);
+              + sec->vma
+              + h->root.u.def.section->output_offset);
       }
       break;
     case bfd_link_hash_common:
       type = N_UNDF | N_EXT;
       val = h->root.u.c.size;
       break;
+    case bfd_link_hash_undefweak:
+      type = N_WEAKU;
+      val = 0;
     case bfd_link_hash_indirect:
     case bfd_link_hash_warning:
       /* FIXME: Ignore these for now.  The circumstances under which
@@ -3881,9 +4597,14 @@ aout_link_write_other_symbol (h, data)
   bfd_h_put_8 (output_bfd, type, outsym.e_type);
   bfd_h_put_8 (output_bfd, 0, outsym.e_other);
   bfd_h_put_16 (output_bfd, 0, outsym.e_desc);
-  PUT_WORD (output_bfd,
-           add_to_stringtab (output_bfd, h->root.root.string, &finfo->strtab),
-           outsym.e_strx);
+  indx = add_to_stringtab (output_bfd, finfo->strtab, h->root.root.string,
+                          false);
+  if (indx == (bfd_size_type) -1)
+    {
+      /* FIXME: No way to handle errors.  */
+      abort ();
+    }
+  PUT_WORD (output_bfd, indx, outsym.e_strx);
   PUT_WORD (output_bfd, val, outsym.e_value);
 
   if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0
@@ -3905,58 +4626,65 @@ aout_link_write_other_symbol (h, data)
 
 static boolean
 aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr,
-                        rel_size, symbol_map)
+                        rel_size)
      struct aout_final_link_info *finfo;
      bfd *input_bfd;
      asection *input_section;
      file_ptr *reloff_ptr;
      bfd_size_type rel_size;
-     int *symbol_map;
 {
   bfd_size_type input_size;
-  bfd_byte *contents;
   PTR relocs;
 
   /* Get the section contents.  */
   input_size = bfd_section_size (input_bfd, input_section);
-  contents = (bfd_byte *) alloca (input_size);
-  if (! bfd_get_section_contents (input_bfd, input_section, (PTR) contents,
+  if (! bfd_get_section_contents (input_bfd, input_section,
+                                 (PTR) finfo->contents,
                                  (file_ptr) 0, input_size))
     return false;
 
-  /* Read in the relocs.  */
-  relocs = (PTR) alloca (rel_size);
-  if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
-      || bfd_read (relocs, 1, rel_size, input_bfd) != rel_size)
-    return false;
+  /* Read in the relocs if we haven't already done it.  */
+  if (aout_section_data (input_section) != NULL
+      && aout_section_data (input_section)->relocs != NULL)
+    relocs = aout_section_data (input_section)->relocs;
+  else
+    {
+      relocs = finfo->relocs;
+      if (rel_size > 0)
+       {
+         if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
+             || bfd_read (relocs, 1, rel_size, input_bfd) != rel_size)
+           return false;
+       }
+    }
 
   /* Relocate the section contents.  */
   if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
     {
       if (! aout_link_input_section_std (finfo, input_bfd, input_section,
                                         (struct reloc_std_external *) relocs,
-                                        rel_size, contents, symbol_map))
+                                        rel_size, finfo->contents))
        return false;
     }
   else
     {
       if (! aout_link_input_section_ext (finfo, input_bfd, input_section,
                                         (struct reloc_ext_external *) relocs,
-                                        rel_size, contents, symbol_map))
+                                        rel_size, finfo->contents))
        return false;
     }
 
   /* Write out the section contents.  */
   if (! bfd_set_section_contents (finfo->output_bfd,
                                  input_section->output_section,
-                                 (PTR) contents,
+                                 (PTR) finfo->contents,
                                  input_section->output_offset,
                                  input_size))
     return false;
 
   /* If we are producing relocateable output, the relocs were
      modified, and we now write them out.  */
-  if (finfo->info->relocateable)
+  if (finfo->info->relocateable && rel_size > 0)
     {
       if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0)
        return false;
@@ -3993,44 +4721,54 @@ aout_reloc_index_to_section (abfd, indx)
     case N_BSS:
       return obj_bsssec (abfd);
     case N_ABS:
-      return &bfd_abs_section;
+    case N_UNDF:
+      return bfd_abs_section_ptr;
     default:
       abort ();
     }
+  /*NOTREACHED*/
+  return NULL;
 }
 
 /* Relocate an a.out section using standard a.out relocs.  */
 
 static boolean
 aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
-                            rel_size, contents, symbol_map)
+                            rel_size, contents)
      struct aout_final_link_info *finfo;
      bfd *input_bfd;
      asection *input_section;
      struct reloc_std_external *relocs;
      bfd_size_type rel_size;
      bfd_byte *contents;
-     int *symbol_map;
 {
+  boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *,
+                                         bfd *, asection *,
+                                         struct aout_link_hash_entry *,
+                                         PTR, bfd_byte *, boolean *,
+                                         bfd_vma *));
   bfd *output_bfd;
   boolean relocateable;
   struct external_nlist *syms;
   char *strings;
   struct aout_link_hash_entry **sym_hashes;
+  int *symbol_map;
   bfd_size_type reloc_count;
   register struct reloc_std_external *rel;
   struct reloc_std_external *rel_end;
 
   output_bfd = finfo->output_bfd;
+  check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
 
   BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE);
-  BFD_ASSERT (input_bfd->xvec->header_byteorder_big_p
-             == output_bfd->xvec->header_byteorder_big_p);
+  BFD_ASSERT (input_bfd->xvec->header_byteorder
+             == output_bfd->xvec->header_byteorder);
 
   relocateable = finfo->info->relocateable;
   syms = obj_aout_external_syms (input_bfd);
   strings = obj_aout_external_strings (input_bfd);
   sym_hashes = obj_aout_sym_hashes (input_bfd);
+  symbol_map = finfo->symbol_map;
 
   reloc_count = rel_size / RELOC_STD_SIZE;
   rel = relocs;
@@ -4041,47 +4779,59 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
       int r_index;
       int r_extern;
       int r_pcrel;
-      int r_baserel;
-      int r_jmptable;
-      int r_relative;
-      int r_length;
-      int howto_idx;
+      int r_baserel = 0;
+      reloc_howto_type *howto;
+      struct aout_link_hash_entry *h = NULL;
       bfd_vma relocation;
       bfd_reloc_status_type r;
 
       r_addr = GET_SWORD (input_bfd, rel->r_address);
 
-      if (input_bfd->xvec->header_byteorder_big_p)
-       {
-         r_index   =  ((rel->r_index[0] << 16)
-                       | (rel->r_index[1] << 8)
-                       | rel->r_index[2]);
-         r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
-         r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
-         r_baserel = (0 != (rel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
-         r_jmptable= (0 != (rel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
-         r_relative= (0 != (rel->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
-         r_length  = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
-                      >> RELOC_STD_BITS_LENGTH_SH_BIG);
-       }
-      else
-       {
-         r_index   = ((rel->r_index[2] << 16)
-                      | (rel->r_index[1] << 8)
-                      | rel->r_index[0]);
-         r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
-         r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
-         r_baserel = (0 != (rel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
-         r_jmptable= (0 != (rel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
-         r_relative= (0 != (rel->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE));
-         r_length  = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
-                      >> RELOC_STD_BITS_LENGTH_SH_LITTLE);
-       }
+#ifdef MY_reloc_howto
+      howto = MY_reloc_howto(input_bfd, rel, r_index, r_extern, r_pcrel);
+#else      
+      {
+       int r_jmptable;
+       int r_relative;
+       int r_length;
+       unsigned int howto_idx;
+
+       if (bfd_header_big_endian (input_bfd))
+         {
+           r_index   =  ((rel->r_index[0] << 16)
+                         | (rel->r_index[1] << 8)
+                         | rel->r_index[2]);
+           r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
+           r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
+           r_baserel = (0 != (rel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
+           r_jmptable= (0 != (rel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
+           r_relative= (0 != (rel->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
+           r_length  = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
+                        >> RELOC_STD_BITS_LENGTH_SH_BIG);
+         }
+       else
+         {
+           r_index   = ((rel->r_index[2] << 16)
+                        | (rel->r_index[1] << 8)
+                        | rel->r_index[0]);
+           r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
+           r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
+           r_baserel = (0 != (rel->r_type[0]
+                              & RELOC_STD_BITS_BASEREL_LITTLE));
+           r_jmptable= (0 != (rel->r_type[0]
+                              & RELOC_STD_BITS_JMPTABLE_LITTLE));
+           r_relative= (0 != (rel->r_type[0]
+                              & RELOC_STD_BITS_RELATIVE_LITTLE));
+           r_length  = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
+                        >> RELOC_STD_BITS_LENGTH_SH_LITTLE);
+         }
 
-      howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel;
-      BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
-      BFD_ASSERT (r_jmptable == 0);
-      BFD_ASSERT (r_relative == 0);
+       howto_idx = (r_length + 4 * r_pcrel + 8 * r_baserel
+                    + 16 * r_jmptable + 32 * r_relative);
+       BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
+       howto = howto_table_std + howto_idx;
+      }
+#endif
 
       if (relocateable)
        {
@@ -4089,19 +4839,18 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
             modify the reloc accordingly.  */
          if (r_extern)
            {
-             struct aout_link_hash_entry *h;
-
              /* If we know the symbol this relocation is against,
                 convert it into a relocation against a section.  This
                 is what the native linker does.  */
              h = sym_hashes[r_index];
              if (h != (struct aout_link_hash_entry *) NULL
-                 && h->root.type == bfd_link_hash_defined)
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak))
                {
                  asection *output_section;
 
                  /* Change the r_extern value.  */
-                 if (output_bfd->xvec->header_byteorder_big_p)
+                 if (bfd_header_big_endian (output_bfd))
                    rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_BIG;
                  else
                    rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_LITTLE;
@@ -4131,22 +4880,42 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
 
                  if (r_index == -1)
                    {
-                     const char *name;
-
-                     name = strings + GET_WORD (input_bfd,
-                                                syms[r_index].e_strx);
-                     if (! ((*finfo->info->callbacks->unattached_reloc)
-                            (finfo->info, name, input_bfd, input_section,
-                             r_addr)))
-                       return false;
-                     r_index = 0;
+                     if (h != NULL)
+                       {
+                         /* We decided to strip this symbol, but it
+                             turns out that we can't.  Note that we
+                             lose the other and desc information here.
+                             I don't think that will ever matter for a
+                             global symbol.  */
+                         if (h->indx < 0)
+                           {
+                             h->indx = -2;
+                             h->written = false;
+                             if (! aout_link_write_other_symbol (h,
+                                                                 (PTR) finfo))
+                               return false;
+                           }
+                         r_index = h->indx;
+                       }
+                     else
+                       {
+                         const char *name;
+
+                         name = strings + GET_WORD (input_bfd,
+                                                    syms[r_index].e_strx);
+                         if (! ((*finfo->info->callbacks->unattached_reloc)
+                                (finfo->info, name, input_bfd, input_section,
+                                 r_addr)))
+                           return false;
+                         r_index = 0;
+                       }
                    }
 
                  relocation = 0;
                }
 
              /* Write out the new r_index value.  */
-             if (output_bfd->xvec->header_byteorder_big_p)
+             if (bfd_header_big_endian (output_bfd))
                {
                  rel->r_index[0] = r_index >> 16;
                  rel->r_index[1] = r_index >> 8;
@@ -4184,38 +4953,43 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
                           + input_section->output_offset
                           - input_section->vma);
 
+#ifdef MY_relocatable_reloc
+         MY_relocatable_reloc (howto, output_bfd, rel, relocation, r_addr);
+#endif
+
          if (relocation == 0)
            r = bfd_reloc_ok;
          else
-           r = _bfd_relocate_contents (howto_table_std + howto_idx,
+           r = MY_relocate_contents (howto,
                                        input_bfd, relocation,
                                        contents + r_addr);
        }
       else
        {
+         boolean hundef;
+
          /* We are generating an executable, and must do a full
             relocation.  */
+         hundef = false;
+
          if (r_extern)
            {
-             struct aout_link_hash_entry *h;
-
              h = sym_hashes[r_index];
+
              if (h != (struct aout_link_hash_entry *) NULL
-                 && h->root.type == bfd_link_hash_defined)
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak))
                {
                  relocation = (h->root.u.def.value
                                + h->root.u.def.section->output_section->vma
                                + h->root.u.def.section->output_offset);
                }
+             else if (h != (struct aout_link_hash_entry *) NULL
+                      && h->root.type == bfd_link_hash_undefweak)
+               relocation = 0;
              else
                {
-                 const char *name;
-
-                 name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
-                 if (! ((*finfo->info->callbacks->undefined_symbol)
-                        (finfo->info, name, input_bfd, input_section,
-                         r_addr)))
-                   return false;
+                 hundef = true;
                  relocation = 0;
                }
            }
@@ -4231,10 +5005,38 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
                relocation += input_section->vma;
            }
 
-         r = _bfd_final_link_relocate (howto_table_std + howto_idx,
-                                       input_bfd, input_section,
-                                       contents, r_addr, relocation,
-                                       (bfd_vma) 0);
+         if (check_dynamic_reloc != NULL)
+           {
+             boolean skip;
+
+             if (! ((*check_dynamic_reloc)
+                    (finfo->info, input_bfd, input_section, h,
+                     (PTR) rel, contents, &skip, &relocation)))
+               return false;
+             if (skip)
+               continue;
+           }
+
+         /* Now warn if a global symbol is undefined.  We could not
+             do this earlier, because check_dynamic_reloc might want
+             to skip this reloc.  */
+         if (hundef && ! finfo->info->shared && ! r_baserel)
+           {
+             const char *name;
+
+             if (h != NULL)
+               name = h->root.root.string;
+             else
+               name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
+             if (! ((*finfo->info->callbacks->undefined_symbol)
+                    (finfo->info, name, input_bfd, input_section, r_addr)))
+               return false;
+           }
+
+         r = MY_final_link_relocate (howto,
+                                     input_bfd, input_section,
+                                     contents, r_addr, relocation,
+                                     (bfd_vma) 0);
        }
 
       if (r != bfd_reloc_ok)
@@ -4245,9 +5047,26 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
            case bfd_reloc_outofrange:
              abort ();
            case bfd_reloc_overflow:
-             if (! ((*finfo->info->callbacks->reloc_overflow)
-                    (finfo->info, input_bfd, input_section, r_addr)))
-               return false;
+             {
+               const char *name;
+
+               if (h != NULL)
+                 name = h->root.root.string;
+               else if (r_extern)
+                 name = strings + GET_WORD (input_bfd,
+                                            syms[r_index].e_strx);
+               else
+                 {
+                   asection *s;
+
+                   s = aout_reloc_index_to_section (input_bfd, r_index);
+                   name = bfd_section_name (input_bfd, s);
+                 }
+               if (! ((*finfo->info->callbacks->reloc_overflow)
+                      (finfo->info, name, howto->name,
+                       (bfd_vma) 0, input_bfd, input_section, r_addr)))
+                 return false;
+             }
              break;
            }
        }
@@ -4260,34 +5079,41 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
 
 static boolean
 aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
-                            rel_size, contents, symbol_map)
+                            rel_size, contents)
      struct aout_final_link_info *finfo;
      bfd *input_bfd;
      asection *input_section;
      struct reloc_ext_external *relocs;
      bfd_size_type rel_size;
      bfd_byte *contents;
-     int *symbol_map;
 {
+  boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *,
+                                         bfd *, asection *,
+                                         struct aout_link_hash_entry *,
+                                         PTR, bfd_byte *, boolean *,
+                                         bfd_vma *));
   bfd *output_bfd;
   boolean relocateable;
   struct external_nlist *syms;
   char *strings;
   struct aout_link_hash_entry **sym_hashes;
+  int *symbol_map;
   bfd_size_type reloc_count;
   register struct reloc_ext_external *rel;
   struct reloc_ext_external *rel_end;
 
   output_bfd = finfo->output_bfd;
+  check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
 
   BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_EXT_SIZE);
-  BFD_ASSERT (input_bfd->xvec->header_byteorder_big_p
-             == output_bfd->xvec->header_byteorder_big_p);
+  BFD_ASSERT (input_bfd->xvec->header_byteorder
+             == output_bfd->xvec->header_byteorder);
 
   relocateable = finfo->info->relocateable;
   syms = obj_aout_external_syms (input_bfd);
   strings = obj_aout_external_strings (input_bfd);
   sym_hashes = obj_aout_sym_hashes (input_bfd);
+  symbol_map = finfo->symbol_map;
 
   reloc_count = rel_size / RELOC_EXT_SIZE;
   rel = relocs;
@@ -4297,13 +5123,15 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
       bfd_vma r_addr;
       int r_index;
       int r_extern;
-      int r_type;
+      unsigned int r_type;
       bfd_vma r_addend;
+      struct aout_link_hash_entry *h = NULL;
+      asection *r_section = NULL;
       bfd_vma relocation;
 
       r_addr = GET_SWORD (input_bfd, rel->r_address);
 
-      if (input_bfd->xvec->header_byteorder_big_p)
+      if (bfd_header_big_endian (input_bfd))
        {
          r_index  = ((rel->r_index[0] << 16)
                      | (rel->r_index[1] << 8)
@@ -4324,28 +5152,34 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
 
       r_addend = GET_SWORD (input_bfd, rel->r_addend);
 
-      BFD_ASSERT (r_type >= 0
-                 && r_type < TABLE_SIZE (howto_table_ext));
+      BFD_ASSERT (r_type < TABLE_SIZE (howto_table_ext));
 
       if (relocateable)
        {
          /* We are generating a relocateable output file, and must
             modify the reloc accordingly.  */
-         if (r_extern)
+         if (r_extern
+             || r_type == RELOC_BASE10
+             || r_type == RELOC_BASE13
+             || r_type == RELOC_BASE22)
            {
-             struct aout_link_hash_entry *h;
-
              /* If we know the symbol this relocation is against,
                 convert it into a relocation against a section.  This
                 is what the native linker does.  */
-             h = sym_hashes[r_index];
+             if (r_type == RELOC_BASE10
+                 || r_type == RELOC_BASE13
+                 || r_type == RELOC_BASE22)
+               h = NULL;
+             else
+               h = sym_hashes[r_index];
              if (h != (struct aout_link_hash_entry *) NULL
-                 && h->root.type == bfd_link_hash_defined)
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak))
                {
                  asection *output_section;
 
                  /* Change the r_extern value.  */
-                 if (output_bfd->xvec->header_byteorder_big_p)
+                 if (bfd_header_big_endian (output_bfd))
                    rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_BIG;
                  else
                    rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_LITTLE;
@@ -4383,15 +5217,35 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
 
                  if (r_index == -1)
                    {
-                     const char *name;
-
-                     name = (strings
-                             + GET_WORD (input_bfd, syms[r_index].e_strx));
-                     if (! ((*finfo->info->callbacks->unattached_reloc)
-                            (finfo->info, name, input_bfd, input_section,
-                             r_addr)))
-                       return false;
-                     r_index = 0;
+                     if (h != NULL)
+                       {
+                         /* We decided to strip this symbol, but it
+                             turns out that we can't.  Note that we
+                             lose the other and desc information here.
+                             I don't think that will ever matter for a
+                             global symbol.  */
+                         if (h->indx < 0)
+                           {
+                             h->indx = -2;
+                             h->written = false;
+                             if (! aout_link_write_other_symbol (h,
+                                                                 (PTR) finfo))
+                               return false;
+                           }
+                         r_index = h->indx;
+                       }
+                     else
+                       {
+                         const char *name;
+
+                         name = strings + GET_WORD (input_bfd,
+                                                    syms[r_index].e_strx);
+                         if (! ((*finfo->info->callbacks->unattached_reloc)
+                                (finfo->info, name, input_bfd, input_section,
+                                 r_addr)))
+                           return false;
+                         r_index = 0;
+                       }
                    }
 
                  relocation = 0;
@@ -4403,7 +5257,7 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
                }
 
              /* Write out the new r_index value.  */
-             if (output_bfd->xvec->header_byteorder_big_p)
+             if (bfd_header_big_endian (output_bfd))
                {
                  rel->r_index[0] = r_index >> 16;
                  rel->r_index[1] = r_index >> 8;
@@ -4418,14 +5272,12 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
            }
          else
            {
-             asection *section;
-
              /* This is a relocation against a section.  We must
                 adjust by the amount that the section moved.  */
-             section = aout_reloc_index_to_section (input_bfd, r_index);
-             relocation = (section->output_section->vma
-                           + section->output_offset
-                           - section->vma);
+             r_section = aout_reloc_index_to_section (input_bfd, r_index);
+             relocation = (r_section->output_section->vma
+                           + r_section->output_offset
+                           - r_section->vma);
 
              /* If this is a PC relative reloc, then the addend is
                 the difference in VMA between the destination and the
@@ -4435,8 +5287,12 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
            }
 
          /* As described above, we must always adjust a PC relative
-            reloc by the change in VMA of the source.  */
-         if (howto_table_ext[r_type].pc_relative)
+            reloc by the change in VMA of the source.  However, if
+            pcrel_offset is set, then the addend does not include the
+            location within the section, in which case we don't need
+            to adjust anything.  */
+         if (howto_table_ext[r_type].pc_relative
+             && ! howto_table_ext[r_type].pcrel_offset)
            relocation -= (input_section->output_section->vma
                           + input_section->output_offset
                           - input_section->vma);
@@ -4452,39 +5308,67 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
        }
       else
        {
+         boolean hundef;
          bfd_reloc_status_type r;
 
          /* We are generating an executable, and must do a full
             relocation.  */
+         hundef = false;
+
          if (r_extern)
            {
-             struct aout_link_hash_entry *h;
-
              h = sym_hashes[r_index];
+
              if (h != (struct aout_link_hash_entry *) NULL
-                 && h->root.type == bfd_link_hash_defined)
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak))
                {
                  relocation = (h->root.u.def.value
                                + h->root.u.def.section->output_section->vma
                                + h->root.u.def.section->output_offset);
                }
+             else if (h != (struct aout_link_hash_entry *) NULL
+                      && h->root.type == bfd_link_hash_undefweak)
+               relocation = 0;
              else
                {
-                 const char *name;
-
-                 name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
-                 if (! ((*finfo->info->callbacks->undefined_symbol)
-                        (finfo->info, name, input_bfd, input_section,
-                         r_addr)))
-                   return false;
+                 hundef = true;
                  relocation = 0;
                }
            }
+         else if (r_type == RELOC_BASE10
+                  || r_type == RELOC_BASE13
+                  || r_type == RELOC_BASE22)
+           {
+             struct external_nlist *sym;
+             int type;
+
+             /* For base relative relocs, r_index is always an index
+                 into the symbol table, even if r_extern is 0.  */
+             sym = syms + r_index;
+             type = bfd_h_get_8 (input_bfd, sym->e_type);
+             if ((type & N_TYPE) == N_TEXT
+                 || type == N_WEAKT)
+               r_section = obj_textsec (input_bfd);
+             else if ((type & N_TYPE) == N_DATA
+                      || type == N_WEAKD)
+               r_section = obj_datasec (input_bfd);
+             else if ((type & N_TYPE) == N_BSS
+                      || type == N_WEAKB)
+               r_section = obj_bsssec (input_bfd);
+             else if ((type & N_TYPE) == N_ABS
+                      || type == N_WEAKA)
+               r_section = bfd_abs_section_ptr;
+             else
+               abort ();
+             relocation = (r_section->output_section->vma
+                           + r_section->output_offset
+                           + (GET_WORD (input_bfd, sym->e_value)
+                              - r_section->vma));
+           }
          else
            {
-             asection *section;
-
-             section = aout_reloc_index_to_section (input_bfd, r_index);
+             r_section = aout_reloc_index_to_section (input_bfd, r_index);
 
              /* If this is a PC relative reloc, then R_ADDEND is the
                 difference between the two vmas, or
@@ -4512,17 +5396,60 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
                 RELOCATION to the change in the destination VMA, or
                   new_dest_sec - old_dest_sec
                 */
-             relocation = (section->output_section->vma
-                           + section->output_offset
-                           - section->vma);
+             relocation = (r_section->output_section->vma
+                           + r_section->output_offset
+                           - r_section->vma);
              if (howto_table_ext[r_type].pc_relative)
                relocation += input_section->vma;
            }
 
-         r = _bfd_final_link_relocate (howto_table_ext + r_type,
+         if (check_dynamic_reloc != NULL)
+           {
+             boolean skip;
+
+             if (! ((*check_dynamic_reloc)
+                    (finfo->info, input_bfd, input_section, h,
+                     (PTR) rel, contents, &skip, &relocation)))
+               return false;
+             if (skip)
+               continue;
+           }
+
+         /* Now warn if a global symbol is undefined.  We could not
+             do this earlier, because check_dynamic_reloc might want
+             to skip this reloc.  */
+         if (hundef
+             && ! finfo->info->shared
+             && r_type != RELOC_BASE10
+             && r_type != RELOC_BASE13
+             && r_type != RELOC_BASE22)
+           {
+             const char *name;
+
+             if (h != NULL)
+               name = h->root.root.string;
+             else
+               name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
+             if (! ((*finfo->info->callbacks->undefined_symbol)
+                    (finfo->info, name, input_bfd, input_section, r_addr)))
+               return false;
+           }
+
+         if (r_type != RELOC_SPARC_REV32)
+           r = MY_final_link_relocate (howto_table_ext + r_type,
                                        input_bfd, input_section,
                                        contents, r_addr, relocation,
                                        r_addend);
+         else
+           {
+             bfd_vma x;
+
+             x = bfd_get_32 (input_bfd, contents + r_addr);
+             x = x + relocation + r_addend;
+             bfd_putl32 (/*input_bfd,*/ x, contents + r_addr);
+             r = bfd_reloc_ok;
+           }
+
          if (r != bfd_reloc_ok)
            {
              switch (r)
@@ -4531,9 +5458,29 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
                case bfd_reloc_outofrange:
                  abort ();
                case bfd_reloc_overflow:
-                 if (! ((*finfo->info->callbacks->reloc_overflow)
-                        (finfo->info, input_bfd, input_section, r_addr)))
-                   return false;
+                 {
+                   const char *name;
+
+                   if (h != NULL)
+                     name = h->root.root.string;
+                   else if (r_extern
+                            || r_type == RELOC_BASE10
+                            || r_type == RELOC_BASE13
+                            || r_type == RELOC_BASE22)
+                     name = strings + GET_WORD (input_bfd,
+                                                syms[r_index].e_strx);
+                   else
+                     {
+                       asection *s;
+
+                       s = aout_reloc_index_to_section (input_bfd, r_index);
+                       name = bfd_section_name (input_bfd, s);
+                     }
+                   if (! ((*finfo->info->callbacks->reloc_overflow)
+                          (finfo->info, name, howto_table_ext[r_type].name,
+                           r_addend, input_bfd, input_section, r_addr)))
+                     return false;
+                 }
                  break;
                }
            }
@@ -4542,3 +5489,227 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
 
   return true;
 }
+
+/* Handle a link order which is supposed to generate a reloc.  */
+
+static boolean
+aout_link_reloc_link_order (finfo, o, p)
+     struct aout_final_link_info *finfo;
+     asection *o;
+     struct bfd_link_order *p;
+{
+  struct bfd_link_order_reloc *pr;
+  int r_index;
+  int r_extern;
+  reloc_howto_type *howto;
+  file_ptr *reloff_ptr = NULL;
+  struct reloc_std_external srel;
+  struct reloc_ext_external erel;
+  PTR rel_ptr;
+
+  pr = p->u.reloc.p;
+
+  if (p->type == bfd_section_reloc_link_order)
+    {
+      r_extern = 0;
+      if (bfd_is_abs_section (pr->u.section))
+       r_index = N_ABS | N_EXT;
+      else
+       {
+         BFD_ASSERT (pr->u.section->owner == finfo->output_bfd);
+         r_index = pr->u.section->target_index;
+       }
+    }
+  else
+    {
+      struct aout_link_hash_entry *h;
+
+      BFD_ASSERT (p->type == bfd_symbol_reloc_link_order);
+      r_extern = 1;
+      h = ((struct aout_link_hash_entry *)
+          bfd_wrapped_link_hash_lookup (finfo->output_bfd, finfo->info,
+                                        pr->u.name, false, false, true));
+      if (h != (struct aout_link_hash_entry *) NULL
+         && h->indx >= 0)
+       r_index = h->indx;
+      else if (h != NULL)
+       {
+         /* We decided to strip this symbol, but it turns out that we
+            can't.  Note that we lose the other and desc information
+            here.  I don't think that will ever matter for a global
+            symbol.  */
+         h->indx = -2;
+         h->written = false;
+         if (! aout_link_write_other_symbol (h, (PTR) finfo))
+           return false;
+         r_index = h->indx;
+       }
+      else
+       {
+         if (! ((*finfo->info->callbacks->unattached_reloc)
+                (finfo->info, pr->u.name, (bfd *) NULL,
+                 (asection *) NULL, (bfd_vma) 0)))
+           return false;
+         r_index = 0;
+       }
+    }
+
+  howto = bfd_reloc_type_lookup (finfo->output_bfd, pr->reloc);
+  if (howto == 0)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      return false;
+    }
+
+  if (o == obj_textsec (finfo->output_bfd))
+    reloff_ptr = &finfo->treloff;
+  else if (o == obj_datasec (finfo->output_bfd))
+    reloff_ptr = &finfo->dreloff;
+  else
+    abort ();
+
+  if (obj_reloc_entry_size (finfo->output_bfd) == RELOC_STD_SIZE)
+    {
+#ifdef MY_put_reloc
+      MY_put_reloc(finfo->output_bfd, r_extern, r_index, p->offset, howto,
+                  &srel);
+#else
+      {
+       int r_pcrel;
+       int r_baserel;
+       int r_jmptable;
+       int r_relative;
+       int r_length;
+
+       r_pcrel = howto->pc_relative;
+       r_baserel = (howto->type & 8) != 0;
+       r_jmptable = (howto->type & 16) != 0;
+       r_relative = (howto->type & 32) != 0;
+       r_length = howto->size;
+
+       PUT_WORD (finfo->output_bfd, p->offset, srel.r_address);
+       if (bfd_header_big_endian (finfo->output_bfd))
+         {
+           srel.r_index[0] = r_index >> 16;
+           srel.r_index[1] = r_index >> 8;
+           srel.r_index[2] = r_index;
+           srel.r_type[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
+         {
+           srel.r_index[2] = r_index >> 16;
+           srel.r_index[1] = r_index >> 8;
+           srel.r_index[0] = r_index;
+           srel.r_type[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));
+         }
+      }
+#endif
+      rel_ptr = (PTR) &srel;
+
+      /* We have to write the addend into the object file, since
+        standard a.out relocs are in place.  It would be more
+        reliable if we had the current contents of the file here,
+        rather than assuming zeroes, but we can't read the file since
+        it was opened using bfd_openw.  */
+      if (pr->addend != 0)
+       {
+         bfd_size_type size;
+         bfd_reloc_status_type r;
+         bfd_byte *buf;
+         boolean ok;
+
+         size = bfd_get_reloc_size (howto);
+         buf = (bfd_byte *) bfd_zmalloc (size);
+         if (buf == (bfd_byte *) NULL)
+           return false;
+         r = MY_relocate_contents (howto, finfo->output_bfd,
+                                     pr->addend, buf);
+         switch (r)
+           {
+           case bfd_reloc_ok:
+             break;
+           default:
+           case bfd_reloc_outofrange:
+             abort ();
+           case bfd_reloc_overflow:
+             if (! ((*finfo->info->callbacks->reloc_overflow)
+                    (finfo->info,
+                     (p->type == bfd_section_reloc_link_order
+                      ? bfd_section_name (finfo->output_bfd,
+                                          pr->u.section)
+                      : pr->u.name),
+                     howto->name, pr->addend, (bfd *) NULL,
+                     (asection *) NULL, (bfd_vma) 0)))
+               {
+                 free (buf);
+                 return false;
+               }
+             break;
+           }
+         ok = bfd_set_section_contents (finfo->output_bfd, o,
+                                        (PTR) buf,
+                                        (file_ptr) p->offset,
+                                        size);
+         free (buf);
+         if (! ok)
+           return false;
+       }
+    }
+  else
+    {
+      PUT_WORD (finfo->output_bfd, p->offset, erel.r_address);
+
+      if (bfd_header_big_endian (finfo->output_bfd))
+       {
+         erel.r_index[0] = r_index >> 16;
+         erel.r_index[1] = r_index >> 8;
+         erel.r_index[2] = r_index;
+         erel.r_type[0] =
+           ((r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
+            | (howto->type << RELOC_EXT_BITS_TYPE_SH_BIG));
+       }
+      else
+       {
+         erel.r_index[2] = r_index >> 16;
+         erel.r_index[1] = r_index >> 8;
+         erel.r_index[0] = r_index;
+         erel.r_type[0] =
+           (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
+             | (howto->type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
+       }
+
+      PUT_WORD (finfo->output_bfd, pr->addend, erel.r_addend);
+
+      rel_ptr = (PTR) &erel;
+    }
+
+  if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0
+      || (bfd_write (rel_ptr, (bfd_size_type) 1,
+                    obj_reloc_entry_size (finfo->output_bfd),
+                    finfo->output_bfd)
+         != obj_reloc_entry_size (finfo->output_bfd)))
+    return false;
+
+  *reloff_ptr += obj_reloc_entry_size (finfo->output_bfd);
+
+  /* Assert that the relocs have not run into the symbols, and that n
+     the text relocs have not run into the data relocs.  */
+  BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd)
+             && (reloff_ptr != &finfo->treloff
+                 || (*reloff_ptr
+                     <= obj_datasec (finfo->output_bfd)->rel_filepos)));
+
+  return true;
+}
This page took 0.105922 seconds and 4 git commands to generate.