* ecoff.c (ecoff_find_nearest_line): Handle fdr.adr != pdr.adr
[binutils-gdb.git] / bfd / ecoff.c
index c99d72453d64d7edf6f6833b3cbd5aab19ee40d1..83a3c22d89c602ed10bcf82c30b0e18d35344af1 100644 (file)
@@ -49,11 +49,12 @@ static boolean ecoff_slurp_symbolic_header PARAMS ((bfd *abfd));
 static boolean ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym,
                                           asymbol *asym, int ext,
                                           asymbol **indirect_ptr_ptr));
-static void ecoff_emit_aggregate PARAMS ((bfd *abfd, char *string,
+static void ecoff_emit_aggregate PARAMS ((bfd *abfd, FDR *fdr,
+                                         char *string,
                                          RNDXR *rndx, long isym,
-                                         CONST char *which));
-static char *ecoff_type_to_string PARAMS ((bfd *abfd, union aux_ext *aux_ptr,
-                                          unsigned int indx, int bigendian));
+                                         const char *which));
+static char *ecoff_type_to_string PARAMS ((bfd *abfd, FDR *fdr,
+                                          unsigned int indx));
 static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section,
                                                asymbol **symbols));
 static void ecoff_compute_section_file_positions PARAMS ((bfd *abfd));
@@ -98,7 +99,6 @@ ecoff_mkobject_hook (abfd, filehdr, aouthdr)
   struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
   struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr;
   ecoff_data_type *ecoff;
-  asection *regsec;
 
   if (ecoff_mkobject (abfd) == false)
     return NULL;
@@ -107,13 +107,6 @@ ecoff_mkobject_hook (abfd, filehdr, aouthdr)
   ecoff->gp_size = 8;
   ecoff->sym_filepos = internal_f->f_symptr;
 
-  /* Create the .reginfo section to give programs outside BFD a way to
-     see the information stored in the a.out header.  See the comment
-     in coff/ecoff.h.  */
-  regsec = bfd_make_section (abfd, REGINFO);
-  if (regsec == NULL)
-    return NULL;
-
   if (internal_a != (struct internal_aouthdr *) NULL)
     {
       int i;
@@ -178,14 +171,10 @@ ecoff_new_section_hook (abfd, section)
   else if (strcmp (section->name, _BSS) == 0
           || strcmp (section->name, _SBSS) == 0)
     section->flags |= SEC_ALLOC;
-  else if (strcmp (section->name, REGINFO) == 0)
+  else if (strcmp (section->name, _LIB) == 0)
     {
-      /* Setting SEC_SHARED_LIBRARY should make the linker leave the
-        section completely alone.  */
-      section->flags |= (SEC_SHARED_LIBRARY
-                        | SEC_HAS_CONTENTS
-                        | SEC_NEVER_LOAD);
-      section->_raw_size = sizeof (struct ecoff_reginfo);
+      /* An Irix 4 shared libary.  */
+      section->flags |= SEC_COFF_SHARED_LIBRARY;
     }
 
   /* Probably any other section name is SEC_NEVER_LOAD, but I'm
@@ -326,6 +315,8 @@ ecoff_sec_to_styp_flags (name, flags)
     styp = STYP_PDATA;
   else if (strcmp (name, _XDATA) == 0)
     styp = STYP_XDATA;
+  else if (strcmp (name, _LIB) == 0)
+    styp = STYP_ECOFF_LIB;
   else if (flags & SEC_CODE) 
     styp = STYP_TEXT;
   else if (flags & SEC_DATA) 
@@ -365,19 +356,22 @@ ecoff_styp_to_sec_flags (abfd, hdr)
       || (styp_flags & STYP_ECOFF_FINI))
     {
       if (sec_flags & SEC_NEVER_LOAD)
-       sec_flags |= SEC_CODE | SEC_SHARED_LIBRARY;
+       sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY;
       else
        sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
     }
   else if ((styp_flags & STYP_DATA)
           || (styp_flags & STYP_RDATA)
-          || (styp_flags & STYP_SDATA))
+          || (styp_flags & STYP_SDATA)
+          || styp_flags == STYP_PDATA
+          || styp_flags == STYP_XDATA)
     {
       if (sec_flags & SEC_NEVER_LOAD)
-       sec_flags |= SEC_DATA | SEC_SHARED_LIBRARY;
+       sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY;
       else
        sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
-      if (styp_flags & STYP_RDATA)
+      if ((styp_flags & STYP_RDATA)
+         || styp_flags == STYP_PDATA)
        sec_flags |= SEC_READONLY;
     }
   else if ((styp_flags & STYP_BSS)
@@ -385,7 +379,7 @@ ecoff_styp_to_sec_flags (abfd, hdr)
     {
       sec_flags |= SEC_ALLOC;
     }
-  else if (styp_flags & STYP_INFO) 
+  else if ((styp_flags & STYP_INFO) || styp_flags == STYP_COMMENT)
     {
       sec_flags |= SEC_NEVER_LOAD;
     }
@@ -395,6 +389,10 @@ ecoff_styp_to_sec_flags (abfd, hdr)
     {
       sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
     }
+  else if (styp_flags & STYP_ECOFF_LIB)
+    {
+      sec_flags |= SEC_COFF_SHARED_LIBRARY;
+    }
   else
     {
       sec_flags |= SEC_ALLOC | SEC_LOAD;
@@ -550,7 +548,8 @@ ecoff_swap_rndx_in (bigend, ext_copy, intern)
     intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE)
                                    >> RNDX_BITS1_INDEX_SH_LITTLE)
                  | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE)
-                 | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_LITTLE);
+                 | ((unsigned int) ext->r_bits[3]
+                    << RNDX_BITS3_INDEX_SH_LEFT_LITTLE);
   }
 
 #ifdef TEST
@@ -605,7 +604,7 @@ ecoff_slurp_symbolic_header (abfd)
 {
   const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
   bfd_size_type external_hdr_size;
-  PTR raw;
+  PTR raw = NULL;
   HDRR *internal_symhdr;
 
   /* See if we've already read it in.  */
@@ -632,28 +631,37 @@ ecoff_slurp_symbolic_header (abfd)
     }
 
   /* Read the symbolic information header.  */
-  raw = (PTR) alloca ((size_t) external_hdr_size);
+  raw = (PTR) malloc ((size_t) external_hdr_size);
+  if (raw == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
+
   if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1
       || (bfd_read (raw, external_hdr_size, 1, abfd)
          != external_hdr_size))
-    {
-      bfd_set_error (bfd_error_system_call);
-      return false;
-    }
+    goto error_return;
   internal_symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
   (*backend->debug_swap.swap_hdr_in) (abfd, raw, internal_symhdr);
 
   if (internal_symhdr->magic != backend->debug_swap.sym_magic)
     {
       bfd_set_error (bfd_error_bad_value);
-      return false;
+      goto error_return;
     }
 
   /* Now we can get the correct number of symbols.  */
   bfd_get_symcount (abfd) = (internal_symhdr->isymMax
                             + internal_symhdr->iextMax);
 
+  if (raw != NULL)
+    free (raw);
   return true;
+ error_return:
+  if (raw != NULL)
+    free (raw);
+  return false;
 }
 
 /* Read in and swap the important symbolic information for an ECOFF
@@ -739,7 +747,6 @@ ecoff_slurp_symbolic_info (abfd)
                SEEK_SET) != 0
       || bfd_read (raw, raw_size, 1, abfd) != raw_size)
     {
-      bfd_set_error (bfd_error_system_call);
       bfd_release (abfd, raw);
       return false;
     }
@@ -820,7 +827,7 @@ ecoff_make_empty_symbol (abfd)
       bfd_set_error (bfd_error_no_memory);
       return (asymbol *) NULL;
     }
-  memset (new, 0, sizeof *new);
+  memset ((PTR) new, 0, sizeof *new);
   new->symbol.section = (asection *) NULL;
   new->fdr = (FDR *) NULL;
   new->local = false;
@@ -1200,12 +1207,14 @@ ecoff_slurp_symbol_table (abfd)
 
 /* Return the amount of space needed for the canonical symbols.  */
 
-unsigned int
+long
 ecoff_get_symtab_upper_bound (abfd)
      bfd *abfd;
 {
-  if (ecoff_slurp_symbolic_info (abfd) == false
-      || bfd_get_symcount (abfd) == 0)
+  if (! ecoff_slurp_symbolic_info (abfd))
+    return -1;
+
+  if (bfd_get_symcount (abfd) == 0)
     return 0;
 
   return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *));
