Patch from minyard@bnr.ca: For empty symbol table, write out number "4" in
[deliverable/binutils-gdb.git] / bfd / aoutx.h
index 71b56e831a96f83ed108a7fb2be6cbb9fb7a5c59..876083f652edbb1903f366b9fab01b742fdc15ed 100644 (file)
@@ -1,6 +1,5 @@
-#define BFD_AOUT_DEBUG
-/* BFD semi-generic back-end for a.out binaries
-   Copyright (C) 1990-1991 Free Software Foundation, Inc.
+/* BFD semi-generic back-end for a.out binaries.
+   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -121,6 +120,8 @@ 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>
@@ -179,7 +180,6 @@ reloc_howto_type howto_table_ext[] =
   HOWTO(RELOC_GLOB_DAT,0, 2,   0,  false, 0, false, true,0,"GLOB_DAT", false, 0,0x00000000, false),
   HOWTO(RELOC_JMP_SLOT,0, 2,   0,  false, 0, false, true,0,"JMP_SLOT", false, 0,0x00000000, false),
   HOWTO(RELOC_RELATIVE,0, 2,   0,  false, 0, false,    true,0,"RELATIVE",      false, 0,0x00000000, false),
-
 };
 
 /* Convert standard reloc records to "arelent" format (incl byte swap).  */
@@ -196,6 +196,42 @@ HOWTO( 6,         0,  2,   32, true,  0, false, true,0,"DISP32",   true, 0xfffffff
 HOWTO( 7,             0,  3,   64, true,  0, false, true,0,"DISP64",   true, 0xfeedface,0xfeedface, false),
 };
 
+CONST struct reloc_howto_struct *
+DEFUN(NAME(aout,reloc_type_lookup),(abfd,code),
+      bfd *abfd AND
+      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]
+  int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE;
+  if (code == BFD_RELOC_CTOR)
+    switch (bfd_get_arch_info (abfd)->bits_per_address)
+      {
+      case 32:
+       code = BFD_RELOC_32;
+       break;
+      }
+  if (ext)
+    switch (code)
+      {
+       EXT (BFD_RELOC_32, 2);
+       EXT (BFD_RELOC_HI22, 8);
+       EXT (BFD_RELOC_LO10, 11);
+       EXT (BFD_RELOC_32_PCREL_S2, 6);
+      default: return (CONST struct reloc_howto_struct *) 0;
+      }
+  else
+    /* std relocs */
+    switch (code)
+      {
+       STD (BFD_RELOC_16, 1);
+       STD (BFD_RELOC_32, 2);
+       STD (BFD_RELOC_8_PCREL, 4);
+       STD (BFD_RELOC_16_PCREL, 5);
+       STD (BFD_RELOC_32_PCREL, 6);
+      default: return (CONST struct reloc_howto_struct *) 0;
+      }
+}
 
 extern bfd_error_vector_type bfd_error_vector;
 
@@ -219,7 +255,7 @@ DESCRIPTION
        byte stream memory image, into the internal exec_header
        structure.
 
-EXAMPLE
+SYNOPSIS
        void aout_<size>_swap_exec_header_in,
            (bfd *abfd,
             struct external_exec *raw_bytes,
@@ -258,7 +294,7 @@ DESCRIPTION
        Swaps the information in an internal exec header structure
        into the supplied buffer ready for writing to disk.
 
-EXAMPLE
+SYNOPSIS
        void aout_<size>_swap_exec_header_out
          (bfd *abfd,
           struct internal_exec *execp,
@@ -296,7 +332,7 @@ DESCRIPTION
        environments "finish up" function just before returning, to
        handle any last-minute setup.  
 
-EXAMPLE
+SYNOPSIS
        bfd_target *aout_<size>_some_aout_object_p
         (bfd *abfd,
          bfd_target *(*callback_to_real_object_p)());
@@ -306,9 +342,9 @@ 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) ())
+      bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *)))
 {
-  struct aout_data_struct  *rawptr;
+  struct aout_data_struct *rawptr, *oldrawptr;
   bfd_target *result;
 
   rawptr = (struct aout_data_struct  *) bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
@@ -317,6 +353,7 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
     return 0;
   }
 
+  oldrawptr = abfd->tdata.aout_data;
   abfd->tdata.aout_data = rawptr;
   abfd->tdata.aout_data->a.hdr = &rawptr->e;
   *(abfd->tdata.aout_data->a.hdr) = *execp;    /* Copy in the internal_exec struct */
@@ -357,29 +394,25 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
   /* create the sections.  This is raunchy, but bfd_close wants to reclaim
      them */
 
-  obj_textsec (abfd) = (asection *)NULL;
-  obj_datasec (abfd) = (asection *)NULL;
-  obj_bsssec (abfd) = (asection *)NULL;
-  
-  (void)bfd_make_section(abfd, ".text");
-  (void)bfd_make_section(abfd, ".data");
-  (void)bfd_make_section(abfd, ".bss");
-/*  (void)bfd_make_section(abfd, BFD_ABS_SECTION_NAME);
-  (void)bfd_make_section (abfd, BFD_UND_SECTION_NAME);
-  (void)bfd_make_section (abfd, BFD_COM_SECTION_NAME);*/
-  abfd->sections = obj_textsec (abfd);
-  obj_textsec (abfd)->next = obj_datasec (abfd);
-  obj_datasec (abfd)->next = obj_bsssec (abfd);
+  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
 
   obj_datasec (abfd)->_raw_size = execp->a_data;
   obj_bsssec (abfd)->_raw_size = execp->a_bss;
 
   obj_textsec (abfd)->flags = (execp->a_trsize != 0 ?
-                      (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_HAS_CONTENTS) :
-                      (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS));
+       (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC) :
+       (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS));
   obj_datasec (abfd)->flags = (execp->a_drsize != 0 ?
-                      (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_HAS_CONTENTS) :
-                      (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS));
+       (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC) :
+       (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS));
   obj_bsssec (abfd)->flags = SEC_ALLOC;
 
 #ifdef THIS_IS_ONLY_DOCUMENTATION
