import gdb-1999-06-21 snapshot
[external/binutils.git] / bfd / coffgen.c
index ebc596f..a06ed66 100644 (file)
@@ -1,5 +1,6 @@
 /* Support for the generic parts of COFF, for BFD.
-   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 1998
+   Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -16,7 +17,7 @@ GNU General Public License for more details.
 
 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.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* Most of this hacked by  Steve Chamberlain, sac@cygnus.com.
    Split out of coffcode.h by Ian Taylor, ian@cygnus.com.  */
@@ -41,63 +42,111 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "coff/internal.h"
 #include "libcoff.h"
 
-static asection bfd_debug_section = { "*DEBUG*" };
+static void coff_fix_symbol_name
+  PARAMS ((bfd *, asymbol *, combined_entry_type *, bfd_size_type *,
+          asection **, bfd_size_type *));
+static boolean coff_write_symbol
+  PARAMS ((bfd *, asymbol *, combined_entry_type *, unsigned int *,
+          bfd_size_type *, asection **, bfd_size_type *));
+static boolean coff_write_alien_symbol
+  PARAMS ((bfd *, asymbol *, unsigned int *, bfd_size_type *,
+          asection **, bfd_size_type *));
+static boolean coff_write_native_symbol
+  PARAMS ((bfd *, coff_symbol_type *, unsigned int *, bfd_size_type *,
+          asection **, bfd_size_type *));
+static void coff_pointerize_aux
+  PARAMS ((bfd *, combined_entry_type *, combined_entry_type *,
+          unsigned int, combined_entry_type *));
+static boolean make_a_section_from_file
+  PARAMS ((bfd *, struct internal_scnhdr *, unsigned int));
+static const bfd_target *coff_real_object_p
+  PARAMS ((bfd *, unsigned, struct internal_filehdr *, 
+          struct internal_aouthdr *));
+static void fixup_symbol_value
+  PARAMS ((bfd *, coff_symbol_type *, struct internal_syment *));
+static char *build_debug_section
+  PARAMS ((bfd *));
+static char *copy_name
+  PARAMS ((bfd *, char *, int));
+
+#define STRING_SIZE_SIZE (4)
 
 /* Take a section header read from a coff file (in HOST byte order),
    and make a BFD "section" out of it.  This is used by ECOFF.  */
-static          boolean
-DEFUN(make_a_section_from_file,(abfd, hdr, target_index),
-      bfd            *abfd AND
-      struct internal_scnhdr  *hdr AND
-      unsigned int target_index)
+static boolean
+make_a_section_from_file (abfd, hdr, target_index)
+     bfd *abfd;
+     struct internal_scnhdr *hdr;
+     unsigned int target_index;
 {
-  asection       *return_section;
+  asection *return_section;
   char *name;
-    
-  /* Assorted wastage to null-terminate the name, thanks AT&T! */
-  name = bfd_alloc(abfd, sizeof (hdr->s_name)+1);
-  if (name == NULL) {
-      bfd_error = no_memory;
-      return false;
-    }
-  strncpy(name, (char *) &hdr->s_name[0], sizeof (hdr->s_name));
-  name[sizeof (hdr->s_name)] = 0;
 
-  return_section = bfd_make_section(abfd, name);
-  if (return_section == NULL)
-    return_section = bfd_coff_make_section_hook (abfd, name);
+  name = NULL;
 
-  /* Handle several sections of the same name.  For example, if an executable
-     has two .bss sections, GDB better be able to find both of them
-     (PR 3562).  */
-  if (return_section == NULL)
-    return_section = bfd_make_section_anyway (abfd, name);
+  /* Handle long section names as in PE.  */
+  if (bfd_coff_long_section_names (abfd)
+      && hdr->s_name[0] == '/')
+    {
+      char buf[SCNNMLEN];
+      long strindex;
+      char *p;
+      const char *strings;
+
+      memcpy (buf, hdr->s_name + 1, SCNNMLEN - 1);
+      buf[SCNNMLEN - 1] = '\0';
+      strindex = strtol (buf, &p, 10);
+      if (*p == '\0' && strindex >= 0)
+       {
+         strings = _bfd_coff_read_string_table (abfd);
+         if (strings == NULL)
+           return false;
+         /* FIXME: For extra safety, we should make sure that
+             strindex does not run us past the end, but right now we
+             don't know the length of the string table.  */
+         strings += strindex;
+         name = bfd_alloc (abfd, strlen (strings) + 1);
+         if (name == NULL)
+           return false;
+         strcpy (name, strings);
+       }
+    }
 
+  if (name == NULL)
+    {
+      /* Assorted wastage to null-terminate the name, thanks AT&T! */
+      name = bfd_alloc (abfd, sizeof (hdr->s_name) + 1);
+      if (name == NULL)
+       return false;
+      strncpy (name, (char *) &hdr->s_name[0], sizeof (hdr->s_name));
+      name[sizeof (hdr->s_name)] = 0;
+    }
+
+  return_section = bfd_make_section_anyway (abfd, name);
   if (return_section == NULL)
     return false;
 
-  /* s_paddr is presumed to be = to s_vaddr */
-
   return_section->vma = hdr->s_vaddr;
+  return_section->lma = hdr->s_paddr;
   return_section->_raw_size = hdr->s_size;
   return_section->filepos = hdr->s_scnptr;
-  return_section->rel_filepos =  hdr->s_relptr;
+  return_section->rel_filepos = hdr->s_relptr;
   return_section->reloc_count = hdr->s_nreloc;
 
   bfd_coff_set_alignment_hook (abfd, return_section, hdr);
 
-  return_section->line_filepos =  hdr->s_lnnoptr;
+  return_section->line_filepos = hdr->s_lnnoptr;
 
   return_section->lineno_count = hdr->s_nlnno;
   return_section->userdata = NULL;
   return_section->next = (asection *) NULL;
-  return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr);
+  return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr, name);
 
   return_section->target_index = target_index;
 
   /* At least on i386-coff, the line number count for a shared library
      section must be ignored.  */
-  if ((return_section->flags & SEC_SHARED_LIBRARY) != 0)
+  if ((return_section->flags & SEC_COFF_SHARED_LIBRARY) != 0)
     return_section->lineno_count = 0;
 
   if (hdr->s_nreloc != 0)