@@ -1213,7 +1222,7 @@ ecoff_get_symtab_upper_bound (abfd)
 
 /* Get the canonical symbols.  */
 
-unsigned int
+long
 ecoff_get_symtab (abfd, alocation)
      bfd *abfd;
      asymbol **alocation;
@@ -1222,8 +1231,9 @@ ecoff_get_symtab (abfd, alocation)
   ecoff_symbol_type *symbase;
   ecoff_symbol_type **location = (ecoff_symbol_type **) alocation;
 
-  if (ecoff_slurp_symbol_table (abfd) == false
-      || bfd_get_symcount (abfd) == 0)
+  if (ecoff_slurp_symbol_table (abfd) == false)
+    return -1;
+  if (bfd_get_symcount (abfd) == 0)
     return 0;
 
   symbase = ecoff_data (abfd)->canonical_symbols;
@@ -1243,57 +1253,76 @@ ecoff_get_symtab (abfd, alocation)
 /* Write aggregate information to a string.  */
 
 static void
-ecoff_emit_aggregate (abfd, string, rndx, isym, which)
+ecoff_emit_aggregate (abfd, fdr, string, rndx, isym, which)
      bfd *abfd;
+     FDR *fdr;
      char *string;
      RNDXR *rndx;
      long isym;
-     CONST char *which;
+     const char *which;
 {
-  int ifd = rndx->rfd;
-  int indx = rndx->index;
-  int sym_base, ss_base;
-  CONST char *name;
+  const struct ecoff_debug_swap * const debug_swap =
+    &ecoff_backend (abfd)->debug_swap;
+  struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info;
+  unsigned int ifd = rndx->rfd;
+  unsigned int indx = rndx->index;
+  const char *name;
   
   if (ifd == 0xfff)
     ifd = isym;
 
-  sym_base = ecoff_data (abfd)->debug_info.fdr[ifd].isymBase;
-  ss_base  = ecoff_data (abfd)->debug_info.fdr[ifd].issBase;
-  
-  if (indx == indexNil)
-    name = "/* no name */";
+  /* An ifd of -1 is an opaque type.  An escaped index of 0 is a
+     struct return type of a procedure compiled without -g.  */
+  if (ifd == 0xffffffff
+      || (rndx->rfd == 0xfff && indx == 0))
+    name = "<undefined>";
+  else if (indx == indexNil)
+    name = "<no name>";
   else
     {
-      const struct ecoff_debug_swap * const debug_swap
-       = &ecoff_backend (abfd)->debug_swap;
       SYMR sym;
 
-      indx += sym_base;
-      (*debug_swap->swap_sym_in)
-       (abfd,
-        ((char *) ecoff_data (abfd)->debug_info.external_sym
-         + indx * debug_swap->external_sym_size),
-        &sym);
-      name = ecoff_data (abfd)->debug_info.ss + ss_base + sym.iss;
+      if (debug_info->external_rfd == NULL)
+       fdr = debug_info->fdr + ifd;
+      else
+       {
+         RFDT rfd;
+
+         (*debug_swap->swap_rfd_in) (abfd,
+                                     ((char *) debug_info->external_rfd
+                                      + ((fdr->rfdBase + ifd)
+                                         * debug_swap->external_rfd_size)),
+                                     &rfd);
+         fdr = debug_info->fdr + rfd;
+       }
+
+      indx += fdr->isymBase;
+
+      (*debug_swap->swap_sym_in) (abfd,
+                                 ((char *) debug_info->external_sym
+                                  + indx * debug_swap->external_sym_size),
+                                 &sym);
+
+      name = debug_info->ss + fdr->issBase + sym.iss;
     }
 
   sprintf (string,
-          "%s %s { ifd = %d, index = %ld }",
+          "%s %s { ifd = %u, index = %lu }",
           which, name, ifd,
           ((long) indx
-           + ecoff_data (abfd)->debug_info.symbolic_header.iextMax));
+           + debug_info->symbolic_header.iextMax));
 }
 
 /* Convert the type information to string format.  */
 
 static char *
-ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
+ecoff_type_to_string (abfd, fdr, indx)
      bfd *abfd;
-     union aux_ext *aux_ptr;
+     FDR *fdr;
      unsigned int indx;
-     int bigendian;
 {
+  union aux_ext *aux_ptr;
+  int bigendian;
   AUXU u;
   struct qual {
     unsigned int  type;
@@ -1301,7 +1330,6 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
     int  high_bound;
     int  stride;
   } qualifiers[7];
-
   unsigned int basic_type;
   int i;
   static char buffer1[1024];
@@ -1310,6 +1338,9 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
   char *p2 = buffer2;
   RNDXR rndx;
 
+  aux_ptr = ecoff_data (abfd)->debug_info.external_aux + fdr->iauxBase;
+  bigendian = fdr->fBigendian;
+
   for (i = 0; i < 7; i++)
     {
       qualifiers[i].low_bound = 0;
@@ -1389,7 +1420,7 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
 
     case btStruct:             /* Structure (Record) */
       ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
-      ecoff_emit_aggregate (abfd, p1, &rndx,
+      ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
                            (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
                            "struct");
       indx++;                  /* skip aux words */
@@ -1401,7 +1432,7 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
 
     case btUnion:              /* Union */
       ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
-      ecoff_emit_aggregate (abfd, p1, &rndx,
+      ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
                            (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
                            "union");
       indx++;                  /* skip aux words */
@@ -1413,7 +1444,7 @@ ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
 
     case btEnum:               /* Enumeration */
       ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
-      ecoff_emit_aggregate (abfd, p1, &rndx,
+      ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
                            (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
                            "enum");
       indx++;                  /* skip aux words */
@@ -1694,17 +1725,19 @@ ecoff_print_symbol (abfd, filep, symbol, how)
        if (ecoffsymbol (symbol)->fdr != NULL
            && ecoff_ext.asym.index != indexNil)
          {
+           FDR *fdr;
            unsigned int indx;
            int bigendian;
            bfd_size_type sym_base;
            union aux_ext *aux_base;
 
+           fdr = ecoffsymbol (symbol)->fdr;
            indx = ecoff_ext.asym.index;
 
            /* sym_base is used to map the fdr relative indices which
               appear in the file to the position number which we are
               using.  */
-           sym_base = ecoffsymbol (symbol)->fdr->isymBase;
+           sym_base = fdr->isymBase;
            if (ecoffsymbol (symbol)->local)
              sym_base +=
                ecoff_data (abfd)->debug_info.symbolic_header.iextMax;
@@ -1712,11 +1745,11 @@ ecoff_print_symbol (abfd, filep, symbol, how)
            /* aux_base is the start of the aux entries for this file;
               asym.index is an offset from this.  */
            aux_base = (ecoff_data (abfd)->debug_info.external_aux
-                       + ecoffsymbol (symbol)->fdr->iauxBase);
+                       + fdr->iauxBase);
 
            /* The aux entries are stored in host byte order; the
               order is indicated by a bit in the fdr.  */
-           bigendian = ecoffsymbol (symbol)->fdr->fBigendian;
+           bigendian = fdr->fBigendian;
 
            /* This switch is basically from gcc/mips-tdump.c  */
            switch (ecoff_ext.asym.st)
@@ -1738,9 +1771,10 @@ ecoff_print_symbol (abfd, filep, symbol, how)
                           (long) (indx + sym_base));
                else
                  fprintf (file, "\n      First symbol: %ld", 
-                          (long) (AUX_GET_ISYM (bigendian,
-                                                &aux_base[ecoff_ext.asym.index])
-                                  + sym_base));
+                          ((long)
+                           (AUX_GET_ISYM (bigendian,
+                                          &aux_base[ecoff_ext.asym.index])
+                            + sym_base)));
                break;
 
              case stProc:
@@ -1749,11 +1783,11 @@ ecoff_print_symbol (abfd, filep, symbol, how)
                  ;
                else if (ecoffsymbol (symbol)->local)
                  fprintf (file, "\n      End+1 symbol: %-7ld   Type:  %s",
-                          (long) (AUX_GET_ISYM (bigendian,
-                                                &aux_base[ecoff_ext.asym.index])
-                                  + sym_base),
-                          ecoff_type_to_string (abfd, aux_base, indx + 1,
-                                                bigendian));
+                          ((long)
+                           (AUX_GET_ISYM (bigendian,
+                                          &aux_base[ecoff_ext.asym.index])
+                            + sym_base)),
+                          ecoff_type_to_string (abfd, fdr, indx + 1));
                else
                  fprintf (file, "\n      Local symbol: %ld",
                           ((long) indx
@@ -1762,11 +1796,25 @@ ecoff_print_symbol (abfd, filep, symbol, how)
                               ->debug_info.symbolic_header.iextMax)));
                break;
 
+             case stStruct:
+               fprintf (file, "\n      struct; End+1 symbol: %ld",
+                        (long) (indx + sym_base));
+               break;
+
+             case stUnion:
+               fprintf (file, "\n      union; End+1 symbol: %ld",
+                        (long) (indx + sym_base));
+               break;
+
+             case stEnum:
+               fprintf (file, "\n      enum; End+1 symbol: %ld",
+                        (long) (indx + sym_base));
+               break;
+
              default:
                if (! ECOFF_IS_STAB (&ecoff_ext.asym))
                  fprintf (file, "\n      Type: %s",
-                          ecoff_type_to_string (abfd, aux_base, indx,
-                                                bigendian));
+                          ecoff_type_to_string (abfd, fdr, indx));
                break;
              }
          }