@@ -423,15 +456,6 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
     break;
   }
 
-  /* Determine the size of a relocation entry */
-  switch (abfd->obj_arch) {
-  case bfd_arch_sparc:
-  case bfd_arch_a29k:
-    obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
-  default:
-    obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
-  }
-
   adata(abfd)->page_size = PAGE_SIZE;
   adata(abfd)->segment_size = SEGMENT_SIZE;
   adata(abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
@@ -461,6 +485,19 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
   if ((execp->a_entry >= obj_textsec(abfd)->vma) &&
       (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size))
     abfd->flags |= EXEC_P;
+  if (result)
+    {
+#if 0 /* These should be set correctly anyways.  */
+      abfd->sections = obj_textsec (abfd);
+      obj_textsec (abfd)->next = obj_datasec (abfd);
+      obj_datasec (abfd)->next = obj_bsssec (abfd);
+#endif
+    }
+  else
+    {
+      free (rawptr);
+      abfd->tdata.aout_data = oldrawptr;
+    }
   return result;
 }
 
@@ -471,7 +508,7 @@ FUNCTION
 DESCRIPTION
        This routine initializes a BFD for use with a.out files.
 
-EXAMPLE
+SYNOPSIS
        boolean aout_<size>_mkobject, (bfd *);
 */
 
@@ -523,7 +560,7 @@ DESCRIPTION
        If the architecture is understood, machine type 0 (default)
        should always be understood.  
 
-EXAMPLE
+SYNOPSIS
        enum machine_type  aout_<size>_machine_type
         (enum bfd_architecture arch,
          unsigned long machine));
@@ -561,9 +598,20 @@ DEFUN(NAME(aout,machine_type),(arch, machine),
     if (machine == 0)  arch_flags = M_29K;
     break;
       
+  case bfd_arch_mips:
+    switch (machine) {
+    case 0:
+    case 2000:
+    case 3000:          arch_flags = M_MIPS1; break;
+    case 4000:
+    case 4400:
+    case 6000:          arch_flags = M_MIPS2; break;
+    default:            arch_flags = M_UNKNOWN; break;
+    }
+    break;
+
   default:
     arch_flags = M_UNKNOWN;
-    break;
   }
   return arch_flags;
 }
@@ -578,7 +626,7 @@ DESCRIPTION
        values supplied. Verifies that the format can support the
        architecture required.
 
-EXAMPLE
+SYNOPSIS
        boolean aout_<size>_set_arch_mach,
         (bfd *,
          enum bfd_architecture,
@@ -591,20 +639,24 @@ DEFUN(NAME(aout,set_arch_mach),(abfd, arch, machine),
       enum bfd_architecture arch AND
       unsigned long machine)
 {
-  bfd_arch_info_type *ainfo;
-
   bfd_default_set_arch_mach(abfd, arch, machine);
   if (arch != bfd_arch_unknown &&
       NAME(aout,machine_type) (arch, machine) == M_UNKNOWN)
     return false;              /* We can't represent this type */
 
-  BFD_ASSERT (&adata(abfd) != 0);
-  ainfo = bfd_get_arch_info (abfd);
-  if (ainfo->segment_size)
-    adata(abfd).segment_size = ainfo->segment_size;
-  if (ainfo->page_size)
-    adata(abfd).page_size = ainfo->page_size;
-  return true;                 /* We're easy ... */
+  /* Determine the size of a relocation entry */
+  switch (arch) {
+  case bfd_arch_sparc:
+  case bfd_arch_a29k:
+  case bfd_arch_mips:
+    obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
+    break;
+  default:
+    obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
+    break;
+  }
+
+  return (*aout_backend_info(abfd)->set_sizes) (abfd);
 }
 
 boolean
@@ -673,15 +725,16 @@ DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
       {
        file_ptr pos = adata (abfd).exec_bytes_size;
        bfd_vma vma = 0;
-       int pad;
+       int pad = 0;
 
        obj_textsec(abfd)->filepos = pos;
        pos += obj_textsec(abfd)->_raw_size;
        vma += obj_textsec(abfd)->_raw_size;
        if (!obj_datasec(abfd)->user_set_vma)
          {
-           /* ?? Does alignment in the file image really matter? */
+#if 0      /* ?? Does alignment in the file image really matter? */
            pad = align_power (vma, obj_datasec(abfd)->alignment_power) - vma;
+#endif
            obj_textsec(abfd)->_raw_size += pad;
            pos += pad;
            vma += pad;
@@ -692,7 +745,9 @@ DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
        vma += obj_datasec(abfd)->_raw_size;
        if (!obj_bsssec(abfd)->user_set_vma)
          {
+#if 0
            pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma;
+#endif
            obj_datasec(abfd)->_raw_size += pad;
            pos += pad;
            vma += pad;
@@ -753,7 +808,7 @@ DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
 
        /* Fix up exec header while we're at it.  */
        execp->a_text = obj_textsec(abfd)->_raw_size;
-       if (ztih)
+       if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted)))
          execp->a_text += adata(abfd).exec_bytes_size;
        N_SET_MAGIC (*execp, ZMAGIC);
        /* Spec says data section should be rounded up to page boundary.  */
@@ -766,18 +821,7 @@ DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
        execp->a_data = BFD_ALIGN (obj_datasec(abfd)->_raw_size,
                                   adata(abfd).page_size);
        data_pad = execp->a_data - obj_datasec(abfd)->_raw_size;
-       /* This code is almost surely botched.  It'll only get tested
-          for the case where the application does explicitly set the VMA
-          of the BSS section.  */
-       if (obj_bsssec(abfd)->user_set_vma
-           && (obj_bsssec(abfd)->vma
-               > BFD_ALIGN (obj_datasec(abfd)->vma
-                            + obj_datasec(abfd)->_raw_size,
-                            adata(abfd).page_size)))
-         {
-           /* Can't play with squeezing into data pages; fix this code.  */
-           abort ();
-         }
+
        if (!obj_bsssec(abfd)->user_set_vma)
          obj_bsssec(abfd)->vma = (obj_datasec(abfd)->vma
                                   + obj_datasec(abfd)->_raw_size);
@@ -789,7 +833,6 @@ DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
       break;
     case n_magic:
       {
-       CONST struct aout_backend_data *abdp;
        file_ptr pos = adata(abfd).exec_bytes_size;
        bfd_vma vma = 0;
        int pad;
@@ -831,17 +874,18 @@ DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
           obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size, obj_datasec(abfd)->filepos,
           obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size);
 #endif
+  return true;
 }
 
 /*
 FUNCTION
-       aout_<size>new_section_hook
+       aout_<size>_new_section_hook
   
 DESCRIPTION
        Called by the BFD in response to a @code{bfd_make_section}
        request.
 
-EXAMPLE
+SYNOPSIS
         boolean aout_<size>_new_section_hook,
           (bfd *abfd,
            asection *newsect));
@@ -967,179 +1011,201 @@ boolean
   stabilised these should be inlined into their (single) caller */
   
 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)
