Basically a checkpoint for coff-mips.c.
authorIan Lance Taylor <ian@airs.com>
Fri, 15 Jan 1993 23:39:05 +0000 (23:39 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 15 Jan 1993 23:39:05 +0000 (23:39 +0000)
Fri Jan 15 18:13:17 1993  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)

* coff-msym.c (ecoff_swap_hdr_out, ecoff_swap_fdr_out,
ecoff_swap_pdr_out, ecoff_swap_sym_out, ecoff_swap_ext_out,
ecoff_swap_rndx_out, ecoff_swap_rfd_out, ecoff_swap_opt_in,
ecoff_swap_opt_out, ecoff_swap_dnr_in, ecoff_swap_dnr_out): New
functions.
* coffswap.h: If NO_COFF_RELOCS is defined, don't define
bfd_swap_reloc_in or coff_swap_reloc_out.
* coff-mips.c: Added code to link and write out symbolic debugging
information, and to swap relocs in and out.

bfd/ChangeLog
bfd/coff-mips.c
bfd/coff-msym.c

index 983caad..1c14ddb 100644 (file)
@@ -1,3 +1,15 @@
+Fri Jan 15 18:13:17 1993  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
+
+       * coff-msym.c (ecoff_swap_hdr_out, ecoff_swap_fdr_out,
+       ecoff_swap_pdr_out, ecoff_swap_sym_out, ecoff_swap_ext_out,
+       ecoff_swap_rndx_out, ecoff_swap_rfd_out, ecoff_swap_opt_in,
+       ecoff_swap_opt_out, ecoff_swap_dnr_in, ecoff_swap_dnr_out): New
+       functions.
+       * coffswap.h: If NO_COFF_RELOCS is defined, don't define
+       bfd_swap_reloc_in or coff_swap_reloc_out.
+       * coff-mips.c: Added code to link and write out symbolic debugging
+       information, and to swap relocs in and out.
+
 Thu Jan 14 15:51:58 1993  Steve Chamberlain  (sac@thepub.cygnus.com)
 
        * libcoff.h, coffgen.c (coff_count_linenumbers), coffcode.h
index 0fd65a7..c49d87e 100644 (file)
@@ -1,7 +1,7 @@
 /* BFD back-end for MIPS Extended-Coff files.
    Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
-   Written by Per Bothner.
-   Symbol and line number support added by Ian Lance Taylor.
+   Original version by Per Bothner.
+   Full support by Ian Lance Taylor, ian@cygnus.com.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -22,6 +22,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
+#include "seclet.h"
 #include "coff/mips.h"
 #include "coff/internal.h"
 #include "coff/sym.h"
@@ -35,9 +36,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 typedef struct ecoff_tdata
 {
-  /* The symbol table file position.  */
+  /* 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 size of the unswapped ECOFF symbolic information.  */
+  bfd_size_type raw_size;
+
   /* The unswapped ECOFF symbolic information.  */
   PTR raw_syments;
 
@@ -97,12 +105,11 @@ typedef struct ecoff_symbol_struct
    COFF routines in coffgen.c, but, unlike the real COFF targets, does
    not use coffcode.h itself.  */
 
-/* Get the generic COFF swapping routines, except for the symbol and
-   lineno ones.  Give them ecoff names.  */
+/* Get the generic COFF swapping routines, except for the reloc,
+   symbol, and lineno ones.  Give them ecoff names.  */
+#define NO_COFF_RELOCS
 #define NO_COFF_SYMBOLS
 #define NO_COFF_LINENOS
-#define coff_swap_reloc_in ecoff_swap_reloc_in
-#define coff_swap_reloc_out ecoff_swap_reloc_out
 #define coff_swap_filehdr_in ecoff_swap_filehdr_in
 #define coff_swap_filehdr_out ecoff_swap_filehdr_out
 #define coff_swap_aouthdr_in ecoff_swap_aouthdr_in
@@ -148,6 +155,24 @@ DEFUN (ecoff_new_section_hook, (abfd, section),
        asection *section)
 {
   section->alignment_power = abfd->xvec->align_power_min;
+
+  if (strcmp (section->name, _TEXT) == 0)
+    section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
+  else if (strcmp (section->name, _DATA) == 0
+          || strcmp (section->name, _SDATA) == 0)
+    section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
+  else if (strcmp (section->name, _RDATA) == 0
+          || strcmp (section->name, _LIT8) == 0
+          || strcmp (section->name, _LIT4) == 0)
+    section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
+  else if (strcmp (section->name, _BSS) == 0
+          || strcmp (section->name, _SBSS) == 0)
+    section->flags |= SEC_ALLOC;
+
+  /* Probably any other section name is SEC_NEVER_LOAD, but I'm
+     uncertain about .init on some systems and I don't know how shared
+     libraries work.  */
+
   return true;
 }
 
@@ -215,12 +240,56 @@ DEFUN (ecoff_set_arch_mach_hook, (abfd, filehdr),
   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)
+{
+  long styp;
+
+  styp = 0;
+
+  if (strcmp (name, _TEXT) == 0)
+    styp = STYP_TEXT;
+  else if (strcmp (name, _DATA) == 0)
+    styp == STYP_DATA;
+  else if (strcmp (name, _SDATA) == 0)
+    styp == STYP_SDATA;
+  else if (strcmp (name, _RDATA) == 0)
+    styp = STYP_RDATA;
+  else if (strcmp (name, _LIT8) == 0)
+    styp = STYP_LIT8;
+  else if (strcmp (name, _LIT4) == 0)
+    styp = STYP_LIT4;
+  else if (strcmp (name, _BSS) == 0)
+    styp = STYP_BSS;
+  else if (strcmp (name, _SBSS) == 0)
+    styp = STYP_SBSS;
+  else if (flags & SEC_CODE) 
+    styp = STYP_TEXT;
+  else if (flags & SEC_DATA) 
+    styp = STYP_DATA;
+  else if (flags & SEC_READONLY)
+    styp = STYP_RDATA;
+  else if (flags & SEC_LOAD)
+    styp = STYP_TEXT;
+  else
+    styp = STYP_BSS;
+
+  if (flags & SEC_NEVER_LOAD)
+    styp |= STYP_NOLOAD;
+
+  return styp;
+}
+
 /* Get the BFD flags to use for a section.  */
 
 static flagword
-DEFUN(styp_to_sec_flags, (abfd, hdr),
-      bfd *abfd AND
-      PTR hdr)
+DEFUN (styp_to_sec_flags, (abfd, hdr),
+       bfd *abfd AND
+       PTR hdr)
 {
   struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
   long styp_flags = internal_s->s_flags;
@@ -271,6 +340,203 @@ DEFUN(styp_to_sec_flags, (abfd, hdr),
   return sec_flags;
 }
 \f
+/* Reloc handling.  MIPS ECOFF relocs are packed into 8 bytes in
+   external form.  They use a bit which indicates whether the symbol
+   is external.  */
+
+/* Swap a reloc in.  */
+
+static void
+DEFUN (ecoff_swap_reloc_in, (abfd, ext, intern),
+       bfd *abfd AND
+       RELOC *ext AND
+       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)
+    {
+      intern->r_symndx = ((ext->r_bits[0]
+                          << RELOC_BITS0_SYMNDX_SH_LEFT_BIG)
+                         | (ext->r_bits[1]
+                            << RELOC_BITS1_SYMNDX_SH_LEFT_BIG)
+                         | (ext->r_bits[2]
+                            << RELOC_BITS2_SYMNDX_SH_LEFT_BIG));
+      intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG)
+                       >> RELOC_BITS3_TYPE_SH_BIG);
+      intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0;
+    }
+  else
+    {
+      intern->r_symndx = ((ext->r_bits[0]
+                          << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE)
+                         | (ext->r_bits[1]
+                            << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE)
+                         | (ext->r_bits[2]
+                            << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE));
+      intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
+                       >> RELOC_BITS3_TYPE_SH_LITTLE);
+      intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
+    }
+}
+
+/* Swap a reloc out.  */
+
+static unsigned int
+DEFUN (ecoff_swap_reloc_out, (abfd, src, dst),
+       bfd *abfd AND
+       PTR src AND
+       PTR dst)
+{
+  struct internal_reloc *intern = (struct internal_reloc *) src;
+  RELOC *ext = (RELOC *) dst;
+
+  bfd_h_put_32 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr);
+  if (abfd->xvec->header_byteorder_big_p != false)
+    {
+      ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG;
+      ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG;
+      ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG;
+      ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG)
+                        & RELOC_BITS3_TYPE_BIG)
+                       | (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0));
+    }
+  else
+    {
+      ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE;
+      ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE;
+      ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE;
+      ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE)
+                        & RELOC_BITS3_TYPE_LITTLE)
+                       | (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0));
+    }
+
+  return RELSZ;
+}
+\f
+/* Read in and swap the important symbolic information for an ECOFF
+   object file.  */
+
+static boolean
+DEFUN (ecoff_slurp_symbolic_info, (abfd),
+       bfd *abfd)
+{
+  struct hdr_ext external_symhdr;
+  HDRR *internal_symhdr;
+  bfd_size_type raw_base;
+  bfd_size_type raw_size;
+  PTR raw;
+  struct fdr_ext *fraw_src;
+  struct fdr_ext *fraw_end;
+  struct fdr *fdr_ptr;
+
+  /* Check whether we've already gotten it, and whether there's any to
+     get.  */
+  if (ecoff_data (abfd)->raw_syments != (PTR) NULL)
+    return true;
+  if (ecoff_data (abfd)->sym_filepos == 0)
+    {
+      bfd_get_symcount (abfd) = 0;
+      return true;
+    }
+
+  /* At this point bfd_get_symcount (abfd) holds the number of symbols
+     as read from the file header, but on ECOFF this is always the
+     size of the symbolic information header.  It would be cleaner to
+     handle this when we first read the file in coffgen.c.  */
+  if (bfd_get_symcount (abfd) != sizeof (external_symhdr))
+    {
+      bfd_error = bad_value;
+      return false;
+    }
+
+  /* Read the symbolic information header.  */
+  if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1
+      || (bfd_read ((PTR) &external_symhdr, sizeof (external_symhdr), 1, abfd)
+         != sizeof (external_symhdr)))
+    {
+      bfd_error = system_call_error;
+      return false;
+    }
+  internal_symhdr = &ecoff_data (abfd)->symbolic_header;
+  ecoff_swap_hdr_in (abfd, &external_symhdr, internal_symhdr);
+
+  if (internal_symhdr->magic != magicSym)
+    {
+      bfd_error = bad_value;
+      return false;
+    }
+
+  /* Now we can get the correct number of symbols.  */
+  bfd_get_symcount (abfd) = (internal_symhdr->isymMax
+                            + internal_symhdr->iextMax);
+
+  /* Read all the symbolic information at once.  This expression
+     assumes that the external symbols are always the last item.  */
+  raw_base = ecoff_data (abfd)->sym_filepos + sizeof (external_symhdr);
+  raw_size = (internal_symhdr->cbExtOffset - raw_base
+             + internal_symhdr->iextMax * sizeof (struct ext_ext));
+  raw = (PTR) bfd_alloc (abfd, raw_size);
+  if (raw == NULL)
+    {
+      bfd_error = no_memory;
+      return false;
+    }
+  if (bfd_read (raw, raw_size, 1, abfd) != raw_size)
+    {
+      bfd_error = system_call_error;
+      bfd_release (abfd, raw);
+      return false;
+    }
+
+  ecoff_data (abfd)->raw_size = raw_size;
+  ecoff_data (abfd)->raw_syments = raw;
+
+  /* Get pointers for the numeric offsets in the HDRR structure.  */
+#define FIX(off1, off2, type) \
+  if (internal_symhdr->off1 == 0) \
+    ecoff_data (abfd)->off2 = (type *) NULL; \
+  else \
+    ecoff_data (abfd)->off2 = (type *) ((char *) raw \
+                                       + internal_symhdr->off1 \
+                                       - raw_base)
+  FIX (cbLineOffset, line, unsigned char);
+  FIX (cbDnOffset, external_dnr, struct dnr_ext);
+  FIX (cbPdOffset, external_pdr, struct pdr_ext);
+  FIX (cbSymOffset, external_sym, struct sym_ext);
+  FIX (cbOptOffset, external_opt, struct opt_ext);
+  FIX (cbAuxOffset, external_aux, union aux_ext);
+  FIX (cbSsOffset, ss, char);
+  FIX (cbSsExtOffset, ssext, char);
+  FIX (cbFdOffset, external_fdr, struct fdr_ext);
+  FIX (cbRfdOffset, external_rfd, struct rfd_ext);
+  FIX (cbExtOffset, external_ext, struct ext_ext);
+#undef FIX
+
+  /* I don't want to always swap all the data, because it will just
+     waste time and most programs will never look at it.  The only
+     time the linker needs most of the debugging information swapped
+     is when linking big-endian and little-endian MIPS object files
+     together, which is not a common occurrence.
+
+     We need to look at the fdr to deal with a lot of information in
+     the symbols, so we swap them here.  */
+  ecoff_data (abfd)->fdr = (struct fdr *) bfd_alloc (abfd,
+                                                    (internal_symhdr->ifdMax *
+                                                     sizeof (struct fdr)));
+  if (ecoff_data (abfd)->fdr == NULL)
+    {
+      bfd_error = no_memory;
+      return false;
+    }
+  fdr_ptr = ecoff_data (abfd)->fdr;
+  fraw_src = ecoff_data (abfd)->external_fdr;
+  fraw_end = fraw_src + internal_symhdr->ifdMax;
+  for (; fraw_src < fraw_end; fraw_src++, fdr_ptr++)
+    ecoff_swap_fdr_in (abfd, fraw_src, fdr_ptr);
+
+  return true;
+}
+\f
 /* ECOFF symbol table routines.  The ECOFF symbol table is described
    in gcc/mips-tfile.c.  */
 