@@ -1815,10 +1863,7 @@ ecoff_slurp_reloc_table (abfd, section, symbols)
     return false;
   if (bfd_read (external_relocs, 1, external_relocs_size, abfd)
       != external_relocs_size)
-    {
-      bfd_set_error (bfd_error_system_call);
-      return false;
-    }
+    return false;
 
   for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++)
     {
@@ -1892,7 +1937,7 @@ ecoff_slurp_reloc_table (abfd, section, symbols)
 
 /* Get a canonical list of relocs.  */
 
-unsigned int
+long
 ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
      bfd *abfd;
      asection *section;
@@ -1918,11 +1963,9 @@ ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
       arelent *tblptr;
 
       if (ecoff_slurp_reloc_table (abfd, section, symbols) == false)
-       return 0;
+       return -1;
 
       tblptr = section->relocation;
-      if (tblptr == (arelent *) NULL)
-       return 0;
 
       for (count = 0; count < section->reloc_count; count++)
        *relptr++ = tblptr++;
@@ -1964,6 +2007,7 @@ ecoff_find_nearest_line (abfd,
   char *pdr_ptr;
   char *pdr_end;
   PDR pdr;
+  bfd_vma first_off;
   unsigned char *line_ptr;
   unsigned char *line_end;
   int lineno;
@@ -2009,10 +2053,12 @@ ecoff_find_nearest_line (abfd,
             + fdr_ptr->ipdFirst * external_pdr_size);
   pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
   (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+  if (offset < pdr.adr)
+    return false;
 
   /* The address of the first PDR is an offset which applies to the
      addresses of all the PDR's.  */
-  offset += pdr.adr;
+  first_off = pdr.adr;
 
   for (pdr_ptr += external_pdr_size;
        pdr_ptr < pdr_end;
@@ -2037,7 +2083,7 @@ ecoff_find_nearest_line (abfd,
   pdr_ptr -= external_pdr_size;
   (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
 
-  offset -= pdr.adr;
+  offset -= pdr.adr - first_off;
   lineno = pdr.lnLow;
   line_ptr = (ecoff_data (abfd)->debug_info.line
              + fdr_ptr->cbLineOffset
@@ -2107,6 +2153,121 @@ ecoff_find_nearest_line (abfd,
   return true;
 }
 \f
+/* Copy private BFD data.  This is called by objcopy and strip.  We
+   use it to copy the ECOFF debugging information from one BFD to the
+   other.  It would be theoretically possible to represent the ECOFF
+   debugging information in the symbol table.  However, it would be a
+   lot of work, and there would be little gain (gas, gdb, and ld
+   already access the ECOFF debugging information via the
+   ecoff_debug_info structure, and that structure would have to be
+   retained in order to support ECOFF debugging in MIPS ELF).
+
+   The debugging information for the ECOFF external symbols comes from
+   the symbol table, so this function only handles the other debugging
+   information.  */
+
+boolean
+ecoff_bfd_copy_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  struct ecoff_debug_info *iinfo = &ecoff_data (ibfd)->debug_info;
+  struct ecoff_debug_info *oinfo = &ecoff_data (obfd)->debug_info;
+  register int i;
+  asymbol **sym_ptr_ptr;
+  size_t c;
+  boolean local;
+
+  BFD_ASSERT (ibfd->xvec == obfd->xvec);
+
+  /* Copy the GP value and the register masks.  */
+  ecoff_data (obfd)->gp = ecoff_data (ibfd)->gp;
+  ecoff_data (obfd)->gprmask = ecoff_data (ibfd)->gprmask;
+  ecoff_data (obfd)->fprmask = ecoff_data (ibfd)->fprmask;
+  for (i = 0; i < 3; i++)
+    ecoff_data (obfd)->cprmask[i] = ecoff_data (ibfd)->cprmask[i];
+
+  /* Copy the version stamp.  */
+  oinfo->symbolic_header.vstamp = iinfo->symbolic_header.vstamp;
+
+  /* If there are no symbols, don't copy any debugging information.  */
+  c = bfd_get_symcount (obfd);
+  sym_ptr_ptr = bfd_get_outsymbols (obfd);
+  if (c == 0 || sym_ptr_ptr == (asymbol **) NULL)
+    return true;
+
+  /* See if there are any local symbols.  */
+  local = false;
+  for (; c > 0; c--, sym_ptr_ptr++)
+    {
+      if (ecoffsymbol (*sym_ptr_ptr)->local)
+       {
+         local = true;
+         break;
+       }
+    }
+
+  if (local)
+    {
+      /* There are some local symbols.  We just bring over all the
+        debugging information.  FIXME: This is not quite the right
+        thing to do.  If the user has asked us to discard all
+        debugging information, then we are probably going to wind up
+        keeping it because there will probably be some local symbol
+        which objcopy did not discard.  We should actually break
+        apart the debugging information and only keep that which
+        applies to the symbols we want to keep.  */
+      oinfo->symbolic_header.ilineMax = iinfo->symbolic_header.ilineMax;
+      oinfo->symbolic_header.cbLine = iinfo->symbolic_header.cbLine;
+      oinfo->line = iinfo->line;
+
+      oinfo->symbolic_header.idnMax = iinfo->symbolic_header.idnMax;
+      oinfo->external_dnr = iinfo->external_dnr;
+
+      oinfo->symbolic_header.ipdMax = iinfo->symbolic_header.ipdMax;
+      oinfo->external_pdr = iinfo->external_pdr;
+
+      oinfo->symbolic_header.isymMax = iinfo->symbolic_header.isymMax;
+      oinfo->external_sym = iinfo->external_sym;
+
+      oinfo->symbolic_header.ioptMax = iinfo->symbolic_header.ioptMax;
+      oinfo->external_opt = iinfo->external_opt;
+
+      oinfo->symbolic_header.iauxMax = iinfo->symbolic_header.iauxMax;
+      oinfo->external_aux = iinfo->external_aux;
+
+      oinfo->symbolic_header.issMax = iinfo->symbolic_header.issMax;
+      oinfo->ss = iinfo->ss;
+
+      oinfo->symbolic_header.ifdMax = iinfo->symbolic_header.ifdMax;
+      oinfo->external_fdr = iinfo->external_fdr;
+
+      oinfo->symbolic_header.crfd = iinfo->symbolic_header.crfd;
+      oinfo->external_rfd = iinfo->external_rfd;
+    }
+  else
+    {
+      /* We are discarding all the local symbol information.  Look
+        through the external symbols and remove all references to FDR
+        or aux information.  */
+      c = bfd_get_symcount (obfd);
+      sym_ptr_ptr = bfd_get_outsymbols (obfd);
+      for (; c > 0; c--, sym_ptr_ptr++)
+       {
+         EXTR esym;
+
+         (*(ecoff_backend (obfd)->debug_swap.swap_ext_in))
+           (obfd, ecoffsymbol (*sym_ptr_ptr)->native, &esym);
+         esym.ifd = ifdNil;
+         esym.asym.index = indexNil;
+         (*(ecoff_backend (obfd)->debug_swap.swap_ext_out))
+           (obfd, &esym, ecoffsymbol (*sym_ptr_ptr)->native);
+       }
+    }
+
+  return true;
+}
+\f
 /* Set the architecture.  The supported architecture is stored in the
    backend pointer.  We always set the architecture anyhow, since many
    callers ignore the return value.  */
@@ -2121,8 +2282,7 @@ ecoff_set_arch_mach (abfd, arch, machine)
   return arch == ecoff_backend (abfd)->arch;
 }
 
-/* Get the size of the section headers.  We do not output the .reginfo
-   section.  */
+/* Get the size of the section headers.  */
 
 /*ARGSUSED*/
 int
@@ -2132,13 +2292,13 @@ ecoff_sizeof_headers (abfd, reloc)
 {
   asection *current;
   int c;
+  int ret;
 
   c = 0;
   for (current = abfd->sections;
        current != (asection *)NULL; 
        current = current->next) 
-    if (strcmp (current->name, REGINFO) != 0)
-      ++c;
+    ++c;
 
   ret = (bfd_coff_filhsz (abfd)
         + bfd_coff_aoutsz (abfd)
@@ -2146,9 +2306,7 @@ ecoff_sizeof_headers (abfd, reloc)
   return BFD_ALIGN (ret, 16);
 }
 
-/* Get the contents of a section.  This is where we handle reading the
-   .reginfo section, which implicitly holds the contents of an
-   ecoff_reginfo structure.  */
+/* Get the contents of a section.  */
 
 boolean
 ecoff_get_section_contents (abfd, section, location, offset, count)
@@ -2158,26 +2316,8 @@ ecoff_get_section_contents (abfd, section, location, offset, count)
      file_ptr offset;
      bfd_size_type count;
 {
-  ecoff_data_type *tdata = ecoff_data (abfd);
-  struct ecoff_reginfo s;
-  int i;
-
-  if (strcmp (section->name, REGINFO) != 0)
-    return bfd_generic_get_section_contents (abfd, section, location,
-                                            offset, count);
-
-  s.gp_value = tdata->gp;
-  s.gprmask = tdata->gprmask;
-  for (i = 0; i < 4; i++)
-    s.cprmask[i] = tdata->cprmask[i];
-  s.fprmask = tdata->fprmask;
-
-  /* bfd_get_section_contents has already checked that the offset and
-     size is reasonable.  We don't have to worry about swapping or any
-     such thing; the .reginfo section is defined such that the
-     contents are an ecoff_reginfo structure as seen on the host.  */
-  memcpy (location, ((char *) &s) + offset, (size_t) count);
-  return true;
+  return _bfd_generic_get_section_contents (abfd, section, location,
+                                           offset, count);
 }
 
 /* Calculate the file position for each section, and set
@@ -2202,8 +2342,7 @@ ecoff_compute_section_file_positions (abfd)
       unsigned int alignment_power;
 
       /* Only deal with sections which have contents */
-      if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) == 0
-         || strcmp (current->name, REGINFO) == 0)
+      if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) == 0)
        continue;
 
       /* For the Alpha ECOFF .pdata section the lnnoptr field is
@@ -2237,6 +2376,15 @@ ecoff_compute_section_file_positions (abfd)
          sofar = (sofar + round - 1) &~ (round - 1);
          first_data = false;
        }
+      else if (strcmp (current->name, _LIB) == 0)
+       {
+         const bfd_vma round = ecoff_backend (abfd)->round;
+         /* On Irix 4, the location of contents of the .lib section
+            from a shared library section is also rounded up to a
+            page boundary.  */
+
+         sofar = (sofar + round - 1) &~ (round - 1);
+       }
 
       /* Align the sections in the file to the same boundary on
         which they are aligned in virtual memory.  */
@@ -2284,8 +2432,6 @@ ecoff_compute_reloc_file_positions (abfd)
        current != (asection *)NULL; 
        current = current->next) 
     {
-      if (strcmp (current->name, REGINFO) == 0)
-       continue;
       if (current->reloc_count == 0)
        current->rel_filepos = 0;
       else
@@ -2314,9 +2460,7 @@ ecoff_compute_reloc_file_positions (abfd)
   return reloc_size;
 }
 