+DEFUN (translate_from_native_sym_flags, (sym_pointer, cache_ptr, abfd, statep),
+       struct external_nlist *sym_pointer AND
+       aout_symbol_type * cache_ptr AND
+       bfd * abfd AND
+       int *statep)
 {
-  switch (cache_ptr->type & N_TYPE) 
-  {
-  case N_SETA:
-  case N_SETT:
-  case N_SETD:
-  case N_SETB:
-  {
-    char *copy = bfd_alloc(abfd, strlen(cache_ptr->symbol.name)+1);
-    asection *section ;
-    asection *into_section;
-      
-    arelent_chain *reloc = (arelent_chain *)bfd_alloc(abfd, sizeof(arelent_chain));
-    strcpy(copy, cache_ptr->symbol.name);
-
-    /* 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);
-
-    /* Build a relocation entry for the constructor */
-    switch ( (cache_ptr->type  & N_TYPE) ) 
+  cache_ptr->symbol.section = 0;
+  if (*statep)
     {
-    case N_SETA:
-      into_section = &bfd_abs_section;
-      break;
-    case N_SETT:
-      into_section = (asection *)obj_textsec(abfd);
-      break;
-    case N_SETD:
-      into_section = (asection *)obj_datasec(abfd);
-      break;
-    case N_SETB:
-      into_section = (asection *)obj_bsssec(abfd);
-      break;
-    default:
-      abort();
+      /* This is an indirect symbol  */
+      cache_ptr->symbol.flags = BSF_DEBUGGING;
+      cache_ptr->symbol.section = &bfd_und_section;
+      *statep = 0;
     }
-
-    /* Build a relocation pointing into the constuctor 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;
-    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;
-
-         
-    section->reloc_count++;
-    section->alignment_power = 2;
-
-    reloc->next = section->constructor_chain;
-    section->constructor_chain = reloc;
-    reloc->relent.address = section->_raw_size;
-    section->_raw_size += sizeof(int *);
-
-    reloc->relent.howto = howto_table_ext + CTOR_TABLE_RELOC_IDX;
-    cache_ptr->symbol.flags |=  BSF_DEBUGGING  | BSF_CONSTRUCTOR;
-  }
-    break;
-  default:
-    if (cache_ptr->type ==  N_WARNING) 
+  else
     {
-      /* 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;
-      cache_ptr->symbol.value = (bfd_vma)((cache_ptr+1));
-      /* 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;
-       cache_ptr->symbol.value = (bfd_vma)((cache_ptr+1));
-       cache_ptr->symbol.section = &bfd_und_section;
-       break;
-      }
-
-      
-    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) 
+      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:
+       case N_SETA:
+       case N_SETT:
+       case N_SETD:
+       case N_SETB:
+         {
+           char *copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1);
+           asection *section;
+           asection *into_section;
 
-         cache_ptr->symbol.section = &bfd_abs_section;
-         break;
-       }
-      }
-    else {
+           arelent_chain *reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain));
+           strcpy (copy, cache_ptr->symbol.name);
 
-       if (sym_is_fortrancommon (cache_ptr))
-       {
-         cache_ptr->symbol.flags = 0;
-         cache_ptr->symbol.section = &bfd_com_section;
-       }
-       else {
+           /* 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);
 
+           /* Build a relocation entry for the constructor */
+           switch ((cache_ptr->type & N_TYPE))
+             {
+             case N_SETA:
+               into_section = &bfd_abs_section;
+               break;
+             case N_SETT:
+               into_section = (asection *) obj_textsec (abfd);
+               break;
+             case N_SETD:
+               into_section = (asection *) obj_datasec (abfd);
+               break;
+             case N_SETB:
+               into_section = (asection *) obj_bsssec (abfd);
+               break;
+             default:
+               abort ();
+             }
 
+           /* Build a relocation pointing into the constuctor 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;
+           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;
+
+
+           section->reloc_count++;
+           section->alignment_power = 2;
+
+           reloc->next = section->constructor_chain;
+           section->constructor_chain = reloc;
+           reloc->relent.address = section->_raw_size;
+           section->_raw_size += sizeof (int *);
+
+           reloc->relent.howto = howto_table_ext + CTOR_TABLE_RELOC_IDX;
+           cache_ptr->symbol.flags |= BSF_DEBUGGING | BSF_CONSTRUCTOR;
          }
-         
-       /* In a.out, the value of a symbol is always relative to the 
-        * start of the file, if this is a data symbol we'll subtract
-        * the size of the text section to get the section relative
-        * value. If this is a bss symbol (which would be strange)
-        * we'll subtract the size of the previous two sections
-        * to find the section relative address.
-        */
-         
-       if (sym_in_text_section (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;
-       }
-           
-       if (sym_is_global_defn (cache_ptr)) 
-       {
-         cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT;
-       } 
-       else 
-       {
-         cache_ptr->symbol.flags = BSF_LOCAL;
+         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;
+             cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1));
+             /* 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;
+             cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1));
+             cache_ptr->symbol.section = &bfd_ind_section;
+             *statep = 1;
+           }
+
+         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
+           {
+
+             if (sym_is_fortrancommon (cache_ptr))
+               {
+                 cache_ptr->symbol.flags = 0;
+                 cache_ptr->symbol.section = &bfd_com_section;
+               }
+             else
+               {
+
+
+               }
+
+             /* In a.out, the value of a symbol is always relative to the
+              * start of the file, if this is a data symbol we'll subtract
+              * the size of the text section to get the section relative
+              * value. If this is a bss symbol (which would be strange)
+              * we'll subtract the size of the previous two sections
+              * to find the section relative address.
+              */
+
+             if (sym_in_text_section (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;
+               }
+
+             if (sym_is_global_defn (cache_ptr))
+               {
+                 cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT;
+               }
+             else
+               {
+                 cache_ptr->symbol.flags = BSF_LOCAL;
+               }
+           }
        }
-      }
-  }
+    }
+  if (cache_ptr->symbol.section == 0)
+    abort ();
 }
 
 
