]> Git Repo - binutils.git/blobdiff - bfd/aoutx.h
* aoutx.h (translate_from_native_sym_flags): Treat N_SETV symbols
[binutils.git] / bfd / aoutx.h
index bff9b2bb568dcfa12a8626900e517dacc382b178..97d3f617b5a8e7715bde36ba6c9c82adfaad8060 100644 (file)
@@ -1,5 +1,5 @@
 /* BFD semi-generic back-end for a.out binaries.
-   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -121,11 +121,9 @@ DESCRIPTION
 #define KEEPIT flags
 #define KEEPITTYPE int
 
-#include <assert.h>
 #include <string.h>            /* For strchr and friends */
 #include "bfd.h"
 #include <sysdep.h>
-#include <ansidecl.h>
 #include "bfdlink.h"
 
 #include "libaout.h"
@@ -134,11 +132,11 @@ 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 *));
 
 /*
 SUBSECTION
@@ -203,14 +201,37 @@ HOWTO( 7,        0,  4,   64, true,  0, complain_overflow_signed,  0,"DISP64",    tr
 { -1 },
 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 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+  HOWTO(16,           0,  2,    0, false, 0, complain_overflow_bitfield,0,"JMP_TABLE", false,         0,0x00000000, false),
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 },
+  HOWTO(32,           0,  2,    0, false, 0, complain_overflow_bitfield,0,"RELATIVE",  false,         0,0x00000000, false),
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+{ -1 },
+  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)
+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 +242,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,6 +254,8 @@ 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);
+       EXT (BFD_RELOC_SPARC13, 10);
+       EXT (BFD_RELOC_SPARC_BASE13, 15);
       default: return (CONST struct reloc_howto_struct *) 0;
       }
   else
@@ -276,10 +302,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 +313,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 +342,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,7 +360,23 @@ 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
@@ -354,17 +396,17 @@ DESCRIPTION
 */
 
 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 *)))
+NAME(aout,some_aout_object_p) (abfd, execp, callback_to_real_object_p)
+     bfd *abfd;
+     struct internal_exec *execp;
+     bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *));
 {
   struct aout_data_struct *rawptr, *oldrawptr;
   bfd_target *result;
 
   rawptr = (struct aout_data_struct  *) bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
   if (rawptr == NULL) {
-    bfd_error = no_memory;
+    bfd_set_error (bfd_error_no_memory);
     return 0;
   }
 
@@ -394,16 +436,28 @@ 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)
+    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;
 
@@ -420,18 +474,8 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
   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;
@@ -452,7 +496,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.  */
 
@@ -547,35 +591,27 @@ 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;
+    bfd_set_error (bfd_error_no_memory);
     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,13 +637,15 @@ 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:
