]> Git Repo - binutils.git/blobdiff - bfd/aoutx.h
Don't let netbsd386.c get sanitized out.
[binutils.git] / bfd / aoutx.h
index 909c5b281dcb6962949fdcafb1a3845af6b80bb2..b4cc7e60183363f7c5cc81c6efa6015a562a7335 100644 (file)
@@ -1,5 +1,5 @@
 /* BFD semi-generic back-end for a.out binaries.
-   Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -120,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>
@@ -154,44 +156,45 @@ DESCRIPTION
 
 reloc_howto_type howto_table_ext[] = 
 {
-  HOWTO(RELOC_8,      0,  0,   8,  false, 0, true,  true,0,"8",      false, 0,0x000000ff, false),
-  HOWTO(RELOC_16,     0,  1,   16, false, 0, true,  true,0,"16",      false, 0,0x0000ffff, false),
-  HOWTO(RELOC_32,     0,  2,   32, false, 0, true,  true,0,"32",      false, 0,0xffffffff, false),
-  HOWTO(RELOC_DISP8,  0,  0,   8,  true,  0, false, true,0,"DISP8",    false, 0,0x000000ff, false),
-  HOWTO(RELOC_DISP16, 0,  1,   16, true,  0, false, true,0,"DISP16",   false, 0,0x0000ffff, false),
-  HOWTO(RELOC_DISP32, 0,  2,   32, true,  0, false, true,0,"DISP32",   false, 0,0xffffffff, false),
-  HOWTO(RELOC_WDISP30,2,  2,   30, true,  0, false, true,0,"WDISP30",  false, 0,0x3fffffff, false),
-  HOWTO(RELOC_WDISP22,2,  2,   22, true,  0, false, true,0,"WDISP22",  false, 0,0x003fffff, false),
-  HOWTO(RELOC_HI22,   10, 2,   22, false, 0, false, true,0,"HI22",     false, 0,0x003fffff, false),
-  HOWTO(RELOC_22,      0, 2,   22, false, 0, false, true,0,"22",       false, 0,0x003fffff, false),
-  HOWTO(RELOC_13,      0, 2,   13, false, 0, false, true,0,"13",       false, 0,0x00001fff, false),
-  HOWTO(RELOC_LO10,    0, 2,   10, false, 0, false, true,0,"LO10",     false, 0,0x000003ff, false),
-  HOWTO(RELOC_SFA_BASE,0, 2,   32, false, 0, false, true,0,"SFA_BASE", false, 0,0xffffffff, false),
-  HOWTO(RELOC_SFA_OFF13,0,2,   32, false, 0, false, true,0,"SFA_OFF13",false, 0,0xffffffff, false),
-  HOWTO(RELOC_BASE10, 0,  2,   16, false, 0, false, true,0,"BASE10",   false, 0,0x0000ffff, false),
-  HOWTO(RELOC_BASE13, 0,  2,   13, false, 0, false, true,0,"BASE13",   false, 0,0x00001fff, false),
-  HOWTO(RELOC_BASE22, 0,  2,   0,  false, 0, false, true,0,"BASE22",   false, 0,0x00000000, false),
-  HOWTO(RELOC_PC10,   0,  2,   10, false, 0, false, true,0,"PC10",     false, 0,0x000003ff, false),
-  HOWTO(RELOC_PC22,   0,  2,   22, false, 0, false, true,0,"PC22",     false, 0,0x003fffff, false),
-  HOWTO(RELOC_JMP_TBL,0,  2,   32, false, 0, false, true,0,"JMP_TBL",  false, 0,0xffffffff, false),
-  HOWTO(RELOC_SEGOFF16,0, 2,   0,  false, 0, false, true,0,"SEGOFF16", false, 0,0x00000000, false),
-  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),
+  /* type           rs   size bsz  pcrel bitpos ovrf sf name    part_inpl   readmask  setmask  pcdone */
+  HOWTO(RELOC_8,      0,  0,   8,  false, 0, complain_overflow_bitfield,0,"8",        false, 0,0x000000ff, false),
+  HOWTO(RELOC_16,     0,  1,   16, false, 0, complain_overflow_bitfield,0,"16",       false, 0,0x0000ffff, false),
+  HOWTO(RELOC_32,     0,  2,   32, false, 0, complain_overflow_bitfield,0,"32",       false, 0,0xffffffff, false),
+  HOWTO(RELOC_DISP8,  0,  0,   8,  true,  0, complain_overflow_signed,0,"DISP8",       false, 0,0x000000ff, false),
+  HOWTO(RELOC_DISP16, 0,  1,   16, true,  0, complain_overflow_signed,0,"DISP16",      false, 0,0x0000ffff, false),
+  HOWTO(RELOC_DISP32, 0,  2,   32, true,  0, complain_overflow_signed,0,"DISP32",      false, 0,0xffffffff, false),
+  HOWTO(RELOC_WDISP30,2,  2,   30, true,  0, complain_overflow_signed,0,"WDISP30",     false, 0,0x3fffffff, false),
+  HOWTO(RELOC_WDISP22,2,  2,   22, true,  0, complain_overflow_signed,0,"WDISP22",     false, 0,0x003fffff, false),
+  HOWTO(RELOC_HI22,   10, 2,   22, false, 0, complain_overflow_bitfield,0,"HI22",      false, 0,0x003fffff, false),
+  HOWTO(RELOC_22,     0,  2,   22, false, 0, complain_overflow_bitfield,0,"22",       false, 0,0x003fffff, false),
+  HOWTO(RELOC_13,     0,  2,   13, false, 0, complain_overflow_bitfield,0,"13",       false, 0,0x00001fff, false),
+  HOWTO(RELOC_LO10,   0,  2,   10, false, 0, complain_overflow_dont,0,"LO10",     false, 0,0x000003ff, false),
+  HOWTO(RELOC_SFA_BASE,0, 2,   32, false, 0, complain_overflow_bitfield,0,"SFA_BASE", false, 0,0xffffffff, false),
+  HOWTO(RELOC_SFA_OFF13,0,2,   32, false, 0, complain_overflow_bitfield,0,"SFA_OFF13",false, 0,0xffffffff, false),
+  HOWTO(RELOC_BASE10, 0,  2,   16, false, 0, complain_overflow_bitfield,0,"BASE10",   false, 0,0x0000ffff, false),
+  HOWTO(RELOC_BASE13, 0,  2,   13, false, 0, complain_overflow_bitfield,0,"BASE13",   false, 0,0x00001fff, false),
+  HOWTO(RELOC_BASE22, 0,  2,   0,  false, 0, complain_overflow_bitfield,0,"BASE22",   false, 0,0x00000000, false),
+  HOWTO(RELOC_PC10,   0,  2,   10, false, 0, complain_overflow_bitfield,0,"PC10",      false, 0,0x000003ff, false),
+  HOWTO(RELOC_PC22,   0,  2,   22, false, 0, complain_overflow_bitfield,0,"PC22",      false, 0,0x003fffff, false),
+  HOWTO(RELOC_JMP_TBL,0,  2,   32, false, 0, complain_overflow_bitfield,0,"JMP_TBL",   false, 0,0xffffffff, false),
+  HOWTO(RELOC_SEGOFF16,0, 2,   0,  false, 0, complain_overflow_bitfield,0,"SEGOFF16",  false, 0,0x00000000, false),
+  HOWTO(RELOC_GLOB_DAT,0, 2,   0,  false, 0, complain_overflow_bitfield,0,"GLOB_DAT",  false, 0,0x00000000, false),
+  HOWTO(RELOC_JMP_SLOT,0, 2,   0,  false, 0, complain_overflow_bitfield,0,"JMP_SLOT",  false, 0,0x00000000, false),
+  HOWTO(RELOC_RELATIVE,0, 2,   0,  false, 0, complain_overflow_bitfield,0,"RELATIVE",  false, 0,0x00000000, false),
 };
 
 /* Convert standard reloc records to "arelent" format (incl byte swap).  */
 
 reloc_howto_type howto_table_std[] = {
-  /* type           rs   size bsz  pcrel bitpos  abs ovrf sf name    part_inpl   readmask  setmask  pcdone */
-HOWTO( 0,             0,  0,   8,  false, 0, true,  true,0,"8",        true, 0x000000ff,0x000000ff, false),
-HOWTO( 1,             0,  1,   16, false, 0, true,  true,0,"16",       true, 0x0000ffff,0x0000ffff, false),
-HOWTO( 2,             0,  2,   32, false, 0, true,  true,0,"32",       true, 0xffffffff,0xffffffff, false),
-HOWTO( 3,             0,  3,   64, false, 0, true,  true,0,"64",       true, 0xdeaddead,0xdeaddead, false),
-HOWTO( 4,             0,  0,   8,  true,  0, false, true,0,"DISP8",    true, 0x000000ff,0x000000ff, false),
-HOWTO( 5,             0,  1,   16, true,  0, false, true,0,"DISP16",   true, 0x0000ffff,0x0000ffff, false),
-HOWTO( 6,             0,  2,   32, true,  0, false, true,0,"DISP32",   true, 0xffffffff,0xffffffff, false),
-HOWTO( 7,             0,  3,   64, true,  0, false, true,0,"DISP64",   true, 0xfeedface,0xfeedface, false),
+  /* type           rs   size bsz  pcrel bitpos ovrf sf name    part_inpl   readmask  setmask  pcdone */
+HOWTO( 0,             0,  0,   8,  false, 0, complain_overflow_bitfield,0,"8", true, 0x000000ff,0x000000ff, false),
+HOWTO( 1,             0,  1,   16, false, 0, complain_overflow_bitfield,0,"16",        true, 0x0000ffff,0x0000ffff, false),
+HOWTO( 2,             0,  2,   32, false, 0, complain_overflow_bitfield,0,"32",        true, 0xffffffff,0xffffffff, false),
+HOWTO( 3,             0,  3,   64, false, 0, complain_overflow_bitfield,0,"64",       true, 0xdeaddead,0xdeaddead, false),
+HOWTO( 4,             0,  0,   8,  true,  0, complain_overflow_signed,0,"DISP8",    true, 0x000000ff,0x000000ff, false),
+HOWTO( 5,             0,  1,   16, true,  0, complain_overflow_signed,0,"DISP16",   true, 0x0000ffff,0x0000ffff, false),
+HOWTO( 6,             0,  2,   32, true,  0, complain_overflow_signed,0,"DISP32",   true, 0xffffffff,0xffffffff, false),
+HOWTO( 7,             0,  3,   64, true,  0, complain_overflow_signed,0,"DISP64",   true, 0xfeedface,0xfeedface, false),
 };
 
 CONST struct reloc_howto_struct *
