* coff-mips.c (ecoff_set_symbol_info): stBlock symbols are always
[platform/upstream/binutils.git] / bfd / coff-mips.c
index 85a9056..c5b3946 100644 (file)
@@ -1,7 +1,7 @@
 /* BFD back-end for MIPS Extended-Coff files.
-   Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
    Original version by Per Bothner.
-   Full support by Ian Lance Taylor, ian@cygnus.com.
+   Full support added by Ian Lance Taylor, ian@cygnus.com.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -31,61 +31,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "coff/symconst.h"
 #include "coff/ecoff-ext.h"
 #include "libcoff.h"
-
-/* `Tdata' information kept for ECOFF files.  */
-
-#define ecoff_data(abfd) ((abfd)->tdata.ecoff_obj_data)
-
-typedef struct ecoff_tdata
-{
-  /* The reloc file position, set by
-     ecoff_compute_section_file_positions.  */
-  file_ptr reloc_filepos;
-
-  /* The symbol table file position, set by ecoff_mkobject_hook.  */
-  file_ptr sym_filepos;
-
-  /* The cached gp value.  This is used when relocating.  */
-  bfd_vma gp;
-
-  /* The register masks.  When linking, all the masks found in the
-     input files are combined into the masks of the output file.  */
-  unsigned long gprmask;
-  unsigned long cprmask[4];
-
-  /* The size of the unswapped ECOFF symbolic information.  */
-  bfd_size_type raw_size;
-
-  /* The unswapped ECOFF symbolic information.  */
-  PTR raw_syments;
-
-  /* The swapped ECOFF symbolic header.  */
-  HDRR symbolic_header;
-
-  /* Pointers to the unswapped symbolic information.  */
-  unsigned char *line;
-  struct dnr_ext *external_dnr;
-  struct pdr_ext *external_pdr;
-  struct sym_ext *external_sym;
-  struct opt_ext *external_opt;
-  union aux_ext *external_aux;
-  char *ss;
-  char *ssext;
-  struct fdr_ext *external_fdr;
-  struct rfd_ext *external_rfd;
-  struct ext_ext *external_ext;
-
-  /* The swapped FDR information.  */
-  FDR *fdr;
-
-  /* The FDR index.  This is set for an input BFD to a link so that
-     the external symbols can set their FDR index correctly.  */
-  unsigned int ifdbase;
-
-  /* The canonical BFD symbols.  */
-  struct ecoff_symbol_struct *canonical_symbols;
-
-} ecoff_data_type;
+#include "libecoff.h"
 
 /* Each canonical asymbol really looks like this.  */
 
@@ -122,12 +68,116 @@ typedef struct ecoff_symbol_struct
 /* The page boundary used to align sections in the executable file.  */
 #define PAGE_SIZE 0x2000
 
+/* The linker needs a section to hold small common variables while
+   linking.  There is no convenient way to create it when the linker
+   needs it, so we always create one for each BFD.  We then avoid
+   writing it out.  */
+#define SCOMMON ".scommon"
+
 /* MIPS ECOFF has COFF sections, but the debugging information is
    stored in a completely different format.  This files uses the some
    of the swapping routines from coffswap.h, and some of the generic
    COFF routines in coffgen.c, but, unlike the real COFF targets, does
    not use coffcode.h itself.  */
-
+\f
+/* Prototypes for static functions.  */
+
+static boolean ecoff_bad_format_hook PARAMS ((bfd *abfd, PTR filehdr));
+static asection *ecoff_make_section_hook PARAMS ((bfd *abfd, char *name));
+static boolean ecoff_new_section_hook PARAMS ((bfd *abfd, asection *section));
+static boolean ecoff_mkobject PARAMS ((bfd *abfd));
+static PTR ecoff_mkobject_hook PARAMS ((bfd *abfd, PTR filehdr, PTR aouthdr));
+static boolean ecoff_set_arch_mach_hook PARAMS ((bfd *abfd, PTR filehdr));
+static long ecoff_sec_to_styp_flags PARAMS ((CONST char *name,
+                                            flagword flags));
+static flagword ecoff_styp_to_sec_flags PARAMS ((bfd *abfd, PTR hdr));
+static asymbol *ecoff_make_empty_symbol PARAMS ((bfd *abfd));
+static void ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym,
+                                          asymbol *asym, int ext));
+static boolean ecoff_slurp_symbol_table PARAMS ((bfd *abfd));
+static unsigned int ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd));
+static unsigned int ecoff_get_symtab PARAMS ((bfd *abfd,
+                                             asymbol **alocation));
+static void ecoff_emit_aggregate PARAMS ((bfd *abfd, char *string,
+                                         RNDXR *rndx, long isym,
+                                         CONST char *which));
+static char *ecoff_type_to_string PARAMS ((bfd *abfd, union aux_ext *aux_ptr,
+                                          int indx, int bigendian));
+static void ecoff_print_symbol PARAMS ((bfd *abfd, PTR filep,
+                                       asymbol *symbol,
+                                       bfd_print_symbol_type how));
+static void ecoff_swap_reloc_in PARAMS ((bfd *abfd, RELOC *ext,
+                                        struct internal_reloc *intern));
+static unsigned int ecoff_swap_reloc_out PARAMS ((bfd *abfd, PTR src,
+                                                 PTR dst));
+static bfd_reloc_status_type ecoff_generic_reloc PARAMS ((bfd *abfd,
+                                                         arelent *reloc,
+                                                         asymbol *symbol,
+                                                         PTR data,
+                                                         asection *section,
+                                                         bfd *output_bfd));
+static bfd_reloc_status_type ecoff_refhi_reloc PARAMS ((bfd *abfd,
+                                                       arelent *reloc,
+                                                       asymbol *symbol,
+                                                       PTR data,
+                                                       asection *section,
+                                                       bfd *output_bfd));
+static bfd_reloc_status_type ecoff_gprel_reloc PARAMS ((bfd *abfd,
+                                                       arelent *reloc,
+                                                       asymbol *symbol,
+                                                       PTR data,
+                                                       asection *section,
+                                                       bfd *output_bfd));
+static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section,
+                                               asymbol **symbols));
+static unsigned int ecoff_canonicalize_reloc PARAMS ((bfd *abfd,
+                                                     asection *section,
+                                                     arelent **relptr,
+                                                     asymbol **symbols));
+static boolean ecoff_find_nearest_line PARAMS ((bfd *abfd,
+                                               asection *section,
+                                               asymbol **symbols,
+                                               bfd_vma offset,
+                                               CONST char **filename_ptr,
+                                               CONST char **fnname_ptr,
+                                               unsigned int *retline_ptr));
+static void ecoff_clear_output_flags PARAMS ((bfd *abfd));
+static boolean ecoff_rel PARAMS ((bfd *output_bfd, bfd_seclet_type *seclet,
+                                 asection *output_section, PTR data,
+                                 boolean relocateable));
+static boolean ecoff_dump_seclet PARAMS ((bfd *abfd, bfd_seclet_type *seclet,
+                                         asection *section, PTR data,
+                                         boolean relocateable));
+static long ecoff_add_string PARAMS ((bfd *output_bfd, FDR *fdr,
+                                     CONST char *string, boolean external));
+static boolean ecoff_get_debug PARAMS ((bfd *output_bfd,
+                                       bfd_seclet_type *seclet,
+                                       asection *section,
+                                       boolean relocateable));
+static boolean ecoff_bfd_seclet_link PARAMS ((bfd *abfd, PTR data,
+                                             boolean relocateable));
+static boolean ecoff_set_arch_mach PARAMS ((bfd *abfd,
+                                           enum bfd_architecture arch,
+                                           unsigned long machine));
+static int ecoff_sizeof_headers PARAMS ((bfd *abfd, boolean reloc));
+static void ecoff_compute_section_file_positions PARAMS ((bfd *abfd));
+static boolean ecoff_set_section_contents PARAMS ((bfd *abfd,
+                                                  asection *section,
+                                                  PTR location,
+                                                  file_ptr offset,
+                                                  bfd_size_type count));
+static boolean ecoff_write_object_contents PARAMS ((bfd *abfd));
+static unsigned int ecoff_armap_hash PARAMS ((CONST char *s,
+                                             unsigned int *rehash,
+                                             unsigned int size,
+                                             unsigned int hlog));
+static boolean ecoff_slurp_armap PARAMS ((bfd *abfd));
+static boolean ecoff_write_armap PARAMS ((bfd *abfd, unsigned int elength,
+                                         struct orl *map,
+                                         unsigned int orl_count,
+                                         int stridx));
+static bfd_target *ecoff_archive_p PARAMS ((bfd *abfd));
+\f
 /* Get the generic COFF swapping routines, except for the reloc,
    symbol, and lineno ones.  Give them ecoff names.  */
 #define MIPSECOFF