@@ -617,7 +655,7 @@ DEFUN(NAME(aout,machine_type),(arch, machine),
   case bfd_arch_m68k:
     switch (machine) {
     case 0:            arch_flags = M_68010; break;
-    case 68000:                arch_flags = M_UNKNOWN; break;
+    case 68000:                arch_flags = M_UNKNOWN; *unknown = false; break;
     case 68010:                arch_flags = M_68010; break;
     case 68020:                arch_flags = M_68020; break;
     default:           arch_flags = M_UNKNOWN; break;
@@ -647,6 +685,10 @@ DEFUN(NAME(aout,machine_type),(arch, machine),
   default:
     arch_flags = M_UNKNOWN;
   }
+
+  if (arch_flags != M_UNKNOWN)
+    *unknown = false;
+
   return arch_flags;
 }
 
@@ -668,17 +710,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) {
@@ -798,7 +845,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 +921,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;
 {
   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,
@@ -906,7 +957,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 +1025,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 +1037,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,12 +1060,12 @@ 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;
@@ -1031,7 +1081,8 @@ DEFUN(NAME(aout,set_section_contents),(abfd, section, location, offset, count),
   /* 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 (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0)
+         return false;
 
        if (count) {
          return (bfd_write ((PTR)location, 1, count, abfd) == count) ?
@@ -1042,113 +1093,259 @@ DEFUN(NAME(aout,set_section_contents),(abfd, section, location, offset, count),
   return true;
 }
 \f
-/* Classify stabs symbols */
+/* Read the external symbols from an a.out file.  */
 
-#define sym_in_text_section(sym) \
-  (((sym)->type  & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT)
+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_data_section(sym) \
-  (((sym)->type  & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA)
+      count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE;
 
-#define sym_in_bss_section(sym) \
-  (((sym)->type  & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS)
+      /* We allocate using malloc 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 *)
+             malloc ((size_t) count * EXTERNAL_NLIST_SIZE));
+      if (syms == (struct external_nlist *) NULL && count != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
 
-/* 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)
+      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;
+       }
 
-/* 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)
+      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 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)
+      strings = (char *) malloc ((size_t) stringsize + 1);
+      if (strings == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
 
-#define sym_is_fortrancommon(sym)       \
-  (((sym)->type == (N_EXT)) && (sym)->symbol.value != 0)
+      /* 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;
+       }
 
-/* Symbol is absolute if it has N_ABS set */
-#define sym_is_absolute(sym) \
-  (((sym)->type  & N_TYPE)== N_ABS)
+      /* Sanity preservation.  */
+      strings[stringsize] = '\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;
+         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;
+      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;
+       }
+      else
+       {
+         cache_ptr->symbol.flags = 0;
+         cache_ptr->symbol.section = &bfd_und_section;
+       }
+      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);
        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)
+             {
+               bfd_set_error (bfd_error_no_memory);
+               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)
+         {
+           bfd_set_error (bfd_error_no_memory);
+           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:
+         case N_SETA:
            into_section = &bfd_abs_section;
            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 +1353,170 @@ 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;
+
+       if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE)
+         reloc->relent.howto = howto_table_ext + CTOR_TABLE_RELOC_IDX;
+       else
+         reloc->relent.howto = howto_table_std + CTOR_TABLE_RELOC_IDX;
 
-       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;
 
-         if (sym_is_fortrancommon (cache_ptr))
-           {
-             cache_ptr->symbol.flags = 0;
-             cache_ptr->symbol.section = &bfd_com_section;
-           }
-         else
-           {
+      /* @@ 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_abs_section;
 
-           }
+      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_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;
 
-         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;
-           }
+      /* @@ 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);
 
-         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;
-           }
-       }
+      cache_ptr->symbol.section = &bfd_ind_section;
+
+      break;
+
+    case N_WEAKU:
+      cache_ptr->symbol.section = &bfd_und_section;
+      cache_ptr->symbol.flags = BSF_WEAK;
+      break;
+
+    case N_WEAKA:
+      cache_ptr->symbol.section = &bfd_abs_section;
+      cache_ptr->symbol.flags = BSF_WEAK;
+      break;
+
+    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;
+
+    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;
+
+    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;
 
-  /* 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) {
+  if (bfd_get_section (cache_ptr) == &bfd_abs_section)
     sym_pointer->e_type[0] |= N_ABS;
-  }
-  else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) {
+  else if (bfd_get_section (cache_ptr) == obj_textsec (abfd)
+          || (bfd_get_section (cache_ptr)->output_section
+              == obj_textsec (abfd)))
     sym_pointer->e_type[0] |= N_TEXT;
-  }
-  else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) {
+  else if (bfd_get_section (cache_ptr) == obj_datasec (abfd)
+          || (bfd_get_section (cache_ptr)->output_section
+              == obj_datasec (abfd)))
     sym_pointer->e_type[0] |= N_DATA;
-  }
-  else if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) {
+  else if (bfd_get_section (cache_ptr) == obj_bsssec (abfd)
+          || (bfd_get_section (cache_ptr)->output_section
+              == 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_get_section (cache_ptr) == &bfd_und_section)
+    sym_pointer->e_type[0] = N_UNDF | N_EXT;
+  else if (bfd_get_section (cache_ptr) == &bfd_ind_section)
     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 = 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 = nonrepresentable_section;
-    return false;
-  }
+  else if (bfd_get_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_set_error (bfd_error_nonrepresentable_section);
+      return false;
+    }
+  else if (bfd_is_com_section (bfd_get_section (cache_ptr)))
+    sym_pointer->e_type[0] = N_UNDF | N_EXT;
+  else
+    {
+      bfd_set_error (bfd_error_nonrepresentable_section);
+      return false;
+    }
 
   /* Turn the symbol from section relative to absolute again */
+  value += cache_ptr->section->vma;
 
-  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 +1525,17 @@ 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)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
   new->symbol.the_bfd = abfd;
 
   return &new->symbol;
@@ -1391,8 +1543,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;
@@ -1429,7 +1581,8 @@ translate_symbol_table (abfd, in, ext, count, str, strsize, dynamic)
       in->type = bfd_h_get_8 (abfd,  ext->e_type);
       in->symbol.udata = 0;
 
-      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;
@@ -1443,500 +1596,289 @@ 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;
-    }
+  if (obj_aout_symbols (abfd) != (aout_symbol_type *) NULL)
+    return true;
 
-  bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
-  if (bfd_read ((PTR)string_chars, BYTES_IN_WORD, 1, abfd) != BYTES_IN_WORD)
+  old_external_syms = obj_aout_external_syms (abfd);
+
+  if (! aout_get_external_symbols (abfd))
     return false;
-  string_size = GET_WORD (abfd, string_chars);
 
-  /* 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)
+  if (obj_aout_external_sym_count (abfd) == 0)
     {
-      dynsym_count = ((*aout_backend_info (abfd)->read_dynamic_symbols)
-                     (abfd, &dynsyms, &dynstrs, &dynstr_size));
-      if (dynsym_count == (bfd_size_type) -1)
-       return false;
+      bfd_set_error (bfd_error_no_symbols);
+      return false;
     }
 
-  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))));
-
-  /* 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 *) malloc (cached_size);
+  if (cached == NULL)
     {
-    bailout:
-      if (syms)
-       free (syms);
-      if (cached)
-       bfd_release (abfd, cached);
-      if (strings)
-       bfd_release (abfd, strings);
+      bfd_set_error (bfd_error_no_memory);
       return false;
     }
-
-  bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
-  if (bfd_read ((PTR)strings, 1, string_size, abfd) != string_size)
+  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)))
     {
-      goto bailout;
+      free (cached);
+      return false;
     }
-  strings[string_size] = 0; /* Just in case. */
 
-  /* 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;
+  bfd_get_symcount (abfd) = obj_aout_external_sym_count (abfd);
 
-      bfd_get_symcount (abfd) += dynsym_count;
-    }
+  obj_aout_symbols (abfd) = cached;
 
-  obj_aout_symbols (abfd) =  cached;
-  free((PTR)syms);
+  /* 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)
+    {
+      free (obj_aout_external_syms (abfd));
+      obj_aout_external_syms (abfd) = NULL;
+    }
 
   return true;
 }
-
 \f
-/* Possible improvements:
+/* 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.
+
+   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;
+   + 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?)
 
-#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
+   This hash table code breaks dbx on SunOS 4.1.3, so we don't do it
+   if BFD_TRADITIONAL_FORMAT is set.  */
 
-  /* 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;
+/* An entry in the strtab hash table.  */
 
-  /* Next index value to issue.  */
+struct strtab_hash_entry
+{
+  struct bfd_hash_entry root;
+  /* Index in string table.  */
   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
+  /* Next string in strtab.  */
+  struct strtab_hash_entry *next;
 };
 
-/* Some utility functions for the string table code.  */
+/* The strtab hash table.  */
 
-/* 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
+struct strtab_hash
+{
+  struct bfd_hash_table table;
+  /* Size of strtab--also next available index.  */
+  bfd_size_type size;
+  /* First string in strtab.  */
+  struct strtab_hash_entry *first;
+  /* Last string in strtab.  */
+  struct strtab_hash_entry *last;
+};
 
-#define HASH_CHAR(c) (sum ^= sum >> 20, sum ^= sum << 7, sum += (c))
+static struct bfd_hash_entry *strtab_hash_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static boolean stringtab_init PARAMS ((struct strtab_hash *));
+static bfd_size_type add_to_stringtab
+  PARAMS ((bfd *, struct strtab_hash *, const char *, boolean));
+static boolean emit_stringtab PARAMS ((bfd *, struct strtab_hash *));
 
-static INLINE unsigned int
-hash (string, len)
-     unsigned char *string;
-     register unsigned int len;
+/* Routine to create an entry in a strtab.  */
+
+static struct bfd_hash_entry *
+strtab_hash_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
 {
-  register unsigned int sum = 0;
+  struct strtab_hash_entry *ret = (struct strtab_hash_entry *) entry;
 
-  if (len > HASHMAXLEN)
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == (struct strtab_hash_entry *) NULL)
+    ret = ((struct strtab_hash_entry *)
+          bfd_hash_allocate (table, sizeof (struct strtab_hash_entry)));
+  if (ret == (struct strtab_hash_entry *) NULL)
     {
-      HASH_CHAR (len);
-      len = HASHMAXLEN;
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
     }
 
-  while (len--)
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct strtab_hash_entry *)
+        bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+
+  if (ret)
     {
-      HASH_CHAR (*string++);
+      /* Initialize the local fields.  */
+      ret->index = (bfd_size_type) -1;
+      ret->next = NULL;
     }