@@ -1155,57 +1221,62 @@ DEFUN(translate_to_native_sym_flags,(sym_pointer, cache_ptr, abfd),
   /* mask out any existing type bits in case copying from one section
      to another */
   sym_pointer->e_type[0] &= ~N_TYPE;
+
   
   if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) {
-      sym_pointer->e_type[0] |= N_BSS;
-    }
+    sym_pointer->e_type[0] |= N_BSS;
+  }
   else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) {
-      sym_pointer->e_type[0] |= N_DATA;
-    }
+    sym_pointer->e_type[0] |= N_DATA;
+  }
   else  if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) {
-      sym_pointer->e_type[0] |= N_TEXT;
-    }
-  else if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) 
-  {
-    sym_pointer->e_type[0] |= N_ABS;
+    sym_pointer->e_type[0] |= N_TEXT;
   }
+  else if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) 
+    {
+      sym_pointer->e_type[0] |= N_ABS;
+    }
   else if (bfd_get_output_section(cache_ptr) == &bfd_und_section) 
-  {
-    sym_pointer->e_type[0] = (N_UNDF | N_EXT);
-  }
-  else if (bfd_get_output_section(cache_ptr) == &bfd_com_section) {
+    {
       sym_pointer->e_type[0] = (N_UNDF | N_EXT);
-    }    
+    }
+  else if (bfd_get_output_section(cache_ptr) == &bfd_ind_section) 
+    {
+      sym_pointer->e_type[0] = N_INDR;
+    }
+  else if (bfd_is_com_section (bfd_get_output_section (cache_ptr))) {
+    sym_pointer->e_type[0] = (N_UNDF | N_EXT);
+  }    
   else {    
-      if (cache_ptr->section->output_section) 
+    if (cache_ptr->section->output_section) 
       {
        
        bfd_error_vector.nonrepresentable_section(abfd,
                                                  bfd_get_output_section(cache_ptr)->name);
       }
-      else 
+    else 
       {
        bfd_error_vector.nonrepresentable_section(abfd,
                                                  cache_ptr->section->name);
        
       }
       
-    }
+  }
   /* Turn the symbol from section relative to absolute again */
     
   value +=  cache_ptr->section->output_section->vma  + cache_ptr->section->output_offset ;
 
 
   if (cache_ptr->flags & (BSF_WARNING)) {
-      (sym_pointer+1)->e_type[0] = 1;
-    }  
+    (sym_pointer+1)->e_type[0] = 1;
+  }  
     
   if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) {
-      sym_pointer->e_type[0] |= N_EXT;
-    }
+    sym_pointer->e_type[0] |= N_EXT;
+  }
   if (cache_ptr->flags & BSF_DEBUGGING) {
-      sym_pointer->e_type [0]= ((aout_symbol_type *)cache_ptr)->type;
-    }
+    sym_pointer->e_type [0]= ((aout_symbol_type *)cache_ptr)->type;
+  }
 
   PUT_WORD(abfd, value, sym_pointer->e_value);
 }