@@ -111,48 +160,20 @@ DEFUN(make_a_section_from_file,(abfd, hdr, target_index),
 /* Read in a COFF object and make it into a BFD.  This is used by
    ECOFF as well.  */
 
-static
-bfd_target     *
-DEFUN(coff_real_object_p,(abfd, nscns, internal_f, internal_a),
-    bfd            *abfd AND
-    unsigned        nscns AND
-  struct internal_filehdr *internal_f AND
-  struct internal_aouthdr *internal_a)
+static const bfd_target *
+coff_real_object_p (abfd, nscns, internal_f, internal_a)
+     bfd *abfd;
+     unsigned nscns;
+     struct internal_filehdr *internal_f;
+     struct internal_aouthdr *internal_a;
 {
+  flagword oflags = abfd->flags;
+  bfd_vma ostart = bfd_get_start_address (abfd);
   PTR tdata;
-  size_t          readsize;    /* length of file_info */
+  size_t readsize;             /* length of file_info */
   unsigned int scnhsz;
   char *external_sections;
 
-  /* Build a play area */
-  tdata = bfd_coff_mkobject_hook (abfd, (PTR) internal_f, (PTR) internal_a);
-  if (tdata == NULL)
-    return 0;
-
-  scnhsz = bfd_coff_scnhsz (abfd);
-  readsize = nscns * scnhsz;
-  external_sections = (char *)bfd_alloc(abfd, readsize);
-
-  if (bfd_read((PTR)external_sections, 1, readsize, abfd) != readsize) {
-    goto fail;
-  }
-
-  /* Now copy data as required; construct all asections etc */
-  if (nscns != 0) {
-    unsigned int    i;
-    for (i = 0; i < nscns; i++) {
-      struct internal_scnhdr tmp;
-      bfd_coff_swap_scnhdr_in(abfd, (PTR) (external_sections + i * scnhsz),
-                             (PTR) &tmp);
-      make_a_section_from_file(abfd,&tmp, i+1);
-    }
-  }
-
-/*  make_abs_section(abfd);*/
-  
-  if (bfd_coff_set_arch_mach_hook (abfd, (PTR) internal_f) == false)
-    goto fail;
-
   if (!(internal_f->f_flags & F_RELFLG))
     abfd->flags |= HAS_RELOC;
   if ((internal_f->f_flags & F_EXEC))
@@ -162,8 +183,11 @@ DEFUN(coff_real_object_p,(abfd, nscns, internal_f, internal_a),
   if (!(internal_f->f_flags & F_LSYMS))
     abfd->flags |= HAS_LOCALS;
 
+  /* FIXME: How can we set D_PAGED correctly?  */
+  if ((internal_f->f_flags & F_EXEC) != 0)
+    abfd->flags |= D_PAGED;
 
-  bfd_get_symcount(abfd) = internal_f->f_nsyms;
+  bfd_get_symcount (abfd) = internal_f->f_nsyms;
   if (internal_f->f_nsyms)
     abfd->flags |= HAS_SYMS;
 
@@ -172,28 +196,64 @@ DEFUN(coff_real_object_p,(abfd, nscns, internal_f, internal_a),
   else
     bfd_get_start_address (abfd) = 0;
 
+  /* Set up the tdata area.  ECOFF uses its own routine, and overrides
+     abfd->flags.  */
+  tdata = bfd_coff_mkobject_hook (abfd, (PTR) internal_f, (PTR) internal_a);
+  if (tdata == NULL)
+    return 0;
+
+  scnhsz = bfd_coff_scnhsz (abfd);
+  readsize = nscns * scnhsz;
+  external_sections = (char *) bfd_alloc (abfd, readsize);
+  if (!external_sections)
+    goto fail;
+
+  if (bfd_read ((PTR) external_sections, 1, readsize, abfd) != readsize)
+    goto fail;
+
+  /* Now copy data as required; construct all asections etc */
+  if (nscns != 0)
+    {
+      unsigned int i;
+      for (i = 0; i < nscns; i++)
+       {
+         struct internal_scnhdr tmp;
+         bfd_coff_swap_scnhdr_in (abfd,
+                                  (PTR) (external_sections + i * scnhsz),
+                                  (PTR) & tmp);
+         if (! make_a_section_from_file (abfd, &tmp, i + 1))
+           goto fail;
+       }
+    }
+
+  /*  make_abs_section (abfd); */
+
+  if (bfd_coff_set_arch_mach_hook (abfd, (PTR) internal_f) == false)
+    goto fail;
+
   return abfd->xvec;
+
  fail:
-  bfd_release(abfd, tdata);
-  return (bfd_target *)NULL;
+  bfd_release (abfd, tdata);
+  abfd->flags = oflags;
+  bfd_get_start_address (abfd) = ostart;
+  return (const bfd_target *) NULL;
 }
 
-/* Turn a COFF file into a BFD, but fail with wrong_format if it is
+/* Turn a COFF file into a BFD, but fail with bfd_error_wrong_format if it is
    not a COFF file.  This is also used by ECOFF.  */
 
-bfd_target *
-DEFUN(coff_object_p,(abfd),
-      bfd            *abfd)
+const bfd_target *
+coff_object_p (abfd)
+     bfd *abfd;
 {
   unsigned int filhsz;
   unsigned int aoutsz;
-  int   nscns;
+  int nscns;
   PTR filehdr;
   struct internal_filehdr internal_f;
   struct internal_aouthdr internal_a;
 
-  bfd_error = system_call_error;
-
   /* figure out how much to read */
   filhsz = bfd_coff_filhsz (abfd);
   aoutsz = bfd_coff_aoutsz (abfd);
@@ -201,431 +261,686 @@ DEFUN(coff_object_p,(abfd),
   filehdr = bfd_alloc (abfd, filhsz);
   if (filehdr == NULL)
     return 0;
-  if (bfd_read(filehdr, 1, filhsz, abfd) != filhsz)
-    return 0;
-  bfd_coff_swap_filehdr_in(abfd, filehdr, &internal_f);
+  if (bfd_read (filehdr, 1, filhsz, abfd) != filhsz)
+    {
+      if (bfd_get_error () != bfd_error_system_call)
+       bfd_set_error (bfd_error_wrong_format);
+      return 0;
+    }
+  bfd_coff_swap_filehdr_in (abfd, filehdr, &internal_f);
   bfd_release (abfd, filehdr);
 
-  if (bfd_coff_bad_format_hook (abfd, &internal_f) == false) {
-    bfd_error = wrong_format;
-    return 0;
-  }
-  nscns =internal_f.f_nscns;
-
-  if (internal_f.f_opthdr) {
-    PTR opthdr;
-
-    opthdr = bfd_alloc (abfd, aoutsz);
-    if (opthdr == NULL)
-      return 0;;
-    if (bfd_read(opthdr, 1,aoutsz, abfd) != aoutsz) {
+  if (bfd_coff_bad_format_hook (abfd, &internal_f) == false)
+    {
+      bfd_set_error (bfd_error_wrong_format);
       return 0;
     }
-    bfd_coff_swap_aouthdr_in(abfd, opthdr, (PTR)&internal_a);
-  }
+  nscns = internal_f.f_nscns;
+
+  if (internal_f.f_opthdr)
+    {
+      PTR opthdr;
 
-  /* Seek past the opt hdr stuff */
-  bfd_seek(abfd, (file_ptr) (internal_f.f_opthdr + filhsz), SEEK_SET);
+      opthdr = bfd_alloc (abfd, aoutsz);
+      if (opthdr == NULL)
+       return 0;;
+      if (bfd_read (opthdr, 1, internal_f.f_opthdr, abfd)
+         != internal_f.f_opthdr)
+       {
+         return 0;
+       }
+      bfd_coff_swap_aouthdr_in (abfd, opthdr, (PTR) &internal_a);
+    }
 
-  return coff_real_object_p(abfd, nscns, &internal_f,
-                           (internal_f.f_opthdr != 0
-                            ? &internal_a
-                            : (struct internal_aouthdr *) NULL));
+  return coff_real_object_p (abfd, nscns, &internal_f,
+                            (internal_f.f_opthdr != 0
+                             ? &internal_a
+                             : (struct internal_aouthdr *) NULL));
 }
 
 /* Get the BFD section from a COFF symbol section number.  */
 
-struct sec *
-DEFUN(coff_section_from_bfd_index,(abfd, index),
-      bfd            *abfd AND
-      int             index)
+asection *
+coff_section_from_bfd_index (abfd, index)
+     bfd *abfd;
+     int index;
 {
   struct sec *answer = abfd->sections;
 
-  if (index == N_ABS) 
-  {
-    return &bfd_abs_section;
-  }
+  if (index == N_ABS)
+    return bfd_abs_section_ptr;
   if (index == N_UNDEF)
-  {
-    return &bfd_und_section;
-  }
-  if(index == N_DEBUG)
-  {
-    return &bfd_debug_section;
-    
-  }
-  
-  while (answer) {
+    return bfd_und_section_ptr;
+  if (index == N_DEBUG)
+    return bfd_abs_section_ptr;
+
+  while (answer)
+    {
       if (answer->target_index == index)
-       return answer;
+       return answer;
       answer = answer->next;
     }
-  BFD_ASSERT(0);
-  return &bfd_und_section;     /* For gcc -W and lint.  Never executed. */
+
+  /* We should not reach this point, but the SCO 3.2v4 /lib/libc_s.a
+     has a bad symbol table in biglitpow.o.  */
+  return bfd_und_section_ptr;
 }
 
 /* Get the upper bound of a COFF symbol table.  */
 
-unsigned int
-coff_get_symtab_upper_bound(abfd)
-bfd            *abfd;
+long
+coff_get_symtab_upper_bound (abfd)
+     bfd *abfd;
 {
-  if (!bfd_coff_slurp_symbol_table(abfd))
-    return 0;
+  if (!bfd_coff_slurp_symbol_table (abfd))
+    return -1;
 
-  return (bfd_get_symcount(abfd) + 1) * (sizeof(coff_symbol_type *));
+  return (bfd_get_symcount (abfd) + 1) * (sizeof (coff_symbol_type *));
 }
 
 
 /* Canonicalize a COFF symbol table.  */
 
-unsigned int
-DEFUN(coff_get_symtab, (abfd, alocation),
-      bfd            *abfd AND
-      asymbol       **alocation)
+long
+coff_get_symtab (abfd, alocation)
+     bfd *abfd;
+     asymbol **alocation;
+{
+  unsigned int counter;
+  coff_symbol_type *symbase;
+  coff_symbol_type **location = (coff_symbol_type **) alocation;
+
+  if (!bfd_coff_slurp_symbol_table (abfd))
+    return -1;
+
+  symbase = obj_symbols (abfd);
+  counter = bfd_get_symcount (abfd);
+  while (counter-- > 0)
+    *location++ = symbase++;
+
+  *location = NULL;
+
+  return bfd_get_symcount (abfd);
+}
+
+/* Get the name of a symbol.  The caller must pass in a buffer of size
+   >= SYMNMLEN + 1.  */
+
+const char *
+_bfd_coff_internal_syment_name (abfd, sym, buf)
+     bfd *abfd;
+     const struct internal_syment *sym;
+     char *buf;
 {
-    unsigned int    counter = 0;
-    coff_symbol_type *symbase;
-    coff_symbol_type **location = (coff_symbol_type **) (alocation);
-    if (!bfd_coff_slurp_symbol_table(abfd))
-     return 0;
-
-    symbase = obj_symbols(abfd);
-    while (counter <  bfd_get_symcount(abfd))
-    {
-       /* This nasty code looks at the symbol to decide whether or
-          not it is descibes a constructor/destructor entry point. It
-          is structured this way to (hopefully) speed non matches */
-#if 0  
-       if (0 && symbase->symbol.name[9] == '$') 
+  /* FIXME: It's not clear this will work correctly if sizeof
+     (_n_zeroes) != 4.  */
+  if (sym->_n._n_n._n_zeroes != 0
+      || sym->_n._n_n._n_offset == 0)
+    {
+      memcpy (buf, sym->_n._n_name, SYMNMLEN);
+      buf[SYMNMLEN] = '\0';
+      return buf;
+    }
+  else
+    {
+      const char *strings;
+
+      BFD_ASSERT (sym->_n._n_n._n_offset >= STRING_SIZE_SIZE);
+      strings = obj_coff_strings (abfd);
+      if (strings == NULL)
        {
-           bfd_constructor_entry(abfd, 
-                                (asymbol **)location,
-                                 symbase->symbol.name[10] == 'I' ?
-                                 "CTOR" : "DTOR");
+         strings = _bfd_coff_read_string_table (abfd);
+         if (strings == NULL)
+           return NULL;
        }
-#endif
-       *(location++) = symbase++;
-       counter++;
+      return strings + sym->_n._n_n._n_offset;
+    }
+}
+
+/* Read in and swap the relocs.  This returns a buffer holding the
+   relocs for section SEC in file ABFD.  If CACHE is true and
+   INTERNAL_RELOCS is NULL, the relocs read in will be saved in case
+   the function is called again.  If EXTERNAL_RELOCS is not NULL, it
+   is a buffer large enough to hold the unswapped relocs.  If
+   INTERNAL_RELOCS is not NULL, it is a buffer large enough to hold
+   the swapped relocs.  If REQUIRE_INTERNAL is true, then the return
+   value must be INTERNAL_RELOCS.  The function returns NULL on error.  */
+
+struct internal_reloc *
+_bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs,
+                               require_internal, internal_relocs)
+     bfd *abfd;
+     asection *sec;
+     boolean cache;
+     bfd_byte *external_relocs;
+     boolean require_internal;
+     struct internal_reloc *internal_relocs;
+{
+  bfd_size_type relsz;
+  bfd_byte *free_external = NULL;
+  struct internal_reloc *free_internal = NULL;
+  bfd_byte *erel;
+  bfd_byte *erel_end;
+  struct internal_reloc *irel;
+
+  if (coff_section_data (abfd, sec) != NULL
+      && coff_section_data (abfd, sec)->relocs != NULL)
+    {
+      if (! require_internal)
+       return coff_section_data (abfd, sec)->relocs;
+      memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs,
+             sec->reloc_count * sizeof (struct internal_reloc));
+      return internal_relocs;
+    }
+
+  relsz = bfd_coff_relsz (abfd);
+
+  if (external_relocs == NULL)
+    {
+      free_external = (bfd_byte *) bfd_malloc (sec->reloc_count * relsz);
+      if (free_external == NULL && sec->reloc_count > 0)
+       goto error_return;
+      external_relocs = free_external;
+    }
+
+  if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
+      || (bfd_read (external_relocs, relsz, sec->reloc_count, abfd)
+         != relsz * sec->reloc_count))
+    goto error_return;
+
+  if (internal_relocs == NULL)
+    {
+      free_internal = ((struct internal_reloc *)
+                      bfd_malloc (sec->reloc_count
+                                  * sizeof (struct internal_reloc)));
+      if (free_internal == NULL && sec->reloc_count > 0)
+       goto error_return;
+      internal_relocs = free_internal;
+    }
+
+  /* Swap in the relocs.  */
+  erel = external_relocs;
+  erel_end = erel + relsz * sec->reloc_count;
+  irel = internal_relocs;
+  for (; erel < erel_end; erel += relsz, irel++)
+    bfd_coff_swap_reloc_in (abfd, (PTR) erel, (PTR) irel);
+
+  if (free_external != NULL)
+    {
+      free (free_external);
+      free_external = NULL;
+    }
+
+  if (cache && free_internal != NULL)
+    {
+      if (coff_section_data (abfd, sec) == NULL)
+       {
+         sec->used_by_bfd =
+           (PTR) bfd_zalloc (abfd,
+                             sizeof (struct coff_section_tdata));
+         if (sec->used_by_bfd == NULL)
+           goto error_return;
+         coff_section_data (abfd, sec)->contents = NULL;
+       }
+      coff_section_data (abfd, sec)->relocs = free_internal;
     }
-    *location++ = 0;
-    return bfd_get_symcount(abfd);
+
+  return internal_relocs;
+
+ error_return:
+  if (free_external != NULL)
+    free (free_external);
+  if (free_internal != NULL)
+    free (free_internal);
+  return NULL;
 }
 
 /* Set lineno_count for the output sections of a COFF file.  */
 
 int
-DEFUN(coff_count_linenumbers,(abfd),
-      bfd            *abfd)
+coff_count_linenumbers (abfd)
+     bfd *abfd;
 {
-  unsigned int    limit = bfd_get_symcount(abfd);
-  unsigned int    i;
+  unsigned int limit = bfd_get_symcount (abfd);
+  unsigned int i;
   int total = 0;
-  asymbol       **p;
- {
-   asection       *s = abfd->sections->output_section;
-   while (s) {
-     BFD_ASSERT(s->lineno_count == 0);
-     s = s->next;
-   }
- }
-
-
-  for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) {
-    asymbol        *q_maybe = *p;
-    if (bfd_asymbol_flavour(q_maybe) == bfd_target_coff_flavour) {
-      coff_symbol_type *q = coffsymbol(q_maybe);
-      if (q->lineno) {
-       /*
-         This symbol has a linenumber, increment the owning
-         section's linenumber count
-         */
-       alent          *l = q->lineno;
-       q->symbol.section->output_section->lineno_count++;
-       total ++;
-       l++;
-       while (l->line_number) {
-         total ++;
-         q->symbol.section->output_section->lineno_count++;
-         l++;
+  asymbol **p;
+  asection *s;
+
+  if (limit == 0)
+    {
+      /* This may be from the backend linker, in which case the
+         lineno_count in the sections is correct.  */
+      for (s = abfd->sections; s != NULL; s = s->next)
+       total += s->lineno_count;
+      return total;
+    }
+
+  for (s = abfd->sections; s != NULL; s = s->next)
+    BFD_ASSERT (s->lineno_count == 0);
+
+  for (p = abfd->outsymbols, i = 0; i < limit; i++, p++)
+    {
+      asymbol *q_maybe = *p;
+
+      if (bfd_asymbol_flavour (q_maybe) == bfd_target_coff_flavour)
+       {
+         coff_symbol_type *q = coffsymbol (q_maybe);
+
+         /* The AIX 4.1 compiler can sometimes generate line numbers
+             attached to debugging symbols.  We try to simply ignore
+             those here.  */
+         if (q->lineno != NULL
+             && q->symbol.section->owner != NULL)
+           {
+             /* This symbol has line numbers.  Increment the owning
+                section's linenumber count.  */
+             alent *l = q->lineno;
+
+             ++q->symbol.section->output_section->lineno_count;
+             ++total;
+             ++l;
+             while (l->line_number != 0)
+               {
+                 ++total;
+                 ++q->symbol.section->output_section->lineno_count;
+                 ++l;
+               }
+           }
        }
-      }
     }
-  }
+
   return total;
 }
 
 /* Takes a bfd and a symbol, returns a pointer to the coff specific
    area of the symbol if there is one.  */
 
+/*ARGSUSED*/
 coff_symbol_type *
-DEFUN(coff_symbol_from,(ignore_abfd, symbol),
-      bfd            *ignore_abfd AND
-      asymbol        *symbol)
+coff_symbol_from (ignore_abfd, symbol)
+     bfd *ignore_abfd;
+     asymbol *symbol;
 {
-  if (bfd_asymbol_flavour(symbol) != bfd_target_coff_flavour)
-    return (coff_symbol_type *)NULL;
+  if (bfd_asymbol_flavour (symbol) != bfd_target_coff_flavour)
+    return (coff_symbol_type *) NULL;
 
-  if (bfd_asymbol_bfd(symbol)->tdata.coff_obj_data == (coff_data_type*)NULL)
-    return (coff_symbol_type *)NULL;
+  if (bfd_asymbol_bfd (symbol)->tdata.coff_obj_data == (coff_data_type *) NULL)
+    return (coff_symbol_type *) NULL;
 
-  return  (coff_symbol_type *) symbol;
+  return (coff_symbol_type *) symbol;
 }
 
 static void
-DEFUN(fixup_symbol_value,(coff_symbol_ptr, syment),
-coff_symbol_type *coff_symbol_ptr AND
-struct internal_syment *syment)
+fixup_symbol_value (abfd, coff_symbol_ptr, syment)
+     bfd *abfd;
+     coff_symbol_type *coff_symbol_ptr;
+     struct internal_syment *syment;
 {
 
   /* Normalize the symbol flags */
-  if (bfd_is_com_section (coff_symbol_ptr->symbol.section)) {
-    /* a common symbol is undefined with a value */
-    syment->n_scnum = N_UNDEF;
-    syment->n_value = coff_symbol_ptr->symbol.value;
-  }
-  else if (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING) {
-    syment->n_value = coff_symbol_ptr->symbol.value;
-  }
-  else if (coff_symbol_ptr->symbol.section == & bfd_und_section) {
-    syment->n_scnum = N_UNDEF;
-    syment->n_value = 0;
-  }
-  else {
-    if (coff_symbol_ptr->symbol.section) {
-      syment->n_scnum   =
-       coff_symbol_ptr->symbol.section->output_section->target_index;
-
-      syment->n_value =
-       coff_symbol_ptr->symbol.value +
-       coff_symbol_ptr->symbol.section->output_offset +
-        coff_symbol_ptr->symbol.section->output_section->vma;
-    }
-    else {
-       BFD_ASSERT(0);
-      /* This can happen, but I don't know why yet (steve@cygnus.com) */
-      syment->n_scnum = N_ABS;
+  if (bfd_is_com_section (coff_symbol_ptr->symbol.section))
+    {
+      /* a common symbol is undefined with a value */
+      syment->n_scnum = N_UNDEF;
       syment->n_value = coff_symbol_ptr->symbol.value;
     }
-  }
+  else if (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING)
+    {
+      syment->n_value = coff_symbol_ptr->symbol.value;
+    }
+  else if (bfd_is_und_section (coff_symbol_ptr->symbol.section))
+    {
+      syment->n_scnum = N_UNDEF;
+      syment->n_value = 0;
+    }
+  else
+    {
+      if (coff_symbol_ptr->symbol.section)
+       {
+         syment->n_scnum =
+           coff_symbol_ptr->symbol.section->output_section->target_index;
+
+         syment->n_value = (coff_symbol_ptr->symbol.value
+                            + coff_symbol_ptr->symbol.section->output_offset);
+         if (! obj_pe (abfd))
+           syment->n_value +=
+             coff_symbol_ptr->symbol.section->output_section->vma;
+       }
+      else
+       {
+         BFD_ASSERT (0);
+         /* This can happen, but I don't know why yet (steve@cygnus.com) */
+         syment->n_scnum = N_ABS;
+         syment->n_value = coff_symbol_ptr->symbol.value;
+       }
+    }
 }
 
-/* run through all the symbols in the symbol table and work out what
-   their indexes into the symbol table will be when output
+/* Run through all the symbols in the symbol table and work out what
+   their indexes into the symbol table will be when output.
 
- Coff requires that each C_FILE symbol points to the next one in the
- chain, and that the last one points to the first external symbol. We
- do that here too.
  Coff requires that each C_FILE symbol points to the next one in the
  chain, and that the last one points to the first external symbol. We
+   do that here too.  */
 
-*/
-void
-DEFUN(coff_renumber_symbols,(bfd_ptr),
-      bfd *bfd_ptr)
+boolean
+coff_renumber_symbols (bfd_ptr, first_undef)
+     bfd *bfd_ptr;
+     int *first_undef;
 {
-  unsigned int symbol_count = bfd_get_symcount(bfd_ptr);
+  unsigned int symbol_count = bfd_get_symcount (bfd_ptr);
   asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols;
   unsigned int native_index = 0;
-  struct internal_syment *last_file = (struct internal_syment *)NULL;
+  struct internal_syment *last_file = (struct internal_syment *) NULL;
   unsigned int symbol_index;
 
   /* COFF demands that undefined symbols come after all other symbols.
-     Since we don't need to impose this extra knowledge on all our client
-     programs, deal with that here.  Sort the symbol table; just move the
-     undefined symbols to the end, leaving the rest alone.  */
+     Since we don't need to impose this extra knowledge on all our
+     client programs, deal with that here.  Sort the symbol table;
+     just move the undefined symbols to the end, leaving the rest
+     alone.  The O'Reilly book says that defined global symbols come
+     at the end before the undefined symbols, so we do that here as
+     well.  */
   /* @@ Do we have some condition we could test for, so we don't always
      have to do this?  I don't think relocatability is quite right, but
      I'm not certain.  [raeburn:19920508.1711EST]  */
   {
     asymbol **newsyms;
-    int i;
+    unsigned int i;
 
-    newsyms = (asymbol **) bfd_alloc_by_size_t (bfd_ptr,
-                                               sizeof (asymbol *)
-                                               * (symbol_count + 1));
+    newsyms = (asymbol **) bfd_alloc (bfd_ptr,
+                                     sizeof (asymbol *) * (symbol_count + 1));
+    if (!newsyms)
+      return false;
     bfd_ptr->outsymbols = newsyms;
     for (i = 0; i < symbol_count; i++)
-      if (symbol_ptr_ptr[i]->section != &bfd_und_section)
+      if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) != 0
+         || (!bfd_is_und_section (symbol_ptr_ptr[i]->section)
+             && !bfd_is_com_section (symbol_ptr_ptr[i]->section)
+             && ((symbol_ptr_ptr[i]->flags & BSF_FUNCTION) != 0
+                 || ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_WEAK))
+                     == 0))))
+       *newsyms++ = symbol_ptr_ptr[i];
+
+    for (i = 0; i < symbol_count; i++)
+      if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0
+         && !bfd_is_und_section (symbol_ptr_ptr[i]->section)
+         && (bfd_is_com_section (symbol_ptr_ptr[i]->section)
+             || ((symbol_ptr_ptr[i]->flags & BSF_FUNCTION) == 0
+                 && ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_WEAK))
+                     != 0))))
        *newsyms++ = symbol_ptr_ptr[i];