-  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
+  return (struct bfd_hash_entry *) ret;
 }
 
-static INLINE int
-compare (entry, str, hash)
-     struct stringtab_entry *entry;
-     CONST char *str;
-     unsigned int hash;
-{
-  return hash - entry->hash;
-}
+/* Look up an entry in an strtab.  */
+
+#define strtab_hash_lookup(t, string, create, copy) \
+  ((struct strtab_hash_entry *) \
+   bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
 
-#ifdef GATHER_STATISTICS
-/* Don't want to have to link in math library with all bfd applications...  */
-static INLINE double
-log2 (num)
-     int num;
+/* Create a new strtab.  */
+
+static boolean
+stringtab_init (table)
+     struct strtab_hash *table;
 {
-  double d = num;
-  int n = 0;
-  while (d >= 2.0)
-    n++, d /= 2.0;
-  return ((d > 1.41) ? 0.5 : 0) + n;
+  if (! bfd_hash_table_init (&table->table, strtab_hash_newfunc))
+    return false;
+
+  /* Leave space for the size of the string table.  */
+  table->size = BYTES_IN_WORD;
+
+  table->first = NULL;
+  table->last = NULL;
+
+  return true;
 }
-#endif
 
-/* 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)
+/* Free a strtab.  */
+
+#define stringtab_free(tab) bfd_hash_table_free (&(tab)->table)
+
+/* Get the index of a string in a strtab, adding it if it is not
+   already present.  If HASH is false, we don't really use the hash
+   table, and we don't eliminate duplicate strings.  */
+
+static INLINE bfd_size_type
+add_to_stringtab (abfd, tab, str, copy)
      bfd *abfd;
-     CONST char *str;
-     struct stringtab_data *tab;
+     struct strtab_hash *tab;
+     const char *str;
+     boolean copy;
 {
-  struct stringtab_entry **ep;
-  register struct stringtab_entry *entry;
-  unsigned int hashval, len;
-
-  if (str[0] == 0)
-    {
-      bfd_size_type index;
-      CONST bfd_size_type minus_one = -1;
+  register struct strtab_hash_entry *entry;
 
-#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;
-       }
+  /* An index of 0 always means the empty string.  */
+  if (*str == '\0')
+    return 0;
 
-      /* 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)
+  if ((abfd->flags & BFD_TRADITIONAL_FORMAT) == 0)
     {
-      tab->hash_zero = hashval;
-      hashval = 0;
-      goto add_it;
+      entry = strtab_hash_lookup (tab, str, true, copy);
+      if (entry == NULL)
+       return (bfd_size_type) -1;
     }
-
-  while (*ep)
+  else
     {
-      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;
+      entry = ((struct strtab_hash_entry *)
+              bfd_hash_allocate (&tab->table,
+                                 sizeof (struct strtab_hash_entry)));
+      if (entry == NULL)
+       return (bfd_size_type) -1;
+      if (! copy)
+       entry->root.string = str;
       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;
+         char *n;
+
+         n = (char *) bfd_hash_allocate (&tab->table, strlen (str) + 1);
+         if (n == NULL)
+           return (bfd_size_type) -1;
+         entry->root.string = n;
        }
+      entry->index = (bfd_size_type) -1;
+      entry->next = NULL;
     }
 
-  /* 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);
+  if (entry->index == (bfd_size_type) -1)
+    {
+      entry->index = tab->size;
+      tab->size += strlen (str) + 1;
+      if (tab->first == NULL)
+       tab->first = entry;
+      else
+       tab->last->next = entry;
+      tab->last = entry;
+    }
 
-  {
-    tab->index += len + 1;
-    if (len == 0)
-      tab->empty_string_index = entry->index;
-  }
-  assert (*ep == 0);
-  *ep = entry;
   return entry->index;
 }
 
-static void
-emit_strtab (abfd, tab)
-     bfd *abfd;
-     struct stringtab_data *tab;
-{
-  struct stringtab_entry *entry;
-#ifdef GATHER_STATISTICS
-  int count = 0;
-#endif
+/* Write out a strtab.  ABFD is already at the right location in the
+   file.  */
 
-  /* Be sure to put string length into correct byte ordering before writing
-     it out.  */
-  char buffer[BYTES_IN_WORD];
+static boolean
+emit_stringtab (abfd, tab)
+     register bfd *abfd;
+     struct strtab_hash *tab;
+{
+  bfd_byte buffer[BYTES_IN_WORD];
+  register struct strtab_hash_entry *entry;
 
-  PUT_WORD (abfd, tab->index, (unsigned char *) buffer);
-  bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd);
+  PUT_WORD (abfd, tab->size, buffer);
+  if (bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd) != BYTES_IN_WORD)
+    return false;
 
-  for (entry = tab->output_order; entry; entry = entry->next_to_output)
+  for (entry = tab->first; entry != NULL; entry = entry->next)
     {
-      bfd_write ((PTR) entry->string, 1, strlen (entry->string) + 1, abfd);
-#ifdef GATHER_STATISTICS
-      count++;
-#endif
-    }
+      register const char *str;
+      register size_t len;
 
-#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
-
-/* Old code:
-  unsigned int count;
-  generic = bfd_get_outsymbols(abfd);
-  for (count = 0; count < bfd_get_symcount(abfd); count++)
-    {
-      asymbol *g = *(generic++);
+      str = entry->root.string;
+      len = strlen (str) + 1;
+      if (bfd_write ((PTR) str, 1, len, abfd) != len)
+       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 true;
 }
-
+\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 strtab_hash strtab;
 
-  stringtab_init (&strtab);
+  if (! stringtab_init (&strtab))
+    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)
        {
@@ -1951,33 +1893,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
         here, at the end.  */
       g->KEEPIT = count;
     }
 