@@ -1223,7 +1294,7 @@ DEFUN(NAME(aout,make_empty_symbol),(abfd),
   aout_symbol_type  *new =
     (aout_symbol_type *)bfd_zalloc (abfd, sizeof (aout_symbol_type));
   new->symbol.the_bfd = abfd;
-    
+
   return &new->symbol;
 }
 
@@ -1237,20 +1308,21 @@ DEFUN(NAME(aout,slurp_symbol_table),(abfd),
   struct external_nlist *syms;
   char *strings;
   aout_symbol_type *cached;
-    
+
   /* If there's no work to be done, don't do any */
   if (obj_aout_symbols (abfd) != (aout_symbol_type *)NULL) return true;
   symbol_size = exec_hdr(abfd)->a_syms;
-  if (symbol_size == 0) {
-    bfd_error = no_symbols;
-    return false;
-  }
-    
+  if (symbol_size == 0)
+    {
+      bfd_error = no_symbols;
+      return false;
+    }
+
   bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
   if (bfd_read ((PTR)string_chars, BYTES_IN_WORD, 1, abfd) != BYTES_IN_WORD)
     return false;
   string_size = GET_WORD (abfd, string_chars);
-    
+
   strings =(char *) bfd_alloc(abfd, string_size + 1);
   cached = (aout_symbol_type *)
     bfd_zalloc(abfd, (bfd_size_type)(bfd_get_symcount (abfd) * sizeof(aout_symbol_type)));
@@ -1259,119 +1331,503 @@ DEFUN(NAME(aout,slurp_symbol_table),(abfd),
      might want to allocate onto the bfd's obstack  */
   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) {
-  bailout:
-    if (syms)  free (syms);
-    if (cached)        bfd_release (abfd, cached);
-    if (strings)bfd_release (abfd, strings);
-    return false;
-  }
-    
+  if (bfd_read ((PTR)syms, 1, symbol_size, abfd) != symbol_size)
+    {
+    bailout:
+      if (syms)
+       free (syms);
+      if (cached)
+       bfd_release (abfd, cached);
+      if (strings)
+       bfd_release (abfd, strings);
+      return false;
+    }
+
   bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
-  if (bfd_read ((PTR)strings, 1, string_size, abfd) != string_size) {
-    goto bailout;
-  }
-    
-  /* OK, now walk the new symtable, cacheing symbol properties */
+  if (bfd_read ((PTR)strings, 1, string_size, abfd) != string_size)
     {
-      register struct external_nlist *sym_pointer;
-      register struct external_nlist *sym_end = syms + bfd_get_symcount (abfd);
-      register aout_symbol_type *cache_ptr = cached;
-       
-      /* Run through table and copy values */
-      for (sym_pointer = syms, cache_ptr = cached;
-          sym_pointer < sym_end; sym_pointer++, cache_ptr++) 
-         {
-           bfd_vma x = GET_WORD(abfd, sym_pointer->e_strx);
-           cache_ptr->symbol.the_bfd = abfd;
-           if (x)
-             cache_ptr->symbol.name = x + strings;
-           else
-             cache_ptr->symbol.name = (char *)NULL;
-             
-           cache_ptr->symbol.value = GET_SWORD(abfd,  sym_pointer->e_value);
-           cache_ptr->desc = bfd_get_16(abfd, sym_pointer->e_desc);
-           cache_ptr->other =bfd_get_8(abfd, sym_pointer->e_other);
-           cache_ptr->type = bfd_get_8(abfd,  sym_pointer->e_type);
-           cache_ptr->symbol.udata = 0;
-           translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd);
-         }
+      goto bailout;
     }
-    
+  strings[string_size] = 0; /* Just in case. */
+
+  /* OK, now walk the new symtable, cacheing symbol properties */
+  {
+    register struct external_nlist *sym_pointer;
+    int state = 0;
+    register struct external_nlist *sym_end = syms + bfd_get_symcount (abfd);
+    register aout_symbol_type *cache_ptr = cached;
+
+    /* Run through table and copy values */
+    for (sym_pointer = syms, cache_ptr = cached;
+        sym_pointer < sym_end; sym_pointer ++, cache_ptr++) 
+      {
+       long x = GET_WORD(abfd, sym_pointer->e_strx);
+       cache_ptr->symbol.the_bfd = abfd;
+       if (x == 0)
+         cache_ptr->symbol.name = "";
+       else if (x >= 0 && x < string_size)
+         cache_ptr->symbol.name = x + strings;
+       else
+         goto bailout;
+
+       cache_ptr->symbol.value = GET_SWORD(abfd,  sym_pointer->e_value);
+       cache_ptr->desc = bfd_h_get_16(abfd, sym_pointer->e_desc);
+       cache_ptr->other = bfd_h_get_8(abfd, sym_pointer->e_other);
+       cache_ptr->type = bfd_h_get_8(abfd,  sym_pointer->e_type);
+       cache_ptr->symbol.udata = 0;
+       translate_from_native_sym_flags (sym_pointer, cache_ptr,        
+                                        abfd, &state);
+      }
+  }
+
   obj_aout_symbols (abfd) =  cached;
   free((PTR)syms);
-    
+
   return true;
 }
 