+
+    *first_undef = newsyms - bfd_ptr->outsymbols;
+
     for (i = 0; i < symbol_count; i++)
-      if (symbol_ptr_ptr[i]->section == &bfd_und_section)
+      if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0
+         && bfd_is_und_section (symbol_ptr_ptr[i]->section))
        *newsyms++ = symbol_ptr_ptr[i];
     *newsyms = (asymbol *) NULL;
     symbol_ptr_ptr = bfd_ptr->outsymbols;
   }
 
   for (symbol_index = 0; symbol_index < symbol_count; symbol_index++)
-      {
-       coff_symbol_type *coff_symbol_ptr = coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]);
-       if (coff_symbol_ptr && coff_symbol_ptr->native) {
+    {
+      coff_symbol_type *coff_symbol_ptr = coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]);
+      symbol_ptr_ptr[symbol_index]->udata.i = symbol_index; 
+      if (coff_symbol_ptr && coff_symbol_ptr->native)
+       {
          combined_entry_type *s = coff_symbol_ptr->native;
          int i;
 
          if (s->u.syment.n_sclass == C_FILE)
-             {
-               if (last_file != (struct internal_syment *)NULL) {
-                 last_file->n_value = native_index;
-               }
-               last_file = &(s->u.syment);
-             }
-         else {
-
-           /* Modify the symbol values according to their section and
-              type */
-
-           fixup_symbol_value(coff_symbol_ptr, &(s->u.syment));
-         }
-         for (i = 0; i < s->u.syment.n_numaux + 1; i++) {
-           s[i].offset = native_index ++;
-         }
+           {
+             if (last_file != (struct internal_syment *) NULL)
+               last_file->n_value = native_index;
+             last_file = &(s->u.syment);
+           }
+         else
+           {
+
+             /* Modify the symbol values according to their section and
+                type */
+
+             fixup_symbol_value (bfd_ptr, coff_symbol_ptr, &(s->u.syment));
+           }
+         for (i = 0; i < s->u.syment.n_numaux + 1; i++)
+           s[i].offset = native_index++;
        }
-       else {
+      else
+       {
          native_index++;
        }
-      }
+    }
   obj_conv_table_size (bfd_ptr) = native_index;
+
+  return true;
 }
 
-/*
- Run thorough the symbol table again, and fix it so that all pointers to
- entries are changed to the entries' index in the output symbol table.
+/* Run thorough the symbol table again, and fix it so that all
+   pointers to entries are changed to the entries' index in the output
+   symbol table.  */
 
-*/
 void
-DEFUN(coff_mangle_symbols,(bfd_ptr),
-      bfd *bfd_ptr)
+coff_mangle_symbols (bfd_ptr)
+     bfd *bfd_ptr;
 {
-  unsigned int symbol_count = bfd_get_symcount(bfd_ptr);
+  unsigned int symbol_count = bfd_get_symcount (bfd_ptr);
   asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols;
   unsigned int symbol_index;
 
   for (symbol_index = 0; symbol_index < symbol_count; symbol_index++)
-      {
-       coff_symbol_type *coff_symbol_ptr =
-         coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]);
+    {
+      coff_symbol_type *coff_symbol_ptr =
+      coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]);
 
-       if (coff_symbol_ptr && coff_symbol_ptr->native) {
+      if (coff_symbol_ptr && coff_symbol_ptr->native)
+       {
          int i;
          combined_entry_type *s = coff_symbol_ptr->native;
 
-         for (i = 0; i < s->u.syment.n_numaux ; i++) {
-           combined_entry_type *a = s + i + 1;
-           if (a->fix_tag) {
-             a->u.auxent.x_sym.x_tagndx.l =
-               a->u.auxent.x_sym.x_tagndx.p->offset;
-             a->fix_tag = 0;
+         if (s->fix_value)
+           {
+             /* FIXME: We should use a union here.  */
+             s->u.syment.n_value =
+               ((combined_entry_type *) s->u.syment.n_value)->offset;
+             s->fix_value = 0;
            }
-           if (a->fix_end) {
-             a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l =
-               a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset;
-             a->fix_end = 0;
-             
+         if (s->fix_line)
+           {
+             /* The value is the offset into the line number entries
+                 for the symbol's section.  On output, the symbol's
+                 section should be N_DEBUG.  */
+             s->u.syment.n_value =
+               (coff_symbol_ptr->symbol.section->output_section->line_filepos
+                + s->u.syment.n_value * bfd_coff_linesz (bfd_ptr));
+             coff_symbol_ptr->symbol.section =
+               coff_section_from_bfd_index (bfd_ptr, N_DEBUG);
+             BFD_ASSERT (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING);
+           }
+         for (i = 0; i < s->u.syment.n_numaux; i++)
+           {
+             combined_entry_type *a = s + i + 1;
+             if (a->fix_tag)
+               {
+                 a->u.auxent.x_sym.x_tagndx.l =
+                   a->u.auxent.x_sym.x_tagndx.p->offset;
+                 a->fix_tag = 0;
+               }
+             if (a->fix_end)
+               {
+                 a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l =
+                   a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset;
+                 a->fix_end = 0;
+               }
+             if (a->fix_scnlen)
+               {
+                 a->u.auxent.x_csect.x_scnlen.l =
+                   a->u.auxent.x_csect.x_scnlen.p->offset;
+                 a->fix_scnlen = 0;
+               }
            }
-
-         }
        }
-      }
+    }
 }
 
-static int string_size;
-
 static void