-  emit_strtab (abfd, &strtab);
+  if (! emit_stringtab (abfd, &strtab))
+    goto error_return;
+
+  stringtab_free (&strtab);
 
   return true;
+
+error_return:
+  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++);
@@ -1990,10 +1940,10 @@ DEFUN(NAME(aout,get_symtab),(abfd, location),
 /* Output standard relocation information to a file in target byte order. */
 
 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);
@@ -2009,9 +1959,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.  */
@@ -2086,10 +2035,10 @@ DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
 /* Output extended relocation information to a file in target byte order. */
 
 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;
@@ -2198,11 +2147,11 @@ DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
   }                                                                    \
 
 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)
+     bfd *abfd;
+     struct reloc_ext_external *bytes;
+     arelent *cache_ptr;
+     asymbol **symbols;
 {
   int r_index;
   int r_extern;
@@ -2233,11 +2182,11 @@ DEFUN(NAME(aout,swap_ext_reloc_in), (abfd, bytes, cache_ptr, symbols),
 }
 
 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)
+     bfd *abfd;
+     struct reloc_std_external *bytes;
+     arelent *cache_ptr;
+     asymbol **symbols;
 {
   int r_index;
   int r_extern;
@@ -2274,38 +2223,36 @@ 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 */
 
   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;
@@ -2313,47 +2260,37 @@ DEFUN(NAME(aout,slurp_reloc_table),(abfd, asect, symbols),
     reloc_size = exec_hdr(abfd)->a_trsize;
   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)
+  reloc_cache = (arelent *) malloc ((size_t) (count * sizeof (arelent)));
+  if (reloc_cache == NULL && count != 0)
     {
-    nomem:
-      bfd_error = no_memory;
+      bfd_set_error (bfd_error_no_memory);
       return false;
     }
+  memset (reloc_cache, 0, count * sizeof (arelent));
 
-  relocs = (PTR) bfd_alloc (abfd, reloc_size);
-  if (!relocs)
+  relocs = malloc (reloc_size);
+  if (relocs == NULL && reloc_size != 0)
     {
-      bfd_release (abfd, reloc_cache);
-      goto nomem;
+      free (reloc_cache);
+      bfd_set_error (bfd_error_no_memory);
+      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;
     }
 
@@ -2368,68 +2305,27 @@ DEFUN(NAME(aout,slurp_reloc_table),(abfd, asect, symbols),
     }
   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);
     }
 