+\f
+/* Possible improvements:
+   + look for strings matching trailing substrings of other strings
+   + better data structures?  balanced trees?
+   + smaller per-string or per-symbol data?  re-use some of the symbol's
+     data fields?
+   + also look at reducing memory use elsewhere -- maybe if we didn't have to
+     construct the entire symbol table at once, we could get by with smaller
+     amounts of VM?  (What effect does that have on the string table
+     reductions?)
+   + rip this out of here, put it into its own file in bfd or libiberty, so
+     coff and elf can use it too.  I'll work on this soon, but have more
+     pressing tasks right now.
+
+   A hash table might(?) be more efficient for handling exactly the cases that
+   are handled now, but for trailing substring matches, I think we want to
+   examine the `nearest' values (reverse-)lexically, not merely impose a strict
+   order, nor look only for exact-match or not-match.  I don't think a hash
+   table would be very useful for that, and I don't feel like fleshing out two
+   completely different implementations.  [raeburn:930419.0331EDT] */
+
+#if __GNUC__ >= 2
+#define INLINE __inline__
+#else
+#define INLINE
+#endif
+
+struct stringtab_entry {
+  /* Hash value for this string.  Only useful so long as we aren't doing
+     substring matches.  */
+  int hash;
+
+  /* Next node to look at, depending on whether the hash value of the string
+     being searched for is less than or greater than the hash value of the
+     current node.  For now, `equal to' is lumped in with `greater than', for
+     space efficiency.  It's not a common enough case to warrant another field
+     to be used for all nodes.  */
+  struct stringtab_entry *less;
+  struct stringtab_entry *greater;
+
+  /* The string itself.  */
+  CONST char *string;
+
+  /* The index allocated for this string.  */
+  bfd_size_type index;
+
+#ifdef GATHER_STATISTICS
+  /* How many references have there been to this string?  (Not currently used;
+     could be dumped out for anaylsis, if anyone's interested.)  */
+  unsigned long count;
+#endif
+
+  /* Next node in linked list, in suggested output order.  */
+  struct stringtab_entry *next_to_output;
+};
+
+struct stringtab_data {
+  /* Tree of string table entries.  */
+  struct stringtab_entry *strings;
+
+  /* Fudge factor used to center top node of tree.  */
+  int hash_zero;
+
+  /* Next index value to issue.  */
+  bfd_size_type index;
+
+  /* Index used for empty strings.  Cached here because checking for them
+     is really easy, and we can avoid searching the tree.  */
+  bfd_size_type empty_string_index;
+
+  /* These fields indicate the two ends of a singly-linked list that indicates
+     the order strings should be written out in.  Use this order, and no
+     seeking will need to be done, so output efficiency should be maximized. */
+  struct stringtab_entry **end;
+  struct stringtab_entry *output_order;
+
+#ifdef GATHER_STATISTICS
+  /* Number of strings which duplicate strings already in the table.  */
+  unsigned long duplicates;
+
+  /* Number of bytes saved by not having to write all the duplicate strings. */
+  unsigned long bytes_saved;
+
+  /* Number of zero-length strings.  Currently, these all turn into
+     references to the null byte at the end of the first string.  In some
+     cases (possibly not all?  explore this...), it should be possible to
+     simply write out a zero index value.  */
+  unsigned long empty_strings;
+
+  /* Number of times the hash values matched but the strings were different.
+     Note that this includes the number of times the other string(s) occurs, so
+     there may only be two strings hashing to the same value, even if this
+     number is very large.  */
+  unsigned long bad_hash_matches;
+
+  /* Null strings aren't counted in this one.
+     This will probably only be nonzero if we've got an input file
+     which was produced by `ld -r' (i.e., it's already been processed
+     through this code).  Under some operating systems, native tools
+     may make all empty strings have the same index; but the pointer
+     check won't catch those, because to get to that stage we'd already
+     have to compute the checksum, which requires reading the string,
+     so we short-circuit that case with empty_string_index above.  */
+  unsigned long pointer_matches;
+
+  /* Number of comparisons done.  I figure with the algorithms in use below,
+     the average number of comparisons done (per symbol) should be roughly
+     log-base-2 of the number of unique strings.  */
+  unsigned long n_compares;
+#endif
+};
+
+/* Some utility functions for the string table code.  */
+
+static INLINE int
+hash (string)
+     char *string;
+{
+  unsigned int sum = 0;
+  while (*string)
+    {
+#if 0
+      /* This expression borrowed from some code in gnu make.  */
+      sum += *string++, sum = (sum << 7) + (sum >> 20);
+#endif
+      /* This appears to get a better distribution, at least for my one
+        test case.  Do some analysis on this later, get a real hash
+        algorithm.  */
+      sum ^= sum >> 20;
+      sum ^= sum << 7;
+      sum += *string++;
+    }
+  return sum;
+}
+
+static INLINE void
+stringtab_init (tab)
+     struct stringtab_data *tab;
+{
+  tab->strings = 0;
+  tab->output_order = 0;
+  tab->end = &tab->output_order;
+
+  /* Initial string table length includes size of length field.  */
+  tab->index = BYTES_IN_WORD;
+  tab->empty_string_index = -1;
+#ifdef GATHER_STATISTICS
+  tab->duplicates = 0;
+  tab->empty_strings = 0;
+  tab->bad_hash_matches = 0;
+  tab->pointer_matches = 0;
+  tab->bytes_saved = 0;
+  tab->n_compares = 0;
+#endif
+}
+
+static INLINE int
+compare (entry, str, hash)
+     struct stringtab_entry *entry;
+     CONST char *str;
+     int hash;
+{
+  if (hash == entry->hash)
+    return 0;
+  if (hash > entry->hash)
+    return 1;
+  if (hash < entry->hash)
+    return -1;
+  abort ();
+}
+
+#ifdef GATHER_STATISTICS
+/* Don't want to have to link in math library with all bfd applications...  */
+static INLINE double
+log2 (num)
+     int num;
+{
+  double d = num;
+#if defined (__i386__) && __GNUC__ >= 2
+  asm ("fyl2x" : "=t" (d) : "0" (d), "u" (1.0));
+  return d;
+#else
+  int n = 0;
+  while (d >= 2.0)
+    n++, d /= 2.0;
+  return ((d > 1.41) ? 0.5 : 0) + n;
+#endif
+}
+#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, check)
+     bfd *abfd;
+     CONST char *str;
+     struct stringtab_data *tab;
+     int check;
+{
+  struct stringtab_entry **ep;
+  struct stringtab_entry *entry;
+  int hashval, len;
+
+  if (str[0] == 0)
+    {
+      bfd_size_type index;
+      CONST bfd_size_type minus_one = -1;
+
+#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;
+       }
+
+      /* 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) ^ tab->hash_zero;
+  ep = &tab->strings;
+  if (!*ep)
+    {
+      tab->hash_zero = hashval;
+      hashval = 0;
+      goto add_it;
+    }
+
+  while (*ep)
+    {
+      int cmp;
+      entry = *ep;
+#ifdef GATHER_STATISTICS
+      tab->n_compares++;
+#endif
+      cmp = compare (entry, str, hashval);
+      if (cmp == 0)
+       {
+         if (entry->string == str)
+           {
+#ifdef GATHER_STATISTICS
+             tab->pointer_matches++;
+#endif
+             goto match;
+           }
+         if (!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;
+       }
+      else if (cmp > 0)
+       ep = &entry->greater;
+      else
+       /* cmp < 0 */
+       ep = &entry->less;
+    }
+
+  /* If we get here, nothing that's in the table already matched.
+     EP points to the `next' field at the end of the chain; stick a
+     new entry on here.  */
+ add_it:
+  entry = (struct stringtab_entry *) bfd_alloc_by_size_t (abfd,
+                                                         sizeof (struct stringtab_entry));
+
+  entry->less = entry->greater = 0;
+  entry->hash = hashval;
+  entry->index = tab->index;
+  entry->string = str;
+  entry->next_to_output = 0;
+#ifdef GATHER_STATISTICS
+  entry->count = 1;
+#endif
+
+  assert (*tab->end == 0);
+  *(tab->end) = entry;
+  tab->end = &entry->next_to_output;
+  assert (*tab->end == 0);
+
+  {
+    tab->index += len + 1;
+    if (len == 0)
+      tab->empty_string_index = entry->index;
+  }
+  assert (*ep == 0);
+  *ep = entry;
+  return entry->index;
+}
+
+static void
+emit_strtab (abfd, tab)
+     bfd *abfd;
+     struct stringtab_data *tab;
+{
+  struct stringtab_entry *entry;
+#ifdef GATHER_STATISTICS
+  int count = 0;
+#endif
+
+  /* Be sure to put string length into correct byte ordering before writing
+     it out.  */
+  char buffer[BYTES_IN_WORD];
+
+  PUT_WORD (abfd, tab->index, (unsigned char *) buffer);
+  bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd);
+
+  for (entry = tab->output_order; entry; entry = entry->next_to_output)
+    {
+      bfd_write ((PTR) entry->string, 1, strlen (entry->string) + 1, abfd);
+#ifdef GATHER_STATISTICS
+      count++;
+#endif
+    }
+
+#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 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++);
+
+      if (g->name)
+       {
+         size_t length = strlen(g->name)+1;
+         bfd_write((PTR)g->name, 1, length, abfd);
+       }
+      g->KEEPIT = (KEEPITTYPE) count;
+    } */
+}
 
 void
 DEFUN(NAME(aout,write_syms),(abfd),
       bfd *abfd)