-DEFUN(coff_fix_symbol_name,(abfd, symbol, native),
-  bfd *abfd AND
-  asymbol *symbol AND
-  combined_entry_type *native)
+coff_fix_symbol_name (abfd, symbol, native, string_size_p,
+                     debug_string_section_p, debug_string_size_p)
+     bfd *abfd;
+     asymbol *symbol;
+     combined_entry_type *native;
+     bfd_size_type *string_size_p;
+     asection **debug_string_section_p;
+     bfd_size_type *debug_string_size_p;
 {
-  unsigned int    name_length;
+  unsigned int name_length;
   union internal_auxent *auxent;
-  char *  name = ( char *)(symbol->name);
+  char *name = (char *) (symbol->name);
 
-  if (name == (char *) NULL) {
-    /* coff symbols always have names, so we'll make one up */
-    symbol->name = "strange";
-    name = (char *)symbol->name;
-  }
-  name_length = strlen(name);
+  if (name == (char *) NULL)
+    {
+      /* coff symbols always have names, so we'll make one up */
+      symbol->name = "strange";
+      name = (char *) symbol->name;
+    }
+  name_length = strlen (name);
 
-  if (native->u.syment.n_sclass == C_FILE) {
-    strncpy(native->u.syment._n._n_name, ".file", SYMNMLEN);
-    auxent = &(native+1)->u.auxent;
+  if (native->u.syment.n_sclass == C_FILE
+      && native->u.syment.n_numaux > 0)
+    {
+      strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN);
+      auxent = &(native + 1)->u.auxent;
 
-    if (bfd_coff_long_filenames (abfd)) {
-      if (name_length <= FILNMLEN) {
-       strncpy(auxent->x_file.x_fname, name, FILNMLEN);
-      }
-      else {
-       auxent->x_file.x_n.x_offset = string_size + 4;
-       auxent->x_file.x_n.x_zeroes = 0;
-       string_size += name_length + 1;
-      }
-    }
-    else {
-      strncpy(auxent->x_file.x_fname, name, FILNMLEN);
-      if (name_length > FILNMLEN) {
-       name[FILNMLEN] = '\0';
-      }
+      if (bfd_coff_long_filenames (abfd))
+       {
+         if (name_length <= FILNMLEN)
+           {
+             strncpy (auxent->x_file.x_fname, name, FILNMLEN);
+           }
+         else
+           {
+             auxent->x_file.x_n.x_offset = *string_size_p + STRING_SIZE_SIZE;
+             auxent->x_file.x_n.x_zeroes = 0;
+             *string_size_p += name_length + 1;
+           }
+       }
+      else
+       {
+         strncpy (auxent->x_file.x_fname, name, FILNMLEN);
+         if (name_length > FILNMLEN)
+           {
+             name[FILNMLEN] = '\0';
+           }
+       }
     }
-  }
   else
-      {                                /* NOT A C_FILE SYMBOL */
-       if (name_length <= SYMNMLEN) {
+    {
+      if (name_length <= SYMNMLEN)
+       {
          /* This name will fit into the symbol neatly */
-         strncpy(native->u.syment._n._n_name, symbol->name, SYMNMLEN);
+         strncpy (native->u.syment._n._n_name, symbol->name, SYMNMLEN);
        }
-       else {
-         native->u.syment._n._n_n._n_offset =  string_size + 4;
+      else if (!bfd_coff_symname_in_debug (abfd, &native->u.syment))
+       {
+         native->u.syment._n._n_n._n_offset = (*string_size_p
+                                               + STRING_SIZE_SIZE);
          native->u.syment._n._n_n._n_zeroes = 0;
-         string_size += name_length + 1;
+         *string_size_p += name_length + 1;
        }
-      }
+      else
+       {
+         long filepos;
+         bfd_byte buf[2];
+
+         /* This name should be written into the .debug section.  For
+            some reason each name is preceded by a two byte length
+            and also followed by a null byte.  FIXME: We assume that
+            the .debug section has already been created, and that it
+            is large enough.  */
+         if (*debug_string_section_p == (asection *) NULL)
+           *debug_string_section_p = bfd_get_section_by_name (abfd, ".debug");
+         filepos = bfd_tell (abfd);
+         bfd_put_16 (abfd, name_length + 1, buf);
+         if (!bfd_set_section_contents (abfd,
+                                        *debug_string_section_p,
+                                        (PTR) buf,
+                                        (file_ptr) *debug_string_size_p,
+                                        (bfd_size_type) 2)
+             || !bfd_set_section_contents (abfd,
+                                           *debug_string_section_p,
+                                           (PTR) symbol->name,
+                                           ((file_ptr) *debug_string_size_p
+                                            + 2),
+                                           (bfd_size_type) name_length + 1))
+           abort ();
+         if (bfd_seek (abfd, filepos, SEEK_SET) != 0)
+           abort ();
+         native->u.syment._n._n_n._n_offset = *debug_string_size_p + 2;
+         native->u.syment._n._n_n._n_zeroes = 0;
+         *debug_string_size_p += name_length + 3;
+       }
+    }
 }
 
-#define        set_index(symbol, idx)  ((symbol)->udata =(PTR) (idx))
+/* We need to keep track of the symbol index so that when we write out
+   the relocs we can get the index for a symbol.  This method is a
+   hack.  FIXME.  */
 
-static unsigned int
-DEFUN(coff_write_symbol,(abfd, symbol, native, written),
-bfd *abfd AND
-asymbol *symbol AND
-combined_entry_type *native AND
-unsigned int written)
+#define set_index(symbol, idx) ((symbol)->udata.i = (idx))
+
+/* Write a symbol out to a COFF file.  */
+
+static boolean
+coff_write_symbol (abfd, symbol, native, written, string_size_p,
+                  debug_string_section_p, debug_string_size_p)
+     bfd *abfd;
+     asymbol *symbol;
+     combined_entry_type *native;
+     unsigned int *written;
+     bfd_size_type *string_size_p;
+     asection **debug_string_section_p;
+     bfd_size_type *debug_string_size_p;
 {
-  unsigned int    numaux = native->u.syment.n_numaux;
-  int             type = native->u.syment.n_type;
-  int             class =  native->u.syment.n_sclass;
+  unsigned int numaux = native->u.syment.n_numaux;
+  int type = native->u.syment.n_type;
+  int class = native->u.syment.n_sclass;
   PTR buf;
   bfd_size_type symesz;
 
-  /* @@ bfd_debug_section isn't accessible outside this file, but we know
-     that C_FILE symbols belong there.  So move them.  */
   if (native->u.syment.n_sclass == C_FILE)
-    symbol->section = &bfd_debug_section;
+    symbol->flags |= BSF_DEBUGGING;
 
-  if (symbol->section == &bfd_abs_section) 
-  {
-    native->u.syment.n_scnum = N_ABS;
-  }
-  else if (symbol->section == &bfd_debug_section) 
-  {
-    native->u.syment.n_scnum = N_DEBUG;
-  }
-  else if (symbol->section == &bfd_und_section)   
-  {
-    native->u.syment.n_scnum = N_UNDEF;
-  }
-  else 
-  {
-    native->u.syment.n_scnum =
-     symbol->section->output_section->target_index;
-  }
-  
-  
-  coff_fix_symbol_name(abfd, symbol, native);
+  if (symbol->flags & BSF_DEBUGGING
+      && bfd_is_abs_section (symbol->section))
+    {
+      native->u.syment.n_scnum = N_DEBUG;
+    }
+  else if (bfd_is_abs_section (symbol->section))
+    {
+      native->u.syment.n_scnum = N_ABS;
+    }
+  else if (bfd_is_und_section (symbol->section))
+    {
+      native->u.syment.n_scnum = N_UNDEF;
+    }
+  else
+    {
+      native->u.syment.n_scnum =
+       symbol->section->output_section->target_index;
+    }
+
+  coff_fix_symbol_name (abfd, symbol, native, string_size_p,
+                       debug_string_section_p, debug_string_size_p);
 
   symesz = bfd_coff_symesz (abfd);
   buf = bfd_alloc (abfd, symesz);
-  bfd_coff_swap_sym_out(abfd, &native->u.syment, buf);
-  bfd_write(buf, 1, symesz, abfd);
+  if (!buf)
+    return false;
+  bfd_coff_swap_sym_out (abfd, &native->u.syment, buf);
+  if (bfd_write (buf, 1, symesz, abfd) != symesz)
+    return false;
   bfd_release (abfd, buf);
 
   if (native->u.syment.n_numaux > 0)
@@ -635,271 +950,418 @@ unsigned int written)
 
       auxesz = bfd_coff_auxesz (abfd);
       buf = bfd_alloc (abfd, auxesz);
-      for (j = 0; j < native->u.syment.n_numaux;  j++)
+      if (!buf)
+       return false;
+      for (j = 0; j < native->u.syment.n_numaux; j++)
        {
-         bfd_coff_swap_aux_out(abfd,
-                               &((native + j + 1)->u.auxent),
-                               type,
-                               class,
-                               buf);
-         bfd_write(buf, 1, auxesz, abfd);
+         bfd_coff_swap_aux_out (abfd,
+                                &((native + j + 1)->u.auxent),
+                                type,
+                                class,
+                                j,
+                                native->u.syment.n_numaux,
+                                buf);
+         if (bfd_write (buf, 1, auxesz, abfd) != auxesz)
+           return false;
        }
       bfd_release (abfd, buf);
     }
-  /*
-    Reuse somewhere in the symbol to keep the index
-    */
-  set_index(symbol, written);
-  return   written + 1 + numaux;
+
+  /* Store the index for use when we write out the relocs.  */
+  set_index (symbol, *written);
+
+  *written += numaux + 1;
+  return true;
 }
 
+/* Write out a symbol to a COFF file that does not come from a COFF
+   file originally.  This symbol may have been created by the linker,
+   or we may be linking a non COFF file to a COFF file.  */
 