-  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;
+  free (relocs);
 
-         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;
-           }
-       }
-    }
-
-  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;
@@ -2444,7 +2340,7 @@ DEFUN(NAME(aout,squirt_out_relocs),(abfd, section),
   natsize = each_size * count;
   native = (unsigned char *) bfd_zalloc (abfd, natsize);
   if (!native) {
-    bfd_error = no_memory;
+    bfd_set_error (bfd_error_no_memory);
     return false;
   }
 
@@ -2475,18 +2371,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;
@@ -2497,7 +2399,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;)
       {
@@ -2509,71 +2410,62 @@ 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 *);
 
-  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;
+     asymbol *ignore_symbol;
 {
 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;
+     asymbol *symbol;
+     symbol_info *ret;
 {
   bfd_symbol_info (symbol, ret);
 
@@ -2597,11 +2489,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;
+     PTR afile;
+     asymbol *symbol;
+     bfd_print_symbol_type how;
 {
   FILE *file = (FILE *)afile;
 
@@ -2641,20 +2533,15 @@ 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;
@@ -2718,7 +2605,18 @@ DEFUN(NAME(aout,find_nearest_line),(abfd,
          if (*line_ptr && func) {
            CONST char *function = func->name;
            char *p;
-           strncpy(buffer, function, sizeof(buffer)-1);
+
+           /* 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')
+             strncpy (buffer, function, sizeof (buffer) - 1);
+           else
+             {
+               buffer[0] = bfd_get_symbol_leading_char (abfd);
+               strncpy (buffer + 1, function, sizeof (buffer) - 2);
+             }
            buffer[sizeof(buffer)-1] = 0;
            /* Have to remove : stuff */
            p = strchr(buffer,':');
@@ -2751,40 +2649,42 @@ DEFUN(NAME(aout,find_nearest_line),(abfd,
 
 /*ARGSUSED*/
 int
-DEFUN(NAME(aout,sizeof_headers),(abfd, execable),
-      bfd *abfd AND
-      boolean execable)
+NAME(aout,sizeof_headers) (abfd, execable)
+     bfd *abfd;
+     boolean execable;
 {
   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;
 
-/* a.out linker hash table.  */
+  if (bfd_get_format (abfd) != bfd_object)
+    return true;
 
-struct aout_link_hash_table
-{
-  struct bfd_link_hash_table root;
-};
+#define FREE(x) if (x != NULL) { free (x); x = NULL; }
+  FREE (obj_aout_symbols (abfd));
+  FREE (obj_aout_external_syms (abfd));
+  FREE (obj_aout_external_strings (abfd));
+  for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+    FREE (o->relocation);
+#undef FREE
+
+  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));
@@ -2793,8 +2693,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;
@@ -2806,16 +2706,37 @@ 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)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      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));
+  if (ret)
+    {
+      /* Set local fields.  */
+      ret->written = false;
+      ret->indx = -1;
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
 
-  /* Set local fields.  */
-  ret->indx = -1;
+/* Initialize an a.out link hash table.  */
 
-  return (struct bfd_hash_entry *) ret;
+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.  */
@@ -2827,9 +2748,14 @@ 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))
+        malloc (sizeof (struct aout_link_hash_table)));
+  if (ret == (struct aout_link_hash_table *) NULL)
+      {
+       bfd_set_error (bfd_error_no_memory);
+       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;
@@ -2837,25 +2763,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.  */
 
@@ -2872,7 +2779,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;
     }
 }
@@ -2884,7 +2791,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;
@@ -2907,7 +2814,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))
@@ -2932,59 +2839,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
@@ -3033,8 +2887,14 @@ 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)
+      /* 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_WEAKA
+         && type != N_WEAKT
+         && type != N_WEAKD
+         && type != N_WEAKB)
        {
          if (type == N_WARNING
              || type == N_INDR)
@@ -3070,7 +2930,13 @@ 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;
@@ -3120,6 +2986,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.  */
@@ -3133,6 +3016,11 @@ 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 **));
   bfd_size_type sym_count;
   char *strings;
   boolean copy;
@@ -3155,8 +3043,24 @@ 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)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
   obj_aout_sym_hashes (abfd) = sym_hash;
 