-/* Set the contents of a section.  This is where we handle setting the
-   contents of the .reginfo section, which implicitly holds a
-   ecoff_reginfo structure.  */
+/* Set the contents of a section.  */
 
 boolean
 ecoff_set_section_contents (abfd, section, location, offset, count)
@@ -2331,45 +2475,88 @@ ecoff_set_section_contents (abfd, section, location, offset, count)
   if (abfd->output_has_begun == false)
     ecoff_compute_section_file_positions (abfd);
 
+  /* If this is a .lib section, bump the vma address so that it winds
+     up being the number of .lib sections output.  This is right for
+     Irix 4.  Ian Taylor <ian@cygnus.com>.  */
+  if (strcmp (section->name, _LIB) == 0)
+    ++section->vma;
+
   if (count == 0)
     return true;
 
-  if (strcmp (section->name, REGINFO) == 0)
+  if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0
+      || bfd_write (location, 1, count, abfd) != count)
+    return false;
+
+  return true;
+}
+
+/* Get the GP value for an ECOFF file.  This is a hook used by
+   nlmconv.  */
+
+bfd_vma
+bfd_ecoff_get_gp_value (abfd)
+     bfd *abfd;
+{
+  if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour
+      || bfd_get_format (abfd) != bfd_object)
     {
-      ecoff_data_type *tdata = ecoff_data (abfd);
-      struct ecoff_reginfo s;
-      int i;
+      bfd_set_error (bfd_error_invalid_operation);
+      return 0;
+    }
+  
+  return ecoff_data (abfd)->gp;
+}
 
-      /* If the caller is only changing part of the structure, we must
-        retrieve the current information before the memcpy.  */
-      if (offset != 0 || count != sizeof (struct ecoff_reginfo))
-       {
-         s.gp_value = tdata->gp;
-         s.gprmask = tdata->gprmask;
-         for (i = 0; i < 4; i++)
-           s.cprmask[i] = tdata->cprmask[i];
-         s.fprmask = tdata->fprmask;
-       }
+/* Set the GP value for an ECOFF file.  This is a hook used by the
+   assembler.  */
 
-      /* bfd_set_section_contents has already checked that the offset
-        and size is reasonable.  We don't have to worry about
-        swapping or any such thing; the .reginfo section is defined
-        such that the contents are an ecoff_reginfo structure as seen
-        on the host.  */
-      memcpy (((char *) &s) + offset, location, (size_t) count);
+boolean
+bfd_ecoff_set_gp_value (abfd, gp_value)
+     bfd *abfd;
+     bfd_vma gp_value;
+{
+  if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour
+      || bfd_get_format (abfd) != bfd_object)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
+    }
 
-      tdata->gp = s.gp_value;
-      tdata->gprmask = s.gprmask;
-      for (i = 0; i < 4; i++)
-       tdata->cprmask[i] = s.cprmask[i];
-      tdata->fprmask = s.fprmask;
+  ecoff_data (abfd)->gp = gp_value;
 
-      return true;
+  return true;
+}
+
+/* Set the register masks for an ECOFF file.  This is a hook used by
+   the assembler.  */
+
+boolean
+bfd_ecoff_set_regmasks (abfd, gprmask, fprmask, cprmask)
+     bfd *abfd;
+     unsigned long gprmask;
+     unsigned long fprmask;
+     unsigned long *cprmask;
+{
+  ecoff_data_type *tdata;
+
+  if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour
+      || bfd_get_format (abfd) != bfd_object)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
     }
 
-  if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0
-      || bfd_write (location, 1, count, abfd) != count)
-    return false;
+  tdata = ecoff_data (abfd);
+  tdata->gprmask = gprmask;
+  tdata->fprmask = fprmask;
+  if (cprmask != (unsigned long *) NULL)
+    {
+      register int i;
+
+      for (i = 0; i < 3; i++)
+       tdata->cprmask[i] = cprmask[i];
+    }
 
   return true;
 }
@@ -2385,15 +2572,15 @@ ecoff_get_extr (sym, esym)
   ecoff_symbol_type *ecoff_sym_ptr;
   bfd *input_bfd;
 
-  /* Don't include debugging, local or section symbols.  */
-  if ((sym->flags & BSF_DEBUGGING) != 0
-      || (sym->flags & BSF_LOCAL) != 0
-      || (sym->flags & BSF_SECTION_SYM) != 0)
-    return false;
-
   if (bfd_asymbol_flavour (sym) != bfd_target_ecoff_flavour
       || ecoffsymbol (sym)->native == NULL)
     {
+      /* Don't include debugging, local, or section symbols.  */
+      if ((sym->flags & BSF_DEBUGGING) != 0
+         || (sym->flags & BSF_LOCAL) != 0
+         || (sym->flags & BSF_SECTION_SYM) != 0)
+       return false;
+
       esym->jmptbl = 0;
       esym->cobol_main = 0;
       esym->weakext = 0;
@@ -2410,7 +2597,7 @@ ecoff_get_extr (sym, esym)
   ecoff_sym_ptr = ecoffsymbol (sym);
 
   if (ecoff_sym_ptr->local)
-    abort ();
+    return false;
 
   input_bfd = bfd_asymbol_bfd (sym);
   (*(ecoff_backend (input_bfd)->debug_swap.swap_ext_in))
@@ -2479,16 +2666,17 @@ ecoff_write_object_contents (abfd)
   bfd_size_type reloc_size;
   bfd_size_type text_size;
   bfd_vma text_start;
+  boolean set_text_start;
   bfd_size_type data_size;
   bfd_vma data_start;
+  boolean set_data_start;
   bfd_size_type bss_size;
-  PTR buff;
+  PTR buff = NULL;
+  PTR reloc_buff = NULL;
   struct internal_filehdr internal_f;
   struct internal_aouthdr internal_a;
   int i;
 
-  bfd_set_error (bfd_error_system_call);
-
   /* Determine where the sections and relocs will go in the output
      file.  */
   reloc_size = ecoff_compute_reloc_file_positions (abfd);
@@ -2498,8 +2686,6 @@ ecoff_write_object_contents (abfd)
        current != (asection *)NULL; 
        current = current->next) 
     {
-      if (strcmp (current->name, REGINFO) == 0)
-       continue;
       current->target_index = count;
       ++count;
     }