@@ -216,6 +219,7 @@ DEFUN(NAME(aout,reloc_type_lookup),(abfd,code),
        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 */
@@ -226,8 +230,8 @@ DEFUN(NAME(aout,reloc_type_lookup),(abfd,code),
        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;
       }
-  return 0;
 }
 
 extern bfd_error_vector_type bfd_error_vector;
@@ -252,13 +256,14 @@ 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,
             struct internal_exec *execp);
 */
         
+#ifndef NAME_swap_exec_header_in
 void
 DEFUN(NAME(aout,swap_exec_header_in),(abfd, raw_bytes, execp),
       bfd *abfd AND
@@ -282,6 +287,8 @@ DEFUN(NAME(aout,swap_exec_header_in),(abfd, raw_bytes, execp),
   execp->a_trsize = GET_WORD (abfd, bytes->e_trsize);
   execp->a_drsize = GET_WORD (abfd, bytes->e_drsize);
 }
+#define NAME_swap_exec_header_in NAME(aout,swap_exec_header_in)
+#endif
 
 /*
 FUNCTION
@@ -291,7 +298,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,
@@ -329,7 +336,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)());
@@ -339,7 +346,7 @@ 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 *))
+      bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *)))
 {
   struct aout_data_struct *rawptr, *oldrawptr;
   bfd_target *result;
@@ -352,6 +359,14 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
 
   oldrawptr = abfd->tdata.aout_data;
   abfd->tdata.aout_data = rawptr;
+
+  /* Copy the contents of the old tdata struct.
+     In particular, we want the subformat, since for hpux it was set in
+     hp300hpux.c:swap_exec_header_in and will be used in
+     hp300hpux.c:callback.  */
+  if (oldrawptr != NULL)
+    *abfd->tdata.aout_data = *oldrawptr;
+
   abfd->tdata.aout_data->a.hdr = &rawptr->e;
   *(abfd->tdata.aout_data->a.hdr) = *execp;    /* Copy in the internal_exec struct */
   execp = abfd->tdata.aout_data->a.hdr;
@@ -388,8 +403,8 @@ DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
   /* The default symbol entry size is that of traditional Unix. */
   obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE;
 
-  /* create the sections.  This is raunchy, but bfd_close wants to reclaim
-     them */
+  /* 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");
@@ -505,7 +520,7 @@ FUNCTION
 DESCRIPTION
        This routine initializes a BFD for use with a.out files.
 
-EXAMPLE
+SYNOPSIS
        boolean aout_<size>_mkobject, (bfd *);
 */
 
@@ -518,7 +533,7 @@ DEFUN(NAME(aout,mkobject),(abfd),
   bfd_error = system_call_error;
 
   /* Use an intermediate variable for clarity */
-  rawptr = (struct aout_data_struct  *)bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
+  rawptr = (struct aout_data_struct *)bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
   
   if (rawptr == NULL) {
     bfd_error = no_memory;
@@ -557,7 +572,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));
@@ -595,9 +610,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;
 }