-  {
-    unsigned int count ;
-    asymbol **generic = bfd_get_outsymbols (abfd);
-    
-    bfd_size_type stindex = BYTES_IN_WORD; /* initial string length */
-    
-    for (count = 0; count < bfd_get_symcount (abfd); count++) {
+{
+  unsigned int count ;
+  asymbol **generic = bfd_get_outsymbols (abfd);
+  struct stringtab_data strtab;
+
+  stringtab_init (&strtab);
+
+  for (count = 0; count < bfd_get_symcount (abfd); count++)
+    {
       asymbol *g = generic[count];
       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);
 
-      if (g->name) {
-       unsigned int length = strlen(g->name) +1;
-       PUT_WORD  (abfd, stindex, (unsigned char *)nsp.e_strx);
-       stindex += length;
-      }
-      else 
-
-      {
-       PUT_WORD  (abfd, 0, (unsigned char *)nsp.e_strx);
-      }
-      
-      if (g->the_bfd->xvec->flavour == abfd->xvec->flavour) 
-         {
-           bfd_h_put_16(abfd, aout_symbol(g)->desc,  nsp.e_desc);
-           bfd_h_put_8(abfd, aout_symbol(g)->other,  nsp.e_other);
-           bfd_h_put_8(abfd, aout_symbol(g)->type,  nsp.e_type);
-         }
+      if (bfd_asymbol_flavour(g) == abfd->xvec->flavour)
+       {
+         bfd_h_put_16(abfd, aout_symbol(g)->desc,  nsp.e_desc);
+         bfd_h_put_8(abfd, aout_symbol(g)->other,  nsp.e_other);
+         bfd_h_put_8(abfd, aout_symbol(g)->type,  nsp.e_type);
+       }
       else
-         {
-           bfd_h_put_16(abfd,0, nsp.e_desc);
-           bfd_h_put_8(abfd, 0,  nsp.e_other);
-           bfd_h_put_8(abfd, 0,  nsp.e_type);
-         }
+       {
+         bfd_h_put_16(abfd,0, nsp.e_desc);
+         bfd_h_put_8(abfd, 0, nsp.e_other);
+         bfd_h_put_8(abfd, 0, nsp.e_type);
+       }
 
       translate_to_native_sym_flags (&nsp, g, abfd);
 
       bfd_write((PTR)&nsp,1,EXTERNAL_NLIST_SIZE, abfd);
-    }
-    
-    /* Now output the strings.  Be sure to put string length into correct
-       byte ordering before writing it.  */
-      {
-       char buffer[BYTES_IN_WORD];
-       PUT_WORD  (abfd, stindex, (unsigned char *)buffer);
-    
-       bfd_write((PTR)buffer, 1, BYTES_IN_WORD, abfd);
-      }
-    generic = bfd_get_outsymbols(abfd);
-    for (count = 0; count < bfd_get_symcount(abfd); count++) 
-       {
-         asymbol *g = *(generic++);
-         
-         if (g->name)
-             {
-               size_t length = strlen(g->name)+1;
-               bfd_write((PTR)g->name, 1, length, abfd);
-             }
-           g->KEEPIT = (KEEPITTYPE) count;
-       }
-  }
 
+      /* NB: `KEEPIT' currently overlays `flags', so set this only
+        here, at the end.  */
+      g->KEEPIT = count;
+    }
 