-static unsigned int
-DEFUN(coff_write_alien_symbol,(abfd, symbol, written),
-      bfd *abfd AND
-      asymbol *symbol AND
-      unsigned int written)
+static boolean
+coff_write_alien_symbol (abfd, symbol, written, string_size_p,
+                        debug_string_section_p, debug_string_size_p)
+     bfd *abfd;
+     asymbol *symbol;
+     unsigned int *written;
+     bfd_size_type *string_size_p;
+     asection **debug_string_section_p;
+     bfd_size_type *debug_string_size_p;
 {
-  /*
-    This symbol has been created by the loader, or come from a non
-    coff format. It  has no native element to inherit, make our
-    own
-    */
   combined_entry_type *native;
   combined_entry_type dummy;
+
   native = &dummy;
-  native->u.syment.n_type =  T_NULL;
-  native->u.syment.n_flags =  0;
-  if (symbol->section == &bfd_und_section) 
-  {
-      native->u.syment.n_scnum =  N_UNDEF;
-      native->u.syment.n_value =  symbol->value;
+  native->u.syment.n_type = T_NULL;
+  native->u.syment.n_flags = 0;
+  if (bfd_is_und_section (symbol->section))
+    {
+      native->u.syment.n_scnum = N_UNDEF;
+      native->u.syment.n_value = symbol->value;
     }
   else if (bfd_is_com_section (symbol->section))
-  {
-      native->u.syment.n_scnum =  N_UNDEF;
-      native->u.syment.n_value =  symbol->value;
-
-  }
-  
-  else if (symbol->flags & BSF_DEBUGGING) {
-      /*
-       remove name so it doesn't take up any space
-       */
-      symbol->name = "";
+    {
+      native->u.syment.n_scnum = N_UNDEF;
+      native->u.syment.n_value = symbol->value;
     }
-  else {
-      native->u.syment.n_scnum  =   symbol->section->output_section->target_index;
-      native->u.syment.n_value =   symbol->value +
-       symbol->section->output_section->vma +
-       symbol->section->output_offset;
-      /* Copy the any flags from the the file hdr into the symbol  */
+  else if (symbol->flags & BSF_DEBUGGING)
     {
-      coff_symbol_type *c = coff_symbol_from(abfd, symbol);
-      if (c != (coff_symbol_type *)NULL) {
-         native->u.syment.n_flags =   bfd_asymbol_bfd(&c->symbol)->flags;
-       }
+      /* There isn't much point to writing out a debugging symbol
+         unless we are prepared to convert it into COFF debugging
+         format.  So, we just ignore them.  We must clobber the symbol
+         name to keep it from being put in the string table.  */
+      symbol->name = "";
+      return true;
     }
+  else
+    {
+      native->u.syment.n_scnum =
+       symbol->section->output_section->target_index;
+      native->u.syment.n_value = (symbol->value
+                                 + symbol->section->output_offset);
+      if (! obj_pe (abfd))
+       native->u.syment.n_value += symbol->section->output_section->vma;
+
+      /* Copy the any flags from the the file header into the symbol.
+         FIXME: Why?  */
+      {
+       coff_symbol_type *c = coff_symbol_from (abfd, symbol);
+       if (c != (coff_symbol_type *) NULL)
+         native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags;
+      }
     }
 
-  native->u.syment.n_type =  0;
+  native->u.syment.n_type = 0;
   if (symbol->flags & BSF_LOCAL)
-   native->u.syment.n_sclass =  C_STAT;
+    native->u.syment.n_sclass = C_STAT;
+  else if (symbol->flags & BSF_WEAK)
+    native->u.syment.n_sclass = obj_pe (abfd) ? C_NT_WEAK : C_WEAKEXT;
   else
-   native->u.syment.n_sclass =  C_EXT;
-  native->u.syment.n_numaux =  0;
+    native->u.syment.n_sclass = C_EXT;
+  native->u.syment.n_numaux = 0;
 
-  return   coff_write_symbol(abfd, symbol, native, written);
+  return coff_write_symbol (abfd, symbol, native, written, string_size_p,
+                           debug_string_section_p, debug_string_size_p);
 }
 
-static unsigned int
-DEFUN(coff_write_native_symbol,(abfd, symbol,   written),
-bfd *abfd AND
-coff_symbol_type *symbol AND
-unsigned int written)
+/* Write a native symbol to a COFF file.  */
+
+static boolean
+coff_write_native_symbol (abfd, symbol, written, string_size_p,
+                         debug_string_section_p, debug_string_size_p)
+     bfd *abfd;
+     coff_symbol_type *symbol;
+     unsigned int *written;
+     bfd_size_type *string_size_p;
+     asection **debug_string_section_p;
+     bfd_size_type *debug_string_size_p;
 {
-  /*
-    Does this symbol have an ascociated line number - if so then
-    make it remember this symbol index. Also tag the auxent of
-    this symbol to point to the right place in the lineno table
-    */
   combined_entry_type *native = symbol->native;
+  alent *lineno = symbol->lineno;
 
-  alent          *lineno = symbol->lineno;
-
-  if (lineno && !symbol->done_lineno) {
-    unsigned int    count = 0;
-    lineno[count].u.offset = written;
-    if (native->u.syment.n_numaux) {
-      union internal_auxent  *a = &((native+1)->u.auxent);
+  /* If this symbol has an associated line number, we must store the
+     symbol index in the line number field.  We also tag the auxent to
+     point to the right place in the lineno table.  */
+  if (lineno && !symbol->done_lineno && symbol->symbol.section->owner != NULL)
+    {
+      unsigned int count = 0;
+      lineno[count].u.offset = *written;
+      if (native->u.syment.n_numaux)
+       {
+         union internal_auxent *a = &((native + 1)->u.auxent);
 
-      a->x_sym.x_fcnary.x_fcn.x_lnnoptr =
-       symbol->symbol.section->output_section->moving_line_filepos;
-    }
-    /*
-      And count and relocate all other linenumbers
-      */
+         a->x_sym.x_fcnary.x_fcn.x_lnnoptr =
+           symbol->symbol.section->output_section->moving_line_filepos;
+       }
 
-    count++;
-    while (lineno[count].line_number) {
+      /* Count and relocate all other linenumbers.  */
+      count++;
+      while (lineno[count].line_number != 0)
+       {
 #if 0
-/* 13 april 92. sac 
-I've been told this, but still need proof:
-> The second bug is also in `bfd/coffcode.h'.  This bug causes the linker to screw
-> up the pc-relocations for all the line numbers in COFF code.  This bug isn't
-> only specific to A29K implementations, but affects all systems using COFF
-> format binaries.  Note that in COFF object files, the line number core offsets
-> output by the assembler are relative to the start of each procedure, not
-> to the start of the .text section.  This patch relocates the line numbers
-> relative to the `native->u.syment.n_value' instead of the section virtual
-> address.  modular!olson@cs.arizona.edu (Jon Olson)
-*/
-       lineno[count].u.offset += native->u.syment.n_value;
-
+         /* 13 april 92. sac 
+            I've been told this, but still need proof:
+            > The second bug is also in `bfd/coffcode.h'.  This bug
+            > causes the linker to screw up the pc-relocations for
+            > all the line numbers in COFF code.  This bug isn't only
+            > specific to A29K implementations, but affects all
+            > systems using COFF format binaries.  Note that in COFF
+            > object files, the line number core offsets output by
+            > the assembler are relative to the start of each
+            > procedure, not to the start of the .text section.  This
+            > patch relocates the line numbers relative to the
+            > `native->u.syment.n_value' instead of the section
+            > virtual address.
+            > modular!olson@cs.arizona.edu (Jon Olson)
+          */
+         lineno[count].u.offset += native->u.syment.n_value;
 #else
-      lineno[count].u.offset +=
-       symbol->symbol.section->output_section->vma +
-         symbol->symbol.section->output_offset;
+         lineno[count].u.offset +=
+           (symbol->symbol.section->output_section->vma
+            + symbol->symbol.section->output_offset);
 #endif
-      count++;
+         count++;
+       }
+      symbol->done_lineno = true;
+
+      symbol->symbol.section->output_section->moving_line_filepos +=
+       count * bfd_coff_linesz (abfd);
     }
-    symbol->done_lineno = true;
-    
-    symbol->symbol.section->output_section->moving_line_filepos +=
-      count * bfd_coff_linesz (abfd);
-  }
-  return coff_write_symbol(abfd, &( symbol->symbol), native,written);
+
+  return coff_write_symbol (abfd, &(symbol->symbol), native, written,
+                           string_size_p, debug_string_section_p,
+                           debug_string_size_p);
 }
 
-void
-DEFUN(coff_write_symbols,(abfd),
-      bfd            *abfd)
-{
-  unsigned int    i;
-  unsigned int    limit = bfd_get_symcount(abfd);
-  unsigned int    written = 0;
+/* Write out the COFF symbols.  */
 
-  asymbol       **p;
+boolean
+coff_write_symbols (abfd)
+     bfd *abfd;
+{
+  bfd_size_type string_size;
+  asection *debug_string_section;
+  bfd_size_type debug_string_size;
+  unsigned int i;
+  unsigned int limit = bfd_get_symcount (abfd);
+  unsigned int written = 0;
+  asymbol **p;
 
   string_size = 0;
+  debug_string_section = NULL;
+  debug_string_size = 0;
+
+  /* If this target supports long section names, they must be put into
+     the string table.  This is supported by PE.  This code must
+     handle section names just as they are handled in
+     coff_write_object_contents.  */
+  if (bfd_coff_long_section_names (abfd))
+    {
+      asection *o;
 
+      for (o = abfd->sections; o != NULL; o = o->next)
+       {
+         size_t len;
+
+         len = strlen (o->name);
+         if (len > SCNNMLEN)
+           string_size += len + 1;
+       }
+    }
 
   /* Seek to the right place */
-  bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET);
+  if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0)
+    return false;
 
   /* Output all the symbols we have */
 
   written = 0;
   for (p = abfd->outsymbols, i = 0; i < limit; i++, p++)
-      {
-       asymbol        *symbol = *p;
-       coff_symbol_type *c_symbol = coff_symbol_from(abfd, symbol);
+    {
+      asymbol *symbol = *p;
+      coff_symbol_type *c_symbol = coff_symbol_from (abfd, symbol);
 
-       if (c_symbol == (coff_symbol_type *) NULL ||
-           c_symbol->native == (combined_entry_type *)NULL)
+      if (c_symbol == (coff_symbol_type *) NULL
+         || c_symbol->native == (combined_entry_type *) NULL)
+       {
+         if (!coff_write_alien_symbol (abfd, symbol, &written, &string_size,
+                                       &debug_string_section,
+                                       &debug_string_size))
+           return false;
+       }
+      else
+       {
+         if (!coff_write_native_symbol (abfd, c_symbol, &written,
+                                        &string_size, &debug_string_section,
+                                        &debug_string_size))
+           return false;
+       }
+    }
+
+  obj_raw_syment_count (abfd) = written;
+
+  /* Now write out strings */
+
+  if (string_size != 0)
+    {
+      unsigned int size = string_size + STRING_SIZE_SIZE;
+      bfd_byte buffer[STRING_SIZE_SIZE];
+
+#if STRING_SIZE_SIZE == 4
+      bfd_h_put_32 (abfd, size, buffer);
+#else
+ #error Change bfd_h_put_32
+#endif
+      if (bfd_write ((PTR) buffer, 1, sizeof (buffer), abfd) != sizeof (buffer))
+       return false;
+
+      /* Handle long section names.  This code must handle section
+        names just as they are handled in coff_write_object_contents.  */
+      if (bfd_coff_long_section_names (abfd))
+       {
+         asection *o;
+
+         for (o = abfd->sections; o != NULL; o = o->next)
+           {
+             size_t len;
+
+             len = strlen (o->name);
+             if (len > SCNNMLEN)
+               {
+                 if (bfd_write (o->name, 1, len + 1, abfd) != len + 1)
+                   return false;
+               }
+           }
+       }
+
+      for (p = abfd->outsymbols, i = 0;
+          i < limit;
+          i++, p++)
+       {
+         asymbol *q = *p;
+         size_t name_length = strlen (q->name);
+         coff_symbol_type *c_symbol = coff_symbol_from (abfd, q);
+         size_t maxlen;
+
+         /* Figure out whether the symbol name should go in the string
+            table.  Symbol names that are short enough are stored
+            directly in the syment structure.  File names permit a
+            different, longer, length in the syment structure.  On
+            XCOFF, some symbol names are stored in the .debug section
+            rather than in the string table.  */
+
+         if (c_symbol == NULL
+             || c_symbol->native == NULL)
            {
-             written = coff_write_alien_symbol(abfd, symbol, written);
+             /* This is not a COFF symbol, so it certainly is not a
+                file name, nor does it go in the .debug section.  */
+             maxlen = SYMNMLEN;
            }
-       else
+         else if (bfd_coff_symname_in_debug (abfd,
+                                             &c_symbol->native->u.syment))
            {
-             written = coff_write_native_symbol(abfd, c_symbol, written);
+             /* This symbol name is in the XCOFF .debug section.
+                Don't write it into the string table.  */
+             maxlen = name_length;
            }
+         else if (c_symbol->native->u.syment.n_sclass == C_FILE
+                  && c_symbol->native->u.syment.n_numaux > 0)
+           maxlen = FILNMLEN;
+         else
+           maxlen = SYMNMLEN;
 
-      }
-
-  bfd_get_symcount(abfd) = written;
+         if (name_length > maxlen)
+           {
+             if (bfd_write ((PTR) (q->name), 1, name_length + 1, abfd)
+                 != name_length + 1)
+               return false;
+           }
+       }
+    }
+  else
+    {
+      /* We would normally not write anything here, but we'll write
+         out 4 so that any stupid coff reader which tries to read the
+         string table even when there isn't one won't croak.  */
+      unsigned int size = STRING_SIZE_SIZE;
+      bfd_byte buffer[STRING_SIZE_SIZE];
+
+#if STRING_SIZE_SIZE == 4
+      bfd_h_put_32 (abfd, size, buffer);
+#else
+ #error Change bfd_h_put_32
+#endif
+      if (bfd_write ((PTR) buffer, 1, STRING_SIZE_SIZE, abfd)
+         != STRING_SIZE_SIZE)
+       return false;
+    }
 
-  /* Now write out strings */
+  /* Make sure the .debug section was created to be the correct size.
+     We should create it ourselves on the fly, but we don't because
+     BFD won't let us write to any section until we know how large all
+     the sections are.  We could still do it by making another pass
+     over the symbols.  FIXME.  */
+  BFD_ASSERT (debug_string_size == 0
+             || (debug_string_section != (asection *) NULL
+                 && (BFD_ALIGN (debug_string_size,
+                                1 << debug_string_section->alignment_power)
+                     == bfd_section_size (abfd, debug_string_section))));
 
-  if (string_size != 0)
-   {
-     unsigned int    size = string_size + 4;
-     bfd_byte buffer[4];
-
-     bfd_h_put_32(abfd, size, buffer);
-     bfd_write((PTR) buffer, 1, sizeof(buffer), abfd);
-     for (p = abfd->outsymbols, i = 0;
-         i < limit;
-         i++, p++)
-        {
-          asymbol        *q = *p;
-          size_t          name_length = strlen(q->name);
-          int maxlen;
-          coff_symbol_type*       c_symbol = coff_symbol_from(abfd, q);
-          maxlen = ((c_symbol != NULL && c_symbol->native != NULL) &&
-                    (c_symbol->native->u.syment.n_sclass == C_FILE)) ?
-            FILNMLEN : SYMNMLEN;
-
-          if (name_length > maxlen) {
-            bfd_write((PTR) (q->name), 1, name_length + 1, abfd);
-          }
-        }
-   }
-  else {
-    /* We would normally not write anything here, but we'll write
-       out 4 so that any stupid coff reader which tries to read
-       the string table even when there isn't one won't croak.  */
-    unsigned int size = 4;
-    bfd_byte buffer[4];
-
-    bfd_h_put_32 (abfd, size, buffer);
-    bfd_write((PTR) buffer, 1, sizeof (buffer), abfd);
-  }
+  return true;
 }
 
-void
-DEFUN(coff_write_linenumbers,(abfd),
-      bfd            *abfd)
+boolean
+coff_write_linenumbers (abfd)
+     bfd *abfd;
 {
-  asection       *s;
+  asection *s;
   bfd_size_type linesz;
   PTR buff;
 
   linesz = bfd_coff_linesz (abfd);
   buff = bfd_alloc (abfd, linesz);
-  for (s = abfd->sections; s != (asection *) NULL; s = s->next) {
-    if (s->lineno_count) {
-      asymbol       **q = abfd->outsymbols;
-      bfd_seek(abfd, s->line_filepos, SEEK_SET);
-      /* Find all the linenumbers in this section */
-      while (*q) {
-       asymbol        *p = *q;
-       if (p->section->output_section == s) {
-         alent          *l =
-          BFD_SEND(bfd_asymbol_bfd(p), _get_lineno, (bfd_asymbol_bfd(p), p));
-         if (l) {
-           /* Found a linenumber entry, output */
-           struct internal_lineno  out;
-           memset( (PTR)&out, 0, sizeof(out));
-           out.l_lnno = 0;
-           out.l_addr.l_symndx = l->u.offset;
-           bfd_coff_swap_lineno_out(abfd, &out, buff);
-           bfd_write(buff, 1, linesz, abfd);
-           l++;
-           while (l->line_number) {
-             out.l_lnno = l->line_number;
-             out.l_addr.l_symndx = l->u.offset;
-             bfd_coff_swap_lineno_out(abfd, &out, buff);
-             bfd_write(buff, 1, linesz, abfd);
-             l++;
+  if (!buff)
+    return false;
+  for (s = abfd->sections; s != (asection *) NULL; s = s->next)
+    {
+      if (s->lineno_count)
+       {
+         asymbol **q = abfd->outsymbols;
+         if (bfd_seek (abfd, s->line_filepos, SEEK_SET) != 0)
+           return false;
+         /* Find all the linenumbers in this section */
+         while (*q)
+           {
+             asymbol *p = *q;
+             if (p->section->output_section == s)
+               {
+                 alent *l =
+                 BFD_SEND (bfd_asymbol_bfd (p), _get_lineno,
+                           (bfd_asymbol_bfd (p), p));
+                 if (l)
+                   {
+                     /* Found a linenumber entry, output */
+                     struct internal_lineno out;
+                     memset ((PTR) & out, 0, sizeof (out));
+                     out.l_lnno = 0;
+                     out.l_addr.l_symndx = l->u.offset;
+                     bfd_coff_swap_lineno_out (abfd, &out, buff);
+                     if (bfd_write (buff, 1, linesz, abfd) != linesz)
+                       return false;
+                     l++;
+                     while (l->line_number)
+                       {
+                         out.l_lnno = l->line_number;
+                         out.l_addr.l_symndx = l->u.offset;
+                         bfd_coff_swap_lineno_out (abfd, &out, buff);
+                         if (bfd_write (buff, 1, linesz, abfd) != linesz)
+                           return false;
+                         l++;
+                       }
+                   }
+               }
+             q++;
            }
-         }
        }
-       q++;
-      }
     }
-  }
   bfd_release (abfd, buff);
+  return true;
 }
 
-alent   *
-DEFUN(coff_get_lineno,(ignore_abfd, symbol),
-      bfd            *ignore_abfd AND
-      asymbol        *symbol)
+/*ARGSUSED */
+alent *
+coff_get_lineno (ignore_abfd, symbol)
+     bfd *ignore_abfd;
+     asymbol *symbol;
 {
-  return coffsymbol(symbol)->lineno;
+  return coffsymbol (symbol)->lineno;
 }
 
+#if 0
+
+/* This is only called from coff_add_missing_symbols, which has been
+   disabled.  */
+
 asymbol *
 coff_section_symbol (abfd, name)
      bfd *abfd;
@@ -914,19 +1376,25 @@ coff_section_symbol (abfd, name)
   /* Make sure back-end COFF stuff is there.  */
   if (csym == 0)
     {
-      struct foo {
-       coff_symbol_type sym;
-       /* @@FIXME This shouldn't use a fixed size!!  */
-       combined_entry_type e[10];
-      };
+      struct foo
+       {
+         coff_symbol_type sym;
+         /* @@FIXME This shouldn't use a fixed size!!  */
+         combined_entry_type e[10];
+       };
       struct foo *f;
-      f = (struct foo *) bfd_alloc_by_size_t (abfd, sizeof (*f));
+      f = (struct foo *) bfd_alloc (abfd, sizeof (*f));
+      if (!f)
+       {
+         bfd_set_error (bfd_error_no_error);
+         return NULL;
+       }
       memset ((char *) f, 0, sizeof (*f));
       coff_symbol_from (abfd, sym)->native = csym = f->e;
     }
   csym[0].u.syment.n_sclass = C_STAT;
   csym[0].u.syment.n_numaux = 1;
-/*  SF_SET_STATICS (sym);      @@ ??? */
+/*  SF_SET_STATICS (sym);       @@ ??? */
   csym[1].u.auxent.x_scn.x_scnlen = sec->_raw_size;
   csym[1].u.auxent.x_scn.x_nreloc = sec->reloc_count;
   csym[1].u.auxent.x_scn.x_nlinno = sec->lineno_count;
@@ -940,135 +1408,244 @@ coff_section_symbol (abfd, name)
   return sym;
 }
 
+#endif /* 0 */
+
 /* This function transforms the offsets into the symbol table into
    pointers to syments.  */
 
 static void
-DEFUN(coff_pointerize_aux,(abfd, table_base, type, class, auxent),
-bfd *abfd AND
-combined_entry_type *table_base AND
-int type AND
-int class AND
-combined_entry_type *auxent)
+coff_pointerize_aux (abfd, table_base, symbol, indaux, auxent)
+     bfd *abfd;
+     combined_entry_type *table_base;
+     combined_entry_type *symbol;
+     unsigned int indaux;
+     combined_entry_type *auxent;
 {
+  unsigned int type = symbol->u.syment.n_type;
+  unsigned int class = symbol->u.syment.n_sclass;
+
+  if (coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook)
+    {
+      if ((*coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook)
+         (abfd, table_base, symbol, indaux, auxent))
+       return;
+    }
+
   /* Don't bother if this is a file or a section */
-  if (class == C_STAT && type == T_NULL) return;
-  if (class == C_FILE) return;
+  if (class == C_STAT && type == T_NULL)
+    return;
+  if (class == C_FILE)
+    return;
 
   /* Otherwise patch up */
 #define N_TMASK coff_data (abfd)->local_n_tmask
 #define N_BTSHFT coff_data (abfd)->local_n_btshft
-  if (ISFCN(type) || ISTAG(class) || class == C_BLOCK) {
-      auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = table_base +
-       auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l;
+  if ((ISFCN (type) || ISTAG (class) || class == C_BLOCK || class == C_FCN)
+      && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0)
+    {
+      auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p =
+       table_base + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l;
       auxent->fix_end = 1;
     }
   /* A negative tagndx is meaningless, but the SCO 3.2v4 cc can
      generate one, so we must be careful to ignore it.  */
-  if (auxent->u.auxent.x_sym.x_tagndx.l > 0) {
+  if (auxent->u.auxent.x_sym.x_tagndx.l > 0)
+    {
       auxent->u.auxent.x_sym.x_tagndx.p =
-       table_base +  auxent->u.auxent.x_sym.x_tagndx.l;
+       table_base + auxent->u.auxent.x_sym.x_tagndx.l;
       auxent->fix_tag = 1;
     }
 }
 
+/* Allocate space for the ".debug" section, and read it.
+   We did not read the debug section until now, because
+   we didn't want to go to the trouble until someone needed it. */
+
+static char *
+build_debug_section (abfd)
+     bfd *abfd;
+{
+  char *debug_section;
+  long position;
+
+  asection *sect = bfd_get_section_by_name (abfd, ".debug");
+
+  if (!sect)
+    {
+      bfd_set_error (bfd_error_no_debug_section);
+      return NULL;
+    }
+
+  debug_section = (PTR) bfd_alloc (abfd,
+                                  bfd_get_section_size_before_reloc (sect));
+  if (debug_section == NULL)
+    return NULL;
+
+  /* Seek to the beginning of the `.debug' section and read it. 
+     Save the current position first; it is needed by our caller.
+     Then read debug section and reset the file pointer.  */
+
+  position = bfd_tell (abfd);
+  if (bfd_seek (abfd, sect->filepos, SEEK_SET) != 0
+      || (bfd_read (debug_section,
+                   bfd_get_section_size_before_reloc (sect), 1, abfd)
+         != bfd_get_section_size_before_reloc (sect))
+      || bfd_seek (abfd, position, SEEK_SET) != 0)
+    return NULL;
+  return debug_section;
+}
+
+
+/* Return a pointer to a malloc'd copy of 'name'.  'name' may not be
+   \0-terminated, but will not exceed 'maxlen' characters.  The copy *will*
+   be \0-terminated.  */
 static char *
-DEFUN(build_string_table,(abfd),
-bfd *abfd)
+copy_name (abfd, name, maxlen)
+     bfd *abfd;
+     char *name;
+     int maxlen;
 {
-  char string_table_size_buffer[4];
-  unsigned int string_table_size;
-  char *string_table;
-
-  /* At this point we should be "seek"'d to the end of the
-     symbols === the symbol table size.  */
-  if (bfd_read((char *) string_table_size_buffer,
-              sizeof(string_table_size_buffer),
-              1, abfd) != sizeof(string_table_size)) {
-    bfd_error = system_call_error;
+  int len;
+  char *newname;
+
+  for (len = 0; len < maxlen; ++len)
+    {
+      if (name[len] == '\0')
+       {
+         break;
+       }
+    }
+
+  if ((newname = (PTR) bfd_alloc (abfd, len + 1)) == NULL)
     return (NULL);
-  }                            /* on error */
+  strncpy (newname, name, len);
+  newname[len] = '\0';
+  return newname;
+}
+
+/* Read in the external symbols.  */
+
+boolean
+_bfd_coff_get_external_symbols (abfd)
+     bfd *abfd;
+{
+  bfd_size_type symesz;
+  size_t size;
+  PTR syms;
+
+  if (obj_coff_external_syms (abfd) != NULL)
+    return true;
+
+  symesz = bfd_coff_symesz (abfd);
+
+  size = obj_raw_syment_count (abfd) * symesz;
+
+  syms = (PTR) bfd_malloc (size);
+  if (syms == NULL && size != 0)
+    return false;
+
+  if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
+      || bfd_read (syms, size, 1, abfd) != size)
+    {
+      if (syms != NULL)
+       free (syms);
+      return false;
+    }
 
-  string_table_size = bfd_h_get_32(abfd, (bfd_byte *) string_table_size_buffer);
+  obj_coff_external_syms (abfd) = syms;
 
-  if ((string_table = (PTR) bfd_alloc(abfd, string_table_size -= 4)) == NULL) {
-    bfd_error = no_memory;
-    return (NULL);
-  }                            /* on mallocation error */
-  if (bfd_read(string_table, string_table_size, 1, abfd) != string_table_size) {
-    bfd_error = system_call_error;
-    return (NULL);
-  }
-  return string_table;
+  return true;
 }
 
-/* Allocate space for the ".debug" section, and read it.
-   We did not read the debug section until now, because
-   we didn't want to go to the trouble until someone needed it. */
+/* Read in the external strings.  The strings are not loaded until
+   they are needed.  This is because we have no simple way of
+   detecting a missing string table in an archive.  */
 
-static char *
-DEFUN(build_debug_section,(abfd),
-       bfd *abfd)
+const char *
+_bfd_coff_read_string_table (abfd)
+     bfd *abfd;
 {
-  char *debug_section;
-  long position;
+  char extstrsize[STRING_SIZE_SIZE];
+  size_t strsize;
+  char *strings;
 
-  asection *sect = bfd_get_section_by_name (abfd, ".debug");
+  if (obj_coff_strings (abfd) != NULL)
+    return obj_coff_strings (abfd);
 
-  if (!sect) {
-     bfd_error = no_debug_section;
-     return NULL;
-  }
+  if (obj_sym_filepos (abfd) == 0)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return NULL;
+    }
 
-  debug_section = (PTR) bfd_alloc (abfd,
-                                  bfd_get_section_size_before_reloc (sect));
-  if (debug_section == NULL) {
-    bfd_error = no_memory;
+  if (bfd_seek (abfd,
+               (obj_sym_filepos (abfd)
+                + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd)),
+               SEEK_SET) != 0)
     return NULL;
-  }
+    
+  if (bfd_read (extstrsize, sizeof extstrsize, 1, abfd) != sizeof extstrsize)
+    {
+      if (bfd_get_error () != bfd_error_file_truncated)
+       return NULL;
 
-  /* Seek to the beginning of the `.debug' section and read it. 
-     Save the current position first; it is needed by our caller.
-     Then read debug section and reset the file pointer.  */
+      /* There is no string table.  */
+      strsize = STRING_SIZE_SIZE;
+    }
+  else
+    {
+#if STRING_SIZE_SIZE == 4
+      strsize = bfd_h_get_32 (abfd, (bfd_byte *) extstrsize);
+#else
+ #error Change bfd_h_get_32
+#endif
+    }
 
-  position = bfd_tell (abfd);
-  bfd_seek (abfd, sect->filepos, SEEK_SET);
-  if (bfd_read (debug_section, 
-               bfd_get_section_size_before_reloc (sect), 1, abfd)
-      != bfd_get_section_size_before_reloc(sect)) {
-    bfd_error = system_call_error;
+  if (strsize < STRING_SIZE_SIZE)
+    {
+      (*_bfd_error_handler)
+       (_("%s: bad string table size %lu"), bfd_get_filename (abfd),
+        (unsigned long) strsize);
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+    }
+
+  strings = (char *) bfd_malloc (strsize);
+  if (strings == NULL)
     return NULL;
-  }
-  bfd_seek (abfd, position, SEEK_SET);
-  return debug_section;
+
+  if (bfd_read (strings + STRING_SIZE_SIZE,
+               strsize - STRING_SIZE_SIZE, 1, abfd)
+      != strsize - STRING_SIZE_SIZE)
+    {
+      free (strings);
+      return NULL;
+    }
+
+  obj_coff_strings (abfd) = strings;
+
+  return strings;
 }
 
+/* Free up the external symbols and strings read from a COFF file.  */
 
-/* Return a pointer to a malloc'd copy of 'name'.  'name' may not be
- \0-terminated, but will not exceed 'maxlen' characters.  The copy *will*
- be \0-terminated.  */
-static char *
-DEFUN(copy_name,(abfd, name, maxlen),
-      bfd *abfd AND
-      char *name AND
-      int maxlen)
+boolean
+_bfd_coff_free_symbols (abfd)
+     bfd *abfd;
 {
-  int  len;
-  char *newname;
-
-  for (len = 0; len < maxlen; ++len) {
-    if (name[len] == '\0') {
-      break;
+  if (obj_coff_external_syms (abfd) != NULL
+      && ! obj_coff_keep_syms (abfd))
+    {
+      free (obj_coff_external_syms (abfd));
+      obj_coff_external_syms (abfd) = NULL;
     }
-  }
-
-  if ((newname = (PTR) bfd_alloc(abfd, len+1)) == NULL) {
-    bfd_error = no_memory;
-    return (NULL);
-  }
-  strncpy(newname, name, len);
-  newname[len] = '\0';
-  return newname;
+  if (obj_coff_strings (abfd) != NULL
+      && ! obj_coff_keep_strings (abfd))
+    {
+      free (obj_coff_strings (abfd));
+      obj_coff_strings (abfd) = NULL;
+    }
+  return true;
 }
 
 /* Read a symbol table into freshly bfd_allocated memory, swap it, and
@@ -1077,183 +1654,196 @@ DEFUN(copy_name,(abfd, name, maxlen),
    terminated string.  */
 
 combined_entry_type *
-DEFUN(coff_get_normalized_symtab,(abfd),
-bfd            *abfd)
+coff_get_normalized_symtab (abfd)
+     bfd *abfd;
 {
-  combined_entry_type          *internal;
-  combined_entry_type          *internal_ptr;
-  combined_entry_type          *symbol_ptr;
-  combined_entry_type         *internal_end;
+  combined_entry_type *internal;
+  combined_entry_type *internal_ptr;
+  combined_entry_type *symbol_ptr;
+  combined_entry_type *internal_end;
   bfd_size_type symesz;
-  PTR raw;
   char *raw_src;
   char *raw_end;
-  char           *string_table = NULL;
-  char          *debug_section = NULL;
-  unsigned long   size;
+  const char *string_table = NULL;
+  char *debug_section = NULL;
+  unsigned long size;
 
-  unsigned int raw_size;
-  if (obj_raw_syments(abfd) != (combined_entry_type *)NULL) {
-      return obj_raw_syments(abfd);
-    }
-  if ((size = bfd_get_symcount(abfd) * sizeof(combined_entry_type)) == 0) {
-      bfd_error = no_symbols;
-      return (NULL);
-    }
+  if (obj_raw_syments (abfd) != NULL)
+    return obj_raw_syments (abfd);
 
-  internal = (combined_entry_type *)bfd_alloc(abfd, size);
-  internal_end = internal + bfd_get_symcount(abfd);
+  size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type);
+  internal = (combined_entry_type *) bfd_zalloc (abfd, size);
+  if (internal == NULL && size != 0)
+    return NULL;
+  internal_end = internal + obj_raw_syment_count (abfd);
 
-  symesz = bfd_coff_symesz (abfd);
-  raw_size =      bfd_get_symcount(abfd) * symesz;
-  raw = bfd_alloc(abfd,raw_size);
+  if (! _bfd_coff_get_external_symbols (abfd))
+    return NULL;
+
+  raw_src = (char *) obj_coff_external_syms (abfd);
 
-  if (bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET) == -1
-      || bfd_read(raw, raw_size, 1, abfd) != raw_size) {
-      bfd_error = system_call_error;
-      return (NULL);
-    }
   /* mark the end of the symbols */
-  raw_end = (char *) raw + bfd_get_symcount(abfd) * symesz;
-  /*
-    FIXME SOMEDAY.  A string table size of zero is very weird, but
-    probably possible.  If one shows up, it will probably kill us.
-    */
+  symesz = bfd_coff_symesz (abfd);
+  raw_end = (char *) raw_src + obj_raw_syment_count (abfd) * symesz;
+
+  /* FIXME SOMEDAY.  A string table size of zero is very weird, but
+     probably possible.  If one shows up, it will probably kill us.  */
 
   /* Swap all the raw entries */
-  for (raw_src = (char *) raw, internal_ptr = internal;
+  for (internal_ptr = internal;
        raw_src < raw_end;
-       raw_src += symesz, internal_ptr++) {
+       raw_src += symesz, internal_ptr++)
+    {
 
       unsigned int i;
-      bfd_coff_swap_sym_in(abfd, (PTR)raw_src, (PTR)&internal_ptr->u.syment);
-      internal_ptr->fix_tag = 0;
-      internal_ptr->fix_end = 0;
+      bfd_coff_swap_sym_in (abfd, (PTR) raw_src,
+                           (PTR) & internal_ptr->u.syment);
       symbol_ptr = internal_ptr;
 
       for (i = 0;
           i < symbol_ptr->u.syment.n_numaux;
-          i++) 
-      {
-       internal_ptr++;
-       raw_src += symesz;
-      
-       internal_ptr->fix_tag = 0;
-       internal_ptr->fix_end = 0;
-       bfd_coff_swap_aux_in(abfd, (PTR) raw_src,
-                            symbol_ptr->u.syment.n_type,
-                            symbol_ptr->u.syment.n_sclass,
-                            &(internal_ptr->u.auxent));
-       /* Remember that bal entries arn't pointerized */
-       if (i != 1 || symbol_ptr->u.syment.n_sclass != C_LEAFPROC)
+          i++)
        {
-         
-       coff_pointerize_aux(abfd,
-                           internal,
-                           symbol_ptr->u.syment.n_type,
-                           symbol_ptr->u.syment.n_sclass,
-                           internal_ptr);
-      }
-       
-      }
+         internal_ptr++;
+         raw_src += symesz;
+         bfd_coff_swap_aux_in (abfd, (PTR) raw_src,
+                               symbol_ptr->u.syment.n_type,
+                               symbol_ptr->u.syment.n_sclass,
+                               i, symbol_ptr->u.syment.n_numaux,
+                               &(internal_ptr->u.auxent));
+         coff_pointerize_aux (abfd, internal, symbol_ptr, i,
+                              internal_ptr);
+       }
     }
 
-  /* Free all the raw stuff */
-  bfd_release(abfd, raw);
+  /* Free the raw symbols, but not the strings (if we have them).  */
+  obj_coff_keep_strings (abfd) = true;
+  if (! _bfd_coff_free_symbols (abfd))
+    return NULL;
 
   for (internal_ptr = internal; internal_ptr < internal_end;
-       internal_ptr ++)
-  {
-    if (internal_ptr->u.syment.n_sclass == C_FILE) {
-       /* make a file symbol point to the name in the auxent, since
-          the text ".file" is redundant */
-       if ((internal_ptr+1)->u.auxent.x_file.x_n.x_zeroes == 0) {
-           /* the filename is a long one, point into the string table */
-           if (string_table == NULL) {
-               string_table = build_string_table(abfd);
-             }
-
-           internal_ptr->u.syment._n._n_n._n_offset =
-            (long) (string_table - 4 +
-                   (internal_ptr+1)->u.auxent.x_file.x_n.x_offset);
-         }
-       else {
-           /* ordinary short filename, put into memory anyway */
-           internal_ptr->u.syment._n._n_n._n_offset = (long)
-            copy_name(abfd, (internal_ptr+1)->u.auxent.x_file.x_fname,
-                      FILNMLEN);
-         }
-      }
-    else {
-       if (internal_ptr->u.syment._n._n_n._n_zeroes != 0) {
-           /* This is a "short" name.  Make it long.  */
-           unsigned long   i = 0;
-           char           *newstring = NULL;
-
-           /* find the length of this string without walking into memory
-              that isn't ours.  */
-           for (i = 0; i < 8; ++i) {
-               if (internal_ptr->u.syment._n._n_name[i] == '\0') {
-                   break;
-                 }             /* if end of string */
-             }                 /* possible lengths of this string. */
-
-           if ((newstring = (PTR) bfd_alloc(abfd, ++i)) == NULL) {
-               bfd_error = no_memory;
+       internal_ptr++)
+    {
+      if (internal_ptr->u.syment.n_sclass == C_FILE
+         && internal_ptr->u.syment.n_numaux > 0)
+       {
+         /* make a file symbol point to the name in the auxent, since
+            the text ".file" is redundant */
+         if ((internal_ptr + 1)->u.auxent.x_file.x_n.x_zeroes == 0)
+           {
+             /* the filename is a long one, point into the string table */
+             if (string_table == NULL)
+               {
+                 string_table = _bfd_coff_read_string_table (abfd);
+                 if (string_table == NULL)
+                   return NULL;
+               }
+
+             internal_ptr->u.syment._n._n_n._n_offset =
+               ((long)
+                (string_table
+                 + (internal_ptr + 1)->u.auxent.x_file.x_n.x_offset));
+           }
+         else
+           {
+             /* ordinary short filename, put into memory anyway */
+             if (internal_ptr->u.syment.n_numaux > 1
+                 && coff_data (abfd)->pe)
+               {
+                 internal_ptr->u.syment._n._n_n._n_offset = (long)
+                   copy_name (abfd, (internal_ptr + 1)->u.auxent.x_file.x_fname,
+                              internal_ptr->u.syment.n_numaux * symesz);
+               }
+             else
+               {
+                 internal_ptr->u.syment._n._n_n._n_offset = (long)
+                   copy_name (abfd, (internal_ptr + 1)->u.auxent.x_file.x_fname,
+                              FILNMLEN);
+               }
+           }
+       }
+      else
+       {
+         if (internal_ptr->u.syment._n._n_n._n_zeroes != 0)
+           {
+             /* This is a "short" name.  Make it long.  */
+             unsigned long i = 0;
+             char *newstring = NULL;
+
+             /* find the length of this string without walking into memory
+                that isn't ours.  */
+             for (i = 0; i < 8; ++i)
+               {
+                 if (internal_ptr->u.syment._n._n_name[i] == '\0')
+                   {
+                     break;
+                   }           /* if end of string */
+               }               /* possible lengths of this string. */
+
+             if ((newstring = (PTR) bfd_alloc (abfd, ++i)) == NULL)
                return (NULL);
-             }                 /* on error */
-           memset(newstring, 0, i);
-           strncpy(newstring, internal_ptr->u.syment._n._n_name, i-1);
-           internal_ptr->u.syment._n._n_n._n_offset =  (long int) newstring;
-           internal_ptr->u.syment._n._n_n._n_zeroes = 0;
-         }
-       else if (!bfd_coff_symname_in_debug(abfd, &internal_ptr->u.syment)) {
-           /* Long name already.  Point symbol at the string in the table.  */
-           if (string_table == NULL) {
-               string_table = build_string_table(abfd);
-             }
-           internal_ptr->u.syment._n._n_n._n_offset = (long int)
-            (string_table - 4 + internal_ptr->u.syment._n._n_n._n_offset);
-         }
-       else {
-           /* Long name in debug section.  Very similar.  */
-           if (debug_section == NULL) {
-               debug_section = build_debug_section(abfd);
-             }
-           internal_ptr->u.syment._n._n_n._n_offset = (long int)
-            (debug_section + internal_ptr->u.syment._n._n_n._n_offset);
-         }
-      }
-    internal_ptr += internal_ptr->u.syment.n_numaux;
-  }
+             memset (newstring, 0, i);
+             strncpy (newstring, internal_ptr->u.syment._n._n_name, i - 1);
+             internal_ptr->u.syment._n._n_n._n_offset = (long int) newstring;
+             internal_ptr->u.syment._n._n_n._n_zeroes = 0;
+           }
+         else if (internal_ptr->u.syment._n._n_n._n_offset == 0)
+           internal_ptr->u.syment._n._n_n._n_offset = (long int) "";
+         else if (!bfd_coff_symname_in_debug (abfd, &internal_ptr->u.syment))
+           {
+             /* Long name already.  Point symbol at the string in the
+                 table.  */
+             if (string_table == NULL)
+               {
+                 string_table = _bfd_coff_read_string_table (abfd);
+                 if (string_table == NULL)
+                   return NULL;
+               }
+             internal_ptr->u.syment._n._n_n._n_offset =
+               ((long int)
+                (string_table
+                 + internal_ptr->u.syment._n._n_n._n_offset));
+           }
+         else
+           {
+             /* Long name in debug section.  Very similar.  */
+             if (debug_section == NULL)
+               debug_section = build_debug_section (abfd);
+             internal_ptr->u.syment._n._n_n._n_offset = (long int)
+               (debug_section + internal_ptr->u.syment._n._n_n._n_offset);
+           }
+       }
+      internal_ptr += internal_ptr->u.syment.n_numaux;
+    }
 
-  obj_raw_syments(abfd) = internal;
-  obj_raw_syment_count(abfd) = internal_ptr - internal;
+  obj_raw_syments (abfd) = internal;
+  BFD_ASSERT (obj_raw_syment_count (abfd)
+             == (unsigned int) (internal_ptr - internal));
 
   return (internal);
 }                              /* coff_get_normalized_symtab() */
 
-unsigned int
-DEFUN (coff_get_reloc_upper_bound, (abfd, asect),
-       bfd            *abfd AND
-       sec_ptr         asect)
+long
+coff_get_reloc_upper_bound (abfd, asect)
+     bfd *abfd;
+     sec_ptr asect;
 {
-  if (bfd_get_format(abfd) != bfd_object) {
-    bfd_error = invalid_operation;
-    return 0;
-  }
-  return (asect->reloc_count + 1) * sizeof(arelent *);
+  if (bfd_get_format (abfd) != bfd_object)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+  return (asect->reloc_count + 1) * sizeof (arelent *);
 }
 
 asymbol *
-DEFUN (coff_make_empty_symbol, (abfd),
-       bfd            *abfd)
+coff_make_empty_symbol (abfd)
+     bfd *abfd;
 {
-  coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type));
-  if (new == NULL) {
-    bfd_error = no_memory;
+  coff_symbol_type *new = (coff_symbol_type *) bfd_alloc (abfd, sizeof (coff_symbol_type));
+  if (new == NULL)
     return (NULL);
-  }                            /* on error */
+  memset (new, 0, sizeof *new);
   new->symbol.section = 0;
   new->native = 0;
   new->lineno = (alent *) NULL;