@@ -149,9 +199,9 @@ static asection bfd_debug_section = { "*DEBUG*" };
 /* See whether the magic number matches.  */
 
 static boolean
-DEFUN(ecoff_bad_format_hook, (abfd, filehdr),
-      bfd *abfd AND
-      PTR filehdr)
+ecoff_bad_format_hook (abfd, filehdr)
+     bfd *abfd;
+     PTR filehdr;
 {
   struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
 
@@ -164,9 +214,9 @@ DEFUN(ecoff_bad_format_hook, (abfd, filehdr),
 /* This is a hook needed by SCO COFF, but we have nothing to do.  */
 
 static asection *
-DEFUN (ecoff_make_section_hook, (abfd, name),
-       bfd *abfd AND
-       char *name)
+ecoff_make_section_hook (abfd, name)
+     bfd *abfd;
+     char *name;
 {
   return (asection *) NULL;
 }
@@ -174,9 +224,9 @@ DEFUN (ecoff_make_section_hook, (abfd, name),
 /* Initialize a new section.  */
 
 static boolean
-DEFUN (ecoff_new_section_hook, (abfd, section),
-       bfd *abfd AND
-       asection *section)
+ecoff_new_section_hook (abfd, section)
+     bfd *abfd;
+     asection *section;
 {
   section->alignment_power = abfd->xvec->align_power_min;
 
@@ -200,12 +250,16 @@ DEFUN (ecoff_new_section_hook, (abfd, section),
   return true;
 }
 
+/* Set the alignment of a section; we have nothing to do.  */
+
 #define ecoff_set_alignment_hook \
   ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void)
 
+/* Create an ECOFF object.  */
+
 static boolean
-DEFUN (ecoff_mkobject, (abfd),
-       bfd *abfd)
+ecoff_mkobject (abfd)
+     bfd *abfd;
 {
   abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *)
                                bfd_zalloc (abfd, sizeof(ecoff_data_type)));
@@ -215,10 +269,14 @@ DEFUN (ecoff_mkobject, (abfd),
       return false;
     }
 
+  /* Always create a .scommon section for every BFD.  This is a hack so
+     that the linker has something to attach scSCommon symbols to.  */
+  bfd_make_section (abfd, SCOMMON);
+
   return true;
 }
 
-/* Create the COFF backend specific information.  */
+/* Create the ECOFF backend specific information.  */
 
 static PTR
 ecoff_mkobject_hook (abfd, filehdr, aouthdr)
@@ -240,9 +298,11 @@ ecoff_mkobject_hook (abfd, filehdr, aouthdr)
     {
       int i;
 
+      ecoff->text_start = internal_a->text_start;
+      ecoff->text_end = internal_a->text_start + internal_a->tsize;
       ecoff->gp = internal_a->gp_value;
       ecoff->gprmask = internal_a->gprmask;
-      for (i = 0; i < 3; i++)
+      for (i = 0; i < 4; i++)
        ecoff->cprmask[i] = internal_a->cprmask[i];
     }
 
@@ -250,39 +310,39 @@ ecoff_mkobject_hook (abfd, filehdr, aouthdr)
 }
 
 /* Determine the machine architecture and type.  */
+
 static boolean
-DEFUN (ecoff_set_arch_mach_hook, (abfd, filehdr),
-       bfd *abfd AND
-       PTR filehdr)
+ecoff_set_arch_mach_hook (abfd, filehdr)
+     bfd *abfd;
+     PTR filehdr;
 {
-  long machine;
-  enum bfd_architecture arch;
   struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
+  enum bfd_architecture arch;
 
-  machine = 0;
-  switch (internal_f->f_magic) {
-  case  MIPS_MAGIC_1:
-  case  MIPS_MAGIC_2:
-  case  MIPS_MAGIC_3:
-    arch = bfd_arch_mips;
-    machine = 0;
-    break;
-
-  default:                     /* Unreadable input file type */
-    arch = bfd_arch_obscure;
-    break;
-  }
+  switch (internal_f->f_magic)
+    {
+    case MIPS_MAGIC_1:
+    case MIPS_MAGIC_LITTLE:
+    case MIPS_MAGIC_BIG:
+      arch = bfd_arch_mips;
+      break;
+
+    default:
+      arch = bfd_arch_obscure;
+      break;
+    }
+
+  bfd_default_set_arch_mach (abfd, arch, (unsigned long) 0);
 
-  bfd_default_set_arch_mach(abfd, arch, machine);
   return true;
 }
 
 /* Get the section s_flags to use for a section.  */
 
 static long