+  if ((abfd->flags & DYNAMIC) != 0
+      && aout_backend_info (abfd)->add_dynamic_symbols != NULL)
+    {
+      if (! (*aout_backend_info (abfd)->add_dynamic_symbols) (abfd, info))
+       return false;
+    }
+
+  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 = obj_aout_external_syms (abfd);
   pend = p + sym_count;
   for (; p < pend; p++, sym_hash++)
@@ -3176,29 +3080,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;
@@ -3207,11 +3088,32 @@ 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;
+             flags = 0;
+           }
          else
-           section = &bfd_und_section;
+           section = &bfd_com_section;
          break;
        case N_ABS | N_EXT:
          section = &bfd_abs_section;
@@ -3221,6 +3123,9 @@ aout_link_add_symbols (abfd, info)
          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;
@@ -3269,11 +3174,34 @@ aout_link_add_symbols (abfd, info)
          section = &bfd_und_section;
          flags |= BSF_WARNING;
          break;
+       case N_WEAKU:
+         section = &bfd_und_section;
+         flags = BSF_WEAK;
+         break;
+       case N_WEAKA:
+         section = &bfd_abs_section;
+         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;
 
       if (type == (N_INDR | N_EXT) || type == N_WARNING)
@@ -3297,7 +3225,7 @@ struct aout_final_link_info
   /* File position of symbols.  */
   file_ptr symoff;
   /* String table.  */
-  struct stringtab_data strtab;
+  struct strtab_hash strtab;
 };
 
 static boolean aout_link_input_bfd
@@ -3320,6 +3248,9 @@ static boolean aout_link_input_section_ext
           bfd_size_type rel_size, bfd_byte *contents, int *symbol_map));
 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 *));
 
 /* 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
@@ -3340,6 +3271,7 @@ NAME(aout,final_link) (abfd, info, callback)
   file_ptr text_end;
   register struct bfd_link_order *p;
   asection *o;
+  boolean have_link_order_relocs;
 
   aout_info.info = info;
   aout_info.output_bfd = abfd;
@@ -3372,7 +3304,15 @@ NAME(aout,final_link) (abfd, info, callback)
              abort ();
            }
        }
+      if (obj_textsec (abfd) != (asection *) NULL)
+       trsize += (_bfd_count_link_order_relocs (obj_textsec (abfd)
+                                                ->link_order_head)
+                  * obj_reloc_entry_size (abfd));
       exec_hdr (abfd)->a_trsize = trsize;
+      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_drsize = drsize;
     }
 
@@ -3402,7 +3342,8 @@ 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);
+  if (! stringtab_init (&aout_info.strtab))
+    return false;
 
   /* 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
@@ -3428,19 +3369,13 @@ NAME(aout,final_link) (abfd, info, callback)
   for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
     sub->output_has_begun = false;
 
+  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))
@@ -3455,6 +3390,12 @@ NAME(aout,final_link) (abfd, info, callback)
                  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))
@@ -3468,6 +3409,35 @@ 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))
+                   return 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))
+       return false;
+    }
+
   /* Update the header information.  */
   abfd->symcount = obj_aout_external_sym_count (abfd);
   exec_hdr (abfd)->a_syms = abfd->symcount * EXTERNAL_NLIST_SIZE;
@@ -3480,9 +3450,7 @@ NAME(aout,final_link) (abfd, info, callback)
   /* Write out the string table.  */
   if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0)
     return false;
-  emit_strtab (abfd, &aout_info.strtab);
-
-  return true;
+  return emit_stringtab (abfd, &aout_info.strtab);
 }
 
 /* Link an a.out input BFD into the output file.  */
@@ -3493,21 +3461,34 @@ aout_link_input_bfd (finfo, input_bfd)
      bfd *input_bfd;
 {
   bfd_size_type sym_count;
-  int *symbol_map;
+  int *symbol_map = NULL;
 
   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));