@@ -1270,20 +1860,23 @@ coff_bfd_make_debug_symbol (abfd, ptr, sz)
      PTR ptr;
      unsigned long sz;
 {
-  coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type));
-  if (new == NULL) {
-    bfd_error = no_memory;
+  coff_symbol_type *new = (coff_symbol_type *) bfd_alloc (abfd, sizeof (coff_symbol_type));
+  if (new == NULL)
     return (NULL);
-  }                            /* on error */
-  /* @@ This shouldn't be using a constant multiplier.  */
+  /* @@ The 10 is a guess at a plausible maximum number of aux entries
+     (but shouldn't be a constant).  */
   new->native = (combined_entry_type *) bfd_zalloc (abfd, sizeof (combined_entry_type) * 10);
-  new->symbol.section = &bfd_debug_section;
+  if (!new->native)
+    return (NULL);
+  new->symbol.section = bfd_abs_section_ptr;
+  new->symbol.flags = BSF_DEBUGGING;
   new->lineno = (alent *) NULL;
   new->done_lineno = false;
   new->symbol.the_bfd = abfd;
   return &new->symbol;
 }
 
+/*ARGSUSED */
 void
 coff_get_symbol_info (abfd, symbol, ret)
      bfd *abfd;
@@ -1291,6 +1884,87 @@ coff_get_symbol_info (abfd, symbol, ret)
      symbol_info *ret;
 {
   bfd_symbol_info (symbol, ret);
+  if (coffsymbol (symbol)->native != NULL
+      && coffsymbol (symbol)->native->fix_value)
+    {
+      combined_entry_type *psym;
+
+      psym = ((combined_entry_type *)
+             coffsymbol (symbol)->native->u.syment.n_value);
+      ret->value = (bfd_vma) (psym - obj_raw_syments (abfd));
+    }
+}
+
+/* Return the COFF syment for a symbol.  */
+
+boolean
+bfd_coff_get_syment (abfd, symbol, psyment)
+     bfd *abfd;
+     asymbol *symbol;
+     struct internal_syment *psyment;
+{
+  coff_symbol_type *csym;
+
+  csym = coff_symbol_from (abfd, symbol);
+  if (csym == NULL || csym->native == NULL)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
+    }
+
+  *psyment = csym->native->u.syment;
+
+  if (csym->native->fix_value)
+    psyment->n_value = ((combined_entry_type *) psyment->n_value
+                       - obj_raw_syments (abfd));
+
+  /* FIXME: We should handle fix_line here.  */
+
+  return true;
+}
+
+/* Return the COFF auxent for a symbol.  */
+
+boolean
+bfd_coff_get_auxent (abfd, symbol, indx, pauxent)
+     bfd *abfd;
+     asymbol *symbol;
+     int indx;
+     union internal_auxent *pauxent;
+{
+  coff_symbol_type *csym;
+  combined_entry_type *ent;
+
+  csym = coff_symbol_from (abfd, symbol);
+
+  if (csym == NULL
+      || csym->native == NULL
+      || indx >= csym->native->u.syment.n_numaux)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
+    }
+
+  ent = csym->native + indx + 1;
+
+  *pauxent = ent->u.auxent;
+
+  if (ent->fix_tag)
+    pauxent->x_sym.x_tagndx.l =
+      ((combined_entry_type *) pauxent->x_sym.x_tagndx.p
+       - obj_raw_syments (abfd));
+
+  if (ent->fix_end)
+    pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l =
+      ((combined_entry_type *) pauxent->x_sym.x_fcnary.x_fcn.x_endndx.p
+       - obj_raw_syments (abfd));
+
+  if (ent->fix_scnlen)
+    pauxent->x_csect.x_scnlen.l =
+      ((combined_entry_type *) pauxent->x_csect.x_scnlen.p
+       - obj_raw_syments (abfd));
+
+  return true;
 }
 
 /* Print out information about COFF symbol.  */