-DEFUN (sec_to_styp_flags, (name, flags),
-       CONST char *name AND
-       flagword flags)
+ecoff_sec_to_styp_flags (name, flags)
+     CONST char *name;
+     flagword flags;
 {
   long styp;
 
@@ -324,9 +384,9 @@ DEFUN (sec_to_styp_flags, (name, flags),
 /* Get the BFD flags to use for a section.  */
 
 static flagword
-DEFUN (styp_to_sec_flags, (abfd, hdr),
-       bfd *abfd AND
-       PTR hdr)
+ecoff_styp_to_sec_flags (abfd, hdr)
+     bfd *abfd;
+     PTR hdr;
 {
   struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
   long styp_flags = internal_s->s_flags;
@@ -378,11 +438,13 @@ DEFUN (styp_to_sec_flags, (abfd, hdr),
 }
 \f
 /* Read in and swap the important symbolic information for an ECOFF
-   object file.  */
+   object file.  FIXME: This is called by gdb.  If there is ever
+   another ECOFF target, it should be moved into some sort of target
+   specific structure.  */
 
-static boolean
-DEFUN (ecoff_slurp_symbolic_info, (abfd),
-       bfd *abfd)
+boolean
+ecoff_slurp_symbolic_info (abfd)
+     bfd *abfd;
 {
   struct hdr_ext external_symhdr;
   HDRR *internal_symhdr;
@@ -435,17 +497,32 @@ DEFUN (ecoff_slurp_symbolic_info, (abfd),
                             + internal_symhdr->iextMax);
 
   /* Read all the symbolic information at once.  */
-  raw_size = (internal_symhdr->cbLine * sizeof (unsigned char)
-             + internal_symhdr->idnMax * sizeof (struct dnr_ext)
-             + internal_symhdr->ipdMax * sizeof (struct pdr_ext)
-             + internal_symhdr->isymMax * sizeof (struct sym_ext)
-             + internal_symhdr->ioptMax * sizeof (struct opt_ext)
-             + internal_symhdr->iauxMax * sizeof (union aux_ext)
-             + internal_symhdr->issMax * sizeof (char)
-             + internal_symhdr->issExtMax * sizeof (char)
-             + internal_symhdr->ifdMax * sizeof (struct fdr_ext)
-             + internal_symhdr->crfd * sizeof (struct rfd_ext)
-             + internal_symhdr->iextMax * sizeof (struct ext_ext));
+  raw_base = ecoff_data (abfd)->sym_filepos + sizeof (struct hdr_ext);
+
+  if (internal_symhdr->cbExtOffset != 0)
+    raw_size = (internal_symhdr->cbExtOffset
+               - raw_base
+               + internal_symhdr->iextMax * sizeof (struct ext_ext));
+  else
+    {
+      long cbline, issmax, issextmax;
+
+      cbline = (internal_symhdr->cbLine + 3) &~ 3;
+      issmax = (internal_symhdr->issMax + 3) &~ 3;
+      issextmax = (internal_symhdr->issExtMax + 3) &~ 3;
+      raw_size = (cbline * sizeof (unsigned char)
+                 + internal_symhdr->idnMax * sizeof (struct dnr_ext)
+                 + internal_symhdr->ipdMax * sizeof (struct pdr_ext)
+                 + internal_symhdr->isymMax * sizeof (struct sym_ext)
+                 + internal_symhdr->ioptMax * sizeof (struct opt_ext)
+                 + internal_symhdr->iauxMax * sizeof (union aux_ext)
+                 + issmax * sizeof (char)
+                 + issextmax * sizeof (char)
+                 + internal_symhdr->ifdMax * sizeof (struct fdr_ext)
+                 + internal_symhdr->crfd * sizeof (struct rfd_ext)
+                 + internal_symhdr->iextMax * sizeof (struct ext_ext));
+    }
+
   if (raw_size == 0)
     {
       ecoff_data (abfd)->sym_filepos = 0;
@@ -468,8 +545,6 @@ DEFUN (ecoff_slurp_symbolic_info, (abfd),
   ecoff_data (abfd)->raw_syments = raw;
 
   /* Get pointers for the numeric offsets in the HDRR structure.  */
-  raw_base = ecoff_data (abfd)->sym_filepos + sizeof (struct hdr_ext);
-
 #define FIX(off1, off2, type) \
   if (internal_symhdr->off1 == 0) \
     ecoff_data (abfd)->off2 = (type *) NULL; \
@@ -530,8 +605,8 @@ static asymbol *ecoff_scom_symbol_ptr;
 /* Create an empty symbol.  */
 
 static asymbol *
-DEFUN (ecoff_make_empty_symbol, (abfd),
-       bfd *abfd)
+ecoff_make_empty_symbol (abfd)
+     bfd *abfd;
 {
   ecoff_symbol_type *new;
 
@@ -552,11 +627,11 @@ DEFUN (ecoff_make_empty_symbol, (abfd),
 /* Set the BFD flags and section for an ECOFF symbol.  */
 
 static void
-DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
-       bfd *abfd AND
-       SYMR *ecoff_sym AND
-       asymbol *asym AND
-       int ext)
+ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext)
+     bfd *abfd;
+     SYMR *ecoff_sym;
+     asymbol *asym;
+     int ext;
 {
   asym->the_bfd = abfd;
   asym->value = ecoff_sym->value;
@@ -571,7 +646,7 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
     case stLabel:
     case stProc:
     case stStaticProc:
-    case stBlock:
+    case stNil:
       break;
     default:
       asym->flags = BSF_DEBUGGING;
@@ -585,7 +660,11 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
   switch (ecoff_sym->sc)
     {
     case scNil:
-      asym->flags = BSF_DEBUGGING;
+      /* Used for compiler generated labels.  Leave them in the
+        debugging section, and mark them as local.  If BSF_DEBUGGING
+        is set, then nm does not display them for some reason.  If no
+        flags are set then the linker whines about them.  */
+      asym->flags = BSF_LOCAL;
       break;
     case scText:
       asym->section = bfd_make_section_old_way (abfd, ".text");
@@ -597,7 +676,10 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
       break;
     case scBss:
       if (ext)
-       asym->section = &bfd_com_section;
+       {
+         asym->section = &bfd_com_section;
+         asym->flags = 0;
+       }
       else
        {
          asym->section = bfd_make_section_old_way (abfd, ".bss");
@@ -612,6 +694,8 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
       break;
     case scUndefined:
       asym->section = &bfd_und_section;
+      asym->flags = 0;
+      asym->value = 0;
       break;
     case scCdbLocal:
     case scBits:
@@ -638,23 +722,33 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
       asym->flags = BSF_DEBUGGING;
       break;
     case scCommon:
-      asym->section = &bfd_com_section;
-      break;
+      /* FIXME: We should take a -G argument, which gives the maximum
+        size of objects to be put in the small common section.  Until
+        we do, we put objects of sizes up to 8 in the small common
+        section.  The assembler should do this for us, but the native
+        assembler seems to get confused.  */
+      if (asym->value > 8)
+       {
+         asym->section = &bfd_com_section;
+         break;
+       }
+      /* Fall through.  */
     case scSCommon:
       if (ecoff_scom_section.name == NULL)
        {
          /* Initialize the small common section.  */
-         ecoff_scom_section.name = "*SCOM*";
+         ecoff_scom_section.name = SCOMMON;
          ecoff_scom_section.flags = SEC_IS_COMMON;
          ecoff_scom_section.output_section = &ecoff_scom_section;
          ecoff_scom_section.symbol = &ecoff_scom_symbol;
          ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr;
-         ecoff_scom_symbol.name = "*SCOM*";
+         ecoff_scom_symbol.name = SCOMMON;
          ecoff_scom_symbol.flags = BSF_SECTION_SYM;
          ecoff_scom_symbol.section = &ecoff_scom_section;
          ecoff_scom_symbol_ptr = &ecoff_scom_symbol;
        }
       asym->section = &ecoff_scom_section;
+      asym->flags = 0;
       break;
     case scVarRegister:
     case scVariant:
@@ -662,6 +756,8 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
       break;
     case scSUndefined:
       asym->section = &bfd_und_section;
+      asym->flags = 0;
+      asym->value = 0;
       break;
     case scInit:
       asym->section = bfd_make_section_old_way (abfd, ".init");
@@ -684,8 +780,8 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
 /* Read an ECOFF symbol table.  */
 
 static boolean
-DEFUN (ecoff_slurp_symbol_table, (abfd),
-       bfd *abfd)
+ecoff_slurp_symbol_table (abfd)
+     bfd *abfd;
 {
   bfd_size_type internal_size;
   ecoff_symbol_type *internal;
@@ -763,8 +859,8 @@ DEFUN (ecoff_slurp_symbol_table, (abfd),
 }
 
 static unsigned int
-DEFUN (ecoff_get_symtab_upper_bound, (abfd),
-       bfd *abfd)
+ecoff_get_symtab_upper_bound (abfd)
+     bfd *abfd;
 {
   if (ecoff_slurp_symbolic_info (abfd) == false
       || bfd_get_symcount (abfd) == 0)
@@ -774,9 +870,9 @@ DEFUN (ecoff_get_symtab_upper_bound, (abfd),
 }
 
 static unsigned int
-DEFUN (ecoff_get_symtab, (abfd, alocation),
-       bfd *abfd AND
-       asymbol **alocation)
+ecoff_get_symtab (abfd, alocation)
+     bfd *abfd;
+     asymbol **alocation;
 {
   unsigned int counter = 0;
   ecoff_symbol_type *symbase;
@@ -797,18 +893,18 @@ DEFUN (ecoff_get_symtab, (abfd, alocation),
 }
 
 /* Turn ECOFF type information into a printable string.
-   emit_aggregate and type_to_string are from gcc/mips-tdump.c, with
-   swapping added and used_ptr removed.  */
+   ecoff_emit_aggregate and ecoff_type_to_string are from
+   gcc/mips-tdump.c, with swapping added and used_ptr removed.  */
 
 /* Write aggregate information to a string.  */
 
 static void
-DEFUN (emit_aggregate, (abfd, string, rndx, isym, which),
-       bfd *abfd AND
-       char *string AND
-       RNDXR *rndx AND
-       long isym AND
-       CONST char *which)
+ecoff_emit_aggregate (abfd, string, rndx, isym, which)
+     bfd *abfd;
+     char *string;
+     RNDXR *rndx;
+     long isym;
+     CONST char *which;
 {
   int ifd = rndx->rfd;
   int indx = rndx->index;
@@ -843,11 +939,11 @@ DEFUN (emit_aggregate, (abfd, string, rndx, isym, which),
 /* Convert the type information to string format.  */
 
 static char *
-DEFUN (type_to_string, (abfd, aux_ptr, indx, bigendian),
-       bfd *abfd AND
-       union aux_ext *aux_ptr AND
-       int indx AND
-       int bigendian)
+ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
+     bfd *abfd;
+     union aux_ext *aux_ptr;
+     int indx;
+     int bigendian;
 {
   AUXU u;
   struct qual {
@@ -944,9 +1040,9 @@ DEFUN (type_to_string, (abfd, aux_ptr, indx, bigendian),
 
     case btStruct:             /* Structure (Record) */
       ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
-      emit_aggregate (abfd, p1, &rndx,
-                     AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
-                     "struct");
+      ecoff_emit_aggregate (abfd, p1, &rndx,
+                           AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
+                           "struct");
       indx++;                  /* skip aux words */
       break;
 
@@ -956,9 +1052,9 @@ DEFUN (type_to_string, (abfd, aux_ptr, indx, bigendian),
 
     case btUnion:              /* Union */
       ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
-      emit_aggregate (abfd, p1, &rndx,
-                     AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
-                     "union");
+      ecoff_emit_aggregate (abfd, p1, &rndx,
+                           AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
+                           "union");
       indx++;                  /* skip aux words */
       break;
 
@@ -968,9 +1064,9 @@ DEFUN (type_to_string, (abfd, aux_ptr, indx, bigendian),
 
     case btEnum:               /* Enumeration */
       ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
-      emit_aggregate (abfd, p1, &rndx,
-                     AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
-                     "enum");
+      ecoff_emit_aggregate (abfd, p1, &rndx,
+                           AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
+                           "enum");
       indx++;                  /* skip aux words */
       break;
 
@@ -1149,11 +1245,11 @@ DEFUN (type_to_string, (abfd, aux_ptr, indx, bigendian),
 /* Print information about an ECOFF symbol.  */
 
 static void
-DEFUN (ecoff_print_symbol, (abfd, filep, symbol, how),
-       bfd *abfd AND
-       PTR filep AND
-       asymbol *symbol AND
-       bfd_print_symbol_type how)
+ecoff_print_symbol (abfd, filep, symbol, how)
+     bfd *abfd;
+     PTR filep;
+     asymbol *symbol;
+     bfd_print_symbol_type how;
 {
   FILE *file = (FILE *)filep;
 
@@ -1296,8 +1392,8 @@ DEFUN (ecoff_print_symbol, (abfd, filep, symbol, how),
                          (AUX_GET_ISYM (bigendian,
                                         &aux_base[ecoff_ext.asym.index])
                           + sym_base),
-                         type_to_string (abfd, aux_base, indx + 1,
-                                         bigendian));
+                         ecoff_type_to_string (abfd, aux_base, indx + 1,
+                                               bigendian));
                else
                  printf ("\n      Local symbol: %d",
                          (indx
@@ -1308,7 +1404,8 @@ DEFUN (ecoff_print_symbol, (abfd, filep, symbol, how),
              default:
                if (!MIPS_IS_STAB (&ecoff_ext.asym))
                  printf ("\n      Type: %s",
-                         type_to_string (abfd, aux_base, indx, bigendian));
+                         ecoff_type_to_string (abfd, aux_base, indx,
+                                               bigendian));
                break;
              }
          }
@@ -1324,10 +1421,10 @@ DEFUN (ecoff_print_symbol, (abfd, filep, symbol, how),
 /* Swap a reloc in.  */
 
 static void
-DEFUN (ecoff_swap_reloc_in, (abfd, ext, intern),
-       bfd *abfd AND
-       RELOC *ext AND
-       struct internal_reloc *intern)
+ecoff_swap_reloc_in (abfd, ext, intern)
+     bfd *abfd;
+     RELOC *ext;
+     struct internal_reloc *intern;
 {
   intern->r_vaddr = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_vaddr);
   if (abfd->xvec->header_byteorder_big_p != false)
@@ -1359,10 +1456,10 @@ DEFUN (ecoff_swap_reloc_in, (abfd, ext, intern),
 /* Swap a reloc out.  */
 
 static unsigned int
-DEFUN (ecoff_swap_reloc_out, (abfd, src, dst),
-       bfd *abfd AND
-       PTR src AND
-       PTR dst)
+ecoff_swap_reloc_out (abfd, src, dst)
+     bfd *abfd;
+     PTR src;
+     PTR dst;
 {
   struct internal_reloc *intern = (struct internal_reloc *) src;
   RELOC *ext = (RELOC *) dst;
@@ -1768,10 +1865,10 @@ static reloc_howto_type ecoff_howto_table[] =
 /* Read in the relocs for a section.  */
 
 static boolean
-DEFUN (ecoff_slurp_reloc_table, (abfd, section, symbols),
-       bfd *abfd AND
-       asection *section AND
-       asymbol **symbols)
+ecoff_slurp_reloc_table (abfd, section, symbols)
+     bfd *abfd;
+     asection *section;
+     asymbol **symbols;
 {
   RELOC *external_relocs;
   arelent *internal_relocs;
@@ -1873,11 +1970,11 @@ DEFUN (ecoff_slurp_reloc_table, (abfd, section, symbols),
 /* Get a canonical list of relocs.  */
 
 static unsigned int
-DEFUN (ecoff_canonicalize_reloc, (abfd, section, relptr, symbols),
-       bfd *abfd AND
-       asection *section AND
-       arelent **relptr AND
-       asymbol **symbols)
+ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
+     bfd *abfd;
+     asection *section;
+     arelent **relptr;
+     asymbol **symbols;
 {
   unsigned int count;
 
@@ -1918,20 +2015,20 @@ DEFUN (ecoff_canonicalize_reloc, (abfd, section, relptr, symbols),
    wanted location.  */
 
 static boolean
-DEFUN (ecoff_find_nearest_line, (abfd,
-                                section,
-                                ignore_symbols,
-                                offset,
-                                filename_ptr,
-                                functionname_ptr,
-                                retline_ptr),
-       bfd *abfd AND
-       asection *section AND
-       asymbol **ignore_symbols AND
-       bfd_vma offset AND
-       CONST char **filename_ptr AND
-       CONST char **functionname_ptr AND
-       unsigned int *retline_ptr)
+ecoff_find_nearest_line (abfd,
+                        section,
+                        ignore_symbols,
+                        offset,
+                        filename_ptr,
+                        functionname_ptr,
+                        retline_ptr)
+     bfd *abfd;
+     asection *section;
+     asymbol **ignore_symbols;
+     bfd_vma offset;
+     CONST char **filename_ptr;
+     CONST char **functionname_ptr;
+     unsigned int *retline_ptr;
 {
   FDR *fdr_ptr;
   FDR *fdr_start;
@@ -1946,7 +2043,9 @@ DEFUN (ecoff_find_nearest_line, (abfd,
 
   /* If we're not in the .text section, we don't have any line
      numbers.  */
-  if (strcmp (section->name, _TEXT) != 0)
+  if (strcmp (section->name, _TEXT) != 0
+      || offset < ecoff_data (abfd)->text_start
+      || offset >= ecoff_data (abfd)->text_end)
     return false;
 
   /* Make sure we have the FDR's.  */
@@ -1964,10 +2063,11 @@ DEFUN (ecoff_find_nearest_line, (abfd,
   fdr_hold = (FDR *) NULL;
   for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
     {
+      if (fdr_ptr->cpd == 0)
+       continue;
       if (offset < fdr_ptr->adr)
        break;
-      if (fdr_ptr->cpd > 0)
-       fdr_hold = fdr_ptr;
+      fdr_hold = fdr_ptr;
     }
   if (fdr_hold == (FDR *) NULL)
     return false;
@@ -2031,10 +2131,6 @@ DEFUN (ecoff_find_nearest_line, (abfd,
       offset -= count * 4;
     }
 
-  /* If offset is too large, this line is not interesting.  */
-  if (offset > 100)
-    return false;
-
   /* If fdr_ptr->rss is -1, then this file does not have full symbols,
      at least according to gdb/mipsread.c.  */
   if (fdr_ptr->rss == -1)
@@ -2092,8 +2188,8 @@ DEFUN (ecoff_find_nearest_line, (abfd,
    once.  */
 
 static void
-DEFUN (ecoff_clear_output_flags, (abfd),
-       bfd *abfd)
+ecoff_clear_output_flags (abfd)
+     bfd *abfd;
 {
   register asection *o;
   register bfd_seclet_type *p;
@@ -2111,18 +2207,16 @@ DEFUN (ecoff_clear_output_flags, (abfd),
    any.  */
 
 static boolean
-DEFUN (ecoff_rel, (output_bfd, seclet, output_section, data, relocateable),
-       bfd *output_bfd AND
-       bfd_seclet_type *seclet AND
-       asection *output_section AND
-       PTR data AND
-       boolean relocateable)
+ecoff_rel (output_bfd, seclet, output_section, data, relocateable)
+     bfd *output_bfd;
+     bfd_seclet_type *seclet;
+     asection *output_section;
+     PTR data;
+     boolean relocateable;
 {
   bfd *input_bfd;
   HDRR *output_symhdr;
   HDRR *input_symhdr;
-  ecoff_symbol_type *sym_ptr;
-  ecoff_symbol_type *sym_end;
 
   if ((output_section->flags & SEC_HAS_CONTENTS)
       && !(output_section->flags & SEC_NEVER_LOAD)
@@ -2229,12 +2323,12 @@ DEFUN (ecoff_rel, (output_bfd, seclet, output_section, data, relocateable),
 /* Handle an arbitrary seclet on the first pass.  */
 
 static boolean
-DEFUN (ecoff_dump_seclet, (abfd, seclet, section, data, relocateable),
-       bfd *abfd AND
-       bfd_seclet_type *seclet AND
-       asection *section AND
-       PTR data AND
-       boolean relocateable)
+ecoff_dump_seclet (abfd, seclet, section, data, relocateable)
+     bfd *abfd;
+     bfd_seclet_type *seclet;
+     asection *section;
+     PTR data;
+     boolean relocateable;
 {
   switch (seclet->type) 
     {
@@ -2280,11 +2374,11 @@ DEFUN (ecoff_dump_seclet, (abfd, seclet, section, data, relocateable),
    external string base.  */
 
 static long
-DEFUN (ecoff_add_string, (output_bfd, fdr, string, external),
-       bfd *output_bfd AND
-       FDR *fdr AND
-       CONST char *string AND
-       boolean external)
+ecoff_add_string (output_bfd, fdr, string, external)
+     bfd *output_bfd;
+     FDR *fdr;
+     CONST char *string;
+     boolean external;
 {
   HDRR *symhdr;
   size_t len;
@@ -2311,10 +2405,11 @@ DEFUN (ecoff_add_string, (output_bfd, fdr, string, external),
 /* Accumulate the debugging information from an input section.  */
 
 static boolean
-DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
-       bfd *output_bfd AND
-       bfd_seclet_type *seclet AND
-       asection *section)
+ecoff_get_debug (output_bfd, seclet, section, relocateable)
+     bfd *output_bfd;
+     bfd_seclet_type *seclet;
+     asection *section;
+     boolean relocateable;
 {
   bfd *input_bfd;
   HDRR *output_symhdr;
@@ -2323,9 +2418,9 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
   ecoff_data_type *input_ecoff;
   unsigned int count;
   struct sym_ext *sym_out;
-  struct ext_ext *ext_out;
   ecoff_symbol_type *esym_ptr;
   ecoff_symbol_type *esym_end;
+  unsigned long pdr_off;
   FDR *fdr_ptr;
   FDR *fdr_end;
   struct fdr_ext *fdr_out;
@@ -2384,7 +2479,14 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
                                               &fdr,
                                               (*sym_ptr)->name,
                                               false);
-         internal_sym.value = (*sym_ptr)->value;
+
+         if (bfd_is_com_section ((*sym_ptr)->section)
+             || (*sym_ptr)->section == &bfd_und_section)
+           internal_sym.value = (*sym_ptr)->value;
+         else
+           internal_sym.value = ((*sym_ptr)->value
+                                 + (*sym_ptr)->section->output_offset
+                                 + (*sym_ptr)->section->output_section->vma);
          internal_sym.st = stNil;
          internal_sym.sc = scUndefined;
          internal_sym.index = indexNil;
@@ -2435,6 +2537,17 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
          SYMR sym;
 
          ecoff_swap_sym_in (input_bfd, esym_ptr->native.lnative, &sym);
+
+         /* If we're producing an executable, move common symbols
+            into bss.  */
+         if (relocateable == false)
+           {
+             if (sym.sc == scCommon)
+               sym.sc = scBss;
+             else if (sym.sc == scSCommon)
+               sym.sc = scSBss;
+           }
+
          if (! bfd_is_com_section (esym_ptr->symbol.section)
              && (esym_ptr->symbol.flags & BSF_DEBUGGING) == 0
              && esym_ptr->symbol.section != &bfd_und_section)
@@ -2474,6 +2587,15 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
       memcpy (output_ecoff->external_pdr + output_symhdr->ipdMax,
              input_ecoff->external_pdr,
              input_symhdr->ipdMax * sizeof (struct pdr_ext));
+      if (input_symhdr->ipdMax == 0)
+       pdr_off = 0;
+      else
+       {
+         PDR pdr;
+
+         ecoff_swap_pdr_in (input_bfd, input_ecoff->external_pdr, &pdr);
+         pdr_off = pdr.adr;
+       }
       memcpy (output_ecoff->external_opt + output_symhdr->ioptMax,
              input_ecoff->external_opt,
              input_symhdr->ioptMax * sizeof (struct opt_ext));
@@ -2486,6 +2608,7 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
       struct pdr_ext *pdr_in;
       struct pdr_ext *pdr_end;
       struct pdr_ext *pdr_out;
+      int first_pdr;
       struct opt_ext *opt_in;
       struct opt_ext *opt_end;
       struct opt_ext *opt_out;
@@ -2506,12 +2629,19 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
       pdr_in = input_ecoff->external_pdr;
       pdr_end = pdr_in + input_symhdr->ipdMax;
       pdr_out = output_ecoff->external_pdr + output_symhdr->ipdMax;
+      first_pdr = 1;
+      pdr_off = 0;
       for (; pdr_in < pdr_end; pdr_in++, pdr_out++)
        {
          PDR pdr;
 
          ecoff_swap_pdr_in (input_bfd, pdr_in, &pdr);
          ecoff_swap_pdr_out (output_bfd, &pdr, pdr_out);
+         if (first_pdr)
+           {
+             pdr_off = pdr.adr;
+             first_pdr = 0;
+           }
        }
       opt_in = input_ecoff->external_opt;
       opt_end = opt_in + input_symhdr->ioptMax;
@@ -2539,10 +2669,13 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
       fdr = *fdr_ptr;
 
       /* The memory address for this fdr is the address for the seclet
-        plus the offset to this fdr within input_bfd.  */
+        plus the offset to this fdr within input_bfd.  For some
+        reason the offset of the first procedure pointer is also
+        added in.  */
       fdr.adr = (bfd_get_section_vma (output_bfd, section)
                 + seclet->offset
-                + (fdr_ptr->adr - input_ecoff->fdr->adr));
+                + (fdr_ptr->adr - input_ecoff->fdr->adr)
+                + pdr_off);
 
       fdr.issBase += output_symhdr->issMax;
       fdr.isymBase += output_symhdr->isymMax;
@@ -2612,7 +2745,7 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
     int i;
 
     output_ecoff->gprmask |= input_ecoff->gprmask;
-    for (i = 0; i < 3; i++)
+    for (i = 0; i < 4; i++)
       output_ecoff->cprmask[i] |= input_ecoff->cprmask[i];
   }
 
@@ -2634,10 +2767,10 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
    seclets.  */
 
 static boolean
-DEFUN (ecoff_bfd_seclet_link, (abfd, data, relocateable),
-       bfd *abfd AND
-       PTR data AND
-       boolean relocateable)
+ecoff_bfd_seclet_link (abfd, data, relocateable)
+     bfd *abfd;
+     PTR data;
+     boolean relocateable;
 {
   HDRR *symhdr;
   int ipass;
@@ -2804,7 +2937,7 @@ DEFUN (ecoff_bfd_seclet_link, (abfd, data, relocateable),
            {
              if (p->type == bfd_indirect_seclet)
                {
-                 if (ecoff_get_debug (abfd, p, o) == false)
+                 if (ecoff_get_debug (abfd, p, o, relocateable) == false)
                    return false;
                }
            }
@@ -2857,6 +2990,16 @@ DEFUN (ecoff_bfd_seclet_link, (abfd, data, relocateable),
                abort ();
              ecoff_swap_ext_in (abfd, ecoff_sym_ptr->native.enative, &esym);
 
+             /* If we're producing an executable, move common symbols
+                into bss.  */
+             if (relocateable == false)
+               {
+                 if (esym.asym.sc == scCommon)
+                   esym.asym.sc = scBss;
+                 else if (esym.asym.sc == scSCommon)
+                   esym.asym.sc = scSBss;
+               }
+
              /* Adjust the FDR index for the symbol by that used for
                 the input BFD.  */
              esym.ifd += ecoff_data (bfd_asymbol_bfd (sym_ptr))->ifdbase;
@@ -2896,36 +3039,42 @@ DEFUN (ecoff_bfd_seclet_link, (abfd, data, relocateable),
    the return value.  */
 
 static boolean
-DEFUN (ecoff_set_arch_mach, (abfd, arch, machine),
-       bfd *abfd AND
-       enum bfd_architecture arch AND
-       unsigned long machine)
+ecoff_set_arch_mach (abfd, arch, machine)
+     bfd *abfd;
+     enum bfd_architecture arch;
+     unsigned long machine;
 {
   bfd_default_set_arch_mach (abfd, arch, machine);
   return arch == bfd_arch_mips;
 }
 
+/* Get the size of the section headers.  We do not output the .scommon
+   section which we created in ecoff_mkobject.  */
+
+static int
+ecoff_sizeof_headers (abfd, reloc)
+     bfd *abfd;
+     boolean reloc;
+{
+  return FILHSZ + AOUTSZ + (abfd->section_count - 1) * SCNHSZ;
+}
+
 /* Calculate the file position for each section, and set
    reloc_filepos.  */
 
 static void
-DEFUN (ecoff_compute_section_file_positions, (abfd),
-       bfd *abfd)
+ecoff_compute_section_file_positions (abfd)
+     bfd *abfd;
 {
   asection *current;
   file_ptr sofar;
   file_ptr old_sofar;
   boolean first_data;
 
-  sofar = FILHSZ;
-
   if (bfd_get_start_address (abfd)) 
     abfd->flags |= EXEC_P;
 
-  /* Unlike normal COFF, ECOFF always use the ``optional'' header.  */
-  sofar += AOUTSZ;
-
-  sofar += abfd->section_count * SCNHSZ;
+  sofar = ecoff_sizeof_headers (abfd, false);
 
   first_data = true;
   for (current = abfd->sections;
@@ -2933,7 +3082,8 @@ DEFUN (ecoff_compute_section_file_positions, (abfd),
        current = current->next)
     {
       /* Only deal with sections which have contents */
-      if (! (current->flags & SEC_HAS_CONTENTS))
+      if (! (current->flags & SEC_HAS_CONTENTS)
+         || strcmp (current->name, SCOMMON) == 0)
        continue;
 
       /* On Ultrix, the data sections in an executable file must be
@@ -2969,12 +3119,12 @@ DEFUN (ecoff_compute_section_file_positions, (abfd),
 /* Set the contents of a section.  */
 
 static boolean
-DEFUN (ecoff_set_section_contents, (abfd, section, location, offset, count),
-       bfd *abfd AND
-       asection *section AND
-       PTR location AND
-       file_ptr offset AND
-       bfd_size_type count)
+ecoff_set_section_contents (abfd, section, location, offset, count)
+     bfd *abfd;
+     asection *section;
+     PTR location;
+     file_ptr offset;
+     bfd_size_type count;
 {
   if (abfd->output_has_begun == false)
     ecoff_compute_section_file_positions (abfd);
@@ -2990,8 +3140,8 @@ DEFUN (ecoff_set_section_contents, (abfd, section, location, offset, count),
 /* Write out an ECOFF file.  */
 
 static boolean
-DEFUN (ecoff_write_object_contents, (abfd),
-       bfd *abfd)
+ecoff_write_object_contents (abfd)
+     bfd *abfd;
 {
   asection *current;
   unsigned int count;
@@ -3025,6 +3175,8 @@ DEFUN (ecoff_write_object_contents, (abfd),
        current != (asection *)NULL; 
        current = current->next) 
     {
+      if (strcmp (current->name, SCOMMON) == 0)
+       continue;
       current->target_index = count;
       ++count;
       if (current->reloc_count != 0)
@@ -3050,7 +3202,7 @@ DEFUN (ecoff_write_object_contents, (abfd),
 
   ecoff_data (abfd)->sym_filepos = sym_base;
 
-  text_size = 0;
+  text_size = ecoff_sizeof_headers (abfd, false);
   text_start = 0;
   data_size = 0;
   data_start = 0;
@@ -3068,6 +3220,13 @@ DEFUN (ecoff_write_object_contents, (abfd),
       struct internal_scnhdr section;
       bfd_vma vma;
 
+      if (strcmp (current->name, SCOMMON) == 0)
+       {
+         BFD_ASSERT (bfd_get_section_size_before_reloc (current) == 0
+                     && current->reloc_count == 0);
+         continue;
+       }
+
       ++internal_f.f_nscns;
 
       strncpy (section.s_name, current->name, sizeof section.s_name);
@@ -3103,7 +3262,8 @@ DEFUN (ecoff_write_object_contents, (abfd),
 
       section.s_nreloc = current->reloc_count;
       section.s_nlnno = 0;
-      section.s_flags = sec_to_styp_flags (current->name, current->flags);
+      section.s_flags = ecoff_sec_to_styp_flags (current->name,
+                                                current->flags);
 
       {
        SCNHDR buff;
@@ -3136,7 +3296,10 @@ DEFUN (ecoff_write_object_contents, (abfd),
 
   /* Set up the file header.  */
 
-  internal_f.f_magic = MIPS_MAGIC_2;
+  if (abfd->xvec->header_byteorder_big_p != false)
+    internal_f.f_magic = MIPS_MAGIC_BIG;
+  else
+    internal_f.f_magic = MIPS_MAGIC_LITTLE;
 
   /*
     We will NOT put a fucking timestamp in the header here. Every time you
@@ -3177,8 +3340,9 @@ DEFUN (ecoff_write_object_contents, (abfd),
   /* Set up the ``optional'' header.  */
   internal_a.magic = ZMAGIC;
 
-  /* FIXME: What should this be?  */
-  internal_a.vstamp = 0;
+  /* FIXME: This is what Ultrix puts in, and it makes the Ultrix
+     linker happy.  But, is it right?  */
+  internal_a.vstamp = 0x20a;
 
   /* At least on Ultrix, these have to be rounded to page boundaries.
      FIXME: Is this true on other platforms?  */
@@ -3204,7 +3368,7 @@ DEFUN (ecoff_write_object_contents, (abfd),
   internal_a.gp_value = ecoff_data (abfd)->gp;
 
   internal_a.gprmask = ecoff_data (abfd)->gprmask;
-  for (i = 0; i < 3; i++)
+  for (i = 0; i < 4; i++)
     internal_a.cprmask[i] = ecoff_data (abfd)->cprmask[i];
 
   /* Write out the file header and the optional header.  */
@@ -3361,9 +3525,7 @@ DEFUN (ecoff_write_object_contents, (abfd),
    ordering in the armap and the contents.
 
    The first four bytes in the armap are the number of symbol
-   definitions.  This always seems to be a power of two, presumably
-   because ranlib uses a hash table of some sort.  I don't know what
-   the hashing scheme is at the moment.
+   definitions.  This is always a power of two.
 
    This is followed by the symbol definitions.  Each symbol definition
    occupies 8 bytes.  The first four bytes are the offset from the
@@ -3373,11 +3535,20 @@ DEFUN (ecoff_write_object_contents, (abfd),
    are 0, then this is not actually a symbol definition, and it should
    be ignored.
 
+   The symbols are hashed into the armap with a closed hashing scheme.
+   See the functions below for the details of the algorithm.
+
+   We could use the hash table when looking up symbols in a library.
+   This would require a new BFD target entry point to replace the
+   bfd_get_next_mapent function used by the linker.
+
    After the symbol definitions comes four bytes holding the size of
    the string table, followed by the string table itself.  */
 
 /* The name of an archive headers looks like this:
-   __________E[BL]E[BL]_ (with a trailing space).  */
+   __________E[BL]E[BL]_ (with a trailing space).
+   The trailing space is changed to an X if the archive is changed to
+   indicate that the armap is out of date.  */
 
 #define ARMAP_BIG_ENDIAN 'B'
 #define ARMAP_LITTLE_ENDIAN 'L'
@@ -3390,11 +3561,36 @@ DEFUN (ecoff_write_object_contents, (abfd),
 #define ARMAP_END_INDEX 14
 #define ARMAP_END "_ "
 
+/* This is a magic number used in the hashing algorithm.  */
+#define ARMAP_HASH_MAGIC 0x9dd68ab5
+
+/* This returns the hash value to use for a string.  It also sets
+   *REHASH to the rehash adjustment if the first slot is taken.  SIZE
+   is the number of entries in the hash table, and HLOG is the log
+   base 2 of SIZE.  */
+
+static unsigned int
+ecoff_armap_hash (s, rehash, size, hlog)
+     CONST char *s;
+     unsigned int *rehash;
+     unsigned int size;
+     unsigned int hlog;
+{
+  unsigned int hash;
+
+  hash = *s++;
+  while (*s != '\0')
+    hash = ((hash >> 27) | (hash << 5)) + *s++;
+  hash *= ARMAP_HASH_MAGIC;
+  *rehash = (hash & (size - 1)) | 1;
+  return hash >> (32 - hlog);
+}
+
 /* Read in the armap.  */
 
 static boolean
-DEFUN (ecoff_slurp_armap, (abfd),
-       bfd *abfd)
+ecoff_slurp_armap (abfd)
+     bfd *abfd;
 {
   char nextname[17];
   unsigned int i;
@@ -3434,7 +3630,7 @@ DEFUN (ecoff_slurp_armap, (abfd),
   /* Make sure we have the right byte ordering.  */
   if (((nextname[ARMAP_HEADER_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN)
        ^ (abfd->xvec->header_byteorder_big_p != false))
-      || ((nextname[ARMAP_OBJECT_MARKER_INDEX] == ARMAP_BIG_ENDIAN)
+      || ((nextname[ARMAP_OBJECT_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN)
          ^ (abfd->xvec->byteorder_big_p != false)))
     {
       bfd_error = wrong_format;
@@ -3475,9 +3671,51 @@ DEFUN (ecoff_slurp_armap, (abfd),
   ardata->symdefs = (carsym *) symdef_ptr;
   stringbase = raw_ptr + count * (2 * LONG_SIZE) + LONG_SIZE;
 
+#ifdef CHECK_ARMAP_HASH
+  {
+    unsigned int hlog;
+
+    /* Double check that I have the hashing algorithm right by making
+       sure that every symbol can be looked up successfully.  */
+    hlog = 0;
+    for (i = 1; i < count; i <<= 1)
+      hlog++;
+    BFD_ASSERT (i == count);
+
+    for (i = 0; i < count; i++, raw_ptr += 2 * LONG_SIZE)
+      {
+       unsigned int name_offset, file_offset;
+       unsigned int hash, rehash, srch;
+      
+       name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr);
+       file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + LONG_SIZE));
+       if (file_offset == 0)
+         continue;
+       hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count,
+                                hlog);
+       if (hash == i)
+         continue;
+
+       /* See if we can rehash to this location.  */
+       for (srch = (hash + rehash) & (count - 1);
+            srch != hash && srch != i;
+            srch = (srch + rehash) & (count - 1))
+         BFD_ASSERT (bfd_h_get_32 (abfd,
+                                   (PTR) (raw_armap
+                                          + LONG_SIZE
+                                          + (srch * 2 * LONG_SIZE)
+                                          + LONG_SIZE))
+                     != 0);
+       BFD_ASSERT (srch == i);
+      }
+  }
+
+  raw_ptr = raw_armap + LONG_SIZE;
+#endif /* CHECK_ARMAP_HASH */
+
   for (i = 0; i < count; i++, raw_ptr += 2 * LONG_SIZE)
     {
-      unsigned long name_offset, file_offset;
+      unsigned int name_offset, file_offset;
 
       name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr);
       file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + LONG_SIZE));
@@ -3501,13 +3739,14 @@ DEFUN (ecoff_slurp_armap, (abfd),
 /* Write out an armap.  */
 
 static boolean
-DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
-       bfd *abfd AND
-       unsigned int elength AND
-       struct orl *map AND
-       unsigned int orl_count AND
-       int stridx)
+ecoff_write_armap (abfd, elength, map, orl_count, stridx)
+     bfd *abfd;
+     unsigned int elength;
+     struct orl *map;
+     unsigned int orl_count;
+     int stridx;
 {
+  unsigned int hashsize, hashlog;
   unsigned int symdefsize;
   int padit;
   unsigned int stringsize;
@@ -3516,16 +3755,23 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
   struct ar_hdr hdr;
   struct stat statbuf;
   unsigned int i;
-  bfd_byte temp[4];
+  bfd_byte temp[LONG_SIZE];
+  bfd_byte *hashtable;
   bfd *current;
   bfd *last_elt;
 
-  symdefsize = orl_count * 8;
+  /* Ultrix appears to use as a hash table size the least power of two
+     greater than twice the number of entries.  */
+  for (hashlog = 0; (1 << hashlog) <= 2 * orl_count; hashlog++)
+    ;
+  hashsize = 1 << hashlog;
+
+  symdefsize = hashsize * 2 * LONG_SIZE;
   padit = stridx % 2;
   stringsize = stridx + padit;
 
   /* Include 8 bytes to store symdefsize and stringsize in output. */
-  mapsize = 4 + symdefsize + stringsize + 4;
+  mapsize = LONG_SIZE + symdefsize + stringsize + LONG_SIZE;
 
   firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength;
 
@@ -3545,9 +3791,10 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
 
   /* Write the timestamp of the archive header to be just a little bit
      later than the timestamp of the file, otherwise the linker will
-     complain that the index is out of date.  */
-  if (stat (abfd->filename, &statbuf) < 0)
-    statbuf.st_mtime = time ((PTR) NULL);
+     complain that the index is out of date.  Actually, the Ultrix
+     linker just checks the archive name; the GNU linker may check the
+     date.  */
+  stat (abfd->filename, &statbuf);
   sprintf (hdr.ar_date, "%ld", (long) (statbuf.st_mtime + 60));
 
   /* The DECstation uses zeroes for the uid, gid and mode of the
@@ -3566,16 +3813,21 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
    if (((char *)(&hdr))[i] == '\0')
      (((char *)(&hdr))[i]) = ' ';
 
-  bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd);
+  if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd)
+      != sizeof (struct ar_hdr))
+    return false;
 
-  bfd_h_put_32 (abfd, symdefsize, temp);
-  bfd_write (temp, 1, LONG_SIZE, abfd);
+  bfd_h_put_32 (abfd, hashsize, temp);
+  if (bfd_write (temp, 1, LONG_SIZE, abfd) != LONG_SIZE)
+    return false;
   
+  hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize);
+
   current = abfd->archive_head;
   last_elt = current;
   for (i = 0; i < orl_count; i++)
     {
-      bfd_byte buff[8];
+      unsigned int hash, rehash;
 
       /* Advance firstreal to the file position of this archive
         element.  */
@@ -3592,21 +3844,60 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
 
       last_elt = current;
 
-      bfd_h_put_32 (abfd, map[i].namidx, buff);
-      bfd_h_put_32 (abfd, firstreal, buff + LONG_SIZE);
-      bfd_write (buff, 1, 2 * LONG_SIZE, abfd);
+      hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog);
+      if (bfd_h_get_32 (abfd, (PTR) (hashtable
+                                    + (hash * 2 * LONG_SIZE)
+                                    + LONG_SIZE))
+         != 0)
+       {
+         unsigned int srch;
+
+         /* The desired slot is already taken.  */
+         for (srch = (hash + rehash) & (hashsize - 1);
+              srch != hash;
+              srch = (srch + rehash) & (hashsize - 1))
+           if (bfd_h_get_32 (abfd, (PTR) (hashtable
+                                          + (srch * 2 * LONG_SIZE)
+                                          + LONG_SIZE))
+               == 0)
+             break;
+
+         BFD_ASSERT (srch != hash);
+
+         hash = srch;
+       }
+       
+      bfd_h_put_32 (abfd, map[i].namidx,
+                   (PTR) (hashtable + hash * 2 * LONG_SIZE));
+      bfd_h_put_32 (abfd, firstreal,
+                   (PTR) (hashtable + hash * 2 * LONG_SIZE + LONG_SIZE));
     }
 
+  if (bfd_write (hashtable, 1, symdefsize, abfd) != symdefsize)
+    return false;
+
+  bfd_release (abfd, hashtable);
+
   /* Now write the strings.  */
   bfd_h_put_32 (abfd, stringsize, temp);
-  bfd_write (temp, 1, LONG_SIZE, abfd);
+  if (bfd_write (temp, 1, LONG_SIZE, abfd) != LONG_SIZE)
+    return false;
   for (i = 0; i < orl_count; i++)
-    bfd_write ((PTR) (*map[i].name), 1, strlen (*map[i].name) + 1, abfd);
+    {
+      bfd_size_type len;
+
+      len = strlen (*map[i].name) + 1;
+      if (bfd_write ((PTR) (*map[i].name), 1, len, abfd) != len)
+       return false;
+    }
 
   /* The spec sez this should be a newline.  But in order to be
      bug-compatible for DECstation ar we use a null.  */
   if (padit)
-    bfd_write ("\0", 1, 1, abfd);
+    {
+      if (bfd_write ("\0", 1, 1, abfd) != 1)
+       return false;
+    }
 
   return true;
 }
@@ -3619,8 +3910,8 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
    and the extended name table.  */
 
 static bfd_target *
-DEFUN (ecoff_archive_p, (abfd),
-       bfd *abfd)
+ecoff_archive_p (abfd)
+     bfd *abfd;
 {
   char armag[SARMAG + 1];
 
@@ -3656,6 +3947,10 @@ DEFUN (ecoff_archive_p, (abfd),
   return abfd->xvec;
 }
 \f
+/* This is the COFF backend structure.  The backend_data field of the
+   bfd_target structure is set to this.  The section reading code in
+   coffgen.c uses this structure.  */
+
 static CONST bfd_coff_backend_data bfd_ecoff_std_swap_table = {
   (void (*) PARAMS ((bfd *,PTR,int,int,PTR))) bfd_void, /* aux_in */
   (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_in */
@@ -3668,7 +3963,7 @@ static CONST bfd_coff_backend_data bfd_ecoff_std_swap_table = {
   FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, true,
   ecoff_swap_filehdr_in, ecoff_swap_aouthdr_in, ecoff_swap_scnhdr_in,
   ecoff_bad_format_hook, ecoff_set_arch_mach_hook, ecoff_mkobject_hook,
-  styp_to_sec_flags, ecoff_make_section_hook, ecoff_set_alignment_hook,
+  ecoff_styp_to_sec_flags, ecoff_make_section_hook, ecoff_set_alignment_hook,
   ecoff_slurp_symbol_table
 };
 
@@ -3678,21 +3973,24 @@ static CONST bfd_coff_backend_data bfd_ecoff_std_swap_table = {
 #define ecoff_get_lineno \
   ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr)
 
+/* These bfd_target functions are defined in other files.  */
+
 #define ecoff_core_file_failing_command        _bfd_dummy_core_file_failing_command
 #define ecoff_core_file_failing_signal _bfd_dummy_core_file_failing_signal
-#define ecoff_core_file_matches_executable_p   _bfd_dummy_core_file_matches_executable_p
+#define ecoff_core_file_matches_executable_p \
+  _bfd_dummy_core_file_matches_executable_p
 #define ecoff_truncate_arname          bfd_dont_truncate_arname
 #define ecoff_openr_next_archived_file bfd_generic_openr_next_archived_file
 #define ecoff_generic_stat_arch_elt    bfd_generic_stat_arch_elt
 #define        ecoff_get_section_contents      bfd_generic_get_section_contents
 #define ecoff_get_reloc_upper_bound    coff_get_reloc_upper_bound
 #define        ecoff_close_and_cleanup         bfd_generic_close_and_cleanup
-#define ecoff_sizeof_headers           coff_sizeof_headers
 #define ecoff_bfd_debug_info_start     bfd_void
 #define ecoff_bfd_debug_info_end       bfd_void
 #define ecoff_bfd_debug_info_accumulate        \
   ((void (*) PARAMS ((bfd *, struct sec *))) bfd_void)
-#define ecoff_bfd_get_relocated_section_contents  bfd_generic_get_relocated_section_contents
+#define ecoff_bfd_get_relocated_section_contents \
+  bfd_generic_get_relocated_section_contents
 #define ecoff_bfd_relax_section                bfd_generic_relax_section
 
 bfd_target ecoff_little_vec =