+  emit_strtab (abfd, &strtab);
+}
 
+\f
 unsigned int
 DEFUN(NAME(aout,get_symtab),(abfd, location),
       bfd *abfd AND
@@ -1420,13 +1876,33 @@ DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
     
   /* name was clobbered by aout_write_syms to be symbol index */
 
-  if (output_section == &bfd_com_section 
+  /* If this relocation is relative to a symbol then set the 
+     r_index to the symbols index, and the r_extern bit.
+
+     Absolute symbols can come in in two ways, either as an offset
+     from the abs section, or as a symbol which has an abs value.
+     check for that here
+     */
+     
+
+  if (bfd_is_com_section (output_section)
       || output_section == &bfd_abs_section
       || output_section == &bfd_und_section) 
     {
-      /* Fill in symbol */
-      r_extern = 1;
-      r_index =  stoi((*(g->sym_ptr_ptr))->KEEPIT);
+      if (bfd_abs_section.symbol == sym)
+      {
+       /* Whoops, looked like an abs symbol, but is really an offset
+          from the abs section */
+       r_index = 0;
+       r_extern = 0;
+       }
+      else 
+      {
+       /* Fill in symbol */
+       r_extern = 1;
+       r_index =  stoi((*(g->sym_ptr_ptr))->KEEPIT);
+     
+      }
     }
   else 
     {
@@ -1485,13 +1961,30 @@ DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
 
 
- if (output_section == &bfd_com_section 
-     || output_section == &bfd_abs_section
-     || output_section == &bfd_und_section) 
+  /* If this relocation is relative to a symbol then set the 
+     r_index to the symbols index, and the r_extern bit.
+
+     Absolute symbols can come in in two ways, either as an offset
+     from the abs section, or as a symbol which has an abs value.
+     check for that here
+     */
+     
+  if (bfd_is_com_section (output_section)
+      || output_section == &bfd_abs_section
+      || output_section == &bfd_und_section)
   {
-    /* Fill in symbol */
-    r_extern = 1;
-    r_index =  stoi((*(g->sym_ptr_ptr))->KEEPIT);
+    if (bfd_abs_section.symbol == sym)
+    {
+      /* Whoops, looked like an abs symbol, but is really an offset
+        from the abs section */
+      r_index = 0;
+      r_extern = 0;
+     }
+    else 
+    {
+      r_extern = 1;
+      r_index =  stoi((*(g->sym_ptr_ptr))->KEEPIT);
+    }
   }
   else 
   {
@@ -1503,20 +1996,20 @@ DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
         
   /* now the fun stuff */
   if (abfd->xvec->header_byteorder_big_p != false) {
-      natptr->r_index[0] = r_index >> 16;
-      natptr->r_index[1] = r_index >> 8;
-      natptr->r_index[2] = r_index;
-      natptr->r_type[0] =
-       (r_extern? RELOC_EXT_BITS_EXTERN_BIG: 0)
-       | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
-    } else {
-       natptr->r_index[2] = r_index >> 16;
-       natptr->r_index[1] = r_index >> 8;
-       natptr->r_index[0] = r_index;
-       natptr->r_type[0] =
-        (r_extern? RELOC_EXT_BITS_EXTERN_LITTLE: 0)
-         | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
-      }
+    natptr->r_index[0] = r_index >> 16;
+    natptr->r_index[1] = r_index >> 8;
+    natptr->r_index[2] = r_index;
+    natptr->r_type[0] =
+     (r_extern? RELOC_EXT_BITS_EXTERN_BIG: 0)
+      | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
+  } else {
+    natptr->r_index[2] = r_index >> 16;
+    natptr->r_index[1] = r_index >> 8;
+    natptr->r_index[0] = r_index;
+    natptr->r_type[0] =
+     (r_extern? RELOC_EXT_BITS_EXTERN_LITTLE: 0)
+      | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
+  }
 
   PUT_WORD (abfd, r_addend, natptr->r_addend);
 }
@@ -1908,7 +2401,7 @@ DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how),
       if (section_code == '?')
        {
          int type_code = aout_symbol(symbol)->type  & 0xff;
-         char *stab_name = aout_stab_name(type_code);
+         CONST char *stab_name = aout_stab_name(type_code);
          char buf[10];
          if (stab_name == NULL)
            {
This page took 0.038436 seconds and 4 git commands to generate.