@@ -1312,31 +1986,39 @@ coff_print_symbol (abfd, filep, symbol, how)
 
     case bfd_print_symbol_more:
       fprintf (file, "coff %s %s",
-              coffsymbol(symbol)->native ? "n" : "g",
-              coffsymbol(symbol)->lineno ? "l" : " ");
+              coffsymbol (symbol)->native ? "n" : "g",
+              coffsymbol (symbol)->lineno ? "l" : " ");
       break;
 
     case bfd_print_symbol_all:
-      if (coffsymbol(symbol)->native) 
+      if (coffsymbol (symbol)->native)
        {
+         unsigned long val;
          unsigned int aux;
          combined_entry_type *combined = coffsymbol (symbol)->native;
          combined_entry_type *root = obj_raw_syments (abfd);
-         struct lineno_cache_entry *l = coffsymbol(symbol)->lineno;
-       
-         fprintf (file,"[%3d]", combined - root);
+         struct lineno_cache_entry *l = coffsymbol (symbol)->lineno;
+
+         fprintf (file, "[%3ld]", (long) (combined - root));
+
+         if (! combined->fix_value)
+           val = (unsigned long) combined->u.syment.n_value;
+         else
+           val = ((unsigned long)
+                  ((combined_entry_type *) combined->u.syment.n_value
+                   - root));
 
          fprintf (file,
-                  "(sc %2d)(fl 0x%02x)(ty %3x)(sc %3d) (nx %d) 0x%08lx %s",
+                  "(sec %2d)(fl 0x%02x)(ty %3x)(scl %3d) (nx %d) 0x%08lx %s",
                   combined->u.syment.n_scnum,
                   combined->u.syment.n_flags,
                   combined->u.syment.n_type,
                   combined->u.syment.n_sclass,
                   combined->u.syment.n_numaux,
-                  (unsigned long) combined->u.syment.n_value,
+                  val,
                   symbol->name);
 
-         for (aux = 0; aux < combined->u.syment.n_numaux; aux++) 
+         for (aux = 0; aux < combined->u.syment.n_numaux; aux++)
            {
              combined_entry_type *auxp = combined + aux + 1;
              long tagndx;
@@ -1347,26 +2029,54 @@ coff_print_symbol (abfd, filep, symbol, how)
                tagndx = auxp->u.auxent.x_sym.x_tagndx.l;
 
              fprintf (file, "\n");
+
+             if (bfd_coff_print_aux (abfd, file, root, combined, auxp, aux))
+               continue;
+
              switch (combined->u.syment.n_sclass)
                {
                case C_FILE:
                  fprintf (file, "File ");
                  break;
-               default:
 
+               case C_STAT:
+                 if (combined->u.syment.n_type == T_NULL)
+                   /* probably a section symbol? */
+                   {
+                     fprintf (file, "AUX scnlen 0x%lx nreloc %d nlnno %d",
+                              (long) auxp->u.auxent.x_scn.x_scnlen,
+                              auxp->u.auxent.x_scn.x_nreloc,
+                              auxp->u.auxent.x_scn.x_nlinno);
+                     if (auxp->u.auxent.x_scn.x_checksum != 0
+                         || auxp->u.auxent.x_scn.x_associated != 0
+                         || auxp->u.auxent.x_scn.x_comdat != 0)
+                       fprintf (file, " checksum 0x%lx assoc %d comdat %d",
+                                auxp->u.auxent.x_scn.x_checksum,
+                                auxp->u.auxent.x_scn.x_associated,
+                                auxp->u.auxent.x_scn.x_comdat);
+                     break;
+                   }
+                 /* else fall through */
+
+               default:
                  fprintf (file, "AUX lnno %d size 0x%x tagndx %ld",
                           auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno,
                           auxp->u.auxent.x_sym.x_misc.x_lnsz.x_size,
                           tagndx);
+                 if (auxp->fix_end)
+                   fprintf (file, " endndx %ld",
+                            ((long)
+                             (auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p
+                              - root)));
                  break;
                }
            }
-       
+
          if (l)
            {
              fprintf (file, "\n%s :", l->u.sym->name);
              l++;
-             while (l->line_number) 
+             while (l->line_number)
                {
                  fprintf (file, "\n%4d : 0x%lx",
                           l->line_number,
@@ -1375,52 +2085,67 @@ coff_print_symbol (abfd, filep, symbol, how)
                  l++;
                }
            }
-       } 
+       }
       else
        {
          bfd_print_symbol_vandf ((PTR) file, symbol);
          fprintf (file, " %-5s %s %s %s",
                   symbol->section->name,
-                  coffsymbol(symbol)->native ? "n" : "g",
-                  coffsymbol(symbol)->lineno ? "l" : " ",
+                  coffsymbol (symbol)->native ? "n" : "g",
+                  coffsymbol (symbol)->lineno ? "l" : " ",
                   symbol->name);
        }
     }
 }
 