@@ -2509,16 +2695,34 @@ ecoff_write_object_contents (abfd)
   else
     text_size = 0;
   text_start = 0;
+  set_text_start = false;
   data_size = 0;
   data_start = 0;
+  set_data_start = false;
   bss_size = 0;
 
   /* Write section headers to the file.  */
 
-  buff = (PTR) alloca (scnhsz);
+  /* Allocate buff big enough to hold a section header,
+     file header, or a.out header.  */
+  {
+    bfd_size_type siz;
+    siz = scnhsz;
+    if (siz < filhsz)
+      siz = filhsz;
+    if (siz < aoutsz)
+      siz = aoutsz;
+    buff = (PTR) malloc (siz);
+    if (buff == NULL)
+      {
+       bfd_set_error (bfd_error_no_memory);
+       goto error_return;
+      }
+  }
+
   internal_f.f_nscns = 0;
   if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0)
-    return false;
+    goto error_return;
   for (current = abfd->sections;
        current != (asection *) NULL;
        current = current->next)
@@ -2526,18 +2730,11 @@ ecoff_write_object_contents (abfd)
       struct internal_scnhdr section;
       bfd_vma vma;
 
-      if (strcmp (current->name, REGINFO) == 0)
-       {
-         BFD_ASSERT (current->reloc_count == 0);
-         continue;
-       }
-
       ++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.  */
+      /* This seems to be correct for Irix 4 shared libraries.  */
       vma = bfd_get_section_vma (abfd, current);
       if (strcmp (current->name, _LIB) == 0)
        section.s_vaddr = 0;
@@ -2579,7 +2776,7 @@ ecoff_write_object_contents (abfd)
 
       bfd_coff_swap_scnhdr_out (abfd, (PTR) &section, buff);
       if (bfd_write (buff, 1, scnhsz, abfd) != scnhsz)
-       return false;
+       goto error_return;
 
       if ((section.s_flags & STYP_TEXT) != 0
          || ((section.s_flags & STYP_RDATA) != 0
@@ -2587,8 +2784,11 @@ ecoff_write_object_contents (abfd)
          || strcmp (current->name, _PDATA) == 0)
        {
          text_size += bfd_get_section_size_before_reloc (current);
-         if (text_start == 0 || text_start > vma)
-           text_start = vma;
+         if (! set_text_start || text_start > vma)
+           {
+             text_start = vma;
+             set_text_start = true;
+           }
        }
       else if ((section.s_flags & STYP_RDATA) != 0
               || (section.s_flags & STYP_DATA) != 0
@@ -2599,12 +2799,17 @@ ecoff_write_object_contents (abfd)
               || strcmp (current->name, _XDATA) == 0)
        {
          data_size += bfd_get_section_size_before_reloc (current);
-         if (data_start == 0 || data_start > vma)
-           data_start = vma;
+         if (! set_data_start || data_start > vma)
+           {
+             data_start = vma;
+             set_data_start = true;
+           }
        }
       else if ((section.s_flags & STYP_BSS) != 0
               || (section.s_flags & STYP_SBSS) != 0)
        bss_size += bfd_get_section_size_before_reloc (current);
+      else if ((section.s_flags & STYP_ECOFF_LIB) != 0)
+       /* Do nothing */ ;
       else
        abort ();
     }  
@@ -2698,17 +2903,15 @@ ecoff_write_object_contents (abfd)
   /* Write out the file header and the optional header.  */
 
   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
-    return false;
+    goto error_return;
 
-  buff = (PTR) alloca (filhsz);
   bfd_coff_swap_filehdr_out (abfd, (PTR) &internal_f, buff);
   if (bfd_write (buff, 1, filhsz, abfd) != filhsz)
-    return false;
+    goto error_return;
 
-  buff = (PTR) alloca (aoutsz);
   bfd_coff_swap_aouthdr_out (abfd, (PTR) &internal_a, buff);
   if (bfd_write (buff, 1, aoutsz, abfd) != aoutsz)
-    return false;
+    goto error_return;
 
   /* Build the external symbol information.  This must be done before
      writing out the relocs so that we know the symbol indices.  The
@@ -2726,7 +2929,7 @@ ecoff_write_object_contents (abfd)
                                      ? true : false),
                                     ecoff_get_extr, ecoff_set_index)
          == false)
-       return false;
+       goto error_return;
 
       /* Write out the relocs.  */
       for (current = abfd->sections;
@@ -2740,16 +2943,17 @@ ecoff_write_object_contents (abfd)
          if (current->reloc_count == 0)
            continue;
 
-         buff = bfd_alloc (abfd, current->reloc_count * external_reloc_size);
-         if (buff == NULL)
+         reloc_buff =
+           bfd_alloc (abfd, current->reloc_count * external_reloc_size);
+         if (reloc_buff == NULL)
            {
              bfd_set_error (bfd_error_no_memory);
-             return false;
+             goto error_return;
            }
 
          reloc_ptr_ptr = current->orelocation;
          reloc_end = reloc_ptr_ptr + current->reloc_count;
-         out_ptr = (char *) buff;
+         out_ptr = (char *) reloc_buff;
          for (;
               reloc_ptr_ptr < reloc_end;
               reloc_ptr_ptr++, out_ptr += external_reloc_size)
@@ -2758,7 +2962,7 @@ ecoff_write_object_contents (abfd)
              asymbol *sym;
              struct internal_reloc in;
          
-             memset (&in, 0, sizeof in);
+             memset ((PTR) &in, 0, sizeof in);
 
              reloc = *reloc_ptr_ptr;
              sym = *reloc->sym_ptr_ptr;
@@ -2816,11 +3020,13 @@ ecoff_write_object_contents (abfd)
            }
 
          if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0)
-           return false;
-         if (bfd_write (buff, external_reloc_size, current->reloc_count, abfd)
+           goto error_return;
+         if (bfd_write (reloc_buff,
+                        external_reloc_size, current->reloc_count, abfd)
              != external_reloc_size * current->reloc_count)
-           return false;
-         bfd_release (abfd, buff);
+           goto error_return;
+         bfd_release (abfd, reloc_buff);
+         reloc_buff = NULL;
        }
 
       /* Write out the symbolic debugging information.  */
@@ -2830,7 +3036,7 @@ ecoff_write_object_contents (abfd)
          if (bfd_ecoff_write_debug (abfd, debug, &backend->debug_swap,
                                     ecoff_data (abfd)->sym_filepos)
              == false)
-           return false;
+           goto error_return;
        }
     }
 
@@ -2846,17 +3052,27 @@ ecoff_write_object_contents (abfd)
 
       if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1,
                    SEEK_SET) != 0)
-       return false;
+       goto error_return;
       if (bfd_read (&c, 1, 1, abfd) == 0)
        c = 0;
       if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1,
                    SEEK_SET) != 0)
-       return false;
+       goto error_return;
       if (bfd_write (&c, 1, 1, abfd) != 1)
-       return false;      
+       goto error_return;
     }
 
+  if (reloc_buff != NULL)
+    bfd_release (abfd, reloc_buff);
+  if (buff != NULL)
+    free (buff);
   return true;