+  symbol_map = (int *) malloc ((size_t) sym_count * sizeof (int));
+  if (symbol_map == NULL && sym_count != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
 
   /* Write out the symbols and get a map of the new indices.  */
   if (! aout_link_write_symbols (finfo, input_bfd, symbol_map))
-    return false;
+    goto error_return;
 
   /* Relocate and write out the sections.  */
   if (! aout_link_input_section (finfo, input_bfd,
@@ -3520,7 +3501,7 @@ aout_link_input_bfd (finfo, input_bfd)
                                    &finfo->dreloff,
                                    exec_hdr (input_bfd)->a_drsize,
                                    symbol_map))
-    return false;
+    goto error_return;
 
   /* 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
@@ -3528,10 +3509,16 @@ aout_link_input_bfd (finfo, input_bfd)
   if (! finfo->info->keep_memory)
     {
       if (! aout_link_free_symbols (input_bfd))
-       return false;
+       goto error_return;
     }
 
+  if (symbol_map != NULL)
+    free (symbol_map);
   return true;
+ error_return:
+  if (symbol_map != NULL)
+    free (symbol_map);
+  return false;
 }
 
 /* Adjust and write out the symbols for an a.out file.  Set the new
@@ -3548,8 +3535,9 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
   char *strings;
   enum bfd_link_strip strip;
   enum bfd_link_discard discard;
-  struct external_nlist *output_syms;
+  struct external_nlist *output_syms = NULL;
   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;
@@ -3562,7 +3550,12 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
   strip = finfo->info->strip;
   discard = finfo->info->discard;
   output_syms = ((struct external_nlist *)
-                alloca ((size_t) (sym_count + 1) * EXTERNAL_NLIST_SIZE));
+                malloc ((size_t) (sym_count + 1) * EXTERNAL_NLIST_SIZE));
+  if (output_syms == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
   outsym = output_syms;
 
   /* First write out a symbol for this object file, unless we are
@@ -3576,10 +3569,11 @@ 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);
-      PUT_WORD (output_bfd,
-               add_to_stringtab (output_bfd, input_bfd->filename,
-                                 &finfo->strtab),
-               outsym->e_strx);
+      strtab_index = add_to_stringtab (output_bfd, &finfo->strtab,
+                                      input_bfd->filename, false);
+      if (strtab_index == (bfd_size_type) -1)
+       goto error_return;
+      PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
       PUT_WORD (output_bfd,
                (bfd_get_section_vma (output_bfd,
                                      obj_textsec (input_bfd)->output_section)
@@ -3598,15 +3592,19 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
     {
       const char *name;
       int type;
+      struct aout_link_hash_entry *h;
       boolean skip;
       asection *symsec;
       bfd_vma val = 0;
+      boolean copy;
 
       *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
@@ -3624,7 +3622,6 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
        }
       else
        {
-         struct aout_link_hash_entry *h;
          struct aout_link_hash_entry *hresolve;
 
          /* We have saved the hash table entry for this symbol, if
@@ -3643,7 +3640,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;
@@ -3651,8 +3649,11 @@ 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)
+               skip_indirect = true;
              *symbol_map = h->indx;
              continue;
            }
@@ -3679,18 +3680,22 @@ 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)
+         else if ((type & N_TYPE) == N_ABS
+                  || type == N_WEAKA)
            symsec = &bfd_abs_section;
          else if (((type & N_TYPE) == N_INDR
                    && (hresolve == (struct aout_link_hash_entry *) NULL
@@ -3763,6 +3768,11 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
                }
              else if (hresolve->root.type == bfd_link_hash_common)
                val = hresolve->root.u.c.size;
+             else if (hresolve->root.type == bfd_link_hash_weak)
+               {
+                 val = 0;
+                 type = N_WEAKU;
+               }
              else
                val = 0;
 
@@ -3778,7 +3788,7 @@ 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
@@ -3813,9 +3823,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 = (*sym_hash)->root.root.string;
+         else
+           copy = true;
+       }
+      strtab_index = add_to_stringtab (output_bfd, &finfo->strtab,
+                                      name, copy);
+      if (strtab_index == (bfd_size_type) -1)
+       goto error_return;
+      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);
@@ -3828,16 +3851,22 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map)
       bfd_size_type outsym_count;
 
       if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0)
-       return false;
+       goto error_return;
       outsym_count = outsym - output_syms;
       if (bfd_write ((PTR) output_syms, (bfd_size_type) EXTERNAL_NLIST_SIZE,
                     (bfd_size_type) outsym_count, output_bfd)
          != outsym_count * EXTERNAL_NLIST_SIZE)
-       return false;
+       goto error_return;
       finfo->symoff += outsym_count * EXTERNAL_NLIST_SIZE;
     }
 
+  if (output_syms != NULL)
+    free (output_syms);
   return true;
+ error_return:
+  if (output_syms != NULL)
+    free (output_syms);
+  return false;
 }
 
 /* Write out a symbol that was not associated with an a.out input
@@ -3853,11 +3882,30 @@ 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;
+
+  if (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)
     {
@@ -3874,7 +3922,7 @@ aout_link_write_other_symbol (h, data)
       {
        asection *sec;
 
-       sec = h->root.u.def.section;
+       sec = h->root.u.def.section->output_section;
        BFD_ASSERT (sec == &bfd_abs_section
                    || sec->owner == output_bfd);
        if (sec == obj_textsec (output_bfd))
@@ -3886,14 +3934,17 @@ aout_link_write_other_symbol (h, data)
        else
          type = N_ABS | 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_weak:
+      type = N_WEAKU;
+      val = 0;
     case bfd_link_hash_indirect:
     case bfd_link_hash_warning:
       /* FIXME: Ignore these for now.  The circumstances under which
@@ -3904,9 +3955,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
@@ -3937,21 +3993,38 @@ aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr,
      int *symbol_map;
 {
   bfd_size_type input_size;
-  bfd_byte *contents;
+  bfd_byte *contents = NULL;
   PTR relocs;
+  PTR free_relocs = NULL;
 
   /* Get the section contents.  */
   input_size = bfd_section_size (input_bfd, input_section);
-  contents = (bfd_byte *) alloca (input_size);
+  contents = (bfd_byte *) malloc (input_size);
+  if (contents == NULL && input_size != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
   if (! bfd_get_section_contents (input_bfd, input_section, (PTR) contents,
                                  (file_ptr) 0, input_size))
-    return false;
+    goto error_return;
 
-  /* 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 = free_relocs = (PTR) malloc (rel_size);
+      if (relocs == NULL && rel_size != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+      if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
+         || bfd_read (relocs, 1, rel_size, input_bfd) != rel_size)
+       goto error_return;
+    }
 
   /* Relocate the section contents.  */
   if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
@@ -3959,14 +4032,14 @@ aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr,
       if (! aout_link_input_section_std (finfo, input_bfd, input_section,
                                         (struct reloc_std_external *) relocs,
                                         rel_size, contents, symbol_map))
-       return false;
+       goto error_return;
     }
   else
     {
       if (! aout_link_input_section_ext (finfo, input_bfd, input_section,
                                         (struct reloc_ext_external *) relocs,
                                         rel_size, contents, symbol_map))
-       return false;
+       goto error_return;
     }
 
   /* Write out the section contents.  */
@@ -3975,17 +4048,17 @@ aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr,
                                  (PTR) contents,
                                  input_section->output_offset,
                                  input_size))