+/* Return whether a symbol name implies a local symbol.  In COFF,
+   local symbols generally start with ``.L''.  Most targets use this
+   function for the is_local_label_name entry point, but some may
+   override it.  */
+
+boolean
+_bfd_coff_is_local_label_name (abfd, name)
+     bfd *abfd;
+     const char *name;
+{
+  return name[0] == '.' && name[1] == 'L';
+}
+
 /* Provided a BFD, a section and an offset into the section, calculate
    and return the name of the source file and the line nearest to the
    wanted location.  */
 
+/*ARGSUSED*/
 boolean
-DEFUN(coff_find_nearest_line,(abfd,
-                             section,
-                             ignore_symbols,
-                             offset,
-                             filename_ptr,
-                             functionname_ptr,
-                             line_ptr),
-      bfd            *abfd AND
-      asection       *section AND
-      asymbol       **ignore_symbols AND
-      bfd_vma         offset AND
-      CONST char      **filename_ptr AND
-      CONST char       **functionname_ptr AND
-      unsigned int   *line_ptr)
+coff_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
+                       functionname_ptr, line_ptr)
+     bfd *abfd;
+     asection *section;
+     asymbol **symbols;
+     bfd_vma offset;
+     CONST char **filename_ptr;
+     CONST char **functionname_ptr;
+     unsigned int *line_ptr;
 {
-  static bfd     *cache_abfd;
-  static asection *cache_section;
-  static bfd_vma  cache_offset;
-  static unsigned int cache_i;
-  static CONST char *cache_function;
-  static unsigned int    line_base = 0;
-
-  unsigned int    i = 0;
-  coff_data_type *cof = coff_data(abfd);
+  boolean found;
+  unsigned int i;
+  unsigned int line_base;
+  coff_data_type *cof = coff_data (abfd);
   /* Run through the raw syments if available */
   combined_entry_type *p;
-  alent          *l;
-
+  combined_entry_type *pend;
+  alent *l;
+  struct coff_section_tdata *sec_data;
+
+  /* Before looking through the symbol table, try to use a .stab
+     section to find the information.  */
+  if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
+                                            &found, filename_ptr,
+                                            functionname_ptr, line_ptr,
+                                            &coff_data (abfd)->line_info))
+    return false;
+  if (found)
+    return true;
 
   *filename_ptr = 0;
   *functionname_ptr = 0;
@@ -1433,87 +2158,231 @@ DEFUN(coff_find_nearest_line,(abfd,
   if (cof == NULL)
     return false;
 
+  /* Find the first C_FILE symbol.  */
   p = cof->raw_syments;
+  if (!p)
+    return false;
+
+  pend = p + cof->raw_syment_count;
+  while (p < pend)
+    {
+      if (p->u.syment.n_sclass == C_FILE)
+       break;
+      p += 1 + p->u.syment.n_numaux;
+    }
+
+  if (p < pend)
+    {
+      bfd_vma sec_vma;
+      bfd_vma maxdiff;
 
-  for (i = 0; i < cof->raw_syment_count; i++) {
-    if (p->u.syment.n_sclass == C_FILE) {
-      /* File name has been moved into symbol */
+      /* Look through the C_FILE symbols to find the best one.  */
+      sec_vma = bfd_get_section_vma (abfd, section);
       *filename_ptr = (char *) p->u.syment._n._n_n._n_offset;
-      break;
+      maxdiff = (bfd_vma) 0 - (bfd_vma) 1;
+      while (1)
+       {
+         combined_entry_type *p2;
+
+         for (p2 = p + 1 + p->u.syment.n_numaux;
+              p2 < pend;
+              p2 += 1 + p2->u.syment.n_numaux)
+           {
+             if (p2->u.syment.n_scnum > 0
+                 && (section
+                     == coff_section_from_bfd_index (abfd,
+                                                     p2->u.syment.n_scnum)))
+               break;
+             if (p2->u.syment.n_sclass == C_FILE)
+               {
+                 p2 = pend;
+                 break;
+               }
+           }
+
+         if (p2 < pend
+             && offset + sec_vma >= (bfd_vma) p2->u.syment.n_value
+             && offset + sec_vma - (bfd_vma) p2->u.syment.n_value < maxdiff)
+           {
+             *filename_ptr = (char *) p->u.syment._n._n_n._n_offset;
+             maxdiff = offset + sec_vma - p2->u.syment.n_value;
+           }
+
+         /* Avoid endless loops on erroneous files by ensuring that
+            we always move forward in the file.  */
+         if (p - cof->raw_syments >= p->u.syment.n_value)
+           break;
+
+         p = cof->raw_syments + p->u.syment.n_value;
+         if (p > pend || p->u.syment.n_sclass != C_FILE)
+           break;
+       }
     }
-    p += 1 +  p->u.syment.n_numaux;
-  }
+
   /* Now wander though the raw linenumbers of the section */
-  /*
-    If this is the same BFD as we were previously called with and this is
-    the same section, and the offset we want is further down then we can
-    prime the lookup loop
-    */
-  if (abfd == cache_abfd &&
-      section == cache_section &&
-      offset >= cache_offset) {
-    i = cache_i;
-    *functionname_ptr = cache_function;
-  }
-  else {
-    i = 0;
-  }
-  l = &section->lineno[i];
+  /* If we have been called on this section before, and the offset we
+     want is further down then we can prime the lookup loop.  */
+  sec_data = coff_section_data (abfd, section);
+  if (sec_data != NULL
+      && sec_data->i > 0
+      && offset >= sec_data->offset)
+    {
+      i = sec_data->i;
+      *functionname_ptr = sec_data->function;
+      line_base = sec_data->line_base;
+    }
+  else
+    {
+      i = 0;
+      line_base = 0;
+    }
 
-  for (; i < section->lineno_count; i++) {
-    if (l->line_number == 0) {
-      /* Get the symbol this line number points at */
-      coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym);
-      if (coff->symbol.value > offset)
-       break;
-      *functionname_ptr = coff->symbol.name;
-      if (coff->native) {
-       combined_entry_type  *s = coff->native;
-       s = s + 1 + s->u.syment.n_numaux;
-       /*
-         S should now point to the .bf of the function
-         */
-       if (s->u.syment.n_numaux) {
-         /*
-           The linenumber is stored in the auxent
-           */
-         union internal_auxent   *a = &((s + 1)->u.auxent);
-         line_base = a->x_sym.x_misc.x_lnsz.x_lnno;
-         *line_ptr = line_base;
+  if (section->lineno != NULL)
+    {
+      l = &section->lineno[i];
+
+      for (; i < section->lineno_count; i++)
+       {
+         if (l->line_number == 0)
+           {
+             /* Get the symbol this line number points at */
+             coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym);
+             if (coff->symbol.value > offset)
+               break;
+             *functionname_ptr = coff->symbol.name;
+             if (coff->native)
+               {
+                 combined_entry_type *s = coff->native;
+                 s = s + 1 + s->u.syment.n_numaux;
+
+                 /* In XCOFF a debugging symbol can follow the
+                    function symbol.  */
+                 if (s->u.syment.n_scnum == N_DEBUG)
+                   s = s + 1 + s->u.syment.n_numaux;
+
+                 /* S should now point to the .bf of the function.  */
+                 if (s->u.syment.n_numaux)
+                   {
+                     /* The linenumber is stored in the auxent.  */
+                     union internal_auxent *a = &((s + 1)->u.auxent);
+                     line_base = a->x_sym.x_misc.x_lnsz.x_lnno;
+                     *line_ptr = line_base;
+                   }
+               }
+           }
+         else
+           {
+             if (l->u.offset > offset)
+               break;
+             *line_ptr = l->line_number + line_base - 1;
+           }
+         l++;
        }
-      }
-    }
-    else {
-      if (l->u.offset > offset)
-       break;
-      *line_ptr = l->line_number + line_base - 1;
     }
-    l++;
-  }
 
-  cache_abfd = abfd;
-  cache_section = section;
-  cache_offset = offset;
-  cache_i = i;
-  cache_function = *functionname_ptr;
+  /* Cache the results for the next call.  */
+  if (sec_data == NULL && section->owner == abfd)
+    {
+      section->used_by_bfd =
+       ((PTR) bfd_zalloc (abfd,
+                          sizeof (struct coff_section_tdata)));
+      sec_data = (struct coff_section_tdata *) section->used_by_bfd;
+    }
+  if (sec_data != NULL)
+    {
+      sec_data->offset = offset;
+      sec_data->i = i;
+      sec_data->function = *functionname_ptr;
+      sec_data->line_base = line_base;
+    }
 
   return true;
 }
 
 int
-DEFUN(coff_sizeof_headers,(abfd, reloc),
-      bfd *abfd AND
-      boolean reloc)
+coff_sizeof_headers (abfd, reloc)
+     bfd *abfd;
+     boolean reloc;
 {
-    size_t size;
+  size_t size;
 
-    if (reloc == false) {
-       size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd);
+  if (reloc == false)
+    {
+      size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd);
     }
-    else {
-       size = bfd_coff_filhsz (abfd);
+  else
+    {
+      size = bfd_coff_filhsz (abfd);
+    }
+
+  size += abfd->section_count * bfd_coff_scnhsz (abfd);
+  return size;
+}
+
+/* Change the class of a coff symbol held by BFD.  */
+boolean
+bfd_coff_set_symbol_class (abfd, symbol, class)
+     bfd *         abfd;
+     asymbol *     symbol;
+     unsigned int  class;
+{
+  coff_symbol_type * csym;
+
+  csym = coff_symbol_from (abfd, symbol);
+  if (csym == NULL)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
     }
+  else if (csym->native == NULL)
+    {
+      /* This is an alien symbol which no native coff backend data.
+        We cheat here by creating a fake native entry for it and
+        then filling in the class.  This code is based on that in
+        coff_write_alien_symbol().  */
+      
+      combined_entry_type * native;
+
+      native = (combined_entry_type *) bfd_alloc (abfd, sizeof (* native));
+      if (native == NULL)
+       return false;
 
-    size +=  abfd->section_count * bfd_coff_scnhsz (abfd);
-    return size;
+      memset (native, 0, sizeof (* native));
+      
+      native->u.syment.n_type   = T_NULL;
+      native->u.syment.n_sclass = class;
+      
+      if (bfd_is_und_section (symbol->section))
+       {
+         native->u.syment.n_scnum = N_UNDEF;
+         native->u.syment.n_value = symbol->value;
+       }
+      else if (bfd_is_com_section (symbol->section))
+       {
+         native->u.syment.n_scnum = N_UNDEF;
+         native->u.syment.n_value = symbol->value;
+       }
+      else
+       {
+         native->u.syment.n_scnum =
+           symbol->section->output_section->target_index;
+         native->u.syment.n_value = (symbol->value
+                                     + symbol->section->output_offset);
+         if (! obj_pe (abfd))
+           native->u.syment.n_value += symbol->section->output_section->vma;
+         
+         /* Copy the any flags from the the file header into the symbol.
+            FIXME: Why?  */
+         native->u.syment.n_flags = bfd_asymbol_bfd (& csym->symbol)->flags;
+       }
+      
+      csym->native = native;
+    }
+  else
+    {
+      csym->native->u.syment.n_sclass = class;
+    }
+  
+  return true;
 }
+