@@ -402,119 +668,23 @@ static boolean
 DEFUN (ecoff_slurp_symbol_table, (abfd),
        bfd *abfd)
 {
-  struct hdr_ext external_symhdr;
-  HDRR *internal_symhdr;
-  bfd_size_type raw_base;
-  bfd_size_type raw_size;
-  PTR raw;
   bfd_size_type internal_size;
-  struct fdr_ext *fraw_src;
-  struct fdr_ext *fraw_end;
-  struct fdr *fdr_ptr;
-  struct fdr *fdr_end;
   ecoff_symbol_type *internal;
   ecoff_symbol_type *internal_ptr;
   struct ext_ext *eraw_src;
   struct ext_ext *eraw_end;
+  FDR *fdr_ptr;
+  FDR *fdr_end;
 
   /* If we've already read in the symbol table, do nothing.  */
   if (ecoff_data (abfd)->canonical_symbols != NULL)
     return true;
 
-  /* At this point bfd_get_symcount (abfd) holds the number of symbols
-     as read from the file header, but on ECOFF this is always the
-     size of the symbolic information header.  It would be cleaner to
-     handle this when we first read the file in coffgen.c.  */
-  if (bfd_get_symcount (abfd) != sizeof (external_symhdr))
-    {
-      bfd_error = bad_value;
-      return false;
-    }
-
-  /* Read the symbolic information header.  */
-  if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1
-      || (bfd_read ((PTR) &external_symhdr, sizeof (external_symhdr), 1, abfd)
-         != sizeof (external_symhdr)))
-    {
-      bfd_error = system_call_error;
-      return false;
-    }
-  internal_symhdr = &ecoff_data (abfd)->symbolic_header;
-  ecoff_swap_hdr_in (abfd, &external_symhdr, internal_symhdr);
-
-  if (internal_symhdr->magic != magicSym)
-    {
-      bfd_error = bad_value;
-      return false;
-    }
-
-  /* Now we can get the correct number of symbols.  */
-  bfd_get_symcount (abfd) = (internal_symhdr->isymMax
-                            + internal_symhdr->iextMax);
-
-  /* Read the entire symbol table at once.  This expression assumes
-     that the external symbols are always the last item.  */
-  raw_base = ecoff_data (abfd)->sym_filepos + sizeof (external_symhdr);
-  raw_size = (internal_symhdr->cbExtOffset - raw_base
-             + internal_symhdr->iextMax * sizeof (struct ext_ext));
-  raw = (PTR) bfd_alloc (abfd, raw_size);
-  if (raw == NULL)
-    {
-      bfd_error = no_memory;
-      return false;
-    }
-  if (bfd_read (raw, raw_size, 1, abfd) != raw_size)
-    {
-      bfd_error = system_call_error;
-      bfd_release (abfd, raw);
-      return false;
-    }
-
-  ecoff_data (abfd)->raw_syments = raw;
-
-  /* Get pointers for the numeric offsets in the HDRR structure.  */
-#define FIX(off1, off2, type) \
-  if (internal_symhdr->off1 == 0) \
-    ecoff_data (abfd)->off2 = (type *) NULL; \
-  else \
-    ecoff_data (abfd)->off2 = (type *) ((char *) raw \
-                                       + internal_symhdr->off1 \
-                                       - raw_base)
-  FIX (cbLineOffset, line, unsigned char);
-  FIX (cbDnOffset, external_dnr, struct dnr_ext);
-  FIX (cbPdOffset, external_pdr, struct pdr_ext);
-  FIX (cbSymOffset, external_sym, struct sym_ext);
-  FIX (cbOptOffset, external_opt, struct opt_ext);
-  FIX (cbAuxOffset, external_aux, union aux_ext);
-  FIX (cbSsOffset, ss, char);
-  FIX (cbSsExtOffset, ssext, char);
-  FIX (cbFdOffset, external_fdr, struct fdr_ext);
-  FIX (cbRfdOffset, external_rfd, struct rfd_ext);
-  FIX (cbExtOffset, external_ext, struct ext_ext);
-#undef FIX
-
-  /* I don't want to always swap all the data, because it will just
-     waste time and most programs will never look at this data.  The
-     only time the linker needs most of the debugging information
-     swapped is when linking big-endian and little-endian MIPS object
-     files together, which is not a common occurrence.
-
-     We need to look at the fdr to deal with a lot of information in
-     the symbols, so we swap them here.  We also canonicalize the
-     symbols.  */
-  ecoff_data (abfd)->fdr = (struct fdr *) bfd_alloc (abfd,
-                                                    (internal_symhdr->ifdMax *
-                                                     sizeof (struct fdr)));
-  if (ecoff_data (abfd)->fdr == NULL)
-    {
-      bfd_error = no_memory;
-      return false;
-    }
-  fdr_ptr = ecoff_data (abfd)->fdr;
-  fraw_src = ecoff_data (abfd)->external_fdr;
-  fraw_end = fraw_src + internal_symhdr->ifdMax;
-  for (; fraw_src < fraw_end; fraw_src++, fdr_ptr++)
-    ecoff_swap_fdr_in (abfd, fraw_src, fdr_ptr);
+  /* Get the symbolic information.  */
+  if (ecoff_slurp_symbolic_info (abfd) == false)
+    return false;
+  if (bfd_get_symcount (abfd) == 0)
+    return true;
 
   internal_size = bfd_get_symcount (abfd) * sizeof (ecoff_symbol_type);
   internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size);