+ error_return:
+  if (reloc_buff != NULL)
+    bfd_release (abfd, reloc_buff);
+  if (buff != NULL)
+    free (buff);
+  return false;
 }
 \f
 /* Archive handling.  ECOFF uses what appears to be a unique type of
@@ -2949,7 +3165,8 @@ ecoff_slurp_armap (abfd)
   if (i != 16)
       return false;
 
-  bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
+  if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
+    return false;
 
   /* Irix 4.0.5F apparently can use either an ECOFF armap or a
      standard COFF armap.  We could move the ECOFF armap stuff into
@@ -3002,7 +3219,8 @@ ecoff_slurp_armap (abfd)
     
   if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size)
     {
-      bfd_set_error (bfd_error_malformed_archive);
+      if (bfd_get_error () != bfd_error_system_call)
+       bfd_set_error (bfd_error_malformed_archive);
       bfd_release (abfd, (PTR) raw_armap);
       return false;
     }
@@ -3273,7 +3491,8 @@ ecoff_archive_p (abfd)
   if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG
       || strncmp (armag, ARMAG, SARMAG) != 0)
     {
-      bfd_set_error (bfd_error_wrong_format);
+      if (bfd_get_error () != bfd_error_system_call)
+       bfd_set_error (bfd_error_wrong_format);
       return (bfd_target *) NULL;
     }
 
@@ -3354,7 +3573,7 @@ ecoff_link_hash_newfunc (entry, table, string)
       ret->indx = -1;
       ret->abfd = NULL;
     }
-  memset (&ret->esym, 0, sizeof ret->esym);
+  memset ((PTR) &ret->esym, 0, sizeof ret->esym);
 
   return (struct bfd_hash_entry *) ret;
 }
@@ -3587,35 +3806,47 @@ ecoff_link_check_archive_element (abfd, info, pneeded)
     = backend->debug_swap.swap_ext_in;
   HDRR *symhdr;
   bfd_size_type external_ext_size;
-  PTR external_ext;
+  PTR external_ext = NULL;
   size_t esize;
-  char *ssext;
+  char *ssext = NULL;
   char *ext_ptr;
   char *ext_end;
 
   *pneeded = false;
 
   if (! ecoff_slurp_symbolic_header (abfd))
-    return false;
+    goto error_return;
 
   /* If there are no symbols, we don't want it.  */
   if (bfd_get_symcount (abfd) == 0)
-    return true;
+    goto successful_return;
 
   symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
 
   /* Read in the external symbols and external strings.  */
   external_ext_size = backend->debug_swap.external_ext_size;
   esize = symhdr->iextMax * external_ext_size;
-  external_ext = (PTR) alloca (esize);
+  external_ext = (PTR) malloc (esize);
+  if (external_ext == NULL && esize != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
+
   if (bfd_seek (abfd, symhdr->cbExtOffset, SEEK_SET) != 0
       || bfd_read (external_ext, 1, esize, abfd) != esize)
-    return false;
+    goto error_return;
+
+  ssext = (char *) malloc (symhdr->issExtMax);
+  if (ssext == NULL && symhdr->issExtMax != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
 
-  ssext = (char *) alloca (symhdr->issExtMax);
   if (bfd_seek (abfd, symhdr->cbSsExtOffset, SEEK_SET) != 0
       || bfd_read (ssext, 1, symhdr->issExtMax, abfd) != symhdr->issExtMax)
-    return false;
+    goto error_return;
 
   /* Look through the external symbols to see if they define some
      symbol that is currently undefined.  */
@@ -3670,15 +3901,26 @@ ecoff_link_check_archive_element (abfd, info, pneeded)
 
       /* Include this element.  */
       if (! (*info->callbacks->add_archive_element) (info, abfd, name))
-       return false;
+       goto error_return;
       if (! ecoff_link_add_externals (abfd, info, external_ext, ssext))
-       return false;
+       goto error_return;
 
       *pneeded = true;
-      return true;
+      goto successful_return;
     }
 
+ successful_return:
+  if (external_ext != NULL)
+    free (external_ext);
+  if (ssext != NULL)
+    free (ssext);
   return true;
+ error_return:
+  if (external_ext != NULL)
+    free (external_ext);
+  if (ssext != NULL)
+    free (ssext);
+  return false;
 }
 
 /* Add symbols from an ECOFF object file to the global linker hash
@@ -3691,9 +3933,10 @@ ecoff_link_add_object_symbols (abfd, info)
 {
   HDRR *symhdr;
   bfd_size_type external_ext_size;
-  PTR external_ext;
+  PTR external_ext = NULL;
   size_t esize;
-  char *ssext;
+  char *ssext = NULL;
+  boolean result;
 
   if (! ecoff_slurp_symbolic_header (abfd))
     return false;
@@ -3707,17 +3950,42 @@ ecoff_link_add_object_symbols (abfd, info)
   /* Read in the external symbols and external strings.  */
   external_ext_size = ecoff_backend (abfd)->debug_swap.external_ext_size;
   esize = symhdr->iextMax * external_ext_size;
-  external_ext = (PTR) alloca (esize);
+  external_ext = (PTR) malloc (esize);
+  if (external_ext == NULL && esize != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
+
   if (bfd_seek (abfd, symhdr->cbExtOffset, SEEK_SET) != 0
       || bfd_read (external_ext, 1, esize, abfd) != esize)
-    return false;
+    goto error_return;
+
+  ssext = (char *) malloc (symhdr->issExtMax);
+  if (ssext == NULL && symhdr->issExtMax != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
 
-  ssext = (char *) alloca (symhdr->issExtMax);
   if (bfd_seek (abfd, symhdr->cbSsExtOffset, SEEK_SET) != 0
       || bfd_read (ssext, 1, symhdr->issExtMax, abfd) != symhdr->issExtMax)
-    return false;
-
-  return ecoff_link_add_externals (abfd, info, external_ext, ssext);
+    goto error_return;
+
+  result = ecoff_link_add_externals (abfd, info, external_ext, ssext);
+
+  if (ssext != NULL)
+    free (ssext);
+  if (external_ext != NULL)
+    free (external_ext);
+  return result;
+
+ error_return:
+  if (ssext != NULL)
+    free (ssext);
+  if (external_ext != NULL)
+    free (external_ext);
+  return false;
 }
 
 /* Add the external symbols of an object file to the global linker
@@ -3879,9 +4147,10 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
 
       name = ssext + esym.asym.iss;
 
+      h = NULL;
       if (! (_bfd_generic_link_add_one_symbol
             (info, abfd, name, BSF_GLOBAL, section, value,
-             (const char *) NULL, true, true, backend->constructor_bitsize,
+             (const char *) NULL, true, true,
              (struct bfd_link_hash_entry **) &h)))
        return false;
 
@@ -3915,6 +4184,9 @@ static boolean ecoff_link_write_external
 static boolean ecoff_indirect_link_order
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
           struct bfd_link_order *));
+static boolean ecoff_reloc_link_order
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+          struct bfd_link_order *));
 
 /* ECOFF final link routine.  This looks through all the input BFDs
    and gathers together all the debugging information, and then
@@ -3976,14 +4248,6 @@ ecoff_bfd_final_link (abfd, info)
     {
       boolean ret;
 
-      /* If we might be using the C based alloca function, dump memory
-        allocated by ecoff_final_link_debug_accumulate.  */
-#ifndef __GNUC__
-#ifndef alloca
-      (void) alloca (0);
-#endif
-#endif
-
       if (bfd_get_flavour (input_bfd) == bfd_target_ecoff_flavour)
        {
          /* Abitrarily set the symbolic header vstamp to the vstamp
@@ -4028,6 +4292,9 @@ ecoff_bfd_final_link (abfd, info)
               p = p->next)
            if (p->type == bfd_indirect_link_order)
              o->reloc_count += p->u.indirect.section->reloc_count;
+           else if (p->type == bfd_section_reloc_link_order
+                    || p->type == bfd_symbol_reloc_link_order)
+             ++o->reloc_count;
        }
     }
 
@@ -4090,23 +4357,10 @@ ecoff_bfd_final_link (abfd, info)
 
   for (o = abfd->sections; o != (asection *) NULL; o = o->next)
     {
-      /* Ignore any link_orders for the .reginfo section, which does
-        not really exist.  */
-      if (strcmp (o->name, REGINFO) == 0)
-       continue;
-      
       for (p = o->link_order_head;
           p != (struct bfd_link_order *) NULL;
           p = p->next)
        {
-         /* If we might be using the C based alloca function, we need
-            to dump the memory allocated by the function
-            ecoff_indirect_link_order.  */
-#ifndef __GNUC__
-#ifndef alloca
-         (void) alloca (0);
-#endif
-#endif
          if (p->type == bfd_indirect_link_order
              && (bfd_get_flavour (p->u.indirect.section->owner)
                  == bfd_target_ecoff_flavour))
@@ -4114,6 +4368,12 @@ ecoff_bfd_final_link (abfd, info)
              if (! ecoff_indirect_link_order (abfd, info, o, p))
                return false;
            }
+         else if (p->type == bfd_section_reloc_link_order
+                  || p->type == bfd_symbol_reloc_link_order)
+           {
+             if (! ecoff_reloc_link_order (abfd, info, o, p))
+               return false;
+           }
          else
            {
              if (! _bfd_default_link_order (abfd, info, o, p))
@@ -4149,24 +4409,39 @@ ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle)
     debug->ptr = NULL;                                                 \
   else                                                                 \
     {                                                                  \
-      debug->ptr = (type) alloca (size * symhdr->count);               \
+      debug->ptr = (type) malloc (size * symhdr->count);               \
+      if (debug->ptr == NULL)                                          \
+       {                                                               \
+          bfd_set_error (bfd_error_no_memory);                         \
+          ret = false;                                                 \
+          goto return_something;                                       \
+       }                                                               \
       if ((bfd_seek (input_bfd, (file_ptr) symhdr->offset, SEEK_SET)   \
           != 0)                                                        \
          || (bfd_read (debug->ptr, size, symhdr->count,                \
                        input_bfd) != size * symhdr->count))            \
-       return false;                                                   \
+       {                                                               \
+          ret = false;                                                 \
+          goto return_something;                                       \
+       }                                                               \
     }
 
-  READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *);
-  READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR);
-  READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR);
-  READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR);
-  READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR);
-  READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
-       union aux_ext *);
-  READ (ss, cbSsOffset, issMax, sizeof (char), char *);
-  READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
-  READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
+  /* If raw_syments is not NULL, then the data was already by read by
+     ecoff_slurp_symbolic_info.  */
+  if (ecoff_data (input_bfd)->raw_syments == NULL)
+    {
+      READ (line, cbLineOffset, cbLine, sizeof (unsigned char),
+           unsigned char *);
+      READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR);
+      READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR);
+      READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR);
+      READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR);
+      READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
+           union aux_ext *);
+      READ (ss, cbSsOffset, issMax, sizeof (char), char *);
+      READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
+      READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
+    }
 #undef READ
 
   /* We do not read the external strings or the external symbols.  */