@@ -612,7 +638,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,
@@ -625,7 +651,9 @@ DEFUN(NAME(aout,set_arch_mach),(abfd, arch, machine),
       enum bfd_architecture arch AND
       unsigned long machine)
 {
-  bfd_default_set_arch_mach(abfd, arch, 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 */
@@ -634,6 +662,7 @@ DEFUN(NAME(aout,set_arch_mach),(abfd, arch, machine),
   switch (arch) {
   case bfd_arch_sparc:
   case bfd_arch_a29k:
+  case bfd_arch_mips:
     obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
     break;
   default:
@@ -678,7 +707,8 @@ DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
   if (adata(abfd).magic == undecided_magic)
     {
       if (abfd->flags & D_PAGED)
-       /* whether or not WP_TEXT is set */
+       /* 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;
@@ -806,18 +836,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);
@@ -875,13 +894,13 @@ DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
 
 /*
 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));
@@ -922,33 +941,22 @@ 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)
+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)
 {
   file_ptr text_end;
   bfd_size_type text_size;
 
   if (abfd->output_has_begun == false)
-      {                                /* set by bfd.c handler */
-       switch (abfd->direction)
-           {
-           case read_direction:
-           case no_direction:
-             bfd_error = invalid_operation;
-             return false;
-
-           case write_direction:
-             if (NAME(aout,adjust_sizes_and_vmas) (abfd,
-                                                   &text_size,
-                                                   &text_end) == false)
-               return false;
-           case both_direction:
-             break;
-           }
+      {
+       if (NAME(aout,adjust_sizes_and_vmas) (abfd,
+                                             &text_size,
+                                             &text_end) == false)
+         return false;
       }
 
   /* regardless, once we know what we're doing, we might as well get going */
@@ -1007,179 +1015,210 @@ 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),
+       struct external_nlist *sym_pointer AND
+       aout_symbol_type * cache_ptr AND
+       bfd * abfd)
 {
-  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;
+  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();
-    }
+      {
+       char *copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1);
+       asection *section;
+       asection *into_section;
 
-    /* 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) 
-    {
-      /* 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;
-      }
+       arelent_chain *reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain));
+       strcpy (copy, cache_ptr->symbol.name);
 
-      
-    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) 
+       /* 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;
+           cache_ptr->type = N_ABS;
+           break;
+         case N_SETT:
+           into_section = (asection *) obj_textsec (abfd);
+           cache_ptr->type = N_TEXT;
+           break;
+         case N_SETD:
+           into_section = (asection *) obj_datasec (abfd);
+           cache_ptr->type = N_DATA;
+           break;
+         case N_SETB:
+           into_section = (asection *) 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 */
+
+       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
+         = (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)
        {
-       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:
+         /* 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));
 
-         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;
        }
-      }
-    else {
-
-       if (sym_is_fortrancommon (cache_ptr))
+      if ((cache_ptr->type | N_EXT) == (N_INDR | N_EXT))
        {
-         cache_ptr->symbol.flags = 0;
-         cache_ptr->symbol.section = &bfd_com_section;
-       }
-       else {
+         /* 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;
+       }
 
-         }
-         
-       /* 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))
+      else if (sym_is_debugger_info (cache_ptr))
        {
-         cache_ptr->symbol.section = &bfd_abs_section;
+         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;
+           }
        }
-           
-       if (sym_is_global_defn (cache_ptr)) 
-       {
-         cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT;
-       } 
-       else 
+      else
        {
-         cache_ptr->symbol.flags = BSF_LOCAL;
+
+         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 ();
 }
 
 
@@ -1195,57 +1234,74 @@ 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;
-    }
-  else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) {
-      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) 
-  {
+  /* We attempt to order these tests by decreasing frequency of success,
+     according to tcov when linking the linker.  */
+  if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) {
     sym_pointer->e_type[0] |= N_ABS;
   }
-  else if (bfd_get_output_section(cache_ptr) == &bfd_und_section) 
-  {
-    sym_pointer->e_type[0] = (N_UNDF | N_EXT);
+  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) == obj_datasec (abfd)) {
+    sym_pointer->e_type[0] |= N_DATA;
   }
-  else if (bfd_get_output_section(cache_ptr) == &bfd_com_section) {
+  else if (bfd_get_output_section(cache_ptr) == 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) 
+    {
+      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;
-    }
   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;
+  }
+  else if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) {
+    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;
+  }
 
   PUT_WORD(abfd, value, sym_pointer->e_value);
 }