@@ -526,7 +696,7 @@ DEFUN (ecoff_slurp_symbol_table, (abfd),
 
   internal_ptr = internal;
   eraw_src = ecoff_data (abfd)->external_ext;
-  eraw_end = eraw_src + internal_symhdr->iextMax;
+  eraw_end = eraw_src + ecoff_data (abfd)->symbolic_header.iextMax;
   for (; eraw_src < eraw_end; eraw_src++, internal_ptr++)
     {
       EXTR internal_esym;
@@ -544,7 +714,7 @@ DEFUN (ecoff_slurp_symbol_table, (abfd),
   /* The local symbols must be accessed via the fdr's, because the
      string and aux indices are relative to the fdr information.  */
   fdr_ptr = ecoff_data (abfd)->fdr;
-  fdr_end = fdr_ptr + internal_symhdr->ifdMax;
+  fdr_end = fdr_ptr + ecoff_data (abfd)->symbolic_header.ifdMax;
   for (; fdr_ptr < fdr_end; fdr_ptr++)
     {
       struct sym_ext *lraw_src;
@@ -577,7 +747,8 @@ static unsigned int
 DEFUN (ecoff_get_symtab_upper_bound, (abfd),
        bfd *abfd)
 {
-  if (! ecoff_slurp_symbol_table (abfd))
+  if (ecoff_slurp_symbolic_info (abfd) == false
+      || bfd_get_symcount (abfd) == 0)
     return 0;
 
   return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *));
@@ -592,7 +763,8 @@ DEFUN (ecoff_get_symtab, (abfd, alocation),
   ecoff_symbol_type *symbase;
   ecoff_symbol_type **location = (ecoff_symbol_type **) alocation;
 
-  if (! ecoff_slurp_symbol_table (abfd))
+  if (ecoff_slurp_symbol_table (abfd) == false
+      || bfd_get_symcount (abfd) == 0)
     return 0;
 
   symbase = ecoff_data (abfd)->canonical_symbols;
@@ -1008,7 +1180,6 @@ DEFUN (ecoff_print_symbol, (abfd, filep, symbol, how),
     case bfd_print_symbol_all:
       /* Print out the symbols in a reasonable way */
       {
-       CONST char *section_name = symbol->section->name;
        char type;
        int pos;
        EXTR ecoff_ext;
@@ -1163,6 +1334,11 @@ DEFUN (ecoff_find_nearest_line, (abfd,
   if (strcmp (section->name, _TEXT) != 0)
     return false;
 
+  /* Make sure we have the FDR's.  */
+  if (ecoff_slurp_symbolic_info (abfd) == false
+      || bfd_get_symcount (abfd) == 0)
+    return false;
+
   /* Each file descriptor (FDR) has a memory address.  Here we track
      down which FDR we want.  The FDR's are stored in increasing
      memory order.  If speed is ever important, this can become a
@@ -1255,6 +1431,1077 @@ DEFUN (ecoff_find_nearest_line, (abfd,
   return true;
 }
 \f
+/* We can't use the generic linking routines for ECOFF, because we
+   have to handle all the debugging information.  The generic link
+   routine just works out the section contents and attaches a list of
+   symbols.
+
+   We link by looping over all the seclets.  We make two passes.  On
+   the first we set the actual section contents and determine the size
+   of the debugging information.  On the second we accumulate the
+   debugging information and write it out.
+
+   This currently always accumulates the debugging information, which
+   is incorrect, because it ignores the -s and -S options of the
+   linker.  The linker needs to be modified to give us that
+   information in a more useful format (currently it just provides a
+   list of symbols which should appear in the output file).  */
+
+/* Clear the output_has_begun flag for all the input BFD's.  We use it
+   to avoid linking in the debugging information for a BFD more than
+   once.  */
+
+static void
+DEFUN (ecoff_clear_output_flags, (abfd),
+       bfd *abfd)
+{
+  register asection *o;
+  register bfd_seclet_type *p;
+
+  for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+    for (p = o->seclets_head;
+        p != (bfd_seclet_type *) NULL;
+        p = p->next)
+      if (p->type == bfd_indirect_seclet)
+       p->u.indirect.section->owner->output_has_begun = false;
+}
+
+/* Handle an indirect seclet on the first pass.  Set the contents of
+   the output section, and accumulate the debugging information if
+   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)
+{
+  bfd *input_bfd;
+  HDRR *output_symhdr;
+  HDRR *input_symhdr;
+
+  if ((output_section->flags & SEC_HAS_CONTENTS)
+      && !(output_section->flags & SEC_NEVER_LOAD)
+      && (output_section->flags & SEC_LOAD)
+      && seclet->size)
+    {
+      data = (PTR) bfd_get_relocated_section_contents (output_bfd,
+                                                      seclet,
+                                                      data,
+                                                      relocateable);
+      if (bfd_set_section_contents (output_bfd,
+                                   output_section,
+                                   data,
+                                   seclet->offset,
+                                   seclet->size)
+         == false)
+       {
+         abort();
+       }
+    }
+
+  input_bfd = seclet->u.indirect.section->owner;
+
+  /* We want to figure out how much space will be required to
+     incorporate all the debugging information from input_bfd.  We use
+     the output_has_begun field to avoid adding it in more than once.
+     The actual incorporation is done in the second pass, in
+     ecoff_get_debug.  The code has to parallel that code in its
+     manipulations of output_symhdr.  */
+
+  if (input_bfd->output_has_begun)
+    return true;
+  input_bfd->output_has_begun = true;
+
+  output_symhdr = &ecoff_data (output_bfd)->symbolic_header;
+
+  if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour)
+    {
+      asymbol **symbols;
+      asymbol **sym_ptr;
+      asymbol **sym_end;
+
+      /* We just accumulate symbols from a non-ECOFF BFD.  */
+
+      symbols = (asymbol **) bfd_alloc (output_bfd,
+                                       get_symtab_upper_bound (input_bfd));
+      if (symbols == (asymbol **) NULL)
+       {
+         bfd_error = no_memory;
+         return false;
+       }
+      sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols);
+
+      for (sym_ptr = symbols; sym_ptr < sym_end; sym_ptr++)
+       {
+         size_t len;
+
+         len = strlen ((*sym_ptr)->name);
+         if (((*sym_ptr)->flags & BSF_EXPORT) == 0)
+           {
+             ++output_symhdr->isymMax;
+             output_symhdr->issMax += len + 1;
+           }
+         else
+           {
+             ++output_symhdr->iextMax;
+             output_symhdr->issExtMax += len + 1;
+           }
+       }
+
+      bfd_release (output_bfd, (PTR) symbols);
+
+      ++output_symhdr->ifdMax;
+
+      return true;
+    }
+
+  /* We simply add in the information from another ECOFF BFD.  First
+     we make sure we have the symbolic information.  */
+  if (ecoff_slurp_symbolic_info (input_bfd) == false)
+    return false;
+  if (bfd_get_symcount (input_bfd) == 0)
+    return true;
+
+  input_symhdr = &ecoff_data (input_bfd)->symbolic_header;
+
+  output_symhdr->ilineMax += input_symhdr->ilineMax;
+  output_symhdr->cbLine += input_symhdr->cbLine;
+  output_symhdr->idnMax += input_symhdr->idnMax;
+  output_symhdr->ipdMax += input_symhdr->ipdMax;
+  output_symhdr->isymMax += input_symhdr->isymMax;
+  output_symhdr->ioptMax += input_symhdr->ioptMax;
+  output_symhdr->iauxMax += input_symhdr->iauxMax;
+  output_symhdr->issMax += input_symhdr->issMax;
+  output_symhdr->issExtMax += input_symhdr->issExtMax;
+  output_symhdr->ifdMax += input_symhdr->ifdMax;
+  output_symhdr->iextMax += input_symhdr->iextMax;
+
+  /* The RFD's are special, since we create them if needed.  */
+  if (input_symhdr->crfd > 0)
+    output_symhdr->crfd += input_symhdr->crfd;
+  else
+    output_symhdr->crfd += input_symhdr->ifdMax;
+
+  return true;
+}
+
+/* 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)
+{
+  switch (seclet->type) 
+    {
+    case bfd_indirect_seclet:
+      /* The contents of this section come from another one somewhere
+        else.  */
+      return ecoff_rel (abfd, seclet, section, data, relocateable);
+
+    case bfd_fill_seclet:
+      /* Fill in the section with us.  */
+      {
+       char *d = (char *) bfd_alloc (abfd, seclet->size);
+       unsigned int i;
+       boolean ret;
+
+       for (i = 0; i < seclet->size; i+=2)
+         d[i] = seclet->u.fill.value >> 8;
+       for (i = 1; i < seclet->size; i+=2)
+         d[i] = seclet->u.fill.value;
+       ret = bfd_set_section_contents (abfd, section, d, seclet->offset,
+                                       seclet->size);
+       bfd_release (abfd, (PTR) d);
+       return ret;
+      }
+
+    default:
+      abort();
+    }
+
+  return true;
+}
+
+/* Add a string to the debugging information we are accumulating for a
+   file.  Return the offset from the fdr string base or from the
+   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)
+{
+  HDRR *symhdr;
+  size_t len;
+  long ret;
+
+  symhdr = &ecoff_data (output_bfd)->symbolic_header;
+  len = strlen (string);
+  if (external)
+    {
+      strcpy (ecoff_data (output_bfd)->ssext + symhdr->issExtMax, string);
+      ret = symhdr->issExtMax;
+      symhdr->issExtMax += len + 1;
+    }
+  else
+    {
+      strcpy (ecoff_data (output_bfd)->ss + symhdr->issMax, string);
+      ret = fdr->cbSs;
+      symhdr->issMax += len + 1;
+      fdr->cbSs += len + 1;
+    }
+  return ret;
+}
+
+/* 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)
+{
+  bfd *input_bfd;
+  HDRR *output_symhdr;
+  HDRR *input_symhdr;
+  ecoff_data_type *output_ecoff;
+  ecoff_data_type *input_ecoff;
+  FDR *fdr_ptr;
+  FDR *fdr_end;
+  struct fdr_ext *fdr_out;
+  struct ext_ext *ext_ptr;
+  struct ext_ext *ext_end;
+  struct ext_ext *ext_out;
+  long iss;
+  long isym;
+  long iline;
+  long iopt;
+  long ipdr;
+  long iaux;
+  long irfd;
+  long cbline;
+
+  input_bfd = seclet->u.indirect.section->owner;
+
+  /* Don't get the information more than once. */
+  if (input_bfd->output_has_begun)
+    return true;
+  input_bfd->output_has_begun = true;
+
+  output_ecoff = ecoff_data (output_bfd);
+  output_symhdr = &output_ecoff->symbolic_header;
+
+  if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour)
+    {
+      FDR fdr;
+      asymbol **symbols;
+      asymbol **sym_ptr;
+      asymbol **sym_end;
+
+      /* This is not an ECOFF BFD.  Just gather the symbols.  */
+
+      memset (&fdr, 0, sizeof fdr);
+
+      fdr.adr = bfd_get_section_vma (output_bfd, section) + seclet->offset;
+      fdr.issBase = output_symhdr->issMax;
+      fdr.cbSs = 0;
+      fdr.rss = ecoff_add_string (output_bfd,
+                                 &fdr,
+                                 bfd_get_filename (input_bfd),
+                                 false);
+      fdr.isymBase = output_symhdr->isymMax;
+
+      /* Get the symbols from the input BFD.  */
+      symbols = (asymbol **) bfd_alloc (output_bfd,
+                                       get_symtab_upper_bound (input_bfd));
+      if (symbols == (asymbol **) NULL)
+       {
+         bfd_error = no_memory;
+         return false;
+       }
+      sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols);
+
+      /* Handle the local symbols.  */
+      fdr.csym = 0;
+      for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++)
+       {
+         SYMR internal_sym;
+
+         if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
+           continue;
+         memset (&internal_sym, 0, sizeof internal_sym);
+         internal_sym.iss = ecoff_add_string (output_bfd,
+                                              &fdr,
+                                              (*sym_ptr)->name,
+                                              false);
+         internal_sym.value = (*sym_ptr)->value;
+         internal_sym.st = stNil;
+         internal_sym.sc = scUndefined;
+         internal_sym.index = indexNil;
+         ecoff_swap_sym_out (output_bfd, &internal_sym,
+                             (output_ecoff->external_sym
+                              + output_symhdr->isymMax));
+         ++fdr.csym;
+         ++output_symhdr->isymMax;
+       }
+
+      /* Handle the external symbols.  */
+      for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++)
+       {
+         EXTR internal_ext;
+
+         if (((*sym_ptr)->flags & BSF_EXPORT) == 0)
+           continue;
+         memset (&internal_ext, 0, sizeof internal_ext);
+         internal_ext.ifd = output_symhdr->ifdMax;
+         internal_ext.asym.iss = ecoff_add_string (output_bfd,
+                                                   &fdr,
+                                                   (*sym_ptr)->name,
+                                                   true);
+         internal_ext.asym.value = (*sym_ptr)->value;
+         internal_ext.asym.st = stNil;
+         internal_ext.asym.sc = scUndefined;
+         internal_ext.asym.reserved = 0;
+         internal_ext.asym.index = indexNil;
+         ecoff_swap_ext_out (output_bfd, &internal_ext,
+                             (output_ecoff->external_ext
+                              + output_symhdr->iextMax));
+         ++output_symhdr->iextMax;
+       }
+
+      bfd_release (output_bfd, (PTR) symbols);
+
+      /* Leave everything else zeroed out.  This will cause the lang
+        field to be langC.  The fBigendian field will indicate little
+        endian format, but it doesn't matter because it only applies
+        to aux fields and there are none.  */
+
+      ecoff_swap_fdr_out (output_bfd, &fdr,
+                         (output_ecoff->external_fdr
+                          + output_symhdr->ifdMax));
+      ++output_symhdr->ifdMax;
+      return true;
+    }
+
+  /* This is an ECOFF BFD.  We want to grab the information from
+     input_bfd and attach it to output_bfd.  */
+  if (bfd_get_symcount (input_bfd) == 0)
+    return true;
+  input_ecoff = ecoff_data (input_bfd);
+  input_symhdr = &input_ecoff->symbolic_header;
+
+  /* Because ECOFF uses relative pointers for most of the debugging
+     information, much of it can simply be copied from input_bfd to
+     output_bfd.  */
+  memcpy (output_ecoff->line + output_symhdr->cbLineOffset,
+         input_ecoff->line,
+         input_symhdr->cbLine * sizeof (unsigned char));
+  memcpy (output_ecoff->external_aux + output_symhdr->iauxMax,
+         input_ecoff->external_aux,
+         input_symhdr->iauxMax * sizeof (union aux_ext));
+  memcpy (output_ecoff->ss + output_symhdr->issMax,
+         input_ecoff->ss,
+         input_symhdr->issMax * sizeof (char));
+  memcpy (output_ecoff->ssext + output_symhdr->issExtMax,
+         input_ecoff->ssext,
+         input_symhdr->issExtMax * sizeof (char));
+
+  /* Some of the information may need to be swapped.  */
+  if (output_bfd->xvec->byteorder_big_p == input_bfd->xvec->byteorder_big_p)
+    {
+      /* The two BFD's have the same endianness, so memcpy will
+        suffice.  */
+      memcpy (output_ecoff->external_dnr + output_symhdr->idnMax,
+             input_ecoff->external_dnr,
+             input_symhdr->idnMax * sizeof (struct dnr_ext));
+      memcpy (output_ecoff->external_pdr + output_symhdr->ipdMax,
+             input_ecoff->external_pdr,
+             input_symhdr->ipdMax * sizeof (struct pdr_ext));
+      memcpy (output_ecoff->external_sym + output_symhdr->isymMax,
+             input_ecoff->external_sym,
+             input_symhdr->isymMax * sizeof (struct sym_ext));
+      memcpy (output_ecoff->external_opt + output_symhdr->ioptMax,
+             input_ecoff->external_opt,
+             input_symhdr->ioptMax * sizeof (struct opt_ext));
+    }
+  else
+    {
+      struct dnr_ext *dnr_in;
+      struct dnr_ext *dnr_end;
+      struct dnr_ext *dnr_out;
+      struct pdr_ext *pdr_in;
+      struct pdr_ext *pdr_end;
+      struct pdr_ext *pdr_out;
+      struct sym_ext *sym_in;
+      struct sym_ext *sym_end;
+      struct sym_ext *sym_out;
+      struct opt_ext *opt_in;
+      struct opt_ext *opt_end;
+      struct opt_ext *opt_out;
+
+      /* The two BFD's have different endianness, so we must swap
+        everything in and out.  This code would always work, but it
+        would be very slow in the normal case.  */
+      dnr_in = input_ecoff->external_dnr;
+      dnr_end = dnr_in + input_symhdr->idnMax;
+      dnr_out = output_ecoff->external_dnr + output_symhdr->idnMax;
+      for (; dnr_in < dnr_end; dnr_in++, dnr_out++)
+       {
+         DNR dnr;
+
+         ecoff_swap_dnr_in (input_bfd, dnr_in, &dnr);
+         ecoff_swap_dnr_out (output_bfd, &dnr, dnr_out);
+       }
+      pdr_in = input_ecoff->external_pdr;
+      pdr_end = pdr_in + input_symhdr->ipdMax;
+      pdr_out = output_ecoff->external_pdr + output_symhdr->ipdMax;
+      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);
+       }
+      sym_in = input_ecoff->external_sym;
+      sym_end = sym_in + input_symhdr->isymMax;
+      sym_out = output_ecoff->external_sym + output_symhdr->isymMax;
+      for (; sym_in < sym_end; sym_in++, sym_out++)
+       {
+         SYMR sym;
+
+         ecoff_swap_sym_in (input_bfd, sym_in, &sym);
+         ecoff_swap_sym_out (output_bfd, &sym, sym_out);
+       }
+      opt_in = input_ecoff->external_opt;
+      opt_end = opt_in + input_symhdr->ioptMax;
+      opt_out = output_ecoff->external_opt + output_symhdr->ioptMax;
+      for (; opt_in < opt_end; opt_in++, opt_out++)
+       {
+         OPTR opt;
+
+         ecoff_swap_opt_in (input_bfd, opt_in, &opt);
+         ecoff_swap_opt_out (output_bfd, &opt, opt_out);
+       }
+    }
+
+  /* Step through the FDR's of input_bfd, adjust the offsets, and
+     swap them out.  */
+  iss = output_symhdr->issMax;
+  isym = output_symhdr->isymMax;
+  iline = output_symhdr->ilineMax;
+  iopt = output_symhdr->ioptMax;
+  ipdr = output_symhdr->ipdMax;
+  iaux = output_symhdr->iauxMax;
+  irfd = output_symhdr->crfd;
+  cbline = output_symhdr->cbLineOffset;
+
+  fdr_ptr = input_ecoff->fdr;
+  fdr_end = fdr_ptr + input_symhdr->ifdMax;
+  fdr_out = output_ecoff->external_fdr + output_symhdr->ifdMax;
+  for (; fdr_ptr < fdr_end; fdr_ptr++, fdr_out++)
+    {
+      FDR fdr;
+
+      fdr = *fdr_ptr;
+
+      /* The memory address for this fdr is the address for the seclet
+        plus the offset to this fdr within input_bfd.  */
+      fdr.adr = (bfd_get_section_vma (output_bfd, section)
+                + seclet->offset
+                + (fdr_ptr->adr - input_ecoff->fdr->adr));
+
+      fdr.issBase = iss;
+      iss += fdr.cbSs * sizeof (char);
+      fdr.isymBase = isym;
+      isym += fdr.csym * sizeof (struct sym_ext);
+      fdr.ilineBase = iline;
+      iline += fdr.cline;
+      fdr.ioptBase = iopt;
+      iopt += fdr.copt * sizeof (struct opt_ext);
+      fdr.ipdFirst = ipdr;
+      ipdr += fdr.cpd * sizeof (struct pdr_ext);
+      fdr.iauxBase = iaux;
+      iaux += fdr.caux * sizeof (union aux_ext);
+      fdr.rfdBase = irfd;
+      irfd += fdr.crfd * sizeof (struct rfd_ext);
+      fdr.cbLineOffset = cbline;
+      cbline += fdr.cbLine * sizeof (unsigned char);
+
+      ecoff_swap_fdr_out (output_bfd, &fdr, fdr_out);
+    }
+
+  if (input_symhdr->crfd > 0)
+    {
+      struct rfd_ext *rfd_in;
+      struct rfd_ext *rfd_end;
+      struct rfd_ext *rfd_out;
+
+      /* Swap and adjust the RFD's.  RFD's are only created by the
+        linker, so this will only be necessary if one of the input
+        files is the result of a partial link.  Presumably all
+        necessary RFD's are present.  */
+      rfd_in = input_ecoff->external_rfd;
+      rfd_end = rfd_in + input_symhdr->crfd;
+      rfd_out = output_ecoff->external_rfd + output_symhdr->crfd;
+      for (; rfd_in < rfd_end; rfd_in++, rfd_out++)
+       {
+         RFDT rfd;
+
+         ecoff_swap_rfd_in (input_bfd, rfd_in, &rfd);
+         rfd += output_symhdr->ifdMax;
+         ecoff_swap_rfd_out (output_bfd, &rfd, rfd_out);
+       }
+      output_symhdr->crfd += input_symhdr->crfd;
+    }
+  else
+    {
+      struct rfd_ext *rfd_out;
+      struct rfd_ext *rfd_end;
+      RFDT rfd;
+
+      /* Create RFD's.  Some of the debugging information includes
+        relative file indices.  These indices are taken as indices to
+        the RFD table if there is one, or to the global table if
+        there is not.  If we did not create RFD's, we would have to
+        parse and adjust all the debugging information which contains
+        file indices.  */
+      rfd = output_symhdr->ifdMax;
+      rfd_out = output_ecoff->external_rfd + output_symhdr->crfd;
+      rfd_end = rfd_out + input_symhdr->ifdMax;
+      for (; rfd_out < rfd_end; rfd_out++, rfd++)
+       ecoff_swap_rfd_out (output_bfd, &rfd, rfd_out);
+      output_symhdr->crfd += input_symhdr->ifdMax;
+    }
+
+  /* We have to swap the external symbols in and out because we have
+     to adjust the file descriptor indices.  */
+  ext_ptr = input_ecoff->external_ext;
+  ext_end = ext_ptr + input_symhdr->iextMax;
+  ext_out = output_ecoff->external_ext + output_symhdr->iextMax;
+  for (; ext_ptr < ext_end; ext_ptr++, ext_out++)
+    {
+      EXTR ext;
+
+      ecoff_swap_ext_in (input_bfd, ext_ptr, &ext);
+      ext.ifd += output_symhdr->ifdMax;
+      ecoff_swap_ext_out (output_bfd, &ext, ext_out);
+    }
+
+  /* Update the counts.  */
+  output_symhdr->ilineMax += input_symhdr->ilineMax;
+  output_symhdr->cbLine += input_symhdr->cbLine;
+  output_symhdr->idnMax += input_symhdr->idnMax;
+  output_symhdr->ipdMax += input_symhdr->ipdMax;
+  output_symhdr->isymMax += input_symhdr->isymMax;
+  output_symhdr->ioptMax += input_symhdr->ioptMax;
+  output_symhdr->iauxMax += input_symhdr->iauxMax;
+  output_symhdr->issMax += input_symhdr->issMax;
+  output_symhdr->issExtMax += input_symhdr->issExtMax;
+  output_symhdr->ifdMax += input_symhdr->ifdMax;
+  output_symhdr->iextMax += input_symhdr->iextMax;
+
+  /* Double check that the counts we got by stepping through the FDR's
+     match the counts we got from input_symhdr.  */
+  BFD_ASSERT (output_symhdr->issMax == iss
+             && output_symhdr->isymMax == isym
+             && output_symhdr->ilineMax == iline
+             && output_symhdr->ioptMax == iopt
+             && output_symhdr->ipdMax == ipdr
+             && output_symhdr->iauxMax == iaux
+             && output_symhdr->cbLineOffset == cbline);
+
+  return true;
+}
+
+/* This is the actual link routine.  It makes two passes over all the
+   seclets.  */
+
+static boolean
+DEFUN (ecoff_bfd_seclet_link, (abfd, data, relocateable),
+       bfd *abfd AND
+       PTR data AND
+       boolean relocateable)
+{
+  HDRR *symhdr;
+  int ipass;
+  register asection *o;
+  register bfd_seclet_type *p;
+  bfd_size_type size;
+  char *raw;
+
+  /* We accumulate the debugging information counts in the symbolic
+     header.  */
+  symhdr = &ecoff_data (abfd)->symbolic_header;
+  symhdr->ilineMax = 0;
+  symhdr->cbLine = 0;
+  symhdr->idnMax = 0;
+  symhdr->ipdMax = 0;
+  symhdr->isymMax = 0;
+  symhdr->ioptMax = 0;
+  symhdr->iauxMax = 0;
+  symhdr->issMax = 0;
+  symhdr->issExtMax = 0;
+  symhdr->ifdMax = 0;
+  symhdr->crfd = 0;
+  symhdr->iextMax = 0;
+
+  /* We are only going to look at each input BFD once.  It is
+     convenient to look at the code section first, so that the first
+     time we look at a BFD we can set the text address (otherwise,
+     when we get to the text section, we would have to be able to
+     track down the file information associated with that BFD).  So we
+     actually do each pass in two sub passes; first the code sections,
+     then the non-code sections.  */
+
+  /* Do the first pass: set the output section contents and count the
+     debugging information.  */
+  ecoff_clear_output_flags (abfd);
+  for (ipass = 0; ipass < 2; ipass++)
+    {
+      for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+       {
+         /* For SEC_CODE sections, (flags & SEC_CODE) == 0 is false,
+            so they are done on pass 0.  For other sections the
+            expression is true, so they are done on pass 1.  */
+         if (((o->flags & SEC_CODE) == 0) != ipass)
+           continue;
+
+         for (p = o->seclets_head;
+              p != (bfd_seclet_type *) NULL;
+              p = p->next)
+           {
+             if (ecoff_dump_seclet (abfd, p, o, data, relocateable)
+                 == false)
+               return false;
+           }
+       }
+    }
+
+  /* Now the counts in symhdr are the correct size for the debugging
+     information.  We allocate the right amount of space, and reset
+     the counts so that the second pass can use them as indices.  It
+     would be possible to output the debugging information directly to
+     the file in pass 2, rather than to build it in memory and then
+     write it out.  Outputting to the file would require a lot of
+     seeks and small writes, though, and I think this approach is
+     faster.  */
+  size = (symhdr->cbLine * sizeof (unsigned char)
+         + symhdr->idnMax * sizeof (struct dnr_ext)
+         + symhdr->ipdMax * sizeof (struct pdr_ext)
+         + symhdr->isymMax * sizeof (struct sym_ext)
+         + symhdr->ioptMax * sizeof (struct opt_ext)
+         + symhdr->iauxMax * sizeof (union aux_ext)
+         + symhdr->issMax * sizeof (char)
+         + symhdr->issExtMax * sizeof (char)
+         + symhdr->ifdMax * sizeof (struct fdr_ext)
+         + symhdr->crfd * sizeof (struct rfd_ext)
+         + symhdr->iextMax * sizeof (struct ext_ext));
+  raw = (char *) bfd_alloc (abfd, size);
+  if (raw == (char *) NULL)
+    {
+      bfd_error = no_memory;
+      return false;
+    }
+  ecoff_data (abfd)->raw_size = size;
+  ecoff_data (abfd)->raw_syments = (PTR) raw;
+
+  /* Initialize the raw pointers.  */
+#define SET(field, count, type) \
+  ecoff_data (abfd)->field = (type *) raw; \
+  raw += symhdr->count * sizeof (type)
+
+  SET (line, cbLine, unsigned char);
+  SET (external_dnr, idnMax, struct dnr_ext);
+  SET (external_pdr, ipdMax, struct pdr_ext);
+  SET (external_sym, isymMax, struct sym_ext);
+  SET (external_opt, ioptMax, struct opt_ext);
+  SET (external_aux, iauxMax, union aux_ext);
+  SET (ss, issMax, char);
+  SET (ssext, issExtMax, char);
+  SET (external_fdr, ifdMax, struct fdr_ext);
+  SET (external_rfd, crfd, struct rfd_ext);
+  SET (external_ext, iextMax, struct ext_ext);
+#undef SET
+
+  /* Reset the counts so the second pass can use them to know how far
+     it has gotten.  */
+  symhdr->ilineMax = 0;
+  symhdr->cbLine = 0;
+  symhdr->idnMax = 0;
+  symhdr->ipdMax = 0;
+  symhdr->isymMax = 0;
+  symhdr->ioptMax = 0;
+  symhdr->iauxMax = 0;
+  symhdr->issMax = 0;
+  symhdr->issExtMax = 0;
+  symhdr->ifdMax = 0;
+  symhdr->crfd = 0;
+  symhdr->iextMax = 0;
+
+  /* Do the second pass: accumulate the debugging information.  */
+  ecoff_clear_output_flags (abfd);
+  for (ipass = 0; ipass < 2; ipass++)
+    {
+      for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+       {
+         if (((o->flags & SEC_CODE) == 0) != ipass)
+           continue;
+         for (p = o->seclets_head;
+              p != (bfd_seclet_type *) NULL;
+              p = p->next)
+           {
+             if (p->type == bfd_indirect_seclet)
+               {
+                 if (ecoff_get_debug (abfd, p, o) == false)
+                   return false;
+               }
+           }
+       }
+    }
+
+  return true;
+}
+\f
+/* Set the architecture.  The only architecture we support here is
+   mips.  We set the architecture anyhow, since many callers ignore
+   the return value.  */
+
+static boolean
+DEFUN (ecoff_set_arch_mach, (abfd, arch, machine),
+       bfd *abfd AND
+       enum bfd_architecture arch AND
+       unsigned long machine)
+{
+  bfd_default_set_arch_mach (abfd, arch, machine);
+  return arch == bfd_arch_mips;
+}
+
+/* Calculate the file position for each section, and set
+   reloc_filepos.  */
+
+static void
+DEFUN (ecoff_compute_section_file_positions, (abfd),
+       bfd *abfd)
+{
+  asection *current;
+  asection *previous;
+  file_ptr sofar;
+  file_ptr old_sofar;
+
+  sofar = FILHSZ;
+
+  if (bfd_get_start_address (abfd)) 
+    {
+      /* A start address may have been added to the original file. In
+        this case it will need an optional header to record it.  */
+      abfd->flags |= EXEC_P;
+    }
+
+  if (abfd->flags & EXEC_P)
+    sofar += AOUTSZ;
+
+  sofar += abfd->section_count * SCNHSZ;
+
+  previous = (asection *) NULL;
+  for (current = abfd->sections;
+       current != (asection *) NULL;
+       current = current->next)
+    {
+      /* Only deal with sections which have contents */
+      if (! (current->flags & SEC_HAS_CONTENTS))
+       continue;
+
+      /* Align the sections in the file to the same boundary on
+        which they are aligned in virtual memory.  */
+      old_sofar = sofar;
+      sofar = BFD_ALIGN (sofar, 1 << current->alignment_power);
+      if (previous != (asection *) NULL)
+       previous->_raw_size += sofar - old_sofar;
+
+      current->filepos = sofar;
+
+      sofar += current->_raw_size;
+
+      /* make sure that this section is of the right size too */
+      old_sofar = sofar;
+      sofar = BFD_ALIGN (sofar, 1 << current->alignment_power);
+      current->_raw_size += sofar - old_sofar;
+      previous = current;
+    }
+
+  ecoff_data (abfd)->reloc_filepos = sofar;
+}
+
+/* Set the contents of a section.  */
+
+static boolean
+DEFUN (ecoff_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)
+{
+  if (abfd->output_has_begun == false)
+    ecoff_compute_section_file_positions (abfd);
+
+  bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET);
+
+  if (count != 0)
+    return (bfd_write (location, 1, count, abfd) == count) ? true : false;
+
+  return true;
+}
+
+/* Write out an ECOFF file.  */
+
+static boolean
+DEFUN (ecoff_write_object_contents, (abfd),
+       bfd *abfd)
+{
+  asection *current;
+  unsigned int count;
+  file_ptr scn_base;
+  file_ptr reloc_base;
+  file_ptr sym_base;
+  unsigned long reloc_size;
+  unsigned long text_size;
+  unsigned long text_start;
+  unsigned long data_size;
+  unsigned long data_start;
+  unsigned long bss_size;
+  struct internal_filehdr internal_f;
+  struct internal_aouthdr internal_a;
+
+  bfd_error = system_call_error;
+
+  if(abfd->output_has_begun == false)
+    ecoff_compute_section_file_positions(abfd);
+
+  if (abfd->sections != (asection *) NULL)
+    scn_base = abfd->sections->filepos;
+  else
+    scn_base = 0;
+  reloc_base = ecoff_data (abfd)->reloc_filepos;
+
+  count = 1;
+  reloc_size = 0;
+  for (current = abfd->sections;
+       current != (asection *)NULL; 
+       current = current->next) 
+    {
+      current->target_index = count;
+      ++count;
+      if (current->reloc_count != 0)
+       {
+         bfd_size_type relsize;
+
+         current->rel_filepos = reloc_base;
+         relsize = current->reloc_count * RELSZ;
+         reloc_size += relsize;
+         reloc_base += relsize;
+       }
+      else
+       current->rel_filepos = 0;
+    }
+
+  sym_base = reloc_base + reloc_size;
+  ecoff_data (abfd)->sym_filepos = sym_base;
+
+  text_size = 0;
+  text_start = 0;
+  data_size = 0;
+  data_start = 0;
+  bss_size = 0;
+
+  /* Write section headers to the file.  */
+
+  internal_f.f_nscns = 0;
+  if (bfd_seek (abfd,
+               (file_ptr) ((abfd->flags & EXEC_P) ?
+                           (FILHSZ + AOUTSZ) : FILHSZ),
+               SEEK_SET) != 0)
+    return false;
+  for (current = abfd->sections;
+       current != (asection *) NULL;
+       current = current->next)
+    {
+      struct internal_scnhdr section;
+      bfd_vma vma;
+
+      ++internal_f.f_nscns;
+
+      strncpy (section.s_name, current->name, sizeof section.s_name);
+
+      /* FIXME: is this correct for shared libraries?  I think it is
+        but I have no platform to check.  Ian Lance Taylor.  */
+      vma = bfd_get_section_vma (abfd, current);
+      if (strcmp (current->name, _LIB) == 0)
+       section.s_vaddr = 0;
+      else
+       section.s_vaddr = vma;
+
+      section.s_paddr = vma;
+      section.s_size = bfd_get_section_size_before_reloc (current);
+
+      /* If this section has no size or is unloadable then the scnptr
+        will be 0 too.  */
+      if (current->_raw_size == 0
+         || (current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+       section.s_scnptr = 0;
+      else
+       section.s_scnptr = current->filepos;
+      section.s_relptr = current->rel_filepos;
+
+      /* FIXME: the lnnoptr of the .sbss or .sdata section of an
+        object file produced by the assembler is supposed to point to
+        information about how much room is required by objects of
+        various different sizes.  I think this only matters if we
+        want the linker to compute the best size to use, or
+        something.  I don't know what happens if the information is
+        not present.  */
+      section.s_lnnoptr = 0;
+
+      section.s_nreloc = current->reloc_count;
+      section.s_nlnno = 0;
+      section.s_flags = sec_to_styp_flags (current->name, current->flags);
+
+      {
+       SCNHDR buff;
+
+       ecoff_swap_scnhdr_out (abfd, (PTR) &section, (PTR) &buff);
+       if (bfd_write ((PTR) &buff, 1, SCNHSZ, abfd) != SCNHSZ)
+         return false;
+      }
+
+      /* FIXME: These numbers don't add up to what the MIPS tools
+        produce, although I don't think it matters.  */
+      if ((section.s_flags & STYP_TEXT) != 0
+         || (section.s_flags & STYP_RDATA) != 0
+         || (section.s_flags & STYP_LIT8) != 0
+         || (section.s_flags & STYP_LIT4) != 0)
+       {
+         text_size += bfd_get_section_size_before_reloc (current);
+         if (text_start == 0 || text_start > vma)
+           text_start = vma;
+       }
+      else if ((section.s_flags & STYP_DATA) != 0
+              || (section.s_flags & STYP_SDATA) != 0)
+       {
+         data_size += bfd_get_section_size_before_reloc (current);
+         if (data_start == 0 || data_start > vma)
+           data_start = vma;
+       }
+      else if ((section.s_flags & STYP_BSS) != 0
+              || (section.s_flags & STYP_SBSS) != 0)
+       bss_size += bfd_get_section_size_before_reloc (current);
+    }  
+
+  /* Set up the file header.  */
+
+  internal_f.f_magic = MIPS_MAGIC_2;
+
+  /*
+    We will NOT put a fucking timestamp in the header here. Every time you
+    put it back, I will come in and take it out again.  I'm sorry.  This
+    field does not belong here.  We fill it with a 0 so it compares the
+    same but is not a reasonable time. -- gnu@cygnus.com
+    */
+  internal_f.f_timdat = 0;
+
+  internal_f.f_nsyms =  bfd_get_symcount(abfd);
+  if (internal_f.f_nsyms != 0)
+    internal_f.f_symptr = sym_base;
+  else
+    internal_f.f_symptr = 0;
+
+  if (abfd->flags & EXEC_P)
+    internal_f.f_opthdr = AOUTSZ;
+  else
+    internal_f.f_opthdr = 0;
+
+  internal_f.f_flags = 0;
+  if (reloc_size == 0)
+    internal_f.f_flags |= F_RELFLG;
+  if (bfd_get_symcount (abfd) == 0)
+    internal_f.f_flags |= F_LSYMS;
+  if (abfd->flags & EXEC_P)
+    internal_f.f_flags |= F_EXEC;
+
+  if (! abfd->xvec->byteorder_big_p)
+    internal_f.f_flags |= F_AR32WR;
+  else
+    internal_f.f_flags |= F_AR32W;
+
+  /* Set up the optional header.  */
+
+  if ((abfd->flags & EXEC_P) != 0)
+    {
+      internal_a.magic = ZMAGIC;
+
+      /* FIXME: What should this be?  */
+      internal_a.vstamp = 0;
+
+      internal_a.tsize = text_size;
+      internal_a.text_start = text_start;
+      internal_a.dsize = data_size;
+      internal_a.data_start = data_start;
+      internal_a.bsize = bss_size;
+
+      internal_a.entry = bfd_get_start_address (abfd);
+
+      /* FIXME: The MIPS optional header is larger than this....  */
+    }
+
+  /* Write out the file header and the optional header.  */
+
+  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
+    return false;
+
+  {
+    FILHDR buff;
+    ecoff_swap_filehdr_out (abfd, (PTR) &internal_f, (PTR) &buff);
+    if (bfd_write ((PTR) &buff, 1, FILHSZ, abfd) != FILHSZ)
+      return false;
+  }
+
+  if ((abfd->flags & EXEC_P) != 0)
+    {
+      AOUTHDR buff;
+
+      ecoff_swap_aouthdr_out (abfd, (PTR) &internal_a, (PTR) &buff);
+      if (bfd_write ((PTR) &buff, 1, AOUTSZ, abfd) != AOUTSZ)
+       return false;
+    }
+
+  /* Write out the relocs.  */
+
+  /* Write out the symbolic debugging information.  */
+  if (bfd_get_symcount (abfd) > 0)
+    {
+      struct hdr_ext buff;
+
+      ecoff_swap_hdr_out (abfd, &ecoff_data (abfd)->symbolic_header, &buff);
+      if (bfd_write ((PTR) &buff, 1, sizeof buff, abfd) != sizeof buff)
+       return false;
+      if (bfd_write ((PTR) ecoff_data (abfd)->raw_syments, 1,
+                    ecoff_data (abfd)->raw_size, abfd)
+         != ecoff_data (abfd)->raw_size)
+       return false;
+    }
+
+  return true;
+}
+\f
 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 */
@@ -1272,17 +2519,13 @@ static CONST bfd_coff_backend_data bfd_ecoff_std_swap_table = {
 };
 
 /* Routines that need to be written.  */
-#define ecoff_write_object_contents (boolean (*) PARAMS ((bfd *))) bfd_false
-#define ecoff_set_section_contents (boolean (*) PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type))) bfd_false
-#define ecoff_get_reloc_upper_bound (unsigned int (*) PARAMS ((bfd *, sec_ptr))) bfd_0
 #define ecoff_canonicalize_reloc (unsigned int (*) PARAMS ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry **))) bfd_0
-#define ecoff_set_arch_mach (boolean (*) PARAMS ((bfd *, enum bfd_architecture, unsigned long))) bfd_false
-#define ecoff_sizeof_headers (int (*) PARAMS ((bfd *, boolean))) bfd_0
 
 /* get_lineno could be written for ECOFF, but it would currently only
    be useful for linking ECOFF and COFF files together, which doesn't
    seem too likely.  */
-#define ecoff_get_lineno (struct lineno_cache_entry *(*)()) bfd_nullvoidptr
+#define ecoff_get_lineno \
+  ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr)
 
 #define ecoff_core_file_failing_command        _bfd_dummy_core_file_failing_command
 #define ecoff_core_file_failing_signal _bfd_dummy_core_file_failing_signal
@@ -1294,15 +2537,15 @@ static CONST bfd_coff_backend_data bfd_ecoff_std_swap_table = {
 #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_end       bfd_void
 #define ecoff_bfd_debug_info_accumulate        \
-                       (void (*) PARAMS ((bfd *, struct sec *))) bfd_void
+  ((void (*) PARAMS ((bfd *, struct sec *))) bfd_void)
 #define ecoff_bfd_get_relocated_section_contents  bfd_generic_get_relocated_section_contents
 #define ecoff_bfd_relax_section                bfd_generic_relax_section
-#define ecoff_bfd_seclet_link          bfd_generic_seclet_link
 
 bfd_target ecoff_little_vec =
 {
index 4929cff..0a746c1 100644 (file)
@@ -17,12 +17,7 @@ You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
-/* These routines are not yet called from BFD.  They are called from
-   the MIPS symbol reading code in GDB.  However, they are in the BFD
-   library because they will eventually be useful if and when BFD
-   supports reading or writing of MIPS symbol tables.
-
-   The routines in this file convert the external representation of
+/* The routines in this file convert the external representation of
    ECOFF symbol tables to the internal (usual struct) representation.
    On a machine with the same byte-order and the same basic type
    sizes and alignments as a MIPS machine, this is a no-op.  
@@ -37,6 +32,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "coff/symconst.h"     /* MIPS symbols */
 #include "coff/ecoff-ext.h"    /* ECOFF external struct defns */
 
+/* Swap in the symbolic header.  */
+
 void
 DEFUN (ecoff_swap_hdr_in, (abfd, ext_copy, intern),
        bfd *abfd AND
@@ -79,6 +76,50 @@ DEFUN (ecoff_swap_hdr_in, (abfd, ext_copy, intern),
 #endif
 }
 
+/* Swap out the symbolic header.  */
+
+void
+DEFUN (ecoff_swap_hdr_out, (abfd, intern_copy, ext),
+       bfd *abfd AND
+       HDRR *intern_copy AND
+       struct hdr_ext *ext)
+{
+  HDRR intern[1];
+
+  *intern = *intern_copy;
+
+  bfd_h_put_16 (abfd, intern->magic, (bfd_byte *)ext->h_magic);
+  bfd_h_put_16 (abfd, intern->vstamp, (bfd_byte *)ext->h_vstamp);
+  bfd_h_put_32 (abfd, intern->ilineMax, (bfd_byte *)ext->h_ilineMax);
+  bfd_h_put_32 (abfd, intern->cbLine, (bfd_byte *)ext->h_cbLine);
+  bfd_h_put_32 (abfd, intern->cbLineOffset, (bfd_byte *)ext->h_cbLineOffset);
+  bfd_h_put_32 (abfd, intern->idnMax, (bfd_byte *)ext->h_idnMax);
+  bfd_h_put_32 (abfd, intern->cbDnOffset, (bfd_byte *)ext->h_cbDnOffset);
+  bfd_h_put_32 (abfd, intern->ipdMax, (bfd_byte *)ext->h_ipdMax);
+  bfd_h_put_32 (abfd, intern->cbPdOffset, (bfd_byte *)ext->h_cbPdOffset);
+  bfd_h_put_32 (abfd, intern->isymMax, (bfd_byte *)ext->h_isymMax);
+  bfd_h_put_32 (abfd, intern->cbSymOffset, (bfd_byte *)ext->h_cbSymOffset);
+  bfd_h_put_32 (abfd, intern->ioptMax, (bfd_byte *)ext->h_ioptMax);
+  bfd_h_put_32 (abfd, intern->cbOptOffset, (bfd_byte *)ext->h_cbOptOffset);
+  bfd_h_put_32 (abfd, intern->iauxMax, (bfd_byte *)ext->h_iauxMax);
+  bfd_h_put_32 (abfd, intern->cbAuxOffset, (bfd_byte *)ext->h_cbAuxOffset);
+  bfd_h_put_32 (abfd, intern->issMax, (bfd_byte *)ext->h_issMax);
+  bfd_h_put_32 (abfd, intern->cbSsOffset, (bfd_byte *)ext->h_cbSsOffset);
+  bfd_h_put_32 (abfd, intern->issExtMax, (bfd_byte *)ext->h_issExtMax);
+  bfd_h_put_32 (abfd, intern->cbSsExtOffset, (bfd_byte *)ext->h_cbSsExtOffset);
+  bfd_h_put_32 (abfd, intern->ifdMax, (bfd_byte *)ext->h_ifdMax);
+  bfd_h_put_32 (abfd, intern->cbFdOffset, (bfd_byte *)ext->h_cbFdOffset);
+  bfd_h_put_32 (abfd, intern->crfd, (bfd_byte *)ext->h_crfd);
+  bfd_h_put_32 (abfd, intern->cbRfdOffset, (bfd_byte *)ext->h_cbRfdOffset);
+  bfd_h_put_32 (abfd, intern->iextMax, (bfd_byte *)ext->h_iextMax);
+  bfd_h_put_32 (abfd, intern->cbExtOffset, (bfd_byte *)ext->h_cbExtOffset);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
+
 /* Swap in the file descriptor record.  */
 
 void
@@ -138,7 +179,66 @@ DEFUN (ecoff_swap_fdr_in, (abfd, ext_copy, intern),
 #endif
 }
 
+/* Swap out the file descriptor record.  */
+
+void
+DEFUN (ecoff_swap_fdr_out, (abfd, intern_copy, ext),
+       bfd *abfd AND
+       FDR *intern_copy AND
+       struct fdr_ext *ext)
+{
+  FDR intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+  
+  bfd_h_put_32 (abfd, intern->adr, (bfd_byte *)ext->f_adr);
+  bfd_h_put_32 (abfd, intern->rss, (bfd_byte *)ext->f_rss);
+  bfd_h_put_32 (abfd, intern->issBase, (bfd_byte *)ext->f_issBase);
+  bfd_h_put_32 (abfd, intern->cbSs, (bfd_byte *)ext->f_cbSs);
+  bfd_h_put_32 (abfd, intern->isymBase, (bfd_byte *)ext->f_isymBase);
+  bfd_h_put_32 (abfd, intern->csym, (bfd_byte *)ext->f_csym);
+  bfd_h_put_32 (abfd, intern->ilineBase, (bfd_byte *)ext->f_ilineBase);
+  bfd_h_put_32 (abfd, intern->cline, (bfd_byte *)ext->f_cline);
+  bfd_h_put_32 (abfd, intern->ioptBase, (bfd_byte *)ext->f_ioptBase);
+  bfd_h_put_32 (abfd, intern->copt, (bfd_byte *)ext->f_copt);
+  bfd_h_put_16 (abfd, intern->ipdFirst, (bfd_byte *)ext->f_ipdFirst);
+  bfd_h_put_16 (abfd, intern->cpd, (bfd_byte *)ext->f_cpd);
+  bfd_h_put_32 (abfd, intern->iauxBase, (bfd_byte *)ext->f_iauxBase);
+  bfd_h_put_32 (abfd, intern->caux, (bfd_byte *)ext->f_caux);
+  bfd_h_put_32 (abfd, intern->rfdBase, (bfd_byte *)ext->f_rfdBase);
+  bfd_h_put_32 (abfd, intern->crfd, (bfd_byte *)ext->f_crfd);
+
+  /* now the fun stuff... */
+  if (abfd->xvec->header_byteorder_big_p != false) {
+    ext->f_bits1[0] = (((intern->lang << FDR_BITS1_LANG_SH_BIG)
+                       & FDR_BITS1_LANG_BIG)
+                      | (intern->fMerge ? FDR_BITS1_FMERGE_BIG : 0)
+                      | (intern->fReadin ? FDR_BITS1_FREADIN_BIG : 0)
+                      | (intern->fBigendian ? FDR_BITS1_FBIGENDIAN_BIG : 0));
+    ext->f_bits2[0] = ((intern->glevel << FDR_BITS2_GLEVEL_SH_BIG)
+                      & FDR_BITS2_GLEVEL_BIG);
+    ext->f_bits2[1] = 0;
+    ext->f_bits2[2] = 0;
+  } else {
+    ext->f_bits1[0] = (((intern->lang << FDR_BITS1_LANG_SH_LITTLE)
+                       & FDR_BITS1_LANG_LITTLE)
+                      | (intern->fMerge ? FDR_BITS1_FMERGE_LITTLE : 0)
+                      | (intern->fReadin ? FDR_BITS1_FREADIN_LITTLE : 0)
+                      | (intern->fBigendian ? FDR_BITS1_FBIGENDIAN_LITTLE : 0));
+    ext->f_bits2[0] = ((intern->glevel << FDR_BITS2_GLEVEL_SH_LITTLE)
+                      & FDR_BITS2_GLEVEL_LITTLE);
+    ext->f_bits2[1] = 0;
+    ext->f_bits2[2] = 0;
+  }
+
+  bfd_h_put_32 (abfd, intern->cbLineOffset, (bfd_byte *)ext->f_cbLineOffset);
+  bfd_h_put_32 (abfd, intern->cbLine, (bfd_byte *)ext->f_cbLine);
 
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
 
 /* Swap in the procedure descriptor record.  */
 
@@ -173,6 +273,38 @@ DEFUN (ecoff_swap_pdr_in, (abfd, ext_copy, intern),
 #endif
 }
 
+/* Swap out the procedure descriptor record.  */
+
+void
+DEFUN (ecoff_swap_pdr_out, (abfd, intern_copy, ext),
+       bfd *abfd AND
+       PDR *intern_copy AND
+       struct pdr_ext *ext)
+{
+  PDR intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+  
+  bfd_h_put_32 (abfd, intern->adr, (bfd_byte *)ext->p_adr);
+  bfd_h_put_32 (abfd, intern->isym, (bfd_byte *)ext->p_isym);
+  bfd_h_put_32 (abfd, intern->iline, (bfd_byte *)ext->p_iline);
+  bfd_h_put_32 (abfd, intern->regmask, (bfd_byte *)ext->p_regmask);
+  bfd_h_put_32 (abfd, intern->regoffset, (bfd_byte *)ext->p_regoffset);
+  bfd_h_put_32 (abfd, intern->iopt, (bfd_byte *)ext->p_iopt);
+  bfd_h_put_32 (abfd, intern->fregmask, (bfd_byte *)ext->p_fregmask);
+  bfd_h_put_32 (abfd, intern->fregoffset, (bfd_byte *)ext->p_fregoffset);
+  bfd_h_put_32 (abfd, intern->frameoffset, (bfd_byte *)ext->p_frameoffset);
+  bfd_h_put_16 (abfd, intern->framereg, (bfd_byte *)ext->p_framereg);
+  bfd_h_put_16 (abfd, intern->pcreg, (bfd_byte *)ext->p_pcreg);
+  bfd_h_put_32 (abfd, intern->lnLow, (bfd_byte *)ext->p_lnLow);
+  bfd_h_put_32 (abfd, intern->lnHigh, (bfd_byte *)ext->p_lnHigh);
+  bfd_h_put_32 (abfd, intern->cbLineOffset, (bfd_byte *)ext->p_cbLineOffset);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
 
 /* Swap in a symbol record.  */
 
@@ -222,6 +354,53 @@ DEFUN (ecoff_swap_sym_in, (abfd, ext_copy, intern),
 #endif
 }
 
+/* Swap out a symbol record.  */
+
+void
+DEFUN (ecoff_swap_sym_out, (abfd, intern_copy, ext),
+       bfd *abfd AND
+       SYMR *intern_copy AND
+       struct sym_ext *ext)
+{
+  SYMR  intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+  
+  bfd_h_put_32 (abfd, intern->iss, (bfd_byte *)ext->s_iss);
+  bfd_h_put_32 (abfd, intern->value, (bfd_byte *)ext->s_value);
+
+  /* now the fun stuff... */
+  if (abfd->xvec->header_byteorder_big_p != false) {
+    ext->s_bits1[0] = (((intern->st << SYM_BITS1_ST_SH_BIG)
+                       & SYM_BITS1_ST_BIG)
+                      | ((intern->sc >> SYM_BITS1_SC_SH_LEFT_BIG)
+                         & SYM_BITS1_SC_BIG));
+    ext->s_bits2[0] = (((intern->sc << SYM_BITS2_SC_SH_BIG)
+                       & SYM_BITS2_SC_BIG)
+                      | (intern->reserved ? SYM_BITS2_RESERVED_BIG : 0)
+                      | ((intern->index >> SYM_BITS2_INDEX_SH_LEFT_BIG)
+                         & SYM_BITS2_INDEX_BIG));
+    ext->s_bits3[0] = (intern->index >> SYM_BITS3_INDEX_SH_LEFT_BIG) & 0xff;
+    ext->s_bits4[0] = (intern->index >> SYM_BITS4_INDEX_SH_LEFT_BIG) & 0xff;
+  } else {
+    ext->s_bits1[0] = (((intern->st << SYM_BITS1_ST_SH_LITTLE)
+                       & SYM_BITS1_ST_LITTLE)
+                      | ((intern->sc << SYM_BITS1_SC_SH_LITTLE)
+                         & SYM_BITS1_SC_LITTLE));
+    ext->s_bits2[0] = (((intern->sc >> SYM_BITS2_SC_SH_LEFT_LITTLE)
+                       & SYM_BITS2_SC_LITTLE)
+                      | (intern->reserved ? SYM_BITS2_RESERVED_LITTLE : 0)
+                      | ((intern->index << SYM_BITS2_INDEX_SH_LITTLE)
+                         & SYM_BITS2_INDEX_LITTLE));
+    ext->s_bits3[0] = (intern->index >> SYM_BITS3_INDEX_SH_LEFT_LITTLE) & 0xff;
+    ext->s_bits4[0] = (intern->index >> SYM_BITS4_INDEX_SH_LEFT_LITTLE) & 0xff;
+  }
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
 
 /* Swap in an external symbol record.  */
 
@@ -255,6 +434,40 @@ DEFUN (ecoff_swap_ext_in, (abfd, ext_copy, intern),
 #endif
 }
 
+/* Swap out an external symbol record.  */
+
+void
+DEFUN (ecoff_swap_ext_out, (abfd, intern_copy, ext),
+       bfd *abfd AND
+       EXTR *intern_copy AND
+       struct ext_ext *ext)
+{
+  EXTR intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+  
+  /* now the fun stuff... */
+  if (abfd->xvec->header_byteorder_big_p != false) {
+    ext->es_bits1[0] = ((intern->jmptbl ? EXT_BITS1_JMPTBL_BIG : 0)
+                       | (intern->cobol_main ? EXT_BITS1_COBOL_MAIN_BIG : 0)
+                       | (intern->weakext ? EXT_BITS1_WEAKEXT_BIG : 0));
+    ext->es_bits2[0] = 0;
+  } else {
+    ext->es_bits1[0] = ((intern->jmptbl ? EXT_BITS1_JMPTBL_LITTLE : 0)
+                       | (intern->cobol_main ? EXT_BITS1_COBOL_MAIN_LITTLE : 0)
+                       | (intern->weakext ? EXT_BITS1_WEAKEXT_LITTLE : 0));
+    ext->es_bits2[0] = 0;
+  }
+
+  bfd_h_put_16 (abfd, intern->ifd, (bfd_byte *)ext->es_ifd);
+  ecoff_swap_sym_out (abfd, &intern->asym, &ext->es_asym);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
+
 /* Swap in a type information record.
    BIGEND says whether AUX symbols are big-endian or little-endian; this
    info comes from the file header record (fh-fBigendian).  */
@@ -350,6 +563,44 @@ DEFUN (ecoff_swap_rndx_in, (bigend, ext_copy, intern),
 #endif
 }
 
+/* Swap out a relative symbol record.  BIGEND says whether it is in
+   big-endian or little-endian format.*/
+
+void
+DEFUN (ecoff_swap_rndx_out, (bigend, intern_copy, ext),
+       int bigend AND
+       RNDXR *intern_copy AND
+       struct rndx_ext *ext)
+{
+  RNDXR intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+  
+  /* now the fun stuff... */
+  if (bigend) {
+    ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG;
+    ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG)
+                      & RNDX_BITS1_RFD_BIG)
+                     | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG)
+                        & RNDX_BITS1_INDEX_BIG));
+    ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG;
+    ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG;
+  } else {
+    ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE;
+    ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE)
+                      & RNDX_BITS1_RFD_LITTLE)
+                     | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE)
+                        & RNDX_BITS1_INDEX_LITTLE));
+    ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE;
+    ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE;
+  }
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
+
 /* Swap in a relative file descriptor.  */
 
 void