@@ -4176,17 +4451,40 @@ ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle)
          &ecoff_backend (output_bfd)->debug_swap,
          input_bfd, debug, swap, info));
 
-  /* Make sure we don't accidentally follow one of these pointers on
-     to the stack.  */
-  debug->line = NULL;
-  debug->external_dnr = NULL;
-  debug->external_pdr = NULL;
-  debug->external_sym = NULL;
-  debug->external_opt = NULL;
-  debug->external_aux = NULL;
-  debug->ss = NULL;
-  debug->external_fdr = NULL;
-  debug->external_rfd = NULL;
+ return_something:
+  if (ecoff_data (input_bfd)->raw_syments == NULL)
+    {
+      if (debug->line != NULL)
+       free (debug->line);
+      if (debug->external_dnr != NULL)
+       free (debug->external_dnr);
+      if (debug->external_pdr != NULL)
+       free (debug->external_pdr);
+      if (debug->external_sym != NULL)
+       free (debug->external_sym);
+      if (debug->external_opt != NULL)
+       free (debug->external_opt);
+      if (debug->external_aux != NULL)
+       free (debug->external_aux);
+      if (debug->ss != NULL)
+       free (debug->ss);
+      if (debug->external_fdr != NULL)
+       free (debug->external_fdr);
+      if (debug->external_rfd != NULL)
+       free (debug->external_rfd);
+
+      /* Make sure we don't accidentally follow one of these pointers
+        into freed memory.  */
+      debug->line = NULL;
+      debug->external_dnr = NULL;
+      debug->external_pdr = NULL;
+      debug->external_sym = NULL;
+      debug->external_opt = NULL;
+      debug->external_aux = NULL;
+      debug->ss = NULL;
+      debug->external_fdr = NULL;
+      debug->external_rfd = NULL;
+    }
 
   return ret;
 }
@@ -4214,9 +4512,42 @@ ecoff_link_write_external (h, data)
       h->esym.reserved = 0;
       h->esym.ifd = ifdNil;
       h->esym.asym.value = 0;
-      /* FIXME: we can do better than this for st and sc.  */
       h->esym.asym.st = stGlobal;
-      h->esym.asym.sc = scAbs;
+
+      if (h->root.type != bfd_link_hash_defined)
+       h->esym.asym.sc = scAbs;
+      else
+       {
+         asection *output_section;
+         const char *name;
+
+         output_section = h->root.u.def.section->output_section;
+         name = bfd_section_name (output_section->owner, output_section);
+       
+         if (strcmp (name, _TEXT) == 0)
+           h->esym.asym.sc = scText;
+         else if (strcmp (name, _DATA) == 0)
+           h->esym.asym.sc = scData;
+         else if (strcmp (name, _SDATA) == 0)
+           h->esym.asym.sc = scSData;
+         else if (strcmp (name, _RDATA) == 0)
+           h->esym.asym.sc = scRData;
+         else if (strcmp (name, _BSS) == 0)
+           h->esym.asym.sc = scBss;
+         else if (strcmp (name, _SBSS) == 0)
+           h->esym.asym.sc = scSBss;
+         else if (strcmp (name, _INIT) == 0)
+           h->esym.asym.sc = scInit;
+         else if (strcmp (name, _FINI) == 0)
+           h->esym.asym.sc = scFini;
+         else if (strcmp (name, _PDATA) == 0)
+           h->esym.asym.sc = scPData;
+         else if (strcmp (name, _XDATA) == 0)
+           h->esym.asym.sc = scXData;
+         else
+           h->esym.asym.sc = scAbs;
+       }
+
       h->esym.asym.reserved = 0;
       h->esym.asym.index = indexNil;
     }
@@ -4239,9 +4570,9 @@ ecoff_link_write_external (h, data)
       abort ();
     case bfd_link_hash_undefined:
     case bfd_link_hash_weak:
-      if (h->esym.asym.st != scUndefined
-         && h->esym.asym.st != scSUndefined)
-       h->esym.asym.st = scUndefined;
+      if (h->esym.asym.sc != scUndefined
+         && h->esym.asym.sc != scSUndefined)
+       h->esym.asym.sc = scUndefined;
       break;
     case bfd_link_hash_defined:
       if (h->esym.asym.sc == scUndefined
@@ -4290,11 +4621,13 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order)
 {
   asection *input_section;
   bfd *input_bfd;
-  bfd_size_type input_size;
-  bfd_byte *contents;
+  struct ecoff_section_tdata *section_tdata;
+  bfd_size_type raw_size;
+  bfd_size_type cooked_size;
+  bfd_byte *contents = NULL;
   bfd_size_type external_reloc_size;
   bfd_size_type external_relocs_size;
-  PTR external_relocs;
+  PTR external_relocs = NULL;
 
   BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
 
@@ -4303,40 +4636,77 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order)
 
   input_section = link_order->u.indirect.section;
   input_bfd = input_section->owner;
+  section_tdata = ecoff_section_data (input_bfd, input_section);
+
+  raw_size = input_section->_raw_size;
+  cooked_size = input_section->_cooked_size;
+  if (cooked_size == 0)
+    cooked_size = raw_size;
 
   BFD_ASSERT (input_section->output_section == output_section);
   BFD_ASSERT (input_section->output_offset == link_order->offset);
-  BFD_ASSERT (bfd_section_size (input_bfd, input_section) == link_order->size);
+  BFD_ASSERT (cooked_size == link_order->size);
+
+  /* Get the section contents.  We allocate memory for the larger of
+     the size before relocating and the size after relocating.  */
+  contents = (bfd_byte *) malloc (raw_size >= cooked_size
+                                 ? raw_size
+                                 : cooked_size);
+  if (contents == NULL && raw_size != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
 
-  /* Get the section contents.  */
-  input_size = bfd_section_size (input_bfd, input_section);
-  contents = (bfd_byte *) alloca (input_size);
-  if (! bfd_get_section_contents (input_bfd, input_section, (PTR) contents,
-                                 (file_ptr) 0, input_size))
-    return false;
+  /* If we are relaxing, the contents may have already been read into
+     memory, in which case we copy them into our new buffer.  We don't
+     simply reuse the old buffer in case cooked_size > raw_size.  */
+  if (section_tdata != (struct ecoff_section_tdata *) NULL
+      && section_tdata->contents != (bfd_byte *) NULL)
+    memcpy (contents, section_tdata->contents, raw_size);
+  else
+    {
+      if (! bfd_get_section_contents (input_bfd, input_section,
+                                     (PTR) contents,
+                                     (file_ptr) 0, raw_size))
+       goto error_return;
+    }
 
-  /* Get the relocs.  */
+  /* Get the relocs.  If we are relaxing MIPS code, they will already
+     have been read in.  Otherwise, we read them in now.  */
   external_reloc_size = ecoff_backend (input_bfd)->external_reloc_size;
   external_relocs_size = external_reloc_size * input_section->reloc_count;
-  external_relocs = (PTR) alloca (external_relocs_size);
-  if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
-      || (bfd_read (external_relocs, 1, external_relocs_size, input_bfd)
-         != external_relocs_size))
-    return false;
+
+  if (section_tdata != (struct ecoff_section_tdata *) NULL)
+    external_relocs = section_tdata->external_relocs;
+  else
+    {
+      external_relocs = (PTR) malloc (external_relocs_size);
+      if (external_relocs == NULL && external_relocs_size != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+
+      if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
+         || (bfd_read (external_relocs, 1, external_relocs_size, input_bfd)
+             != external_relocs_size))
+       goto error_return;
+    }
 
   /* Relocate the section contents.  */
   if (! ((*ecoff_backend (input_bfd)->relocate_section)
         (output_bfd, info, input_bfd, input_section, contents,
          external_relocs)))