-    return false;
+    goto error_return;
 
   /* If we are producing relocateable output, the relocs were
      modified, and we now write them out.  */
   if (finfo->info->relocateable)
     {
       if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0)
-       return false;
+       goto error_return;
       if (bfd_write (relocs, (bfd_size_type) 1, rel_size, finfo->output_bfd)
          != rel_size)
-       return false;
+       goto error_return;
       *reloff_ptr += rel_size;
 
       /* Assert that the relocs have not run into the symbols, and
@@ -3997,7 +4070,17 @@ aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr,
                          <= obj_datasec (finfo->output_bfd)->rel_filepos)));
     }
 
+  if (free_relocs != NULL)
+    free (free_relocs);
+  if (contents != NULL)
+    free (contents);
   return true;
+ error_return:
+  if (free_relocs != NULL)
+    free (free_relocs);
+  if (contents != NULL)
+    free (contents);
+  return false;
 }
 
 /* Get the section corresponding to a reloc index.  */
@@ -4036,6 +4119,10 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
      bfd_byte *contents;
      int *symbol_map;
 {
+  boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *,
+                                         bfd *, asection *,
+                                         struct aout_link_hash_entry *,
+                                         PTR, boolean *));
   bfd *output_bfd;
   boolean relocateable;
   struct external_nlist *syms;
@@ -4046,6 +4133,7 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
   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
@@ -4102,10 +4190,9 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
                       >> 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));
-      BFD_ASSERT (r_jmptable == 0);
-      BFD_ASSERT (r_relative == 0);
 
       if (relocateable)
        {
@@ -4224,6 +4311,19 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
              struct aout_link_hash_entry *h;
 
              h = sym_hashes[r_index];
+
+             if (check_dynamic_reloc != NULL)
+               {
+                 boolean skip;
+
+                 if (! ((*check_dynamic_reloc)
+                        (finfo->info, input_bfd, input_section, h,
+                         (PTR) rel, &skip)))
+                   return false;
+                 if (skip)
+                   continue;
+               }
+
              if (h != (struct aout_link_hash_entry *) NULL
                  && h->root.type == bfd_link_hash_defined)
                {
@@ -4231,6 +4331,9 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs,
                                + 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_weak)
+               relocation = 0;
              else
                {
                  const char *name;
@@ -4308,6 +4411,10 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
      bfd_byte *contents;
      int *symbol_map;
 {
+  boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *,
+                                         bfd *, asection *,
+                                         struct aout_link_hash_entry *,
+                                         PTR, boolean *));
   bfd *output_bfd;
   boolean relocateable;
   struct external_nlist *syms;
@@ -4318,6 +4425,7 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
   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
@@ -4500,6 +4608,19 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
              struct aout_link_hash_entry *h;
 
              h = sym_hashes[r_index];
+
+             if (check_dynamic_reloc != NULL)
+               {
+                 boolean skip;
+
+                 if (! ((*check_dynamic_reloc)
+                        (finfo->info, input_bfd, input_section, h,
+                         (PTR) rel, &skip)))
+                   return false;
+                 if (skip)
+                   continue;
+               }
+
              if (h != (struct aout_link_hash_entry *) NULL
                  && h->root.type == bfd_link_hash_defined)
                {
@@ -4507,6 +4628,9 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
                                + 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_weak)
+               relocation = 0;
              else
                {
                  const char *name;
@@ -4596,3 +4720,211 @@ 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;
+  const reloc_howto_type *howto;
+  file_ptr *reloff_ptr;
+  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 (pr->u.section == &bfd_abs_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 = aout_link_hash_lookup (aout_hash_table (finfo->info),
+                                pr->u.name, false, false, true);
+      if (h != (struct aout_link_hash_entry *) NULL
+         && h->indx == -1)
+       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 == (const reloc_howto_type *) NULL)
+    {
+      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)
+    {
+      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 (finfo->output_bfd->xvec->header_byteorder_big_p)
+       {
+         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));
+       }
+
+      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)
+           {
+             bfd_set_error (bfd_error_no_memory);
+             return false;
+           }
+         r = _bfd_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 (finfo->output_bfd->xvec->header_byteorder_big_p)
+       {
+         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.12952 seconds and 4 git commands to generate.