@@ -1263,7 +1319,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;
 }
 
@@ -1277,20 +1333,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)));
@@ -1299,119 +1356,493 @@ 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_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);
-         }
+      goto bailout;
     }
-    
+  strings[string_size] = 0; /* Just in case. */
+
+  /* OK, now walk the new symtable, cacheing symbol properties */
+  {
+    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++) 
+      {
+       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);
+      }
+  }
+
   obj_aout_symbols (abfd) =  cached;
   free((PTR)syms);
-    
+
   return true;
 }
 
+\f
+/* Possible improvements:
+   + look for strings matching trailing substrings of other strings
+   + better data structures?  balanced trees?
+   + smaller per-string or per-symbol data?  re-use some of the symbol's
+     data fields?
+   + also look at reducing memory use elsewhere -- maybe if we didn't have to
+     construct the entire symbol table at once, we could get by with smaller
+     amounts of VM?  (What effect does that have on the string table
+     reductions?)
+   + rip this out of here, put it into its own file in bfd or libiberty, so
+     coff and elf can use it too.  I'll work on this soon, but have more
+     pressing tasks right now.
+
+   A hash table might(?) be more efficient for handling exactly the cases that
+   are handled now, but for trailing substring matches, I think we want to
+   examine the `nearest' values (reverse-)lexically, not merely impose a strict
+   order, nor look only for exact-match or not-match.  I don't think a hash
+   table would be very useful for that, and I don't feel like fleshing out two
+   completely different implementations.  [raeburn:930419.0331EDT] */
+
+struct stringtab_entry {
+  /* Hash value for this string.  Only useful so long as we aren't doing
+     substring matches.  */
+  unsigned int hash;
+
+  /* Next node to look at, depending on whether the hash value of the string
+     being searched for is less than or greater than the hash value of the
+     current node.  For now, `equal to' is lumped in with `greater than', for
+     space efficiency.  It's not a common enough case to warrant another field
+     to be used for all nodes.  */
+  struct stringtab_entry *less;
+  struct stringtab_entry *greater;
+
+  /* The string itself.  */
+  CONST char *string;
+
+  /* The index allocated for this string.  */
+  bfd_size_type index;
+
+#ifdef GATHER_STATISTICS
+  /* How many references have there been to this string?  (Not currently used;
+     could be dumped out for anaylsis, if anyone's interested.)  */
+  unsigned long count;
+#endif
+
+  /* Next node in linked list, in suggested output order.  */
+  struct stringtab_entry *next_to_output;
+};
+
+struct stringtab_data {
+  /* Tree of string table entries.  */
+  struct stringtab_entry *strings;
+
+  /* Fudge factor used to center top node of tree.  */
+  int hash_zero;
+
+  /* Next index value to issue.  */
+  bfd_size_type index;
+
+  /* Index used for empty strings.  Cached here because checking for them
+     is really easy, and we can avoid searching the tree.  */
+  bfd_size_type empty_string_index;
+
+  /* These fields indicate the two ends of a singly-linked list that indicates
+     the order strings should be written out in.  Use this order, and no
+     seeking will need to be done, so output efficiency should be maximized. */
+  struct stringtab_entry **end;
+  struct stringtab_entry *output_order;
+
+#ifdef GATHER_STATISTICS
+  /* Number of strings which duplicate strings already in the table.  */
+  unsigned long duplicates;
+
+  /* Number of bytes saved by not having to write all the duplicate strings. */
+  unsigned long bytes_saved;
+
+  /* Number of zero-length strings.  Currently, these all turn into
+     references to the null byte at the end of the first string.  In some
+     cases (possibly not all?  explore this...), it should be possible to
+     simply write out a zero index value.  */
+  unsigned long empty_strings;
+
+  /* Number of times the hash values matched but the strings were different.
+     Note that this includes the number of times the other string(s) occurs, so
+     there may only be two strings hashing to the same value, even if this
+     number is very large.  */
+  unsigned long bad_hash_matches;
+
+  /* Null strings aren't counted in this one.
+     This will probably only be nonzero if we've got an input file
+     which was produced by `ld -r' (i.e., it's already been processed
+     through this code).  Under some operating systems, native tools
+     may make all empty strings have the same index; but the pointer
+     check won't catch those, because to get to that stage we'd already
+     have to compute the checksum, which requires reading the string,
+     so we short-circuit that case with empty_string_index above.  */
+  unsigned long pointer_matches;
+
+  /* Number of comparisons done.  I figure with the algorithms in use below,
+     the average number of comparisons done (per symbol) should be roughly
+     log-base-2 of the number of unique strings.  */
+  unsigned long n_compares;
+#endif
+};
+
+/* Some utility functions for the string table code.  */
+
+/* For speed, only hash on the first this many bytes of strings.
+   This number was chosen by profiling ld linking itself, with -g.  */
+#define HASHMAXLEN 25
+
+#define HASH_CHAR(c) (sum ^= sum >> 20, sum ^= sum << 7, sum += (c))
+
+static INLINE unsigned int
+hash (string, len)
+     unsigned char *string;
+     register unsigned int len;
+{
+  register unsigned int sum = 0;
+
+  if (len > HASHMAXLEN)
+    {
+      HASH_CHAR (len);
+      len = HASHMAXLEN;
+    }
+
+  while (len--)
+    {
+      HASH_CHAR (*string++);
+    }
+  return sum;
+}
+
+static INLINE void
+stringtab_init (tab)
+     struct stringtab_data *tab;
+{
+  tab->strings = 0;
+  tab->output_order = 0;
+  tab->end = &tab->output_order;
+
+  /* Initial string table length includes size of length field.  */
+  tab->index = BYTES_IN_WORD;
+  tab->empty_string_index = -1;
+#ifdef GATHER_STATISTICS
+  tab->duplicates = 0;
+  tab->empty_strings = 0;
+  tab->bad_hash_matches = 0;
+  tab->pointer_matches = 0;
+  tab->bytes_saved = 0;
+  tab->n_compares = 0;
+#endif
+}
+
+static INLINE int
+compare (entry, str, hash)
+     struct stringtab_entry *entry;
+     CONST char *str;
+     unsigned int hash;
+{
+  return hash - entry->hash;
+}
+
+#ifdef GATHER_STATISTICS
+/* Don't want to have to link in math library with all bfd applications...  */
+static INLINE double
+log2 (num)
+     int num;
+{
+  double d = num;
+  int n = 0;
+  while (d >= 2.0)
+    n++, d /= 2.0;
+  return ((d > 1.41) ? 0.5 : 0) + n;
+}
+#endif
+
+/* 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;
+  register struct stringtab_entry *entry;
+  unsigned 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, len) ^ tab->hash_zero;
+  ep = &tab->strings;
+  if (!*ep)
+    {
+      tab->hash_zero = hashval;
+      hashval = 0;
+      goto add_it;
+    }
+
+  while (*ep)
+    {
+      register int cmp;
+
+      entry = *ep;
+#ifdef GATHER_STATISTICS
+      tab->n_compares++;
+#endif
+      cmp = compare (entry, str, hashval);
+      /* The not-equal cases are more frequent, so check them first.  */
+      if (cmp > 0)
+       ep = &entry->greater;
+      else if (cmp < 0)
+       ep = &entry->less;
+      else
+       {
+         if (entry->string == str)
+           {
+#ifdef GATHER_STATISTICS
+             tab->pointer_matches++;
+#endif
+             goto match;
+           }
+         /* Compare the first bytes to save a function call if they
+            don't match.  */
+         if (entry->string[0] == str[0] && !strcmp (entry->string, str))
+           {
+           match:
+#ifdef GATHER_STATISTICS
+             entry->count++;
+             tab->bytes_saved += len + 1;
+             tab->duplicates++;
+#endif
+             /* If we're in the linker, and the new string is from a new
+                input file which might have already had these reductions
+                run over it, we want to keep the new string pointer.  I
+                don't think we're likely to see any (or nearly as many,
+                at least) cases where a later string is in the same location
+                as an earlier one rather than this one.  */
+             entry->string = str;
+             return entry->index;
+           }
+#ifdef GATHER_STATISTICS
+         tab->bad_hash_matches++;
+#endif
+         ep = &entry->greater;
+       }
+    }
+
+  /* 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 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++);
+
+      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
@@ -1469,7 +1900,7 @@ DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
      */
      
 