-    return false;
+    goto error_return;
 
   /* Write out the relocated section.  */
   if (! bfd_set_section_contents (output_bfd,
                                  output_section,
                                  (PTR) contents,
                                  input_section->output_offset,
-                                 input_size))
-    return false;
+                                 cooked_size))
+    goto error_return;
 
   /* If we are producing relocateable output, the relocs were
      modified, and we write them out now.  We use the reloc_count
@@ -4350,9 +4720,203 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order)
                    SEEK_SET) != 0
          || (bfd_write (external_relocs, 1, external_relocs_size, output_bfd)
              != external_relocs_size))
-       return false;
+       goto error_return;
       output_section->reloc_count += input_section->reloc_count;
     }
 
+  if (contents != NULL)
+    free (contents);
+  if (external_relocs != NULL && section_tdata == NULL)
+    free (external_relocs);
   return true;
+
+ error_return:
+  if (contents != NULL)
+    free (contents);
+  if (external_relocs != NULL && section_tdata == NULL)
+    free (external_relocs);
+  return false;
+}
+
+/* Generate a reloc when linking an ECOFF file.  This is a reloc
+   requested by the linker, and does come from any input file.  This
+   is used to build constructor and destructor tables when linking
+   with -Ur.  */
+
+static boolean
+ecoff_reloc_link_order (output_bfd, info, output_section, link_order)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     asection *output_section;
+     struct bfd_link_order *link_order;
+{
+  arelent rel;
+  struct internal_reloc in;
+  bfd_size_type external_reloc_size;
+  bfd_byte *rbuf;
+  boolean ok;
+
+  /* We set up an arelent to pass to the backend adjust_reloc_out
+     routine.  */
+  rel.address = link_order->offset;
+
+  rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
+  if (rel.howto == (const reloc_howto_type *) NULL)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      return false;
+    }
+
+  if (link_order->type == bfd_section_reloc_link_order)
+    rel.sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
+  else
+    {
+      /* We can't set up a reloc against a symbol correctly, because
+        we have no asymbol structure.  Currently no adjust_reloc_out
+        routine cases.  */
+      rel.sym_ptr_ptr = (asymbol **) NULL;
+    }
+
+  /* All ECOFF relocs are in-place.  Put the addend into the object
+     file.  */
+
+  BFD_ASSERT (rel.howto->partial_inplace);
+  if (link_order->u.reloc.p->addend != 0)
+    {
+      bfd_size_type size;
+      bfd_reloc_status_type rstat;
+      bfd_byte *buf;
+      boolean ok;
+
+      size = bfd_get_reloc_size (rel.howto);
+      buf = (bfd_byte *) bfd_zmalloc (size);
+      if (buf == (bfd_byte *) NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
+      rstat = _bfd_relocate_contents (rel.howto, output_bfd,
+                                     link_order->u.reloc.p->addend, buf);
+      switch (rstat)
+       {
+       case bfd_reloc_ok:
+         break;
+       default:
+       case bfd_reloc_outofrange:
+         abort ();
+       case bfd_reloc_overflow:
+         if (! ((*info->callbacks->reloc_overflow)
+                (info,
+                 (link_order->type == bfd_section_reloc_link_order
+                  ? bfd_section_name (output_bfd,
+                                      link_order->u.reloc.p->u.section)
+                  : link_order->u.reloc.p->u.name),
+                 rel.howto->name, link_order->u.reloc.p->addend,
+                 (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+           {
+             free (buf);
+             return false;
+           }
+         break;
+       }
+      ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf,
+                                    (file_ptr) link_order->offset, size);
+      free (buf);
+      if (! ok)
+       return false;
+    }
+
+  rel.addend = 0;
+
+  /* Move the information into a internal_reloc structure.  */
+  in.r_vaddr = (rel.address
+               + bfd_get_section_vma (output_bfd, output_section));
+  in.r_type = rel.howto->type;
+
+  if (link_order->type == bfd_symbol_reloc_link_order)
+    {
+      struct ecoff_link_hash_entry *h;
+
+      h = ecoff_link_hash_lookup (ecoff_hash_table (info),
+                                 link_order->u.reloc.p->u.name,
+                                 false, false, true);
+      if (h != (struct ecoff_link_hash_entry *) NULL
+         && h->indx != -1)
+       in.r_symndx = h->indx;
+      else
+       {
+         if (! ((*info->callbacks->unattached_reloc)
+                (info, link_order->u.reloc.p->u.name, (bfd *) NULL,
+                 (asection *) NULL, (bfd_vma) 0)))
+           return false;
+         in.r_symndx = 0;
+       }
+      in.r_extern = 1;
+    }
+  else
+    {
+      CONST char *name;
+
+      name = bfd_get_section_name (output_bfd,
+                                  link_order->u.reloc.p->u.section);
+      if (strcmp (name, ".text") == 0)
+       in.r_symndx = RELOC_SECTION_TEXT;
+      else if (strcmp (name, ".rdata") == 0)
+       in.r_symndx = RELOC_SECTION_RDATA;
+      else if (strcmp (name, ".data") == 0)
+       in.r_symndx = RELOC_SECTION_DATA;
+      else if (strcmp (name, ".sdata") == 0)
+       in.r_symndx = RELOC_SECTION_SDATA;
+      else if (strcmp (name, ".sbss") == 0)
+       in.r_symndx = RELOC_SECTION_SBSS;
+      else if (strcmp (name, ".bss") == 0)
+       in.r_symndx = RELOC_SECTION_BSS;
+      else if (strcmp (name, ".init") == 0)
+       in.r_symndx = RELOC_SECTION_INIT;
+      else if (strcmp (name, ".lit8") == 0)
+       in.r_symndx = RELOC_SECTION_LIT8;
+      else if (strcmp (name, ".lit4") == 0)
+       in.r_symndx = RELOC_SECTION_LIT4;
+      else if (strcmp (name, ".xdata") == 0)
+       in.r_symndx = RELOC_SECTION_XDATA;
+      else if (strcmp (name, ".pdata") == 0)
+       in.r_symndx = RELOC_SECTION_PDATA;
+      else if (strcmp (name, ".fini") == 0)
+       in.r_symndx = RELOC_SECTION_FINI;
+      else if (strcmp (name, ".lita") == 0)
+       in.r_symndx = RELOC_SECTION_LITA;
+      else if (strcmp (name, "*ABS*") == 0)
+       in.r_symndx = RELOC_SECTION_ABS;
+      else
+       abort ();
+      in.r_extern = 0;
+    }
+
+  /* Let the BFD backend adjust the reloc.  */
+  (*ecoff_backend (output_bfd)->adjust_reloc_out) (output_bfd, &rel, &in);
+
+  /* Get some memory and swap out the reloc.  */
+  external_reloc_size = ecoff_backend (output_bfd)->external_reloc_size;
+  rbuf = (bfd_byte *) malloc (external_reloc_size);
+  if (rbuf == (bfd_byte *) NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+
+  (*ecoff_backend (output_bfd)->swap_reloc_out) (output_bfd, &in, (PTR) rbuf);
+
+  ok = (bfd_seek (output_bfd,
+                 (output_section->rel_filepos +
+                  output_section->reloc_count * external_reloc_size),
+                 SEEK_SET) == 0
+       && (bfd_write ((PTR) rbuf, 1, external_reloc_size, output_bfd)
+           == external_reloc_size));
+
+  if (ok)
+    ++output_section->reloc_count;
+
+  free (rbuf);
+
+  return ok;
 }