@@ -366,3 +617,137 @@ DEFUN (ecoff_swap_rfd_in, (abfd, ext, intern),
     abort();
 #endif
 }
+
+/* Swap out a relative file descriptor.  */
+
+void
+DEFUN (ecoff_swap_rfd_out, (abfd, intern, ext),
+       bfd *abfd AND
+       RFDT *intern AND
+       struct rfd_ext *ext)
+{
+  bfd_h_put_32 (abfd, *intern, (bfd_byte *)ext->rfd);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
+
+/* Swap in an optimization symbol.  */
+
+void
+DEFUN (ecoff_swap_opt_in, (abfd, ext_copy, intern),
+       bfd *abfd AND
+       struct opt_ext *ext_copy AND
+       OPTR *intern)
+{
+  struct opt_ext ext[1];
+
+  *ext = *ext_copy;            /* Make it reasonable to do in-place.  */
+
+  if (abfd->xvec->header_byteorder_big_p != false)
+    {
+      intern->ot = ext->o_bits1[0];
+      intern->value = ((ext->o_bits2[0] << OPT_BITS2_VALUE_SH_LEFT_BIG)
+                      | (ext->o_bits3[0] << OPT_BITS2_VALUE_SH_LEFT_BIG)
+                      | (ext->o_bits4[0] << OPT_BITS2_VALUE_SH_LEFT_BIG));
+    }
+  else
+    {
+      intern->ot = ext->o_bits1[0];
+      intern->value = ((ext->o_bits2[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE)
+                      | (ext->o_bits3[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE)
+                      | (ext->o_bits4[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE));
+    }
+
+  ecoff_swap_rndx_in (abfd->xvec->header_byteorder_big_p != false,
+                     &ext->o_rndx, &intern->rndx);
+
+  intern->offset = bfd_h_get_32 (abfd, (bfd_byte *) ext->o_offset);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
+
+/* Swap out an optimization symbol.  */
+
+void
+DEFUN (ecoff_swap_opt_out, (abfd, intern_copy, ext),
+       bfd *abfd AND
+       OPTR *intern_copy AND
+       struct opt_ext *ext)
+{
+  OPTR intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+
+  if (abfd->xvec->header_byteorder_big_p != false)
+    {
+      ext->o_bits1[0] = intern->ot;
+      ext->o_bits2[0] = intern->value >> OPT_BITS2_VALUE_SH_LEFT_BIG;
+      ext->o_bits3[0] = intern->value >> OPT_BITS3_VALUE_SH_LEFT_BIG;
+      ext->o_bits4[0] = intern->value >> OPT_BITS4_VALUE_SH_LEFT_BIG;
+    }
+  else
+    {
+      ext->o_bits1[0] = intern->ot;
+      ext->o_bits2[0] = intern->value >> OPT_BITS2_VALUE_SH_LEFT_LITTLE;
+      ext->o_bits3[0] = intern->value >> OPT_BITS3_VALUE_SH_LEFT_LITTLE;
+      ext->o_bits4[0] = intern->value >> OPT_BITS4_VALUE_SH_LEFT_LITTLE;
+    }
+
+  ecoff_swap_rndx_out (abfd->xvec->header_byteorder_big_p != false,
+                      &intern->rndx, &ext->o_rndx);
+
+  bfd_h_put_32 (abfd, intern->value, (bfd_byte *) ext->o_offset);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
+
+/* Swap in a dense number.  */
+
+void
+DEFUN (ecoff_swap_dnr_in, (abfd, ext_copy, intern),
+       bfd *abfd AND
+       struct dnr_ext *ext_copy AND
+       DNR *intern)
+{
+  struct dnr_ext ext[1];
+
+  *ext = *ext_copy;            /* Make it reasonable to do in-place.  */
+
+  intern->rfd = bfd_h_get_32 (abfd, (bfd_byte *) ext->d_rfd);
+  intern->index = bfd_h_get_32 (abfd, (bfd_byte *) ext->d_index);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
+
+/* Swap out a dense number.  */
+
+void
+DEFUN (ecoff_swap_dnr_out, (abfd, intern_copy, ext),
+       bfd *abfd AND
+       DNR *intern_copy AND
+       struct dnr_ext *ext)
+{
+  DNR intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+
+  bfd_h_put_32 (abfd, intern->rfd, (bfd_byte *) ext->d_rfd);
+  bfd_h_put_32 (abfd, intern->index, (bfd_byte *) ext->d_index);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}