-  if (output_section == &bfd_com_section 
+  if (bfd_is_com_section (output_section)
       || output_section == &bfd_abs_section
       || output_section == &bfd_und_section) 
     {
@@ -1553,9 +1984,9 @@ DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
      check for that here
      */
      
-  if (output_section == &bfd_com_section 
+  if (bfd_is_com_section (output_section)
       || output_section == &bfd_abs_section
-      || output_section == &bfd_und_section) 
+      || output_section == &bfd_und_section)
   {
     if (bfd_abs_section.symbol == sym)
     {
@@ -1689,7 +2120,7 @@ DEFUN(NAME(aout,swap_std_reloc_in), (abfd, bytes, cache_ptr, symbols),
   int r_baserel, r_jmptable, r_relative;
   struct aoutdata  *su = &(abfd->tdata.aout_data->a);
 
-  cache_ptr->address = (int32_type)(bfd_h_get_32 (abfd, bytes->r_address));
+  cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address);
 
   /* now the fun stuff */
   if (abfd->xvec->header_byteorder_big_p != false) {
@@ -1938,6 +2369,31 @@ DEFUN(NAME(aout,get_lineno),(ignore_abfd, ignore_symbol),
 return (alent *)NULL;
 }
 
+void 
+DEFUN(NAME(aout,get_symbol_info),(ignore_abfd, symbol, ret),
+      bfd *ignore_abfd AND
+      asymbol *symbol AND
+      symbol_info *ret)
+{
+  bfd_symbol_info (symbol, ret);
+
+  if (ret->type == '?')
+    {
+      int type_code = aout_symbol(symbol)->type & 0xff;
+      CONST char *stab_name = aout_stab_name(type_code);
+      static char buf[10];
+
+      if (stab_name == NULL)
+       {
+         sprintf(buf, "(%d)", type_code);
+         stab_name = buf;
+       }
+      ret->type = '-';
+      ret->stab_other = (unsigned)(aout_symbol(symbol)->other & 0xff);
+      ret->stab_desc = (unsigned)(aout_symbol(symbol)->desc & 0xffff);
+      ret->stab_name = stab_name;
+    }
+}
 
 void 
 DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how),
@@ -1974,35 +2430,6 @@ DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how),
         fprintf(file," %s", symbol->name);
     }
     break;
-  case bfd_print_symbol_nm:
-    {
-      int section_code = bfd_decode_symclass  (symbol);
-
-      if (section_code == 'U')
-       fprintf(file, "        ");
-      else
-       fprintf_vma(file, symbol->value+symbol->section->vma);
-      if (section_code == '?')
-       {
-         int type_code = aout_symbol(symbol)->type  & 0xff;
-         char *stab_name = aout_stab_name(type_code);
-         char buf[10];
-         if (stab_name == NULL)
-           {
-             sprintf(buf, "(%d)", type_code);
-             stab_name = buf;
-           }
-         fprintf(file," - %02x %04x %5s",
-                 (unsigned)(aout_symbol(symbol)->other & 0xff),
-                 (unsigned)(aout_symbol(symbol)->desc & 0xffff),
-                 stab_name);
-        }
-      else
-       fprintf(file," %c", section_code);
-      if (symbol->name)
-        fprintf(file," %s", symbol->name);
-    }
-    break;
   }
 }
 
This page took 0.066435 seconds and 4 git commands to generate.