OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [bfd/] [cofflink.c] - Diff between revs 834 and 842

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/* COFF specific linker code.
/* COFF specific linker code.
   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
   Written by Ian Lance Taylor, Cygnus Support.
   Written by Ian Lance Taylor, Cygnus Support.
 
 
   This file is part of BFD, the Binary File Descriptor library.
   This file is part of BFD, the Binary File Descriptor library.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */
   MA 02110-1301, USA.  */
 
 
/* This file contains the COFF backend linker code.  */
/* This file contains the COFF backend linker code.  */
 
 
#include "sysdep.h"
#include "sysdep.h"
#include "bfd.h"
#include "bfd.h"
#include "bfdlink.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "libbfd.h"
#include "coff/internal.h"
#include "coff/internal.h"
#include "libcoff.h"
#include "libcoff.h"
#include "safe-ctype.h"
#include "safe-ctype.h"
 
 
static bfd_boolean coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info);
static bfd_boolean coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info);
static bfd_boolean coff_link_check_archive_element (bfd *abfd, struct bfd_link_info *info, bfd_boolean *pneeded);
static bfd_boolean coff_link_check_archive_element (bfd *abfd, struct bfd_link_info *info, bfd_boolean *pneeded);
static bfd_boolean coff_link_add_symbols (bfd *abfd, struct bfd_link_info *info);
static bfd_boolean coff_link_add_symbols (bfd *abfd, struct bfd_link_info *info);
 
 
/* Return TRUE if SYM is a weak, external symbol.  */
/* Return TRUE if SYM is a weak, external symbol.  */
#define IS_WEAK_EXTERNAL(abfd, sym)                     \
#define IS_WEAK_EXTERNAL(abfd, sym)                     \
  ((sym).n_sclass == C_WEAKEXT                          \
  ((sym).n_sclass == C_WEAKEXT                          \
   || (obj_pe (abfd) && (sym).n_sclass == C_NT_WEAK))
   || (obj_pe (abfd) && (sym).n_sclass == C_NT_WEAK))
 
 
/* Return TRUE if SYM is an external symbol.  */
/* Return TRUE if SYM is an external symbol.  */
#define IS_EXTERNAL(abfd, sym)                          \
#define IS_EXTERNAL(abfd, sym)                          \
  ((sym).n_sclass == C_EXT || IS_WEAK_EXTERNAL (abfd, sym))
  ((sym).n_sclass == C_EXT || IS_WEAK_EXTERNAL (abfd, sym))
 
 
/* Define macros so that the ISFCN, et. al., macros work correctly.
/* Define macros so that the ISFCN, et. al., macros work correctly.
   These macros are defined in include/coff/internal.h in terms of
   These macros are defined in include/coff/internal.h in terms of
   N_TMASK, etc.  These definitions require a user to define local
   N_TMASK, etc.  These definitions require a user to define local
   variables with the appropriate names, and with values from the
   variables with the appropriate names, and with values from the
   coff_data (abfd) structure.  */
   coff_data (abfd) structure.  */
 
 
#define N_TMASK n_tmask
#define N_TMASK n_tmask
#define N_BTSHFT n_btshft
#define N_BTSHFT n_btshft
#define N_BTMASK n_btmask
#define N_BTMASK n_btmask
 
 
/* Create an entry in a COFF linker hash table.  */
/* Create an entry in a COFF linker hash table.  */
 
 
struct bfd_hash_entry *
struct bfd_hash_entry *
_bfd_coff_link_hash_newfunc (struct bfd_hash_entry *entry,
_bfd_coff_link_hash_newfunc (struct bfd_hash_entry *entry,
                             struct bfd_hash_table *table,
                             struct bfd_hash_table *table,
                             const char *string)
                             const char *string)
{
{
  struct coff_link_hash_entry *ret = (struct coff_link_hash_entry *) entry;
  struct coff_link_hash_entry *ret = (struct coff_link_hash_entry *) entry;
 
 
  /* Allocate the structure if it has not already been allocated by a
  /* Allocate the structure if it has not already been allocated by a
     subclass.  */
     subclass.  */
  if (ret == (struct coff_link_hash_entry *) NULL)
  if (ret == (struct coff_link_hash_entry *) NULL)
    ret = ((struct coff_link_hash_entry *)
    ret = ((struct coff_link_hash_entry *)
           bfd_hash_allocate (table, sizeof (struct coff_link_hash_entry)));
           bfd_hash_allocate (table, sizeof (struct coff_link_hash_entry)));
  if (ret == (struct coff_link_hash_entry *) NULL)
  if (ret == (struct coff_link_hash_entry *) NULL)
    return (struct bfd_hash_entry *) ret;
    return (struct bfd_hash_entry *) ret;
 
 
  /* Call the allocation method of the superclass.  */
  /* Call the allocation method of the superclass.  */
  ret = ((struct coff_link_hash_entry *)
  ret = ((struct coff_link_hash_entry *)
         _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
         _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
                                 table, string));
                                 table, string));
  if (ret != (struct coff_link_hash_entry *) NULL)
  if (ret != (struct coff_link_hash_entry *) NULL)
    {
    {
      /* Set local fields.  */
      /* Set local fields.  */
      ret->indx = -1;
      ret->indx = -1;
      ret->type = T_NULL;
      ret->type = T_NULL;
      ret->symbol_class = C_NULL;
      ret->symbol_class = C_NULL;
      ret->numaux = 0;
      ret->numaux = 0;
      ret->auxbfd = NULL;
      ret->auxbfd = NULL;
      ret->aux = NULL;
      ret->aux = NULL;
    }
    }
 
 
  return (struct bfd_hash_entry *) ret;
  return (struct bfd_hash_entry *) ret;
}
}
 
 
/* Initialize a COFF linker hash table.  */
/* Initialize a COFF linker hash table.  */
 
 
bfd_boolean
bfd_boolean
_bfd_coff_link_hash_table_init (struct coff_link_hash_table *table,
_bfd_coff_link_hash_table_init (struct coff_link_hash_table *table,
                                bfd *abfd,
                                bfd *abfd,
                                struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
                                struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
                                                                   struct bfd_hash_table *,
                                                                   struct bfd_hash_table *,
                                                                   const char *),
                                                                   const char *),
                                unsigned int entsize)
                                unsigned int entsize)
{
{
  memset (&table->stab_info, 0, sizeof (table->stab_info));
  memset (&table->stab_info, 0, sizeof (table->stab_info));
  return _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
  return _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
}
}
 
 
/* Create a COFF linker hash table.  */
/* Create a COFF linker hash table.  */
 
 
struct bfd_link_hash_table *
struct bfd_link_hash_table *
_bfd_coff_link_hash_table_create (bfd *abfd)
_bfd_coff_link_hash_table_create (bfd *abfd)
{
{
  struct coff_link_hash_table *ret;
  struct coff_link_hash_table *ret;
  bfd_size_type amt = sizeof (struct coff_link_hash_table);
  bfd_size_type amt = sizeof (struct coff_link_hash_table);
 
 
  ret = (struct coff_link_hash_table *) bfd_malloc (amt);
  ret = (struct coff_link_hash_table *) bfd_malloc (amt);
  if (ret == NULL)
  if (ret == NULL)
    return NULL;
    return NULL;
 
 
  if (! _bfd_coff_link_hash_table_init (ret, abfd,
  if (! _bfd_coff_link_hash_table_init (ret, abfd,
                                        _bfd_coff_link_hash_newfunc,
                                        _bfd_coff_link_hash_newfunc,
                                        sizeof (struct coff_link_hash_entry)))
                                        sizeof (struct coff_link_hash_entry)))
    {
    {
      free (ret);
      free (ret);
      return (struct bfd_link_hash_table *) NULL;
      return (struct bfd_link_hash_table *) NULL;
    }
    }
  return &ret->root;
  return &ret->root;
}
}
 
 
/* Create an entry in a COFF debug merge hash table.  */
/* Create an entry in a COFF debug merge hash table.  */
 
 
struct bfd_hash_entry *
struct bfd_hash_entry *
_bfd_coff_debug_merge_hash_newfunc (struct bfd_hash_entry *entry,
_bfd_coff_debug_merge_hash_newfunc (struct bfd_hash_entry *entry,
                                    struct bfd_hash_table *table,
                                    struct bfd_hash_table *table,
                                    const char *string)
                                    const char *string)
{
{
  struct coff_debug_merge_hash_entry *ret =
  struct coff_debug_merge_hash_entry *ret =
    (struct coff_debug_merge_hash_entry *) entry;
    (struct coff_debug_merge_hash_entry *) entry;
 
 
  /* Allocate the structure if it has not already been allocated by a
  /* Allocate the structure if it has not already been allocated by a
     subclass.  */
     subclass.  */
  if (ret == (struct coff_debug_merge_hash_entry *) NULL)
  if (ret == (struct coff_debug_merge_hash_entry *) NULL)
    ret = ((struct coff_debug_merge_hash_entry *)
    ret = ((struct coff_debug_merge_hash_entry *)
           bfd_hash_allocate (table,
           bfd_hash_allocate (table,
                              sizeof (struct coff_debug_merge_hash_entry)));
                              sizeof (struct coff_debug_merge_hash_entry)));
  if (ret == (struct coff_debug_merge_hash_entry *) NULL)
  if (ret == (struct coff_debug_merge_hash_entry *) NULL)
    return (struct bfd_hash_entry *) ret;
    return (struct bfd_hash_entry *) ret;
 
 
  /* Call the allocation method of the superclass.  */
  /* Call the allocation method of the superclass.  */
  ret = ((struct coff_debug_merge_hash_entry *)
  ret = ((struct coff_debug_merge_hash_entry *)
         bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
         bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
  if (ret != (struct coff_debug_merge_hash_entry *) NULL)
  if (ret != (struct coff_debug_merge_hash_entry *) NULL)
    {
    {
      /* Set local fields.  */
      /* Set local fields.  */
      ret->types = NULL;
      ret->types = NULL;
    }
    }
 
 
  return (struct bfd_hash_entry *) ret;
  return (struct bfd_hash_entry *) ret;
}
}
 
 
/* Given a COFF BFD, add symbols to the global hash table as
/* Given a COFF BFD, add symbols to the global hash table as
   appropriate.  */
   appropriate.  */
 
 
bfd_boolean
bfd_boolean
_bfd_coff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
_bfd_coff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
{
{
  switch (bfd_get_format (abfd))
  switch (bfd_get_format (abfd))
    {
    {
    case bfd_object:
    case bfd_object:
      return coff_link_add_object_symbols (abfd, info);
      return coff_link_add_object_symbols (abfd, info);
    case bfd_archive:
    case bfd_archive:
      return _bfd_generic_link_add_archive_symbols
      return _bfd_generic_link_add_archive_symbols
        (abfd, info, coff_link_check_archive_element);
        (abfd, info, coff_link_check_archive_element);
    default:
    default:
      bfd_set_error (bfd_error_wrong_format);
      bfd_set_error (bfd_error_wrong_format);
      return FALSE;
      return FALSE;
    }
    }
}
}
 
 
/* Add symbols from a COFF object file.  */
/* Add symbols from a COFF object file.  */
 
 
static bfd_boolean
static bfd_boolean
coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
{
{
  if (! _bfd_coff_get_external_symbols (abfd))
  if (! _bfd_coff_get_external_symbols (abfd))
    return FALSE;
    return FALSE;
  if (! coff_link_add_symbols (abfd, info))
  if (! coff_link_add_symbols (abfd, info))
    return FALSE;
    return FALSE;
 
 
  if (! info->keep_memory
  if (! info->keep_memory
      && ! _bfd_coff_free_symbols (abfd))
      && ! _bfd_coff_free_symbols (abfd))
    return FALSE;
    return FALSE;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Look through the symbols to see if this object file should be
/* Look through the symbols to see if this object file should be
   included in the link.  */
   included in the link.  */
 
 
static bfd_boolean
static bfd_boolean
coff_link_check_ar_symbols (bfd *abfd,
coff_link_check_ar_symbols (bfd *abfd,
                            struct bfd_link_info *info,
                            struct bfd_link_info *info,
                            bfd_boolean *pneeded)
                            bfd_boolean *pneeded)
{
{
  bfd_size_type symesz;
  bfd_size_type symesz;
  bfd_byte *esym;
  bfd_byte *esym;
  bfd_byte *esym_end;
  bfd_byte *esym_end;
 
 
  *pneeded = FALSE;
  *pneeded = FALSE;
 
 
  symesz = bfd_coff_symesz (abfd);
  symesz = bfd_coff_symesz (abfd);
  esym = (bfd_byte *) obj_coff_external_syms (abfd);
  esym = (bfd_byte *) obj_coff_external_syms (abfd);
  esym_end = esym + obj_raw_syment_count (abfd) * symesz;
  esym_end = esym + obj_raw_syment_count (abfd) * symesz;
  while (esym < esym_end)
  while (esym < esym_end)
    {
    {
      struct internal_syment sym;
      struct internal_syment sym;
      enum coff_symbol_classification classification;
      enum coff_symbol_classification classification;
 
 
      bfd_coff_swap_sym_in (abfd, esym, &sym);
      bfd_coff_swap_sym_in (abfd, esym, &sym);
 
 
      classification = bfd_coff_classify_symbol (abfd, &sym);
      classification = bfd_coff_classify_symbol (abfd, &sym);
      if (classification == COFF_SYMBOL_GLOBAL
      if (classification == COFF_SYMBOL_GLOBAL
          || classification == COFF_SYMBOL_COMMON)
          || classification == COFF_SYMBOL_COMMON)
        {
        {
          const char *name;
          const char *name;
          char buf[SYMNMLEN + 1];
          char buf[SYMNMLEN + 1];
          struct bfd_link_hash_entry *h;
          struct bfd_link_hash_entry *h;
 
 
          /* This symbol is externally visible, and is defined by this
          /* This symbol is externally visible, and is defined by this
             object file.  */
             object file.  */
          name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
          name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
          if (name == NULL)
          if (name == NULL)
            return FALSE;
            return FALSE;
          h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
          h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
 
 
          /* Auto import.  */
          /* Auto import.  */
          if (!h
          if (!h
              && info->pei386_auto_import
              && info->pei386_auto_import
              && CONST_STRNEQ (name, "__imp_"))
              && CONST_STRNEQ (name, "__imp_"))
            h = bfd_link_hash_lookup (info->hash, name + 6, FALSE, FALSE, TRUE);
            h = bfd_link_hash_lookup (info->hash, name + 6, FALSE, FALSE, TRUE);
 
 
          /* We are only interested in symbols that are currently
          /* We are only interested in symbols that are currently
             undefined.  If a symbol is currently known to be common,
             undefined.  If a symbol is currently known to be common,
             COFF linkers do not bring in an object file which defines
             COFF linkers do not bring in an object file which defines
             it.  */
             it.  */
          if (h != (struct bfd_link_hash_entry *) NULL
          if (h != (struct bfd_link_hash_entry *) NULL
              && h->type == bfd_link_hash_undefined)
              && h->type == bfd_link_hash_undefined)
            {
            {
              if (! (*info->callbacks->add_archive_element) (info, abfd, name))
              if (! (*info->callbacks->add_archive_element) (info, abfd, name))
                return FALSE;
                return FALSE;
              *pneeded = TRUE;
              *pneeded = TRUE;
              return TRUE;
              return TRUE;
            }
            }
        }
        }
 
 
      esym += (sym.n_numaux + 1) * symesz;
      esym += (sym.n_numaux + 1) * symesz;
    }
    }
 
 
  /* We do not need this object file.  */
  /* We do not need this object file.  */
  return TRUE;
  return TRUE;
}
}
 
 
/* Check a single archive element to see if we need to include it in
/* Check a single archive element to see if we need to include it in
   the link.  *PNEEDED is set according to whether this element is
   the link.  *PNEEDED is set according to whether this element is
   needed in the link or not.  This is called via
   needed in the link or not.  This is called via
   _bfd_generic_link_add_archive_symbols.  */
   _bfd_generic_link_add_archive_symbols.  */
 
 
static bfd_boolean
static bfd_boolean
coff_link_check_archive_element (bfd *abfd,
coff_link_check_archive_element (bfd *abfd,
                                 struct bfd_link_info *info,
                                 struct bfd_link_info *info,
                                 bfd_boolean *pneeded)
                                 bfd_boolean *pneeded)
{
{
  if (! _bfd_coff_get_external_symbols (abfd))
  if (! _bfd_coff_get_external_symbols (abfd))
    return FALSE;
    return FALSE;
 
 
  if (! coff_link_check_ar_symbols (abfd, info, pneeded))
  if (! coff_link_check_ar_symbols (abfd, info, pneeded))
    return FALSE;
    return FALSE;
 
 
  if (*pneeded
  if (*pneeded
      && ! coff_link_add_symbols (abfd, info))
      && ! coff_link_add_symbols (abfd, info))
    return FALSE;
    return FALSE;
 
 
  if ((! info->keep_memory || ! *pneeded)
  if ((! info->keep_memory || ! *pneeded)
      && ! _bfd_coff_free_symbols (abfd))
      && ! _bfd_coff_free_symbols (abfd))
    return FALSE;
    return FALSE;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Add all the symbols from an object file to the hash table.  */
/* Add all the symbols from an object file to the hash table.  */
 
 
static bfd_boolean
static bfd_boolean
coff_link_add_symbols (bfd *abfd,
coff_link_add_symbols (bfd *abfd,
                       struct bfd_link_info *info)
                       struct bfd_link_info *info)
{
{
  unsigned int n_tmask = coff_data (abfd)->local_n_tmask;
  unsigned int n_tmask = coff_data (abfd)->local_n_tmask;
  unsigned int n_btshft = coff_data (abfd)->local_n_btshft;
  unsigned int n_btshft = coff_data (abfd)->local_n_btshft;
  unsigned int n_btmask = coff_data (abfd)->local_n_btmask;
  unsigned int n_btmask = coff_data (abfd)->local_n_btmask;
  bfd_boolean keep_syms;
  bfd_boolean keep_syms;
  bfd_boolean default_copy;
  bfd_boolean default_copy;
  bfd_size_type symcount;
  bfd_size_type symcount;
  struct coff_link_hash_entry **sym_hash;
  struct coff_link_hash_entry **sym_hash;
  bfd_size_type symesz;
  bfd_size_type symesz;
  bfd_byte *esym;
  bfd_byte *esym;
  bfd_byte *esym_end;
  bfd_byte *esym_end;
  bfd_size_type amt;
  bfd_size_type amt;
 
 
  symcount = obj_raw_syment_count (abfd);
  symcount = obj_raw_syment_count (abfd);
 
 
  if (symcount == 0)
  if (symcount == 0)
    return TRUE;                /* Nothing to do.  */
    return TRUE;                /* Nothing to do.  */
 
 
  /* Keep the symbols during this function, in case the linker needs
  /* Keep the symbols during this function, in case the linker needs
     to read the generic symbols in order to report an error message.  */
     to read the generic symbols in order to report an error message.  */
  keep_syms = obj_coff_keep_syms (abfd);
  keep_syms = obj_coff_keep_syms (abfd);
  obj_coff_keep_syms (abfd) = TRUE;
  obj_coff_keep_syms (abfd) = TRUE;
 
 
  if (info->keep_memory)
  if (info->keep_memory)
    default_copy = FALSE;
    default_copy = FALSE;
  else
  else
    default_copy = TRUE;
    default_copy = TRUE;
 
 
  /* We keep a list of the linker hash table entries that correspond
  /* We keep a list of the linker hash table entries that correspond
     to particular symbols.  */
     to particular symbols.  */
  amt = symcount * sizeof (struct coff_link_hash_entry *);
  amt = symcount * sizeof (struct coff_link_hash_entry *);
  sym_hash = (struct coff_link_hash_entry **) bfd_zalloc (abfd, amt);
  sym_hash = (struct coff_link_hash_entry **) bfd_zalloc (abfd, amt);
  if (sym_hash == NULL)
  if (sym_hash == NULL)
    goto error_return;
    goto error_return;
  obj_coff_sym_hashes (abfd) = sym_hash;
  obj_coff_sym_hashes (abfd) = sym_hash;
 
 
  symesz = bfd_coff_symesz (abfd);
  symesz = bfd_coff_symesz (abfd);
  BFD_ASSERT (symesz == bfd_coff_auxesz (abfd));
  BFD_ASSERT (symesz == bfd_coff_auxesz (abfd));
  esym = (bfd_byte *) obj_coff_external_syms (abfd);
  esym = (bfd_byte *) obj_coff_external_syms (abfd);
  esym_end = esym + symcount * symesz;
  esym_end = esym + symcount * symesz;
  while (esym < esym_end)
  while (esym < esym_end)
    {
    {
      struct internal_syment sym;
      struct internal_syment sym;
      enum coff_symbol_classification classification;
      enum coff_symbol_classification classification;
      bfd_boolean copy;
      bfd_boolean copy;
 
 
      bfd_coff_swap_sym_in (abfd, esym, &sym);
      bfd_coff_swap_sym_in (abfd, esym, &sym);
 
 
      classification = bfd_coff_classify_symbol (abfd, &sym);
      classification = bfd_coff_classify_symbol (abfd, &sym);
      if (classification != COFF_SYMBOL_LOCAL)
      if (classification != COFF_SYMBOL_LOCAL)
        {
        {
          const char *name;
          const char *name;
          char buf[SYMNMLEN + 1];
          char buf[SYMNMLEN + 1];
          flagword flags;
          flagword flags;
          asection *section;
          asection *section;
          bfd_vma value;
          bfd_vma value;
          bfd_boolean addit;
          bfd_boolean addit;
 
 
          /* This symbol is externally visible.  */
          /* This symbol is externally visible.  */
 
 
          name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
          name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
          if (name == NULL)
          if (name == NULL)
            goto error_return;
            goto error_return;
 
 
          /* We must copy the name into memory if we got it from the
          /* We must copy the name into memory if we got it from the
             syment itself, rather than the string table.  */
             syment itself, rather than the string table.  */
          copy = default_copy;
          copy = default_copy;
          if (sym._n._n_n._n_zeroes != 0
          if (sym._n._n_n._n_zeroes != 0
              || sym._n._n_n._n_offset == 0)
              || sym._n._n_n._n_offset == 0)
            copy = TRUE;
            copy = TRUE;
 
 
          value = sym.n_value;
          value = sym.n_value;
 
 
          switch (classification)
          switch (classification)
            {
            {
            default:
            default:
              abort ();
              abort ();
 
 
            case COFF_SYMBOL_GLOBAL:
            case COFF_SYMBOL_GLOBAL:
              flags = BSF_EXPORT | BSF_GLOBAL;
              flags = BSF_EXPORT | BSF_GLOBAL;
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
              if (! obj_pe (abfd))
              if (! obj_pe (abfd))
                value -= section->vma;
                value -= section->vma;
              break;
              break;
 
 
            case COFF_SYMBOL_UNDEFINED:
            case COFF_SYMBOL_UNDEFINED:
              flags = 0;
              flags = 0;
              section = bfd_und_section_ptr;
              section = bfd_und_section_ptr;
              break;
              break;
 
 
            case COFF_SYMBOL_COMMON:
            case COFF_SYMBOL_COMMON:
              flags = BSF_GLOBAL;
              flags = BSF_GLOBAL;
              section = bfd_com_section_ptr;
              section = bfd_com_section_ptr;
              break;
              break;
 
 
            case COFF_SYMBOL_PE_SECTION:
            case COFF_SYMBOL_PE_SECTION:
              flags = BSF_SECTION_SYM | BSF_GLOBAL;
              flags = BSF_SECTION_SYM | BSF_GLOBAL;
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
              break;
              break;
            }
            }
 
 
          if (IS_WEAK_EXTERNAL (abfd, sym))
          if (IS_WEAK_EXTERNAL (abfd, sym))
            flags = BSF_WEAK;
            flags = BSF_WEAK;
 
 
          addit = TRUE;
          addit = TRUE;
 
 
          /* In the PE format, section symbols actually refer to the
          /* In the PE format, section symbols actually refer to the
             start of the output section.  We handle them specially
             start of the output section.  We handle them specially
             here.  */
             here.  */
          if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0)
          if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0)
            {
            {
              *sym_hash = coff_link_hash_lookup (coff_hash_table (info),
              *sym_hash = coff_link_hash_lookup (coff_hash_table (info),
                                                 name, FALSE, copy, FALSE);
                                                 name, FALSE, copy, FALSE);
              if (*sym_hash != NULL)
              if (*sym_hash != NULL)
                {
                {
                  if (((*sym_hash)->coff_link_hash_flags
                  if (((*sym_hash)->coff_link_hash_flags
                       & COFF_LINK_HASH_PE_SECTION_SYMBOL) == 0
                       & COFF_LINK_HASH_PE_SECTION_SYMBOL) == 0
                      && (*sym_hash)->root.type != bfd_link_hash_undefined
                      && (*sym_hash)->root.type != bfd_link_hash_undefined
                      && (*sym_hash)->root.type != bfd_link_hash_undefweak)
                      && (*sym_hash)->root.type != bfd_link_hash_undefweak)
                    (*_bfd_error_handler)
                    (*_bfd_error_handler)
                      ("Warning: symbol `%s' is both section and non-section",
                      ("Warning: symbol `%s' is both section and non-section",
                       name);
                       name);
 
 
                  addit = FALSE;
                  addit = FALSE;
                }
                }
            }
            }
 
 
          /* The Microsoft Visual C compiler does string pooling by
          /* The Microsoft Visual C compiler does string pooling by
             hashing the constants to an internal symbol name, and
             hashing the constants to an internal symbol name, and
             relying on the linker comdat support to discard
             relying on the linker comdat support to discard
             duplicate names.  However, if one string is a literal and
             duplicate names.  However, if one string is a literal and
             one is a data initializer, one will end up in the .data
             one is a data initializer, one will end up in the .data
             section and one will end up in the .rdata section.  The
             section and one will end up in the .rdata section.  The
             Microsoft linker will combine them into the .data
             Microsoft linker will combine them into the .data
             section, which seems to be wrong since it might cause the
             section, which seems to be wrong since it might cause the
             literal to change.
             literal to change.
 
 
             As long as there are no external references to the
             As long as there are no external references to the
             symbols, which there shouldn't be, we can treat the .data
             symbols, which there shouldn't be, we can treat the .data
             and .rdata instances as separate symbols.  The comdat
             and .rdata instances as separate symbols.  The comdat
             code in the linker will do the appropriate merging.  Here
             code in the linker will do the appropriate merging.  Here
             we avoid getting a multiple definition error for one of
             we avoid getting a multiple definition error for one of
             these special symbols.
             these special symbols.
 
 
             FIXME: I don't think this will work in the case where
             FIXME: I don't think this will work in the case where
             there are two object files which use the constants as a
             there are two object files which use the constants as a
             literal and two object files which use it as a data
             literal and two object files which use it as a data
             initializer.  One or the other of the second object files
             initializer.  One or the other of the second object files
             is going to wind up with an inappropriate reference.  */
             is going to wind up with an inappropriate reference.  */
          if (obj_pe (abfd)
          if (obj_pe (abfd)
              && (classification == COFF_SYMBOL_GLOBAL
              && (classification == COFF_SYMBOL_GLOBAL
                  || classification == COFF_SYMBOL_PE_SECTION)
                  || classification == COFF_SYMBOL_PE_SECTION)
              && coff_section_data (abfd, section) != NULL
              && coff_section_data (abfd, section) != NULL
              && coff_section_data (abfd, section)->comdat != NULL
              && coff_section_data (abfd, section)->comdat != NULL
              && CONST_STRNEQ (name, "??_")
              && CONST_STRNEQ (name, "??_")
              && strcmp (name, coff_section_data (abfd, section)->comdat->name) == 0)
              && strcmp (name, coff_section_data (abfd, section)->comdat->name) == 0)
            {
            {
              if (*sym_hash == NULL)
              if (*sym_hash == NULL)
                *sym_hash = coff_link_hash_lookup (coff_hash_table (info),
                *sym_hash = coff_link_hash_lookup (coff_hash_table (info),
                                                   name, FALSE, copy, FALSE);
                                                   name, FALSE, copy, FALSE);
              if (*sym_hash != NULL
              if (*sym_hash != NULL
                  && (*sym_hash)->root.type == bfd_link_hash_defined
                  && (*sym_hash)->root.type == bfd_link_hash_defined
                  && coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat != NULL
                  && coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat != NULL
                  && strcmp (coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat->name,
                  && strcmp (coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat->name,
                             coff_section_data (abfd, section)->comdat->name) == 0)
                             coff_section_data (abfd, section)->comdat->name) == 0)
                addit = FALSE;
                addit = FALSE;
            }
            }
 
 
          if (addit)
          if (addit)
            {
            {
              if (! (bfd_coff_link_add_one_symbol
              if (! (bfd_coff_link_add_one_symbol
                     (info, abfd, name, flags, section, value,
                     (info, abfd, name, flags, section, value,
                      (const char *) NULL, copy, FALSE,
                      (const char *) NULL, copy, FALSE,
                      (struct bfd_link_hash_entry **) sym_hash)))
                      (struct bfd_link_hash_entry **) sym_hash)))
                goto error_return;
                goto error_return;
            }
            }
 
 
          if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0)
          if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0)
            (*sym_hash)->coff_link_hash_flags |=
            (*sym_hash)->coff_link_hash_flags |=
              COFF_LINK_HASH_PE_SECTION_SYMBOL;
              COFF_LINK_HASH_PE_SECTION_SYMBOL;
 
 
          /* Limit the alignment of a common symbol to the possible
          /* Limit the alignment of a common symbol to the possible
             alignment of a section.  There is no point to permitting
             alignment of a section.  There is no point to permitting
             a higher alignment for a common symbol: we can not
             a higher alignment for a common symbol: we can not
             guarantee it, and it may cause us to allocate extra space
             guarantee it, and it may cause us to allocate extra space
             in the common section.  */
             in the common section.  */
          if (section == bfd_com_section_ptr
          if (section == bfd_com_section_ptr
              && (*sym_hash)->root.type == bfd_link_hash_common
              && (*sym_hash)->root.type == bfd_link_hash_common
              && ((*sym_hash)->root.u.c.p->alignment_power
              && ((*sym_hash)->root.u.c.p->alignment_power
                  > bfd_coff_default_section_alignment_power (abfd)))
                  > bfd_coff_default_section_alignment_power (abfd)))
            (*sym_hash)->root.u.c.p->alignment_power
            (*sym_hash)->root.u.c.p->alignment_power
              = bfd_coff_default_section_alignment_power (abfd);
              = bfd_coff_default_section_alignment_power (abfd);
 
 
          if (bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd))
          if (bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd))
            {
            {
              /* If we don't have any symbol information currently in
              /* If we don't have any symbol information currently in
                 the hash table, or if we are looking at a symbol
                 the hash table, or if we are looking at a symbol
                 definition, then update the symbol class and type in
                 definition, then update the symbol class and type in
                 the hash table.  */
                 the hash table.  */
              if (((*sym_hash)->symbol_class == C_NULL
              if (((*sym_hash)->symbol_class == C_NULL
                   && (*sym_hash)->type == T_NULL)
                   && (*sym_hash)->type == T_NULL)
                  || sym.n_scnum != 0
                  || sym.n_scnum != 0
                  || (sym.n_value != 0
                  || (sym.n_value != 0
                      && (*sym_hash)->root.type != bfd_link_hash_defined
                      && (*sym_hash)->root.type != bfd_link_hash_defined
                      && (*sym_hash)->root.type != bfd_link_hash_defweak))
                      && (*sym_hash)->root.type != bfd_link_hash_defweak))
                {
                {
                  (*sym_hash)->symbol_class = sym.n_sclass;
                  (*sym_hash)->symbol_class = sym.n_sclass;
                  if (sym.n_type != T_NULL)
                  if (sym.n_type != T_NULL)
                    {
                    {
                      /* We want to warn if the type changed, but not
                      /* We want to warn if the type changed, but not
                         if it changed from an unspecified type.
                         if it changed from an unspecified type.
                         Testing the whole type byte may work, but the
                         Testing the whole type byte may work, but the
                         change from (e.g.) a function of unspecified
                         change from (e.g.) a function of unspecified
                         type to function of known type also wants to
                         type to function of known type also wants to
                         skip the warning.  */
                         skip the warning.  */
                      if ((*sym_hash)->type != T_NULL
                      if ((*sym_hash)->type != T_NULL
                          && (*sym_hash)->type != sym.n_type
                          && (*sym_hash)->type != sym.n_type
                          && !(DTYPE ((*sym_hash)->type) == DTYPE (sym.n_type)
                          && !(DTYPE ((*sym_hash)->type) == DTYPE (sym.n_type)
                               && (BTYPE ((*sym_hash)->type) == T_NULL
                               && (BTYPE ((*sym_hash)->type) == T_NULL
                                   || BTYPE (sym.n_type) == T_NULL)))
                                   || BTYPE (sym.n_type) == T_NULL)))
                        (*_bfd_error_handler)
                        (*_bfd_error_handler)
                          (_("Warning: type of symbol `%s' changed from %d to %d in %B"),
                          (_("Warning: type of symbol `%s' changed from %d to %d in %B"),
                           abfd, name, (*sym_hash)->type, sym.n_type);
                           abfd, name, (*sym_hash)->type, sym.n_type);
 
 
                      /* We don't want to change from a meaningful
                      /* We don't want to change from a meaningful
                         base type to a null one, but if we know
                         base type to a null one, but if we know
                         nothing, take what little we might now know.  */
                         nothing, take what little we might now know.  */
                      if (BTYPE (sym.n_type) != T_NULL
                      if (BTYPE (sym.n_type) != T_NULL
                          || (*sym_hash)->type == T_NULL)
                          || (*sym_hash)->type == T_NULL)
                        (*sym_hash)->type = sym.n_type;
                        (*sym_hash)->type = sym.n_type;
                    }
                    }
                  (*sym_hash)->auxbfd = abfd;
                  (*sym_hash)->auxbfd = abfd;
                  if (sym.n_numaux != 0)
                  if (sym.n_numaux != 0)
                    {
                    {
                      union internal_auxent *alloc;
                      union internal_auxent *alloc;
                      unsigned int i;
                      unsigned int i;
                      bfd_byte *eaux;
                      bfd_byte *eaux;
                      union internal_auxent *iaux;
                      union internal_auxent *iaux;
 
 
                      (*sym_hash)->numaux = sym.n_numaux;
                      (*sym_hash)->numaux = sym.n_numaux;
                      alloc = ((union internal_auxent *)
                      alloc = ((union internal_auxent *)
                               bfd_hash_allocate (&info->hash->table,
                               bfd_hash_allocate (&info->hash->table,
                                                  (sym.n_numaux
                                                  (sym.n_numaux
                                                   * sizeof (*alloc))));
                                                   * sizeof (*alloc))));
                      if (alloc == NULL)
                      if (alloc == NULL)
                        goto error_return;
                        goto error_return;
                      for (i = 0, eaux = esym + symesz, iaux = alloc;
                      for (i = 0, eaux = esym + symesz, iaux = alloc;
                           i < sym.n_numaux;
                           i < sym.n_numaux;
                           i++, eaux += symesz, iaux++)
                           i++, eaux += symesz, iaux++)
                        bfd_coff_swap_aux_in (abfd, eaux, sym.n_type,
                        bfd_coff_swap_aux_in (abfd, eaux, sym.n_type,
                                              sym.n_sclass, (int) i,
                                              sym.n_sclass, (int) i,
                                              sym.n_numaux, iaux);
                                              sym.n_numaux, iaux);
                      (*sym_hash)->aux = alloc;
                      (*sym_hash)->aux = alloc;
                    }
                    }
                }
                }
            }
            }
 
 
          if (classification == COFF_SYMBOL_PE_SECTION
          if (classification == COFF_SYMBOL_PE_SECTION
              && (*sym_hash)->numaux != 0)
              && (*sym_hash)->numaux != 0)
            {
            {
              /* Some PE sections (such as .bss) have a zero size in
              /* Some PE sections (such as .bss) have a zero size in
                 the section header, but a non-zero size in the AUX
                 the section header, but a non-zero size in the AUX
                 record.  Correct that here.
                 record.  Correct that here.
 
 
                 FIXME: This is not at all the right place to do this.
                 FIXME: This is not at all the right place to do this.
                 For example, it won't help objdump.  This needs to be
                 For example, it won't help objdump.  This needs to be
                 done when we swap in the section header.  */
                 done when we swap in the section header.  */
              BFD_ASSERT ((*sym_hash)->numaux == 1);
              BFD_ASSERT ((*sym_hash)->numaux == 1);
              if (section->size == 0)
              if (section->size == 0)
                section->size = (*sym_hash)->aux[0].x_scn.x_scnlen;
                section->size = (*sym_hash)->aux[0].x_scn.x_scnlen;
 
 
              /* FIXME: We could test whether the section sizes
              /* FIXME: We could test whether the section sizes
                 matches the size in the aux entry, but apparently
                 matches the size in the aux entry, but apparently
                 that sometimes fails unexpectedly.  */
                 that sometimes fails unexpectedly.  */
            }
            }
        }
        }
 
 
      esym += (sym.n_numaux + 1) * symesz;
      esym += (sym.n_numaux + 1) * symesz;
      sym_hash += sym.n_numaux + 1;
      sym_hash += sym.n_numaux + 1;
    }
    }
 
 
  /* If this is a non-traditional, non-relocatable link, try to
  /* If this is a non-traditional, non-relocatable link, try to
     optimize the handling of any .stab/.stabstr sections.  */
     optimize the handling of any .stab/.stabstr sections.  */
  if (! info->relocatable
  if (! info->relocatable
      && ! info->traditional_format
      && ! info->traditional_format
      && bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd)
      && bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd)
      && (info->strip != strip_all && info->strip != strip_debugger))
      && (info->strip != strip_all && info->strip != strip_debugger))
    {
    {
      asection *stabstr;
      asection *stabstr;
 
 
      stabstr = bfd_get_section_by_name (abfd, ".stabstr");
      stabstr = bfd_get_section_by_name (abfd, ".stabstr");
 
 
      if (stabstr != NULL)
      if (stabstr != NULL)
        {
        {
          bfd_size_type string_offset = 0;
          bfd_size_type string_offset = 0;
          asection *stab;
          asection *stab;
 
 
          for (stab = abfd->sections; stab; stab = stab->next)
          for (stab = abfd->sections; stab; stab = stab->next)
            if (CONST_STRNEQ (stab->name, ".stab")
            if (CONST_STRNEQ (stab->name, ".stab")
                && (!stab->name[5]
                && (!stab->name[5]
                    || (stab->name[5] == '.' && ISDIGIT (stab->name[6]))))
                    || (stab->name[5] == '.' && ISDIGIT (stab->name[6]))))
            {
            {
              struct coff_link_hash_table *table;
              struct coff_link_hash_table *table;
              struct coff_section_tdata *secdata
              struct coff_section_tdata *secdata
                = coff_section_data (abfd, stab);
                = coff_section_data (abfd, stab);
 
 
              if (secdata == NULL)
              if (secdata == NULL)
                {
                {
                  amt = sizeof (struct coff_section_tdata);
                  amt = sizeof (struct coff_section_tdata);
                  stab->used_by_bfd = bfd_zalloc (abfd, amt);
                  stab->used_by_bfd = bfd_zalloc (abfd, amt);
                  if (stab->used_by_bfd == NULL)
                  if (stab->used_by_bfd == NULL)
                    goto error_return;
                    goto error_return;
                  secdata = coff_section_data (abfd, stab);
                  secdata = coff_section_data (abfd, stab);
                }
                }
 
 
              table = coff_hash_table (info);
              table = coff_hash_table (info);
 
 
              if (! _bfd_link_section_stabs (abfd, &table->stab_info,
              if (! _bfd_link_section_stabs (abfd, &table->stab_info,
                                             stab, stabstr,
                                             stab, stabstr,
                                             &secdata->stab_info,
                                             &secdata->stab_info,
                                             &string_offset))
                                             &string_offset))
                goto error_return;
                goto error_return;
            }
            }
        }
        }
    }
    }
 
 
  obj_coff_keep_syms (abfd) = keep_syms;
  obj_coff_keep_syms (abfd) = keep_syms;
 
 
  return TRUE;
  return TRUE;
 
 
 error_return:
 error_return:
  obj_coff_keep_syms (abfd) = keep_syms;
  obj_coff_keep_syms (abfd) = keep_syms;
  return FALSE;
  return FALSE;
}
}


/* Do the final link step.  */
/* Do the final link step.  */
 
 
bfd_boolean
bfd_boolean
_bfd_coff_final_link (bfd *abfd,
_bfd_coff_final_link (bfd *abfd,
                      struct bfd_link_info *info)
                      struct bfd_link_info *info)
{
{
  bfd_size_type symesz;
  bfd_size_type symesz;
  struct coff_final_link_info finfo;
  struct coff_final_link_info finfo;
  bfd_boolean debug_merge_allocated;
  bfd_boolean debug_merge_allocated;
  bfd_boolean long_section_names;
  bfd_boolean long_section_names;
  asection *o;
  asection *o;
  struct bfd_link_order *p;
  struct bfd_link_order *p;
  bfd_size_type max_sym_count;
  bfd_size_type max_sym_count;
  bfd_size_type max_lineno_count;
  bfd_size_type max_lineno_count;
  bfd_size_type max_reloc_count;
  bfd_size_type max_reloc_count;
  bfd_size_type max_output_reloc_count;
  bfd_size_type max_output_reloc_count;
  bfd_size_type max_contents_size;
  bfd_size_type max_contents_size;
  file_ptr rel_filepos;
  file_ptr rel_filepos;
  unsigned int relsz;
  unsigned int relsz;
  file_ptr line_filepos;
  file_ptr line_filepos;
  unsigned int linesz;
  unsigned int linesz;
  bfd *sub;
  bfd *sub;
  bfd_byte *external_relocs = NULL;
  bfd_byte *external_relocs = NULL;
  char strbuf[STRING_SIZE_SIZE];
  char strbuf[STRING_SIZE_SIZE];
  bfd_size_type amt;
  bfd_size_type amt;
 
 
  symesz = bfd_coff_symesz (abfd);
  symesz = bfd_coff_symesz (abfd);
 
 
  finfo.info = info;
  finfo.info = info;
  finfo.output_bfd = abfd;
  finfo.output_bfd = abfd;
  finfo.strtab = NULL;
  finfo.strtab = NULL;
  finfo.section_info = NULL;
  finfo.section_info = NULL;
  finfo.last_file_index = -1;
  finfo.last_file_index = -1;
  finfo.last_bf_index = -1;
  finfo.last_bf_index = -1;
  finfo.internal_syms = NULL;
  finfo.internal_syms = NULL;
  finfo.sec_ptrs = NULL;
  finfo.sec_ptrs = NULL;
  finfo.sym_indices = NULL;
  finfo.sym_indices = NULL;
  finfo.outsyms = NULL;
  finfo.outsyms = NULL;
  finfo.linenos = NULL;
  finfo.linenos = NULL;
  finfo.contents = NULL;
  finfo.contents = NULL;
  finfo.external_relocs = NULL;
  finfo.external_relocs = NULL;
  finfo.internal_relocs = NULL;
  finfo.internal_relocs = NULL;
  finfo.global_to_static = FALSE;
  finfo.global_to_static = FALSE;
  debug_merge_allocated = FALSE;
  debug_merge_allocated = FALSE;
 
 
  coff_data (abfd)->link_info = info;
  coff_data (abfd)->link_info = info;
 
 
  finfo.strtab = _bfd_stringtab_init ();
  finfo.strtab = _bfd_stringtab_init ();
  if (finfo.strtab == NULL)
  if (finfo.strtab == NULL)
    goto error_return;
    goto error_return;
 
 
  if (! coff_debug_merge_hash_table_init (&finfo.debug_merge))
  if (! coff_debug_merge_hash_table_init (&finfo.debug_merge))
    goto error_return;
    goto error_return;
  debug_merge_allocated = TRUE;
  debug_merge_allocated = TRUE;
 
 
  /* Compute the file positions for all the sections.  */
  /* Compute the file positions for all the sections.  */
  if (! abfd->output_has_begun)
  if (! abfd->output_has_begun)
    {
    {
      if (! bfd_coff_compute_section_file_positions (abfd))
      if (! bfd_coff_compute_section_file_positions (abfd))
        goto error_return;
        goto error_return;
    }
    }
 
 
  /* Count the line numbers and relocation entries required for the
  /* Count the line numbers and relocation entries required for the
     output file.  Set the file positions for the relocs.  */
     output file.  Set the file positions for the relocs.  */
  rel_filepos = obj_relocbase (abfd);
  rel_filepos = obj_relocbase (abfd);
  relsz = bfd_coff_relsz (abfd);
  relsz = bfd_coff_relsz (abfd);
  max_contents_size = 0;
  max_contents_size = 0;
  max_lineno_count = 0;
  max_lineno_count = 0;
  max_reloc_count = 0;
  max_reloc_count = 0;
 
 
  long_section_names = FALSE;
  long_section_names = FALSE;
  for (o = abfd->sections; o != NULL; o = o->next)
  for (o = abfd->sections; o != NULL; o = o->next)
    {
    {
      o->reloc_count = 0;
      o->reloc_count = 0;
      o->lineno_count = 0;
      o->lineno_count = 0;
      for (p = o->map_head.link_order; p != NULL; p = p->next)
      for (p = o->map_head.link_order; p != NULL; p = p->next)
        {
        {
          if (p->type == bfd_indirect_link_order)
          if (p->type == bfd_indirect_link_order)
            {
            {
              asection *sec;
              asection *sec;
 
 
              sec = p->u.indirect.section;
              sec = p->u.indirect.section;
 
 
              /* Mark all sections which are to be included in the
              /* Mark all sections which are to be included in the
                 link.  This will normally be every section.  We need
                 link.  This will normally be every section.  We need
                 to do this so that we can identify any sections which
                 to do this so that we can identify any sections which
                 the linker has decided to not include.  */
                 the linker has decided to not include.  */
              sec->linker_mark = TRUE;
              sec->linker_mark = TRUE;
 
 
              if (info->strip == strip_none
              if (info->strip == strip_none
                  || info->strip == strip_some)
                  || info->strip == strip_some)
                o->lineno_count += sec->lineno_count;
                o->lineno_count += sec->lineno_count;
 
 
              if (info->relocatable)
              if (info->relocatable)
                o->reloc_count += sec->reloc_count;
                o->reloc_count += sec->reloc_count;
 
 
              if (sec->rawsize > max_contents_size)
              if (sec->rawsize > max_contents_size)
                max_contents_size = sec->rawsize;
                max_contents_size = sec->rawsize;
              if (sec->size > max_contents_size)
              if (sec->size > max_contents_size)
                max_contents_size = sec->size;
                max_contents_size = sec->size;
              if (sec->lineno_count > max_lineno_count)
              if (sec->lineno_count > max_lineno_count)
                max_lineno_count = sec->lineno_count;
                max_lineno_count = sec->lineno_count;
              if (sec->reloc_count > max_reloc_count)
              if (sec->reloc_count > max_reloc_count)
                max_reloc_count = sec->reloc_count;
                max_reloc_count = sec->reloc_count;
            }
            }
          else if (info->relocatable
          else if (info->relocatable
                   && (p->type == bfd_section_reloc_link_order
                   && (p->type == bfd_section_reloc_link_order
                       || p->type == bfd_symbol_reloc_link_order))
                       || p->type == bfd_symbol_reloc_link_order))
            ++o->reloc_count;
            ++o->reloc_count;
        }
        }
      if (o->reloc_count == 0)
      if (o->reloc_count == 0)
        o->rel_filepos = 0;
        o->rel_filepos = 0;
      else
      else
        {
        {
          o->flags |= SEC_RELOC;
          o->flags |= SEC_RELOC;
          o->rel_filepos = rel_filepos;
          o->rel_filepos = rel_filepos;
          rel_filepos += o->reloc_count * relsz;
          rel_filepos += o->reloc_count * relsz;
          /* In PE COFF, if there are at least 0xffff relocations an
          /* In PE COFF, if there are at least 0xffff relocations an
             extra relocation will be written out to encode the count.  */
             extra relocation will be written out to encode the count.  */
          if (obj_pe (abfd) && o->reloc_count >= 0xffff)
          if (obj_pe (abfd) && o->reloc_count >= 0xffff)
            rel_filepos += relsz;
            rel_filepos += relsz;
        }
        }
 
 
      if (bfd_coff_long_section_names (abfd)
      if (bfd_coff_long_section_names (abfd)
          && strlen (o->name) > SCNNMLEN)
          && strlen (o->name) > SCNNMLEN)
        {
        {
          /* This section has a long name which must go in the string
          /* This section has a long name which must go in the string
             table.  This must correspond to the code in
             table.  This must correspond to the code in
             coff_write_object_contents which puts the string index
             coff_write_object_contents which puts the string index
             into the s_name field of the section header.  That is why
             into the s_name field of the section header.  That is why
             we pass hash as FALSE.  */
             we pass hash as FALSE.  */
          if (_bfd_stringtab_add (finfo.strtab, o->name, FALSE, FALSE)
          if (_bfd_stringtab_add (finfo.strtab, o->name, FALSE, FALSE)
              == (bfd_size_type) -1)
              == (bfd_size_type) -1)
            goto error_return;
            goto error_return;
          long_section_names = TRUE;
          long_section_names = TRUE;
        }
        }
    }
    }
 
 
  /* If doing a relocatable link, allocate space for the pointers we
  /* If doing a relocatable link, allocate space for the pointers we
     need to keep.  */
     need to keep.  */
  if (info->relocatable)
  if (info->relocatable)
    {
    {
      unsigned int i;
      unsigned int i;
 
 
      /* We use section_count + 1, rather than section_count, because
      /* We use section_count + 1, rather than section_count, because
         the target_index fields are 1 based.  */
         the target_index fields are 1 based.  */
      amt = abfd->section_count + 1;
      amt = abfd->section_count + 1;
      amt *= sizeof (struct coff_link_section_info);
      amt *= sizeof (struct coff_link_section_info);
      finfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt);
      finfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt);
      if (finfo.section_info == NULL)
      if (finfo.section_info == NULL)
        goto error_return;
        goto error_return;
      for (i = 0; i <= abfd->section_count; i++)
      for (i = 0; i <= abfd->section_count; i++)
        {
        {
          finfo.section_info[i].relocs = NULL;
          finfo.section_info[i].relocs = NULL;
          finfo.section_info[i].rel_hashes = NULL;
          finfo.section_info[i].rel_hashes = NULL;
        }
        }
    }
    }
 
 
  /* We now know the size of the relocs, so we can determine the file
  /* We now know the size of the relocs, so we can determine the file
     positions of the line numbers.  */
     positions of the line numbers.  */
  line_filepos = rel_filepos;
  line_filepos = rel_filepos;
  linesz = bfd_coff_linesz (abfd);
  linesz = bfd_coff_linesz (abfd);
  max_output_reloc_count = 0;
  max_output_reloc_count = 0;
  for (o = abfd->sections; o != NULL; o = o->next)
  for (o = abfd->sections; o != NULL; o = o->next)
    {
    {
      if (o->lineno_count == 0)
      if (o->lineno_count == 0)
        o->line_filepos = 0;
        o->line_filepos = 0;
      else
      else
        {
        {
          o->line_filepos = line_filepos;
          o->line_filepos = line_filepos;
          line_filepos += o->lineno_count * linesz;
          line_filepos += o->lineno_count * linesz;
        }
        }
 
 
      if (o->reloc_count != 0)
      if (o->reloc_count != 0)
        {
        {
          /* We don't know the indices of global symbols until we have
          /* We don't know the indices of global symbols until we have
             written out all the local symbols.  For each section in
             written out all the local symbols.  For each section in
             the output file, we keep an array of pointers to hash
             the output file, we keep an array of pointers to hash
             table entries.  Each entry in the array corresponds to a
             table entries.  Each entry in the array corresponds to a
             reloc.  When we find a reloc against a global symbol, we
             reloc.  When we find a reloc against a global symbol, we
             set the corresponding entry in this array so that we can
             set the corresponding entry in this array so that we can
             fix up the symbol index after we have written out all the
             fix up the symbol index after we have written out all the
             local symbols.
             local symbols.
 
 
             Because of this problem, we also keep the relocs in
             Because of this problem, we also keep the relocs in
             memory until the end of the link.  This wastes memory,
             memory until the end of the link.  This wastes memory,
             but only when doing a relocatable link, which is not the
             but only when doing a relocatable link, which is not the
             common case.  */
             common case.  */
          BFD_ASSERT (info->relocatable);
          BFD_ASSERT (info->relocatable);
          amt = o->reloc_count;
          amt = o->reloc_count;
          amt *= sizeof (struct internal_reloc);
          amt *= sizeof (struct internal_reloc);
          finfo.section_info[o->target_index].relocs =
          finfo.section_info[o->target_index].relocs =
              (struct internal_reloc *) bfd_malloc (amt);
              (struct internal_reloc *) bfd_malloc (amt);
          amt = o->reloc_count;
          amt = o->reloc_count;
          amt *= sizeof (struct coff_link_hash_entry *);
          amt *= sizeof (struct coff_link_hash_entry *);
          finfo.section_info[o->target_index].rel_hashes =
          finfo.section_info[o->target_index].rel_hashes =
              (struct coff_link_hash_entry **) bfd_malloc (amt);
              (struct coff_link_hash_entry **) bfd_malloc (amt);
          if (finfo.section_info[o->target_index].relocs == NULL
          if (finfo.section_info[o->target_index].relocs == NULL
              || finfo.section_info[o->target_index].rel_hashes == NULL)
              || finfo.section_info[o->target_index].rel_hashes == NULL)
            goto error_return;
            goto error_return;
 
 
          if (o->reloc_count > max_output_reloc_count)
          if (o->reloc_count > max_output_reloc_count)
            max_output_reloc_count = o->reloc_count;
            max_output_reloc_count = o->reloc_count;
        }
        }
 
 
      /* Reset the reloc and lineno counts, so that we can use them to
      /* Reset the reloc and lineno counts, so that we can use them to
         count the number of entries we have output so far.  */
         count the number of entries we have output so far.  */
      o->reloc_count = 0;
      o->reloc_count = 0;
      o->lineno_count = 0;
      o->lineno_count = 0;
    }
    }
 
 
  obj_sym_filepos (abfd) = line_filepos;
  obj_sym_filepos (abfd) = line_filepos;
 
 
  /* Figure out the largest number of symbols in an input BFD.  Take
  /* Figure out the largest number of symbols in an input BFD.  Take
     the opportunity to clear the output_has_begun fields of all the
     the opportunity to clear the output_has_begun fields of all the
     input BFD's.  */
     input BFD's.  */
  max_sym_count = 0;
  max_sym_count = 0;
  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
    {
    {
      size_t sz;
      size_t sz;
 
 
      sub->output_has_begun = FALSE;
      sub->output_has_begun = FALSE;
      sz = obj_raw_syment_count (sub);
      sz = obj_raw_syment_count (sub);
      if (sz > max_sym_count)
      if (sz > max_sym_count)
        max_sym_count = sz;
        max_sym_count = sz;
    }
    }
 
 
  /* Allocate some buffers used while linking.  */
  /* Allocate some buffers used while linking.  */
  amt = max_sym_count * sizeof (struct internal_syment);
  amt = max_sym_count * sizeof (struct internal_syment);
  finfo.internal_syms = (struct internal_syment *) bfd_malloc (amt);
  finfo.internal_syms = (struct internal_syment *) bfd_malloc (amt);
  amt = max_sym_count * sizeof (asection *);
  amt = max_sym_count * sizeof (asection *);
  finfo.sec_ptrs = (asection **) bfd_malloc (amt);
  finfo.sec_ptrs = (asection **) bfd_malloc (amt);
  amt = max_sym_count * sizeof (long);
  amt = max_sym_count * sizeof (long);
  finfo.sym_indices = (long int *) bfd_malloc (amt);
  finfo.sym_indices = (long int *) bfd_malloc (amt);
  finfo.outsyms = (bfd_byte *) bfd_malloc ((max_sym_count + 1) * symesz);
  finfo.outsyms = (bfd_byte *) bfd_malloc ((max_sym_count + 1) * symesz);
  amt = max_lineno_count * bfd_coff_linesz (abfd);
  amt = max_lineno_count * bfd_coff_linesz (abfd);
  finfo.linenos = (bfd_byte *) bfd_malloc (amt);
  finfo.linenos = (bfd_byte *) bfd_malloc (amt);
  finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
  finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
  amt = max_reloc_count * relsz;
  amt = max_reloc_count * relsz;
  finfo.external_relocs = (bfd_byte *) bfd_malloc (amt);
  finfo.external_relocs = (bfd_byte *) bfd_malloc (amt);
  if (! info->relocatable)
  if (! info->relocatable)
    {
    {
      amt = max_reloc_count * sizeof (struct internal_reloc);
      amt = max_reloc_count * sizeof (struct internal_reloc);
      finfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt);
      finfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt);
    }
    }
  if ((finfo.internal_syms == NULL && max_sym_count > 0)
  if ((finfo.internal_syms == NULL && max_sym_count > 0)
      || (finfo.sec_ptrs == NULL && max_sym_count > 0)
      || (finfo.sec_ptrs == NULL && max_sym_count > 0)
      || (finfo.sym_indices == NULL && max_sym_count > 0)
      || (finfo.sym_indices == NULL && max_sym_count > 0)
      || finfo.outsyms == NULL
      || finfo.outsyms == NULL
      || (finfo.linenos == NULL && max_lineno_count > 0)
      || (finfo.linenos == NULL && max_lineno_count > 0)
      || (finfo.contents == NULL && max_contents_size > 0)
      || (finfo.contents == NULL && max_contents_size > 0)
      || (finfo.external_relocs == NULL && max_reloc_count > 0)
      || (finfo.external_relocs == NULL && max_reloc_count > 0)
      || (! info->relocatable
      || (! info->relocatable
          && finfo.internal_relocs == NULL
          && finfo.internal_relocs == NULL
          && max_reloc_count > 0))
          && max_reloc_count > 0))
    goto error_return;
    goto error_return;
 
 
  /* We now know the position of everything in the file, except that
  /* We now know the position of everything in the file, except that
     we don't know the size of the symbol table and therefore we don't
     we don't know the size of the symbol table and therefore we don't
     know where the string table starts.  We just build the string
     know where the string table starts.  We just build the string
     table in memory as we go along.  We process all the relocations
     table in memory as we go along.  We process all the relocations
     for a single input file at once.  */
     for a single input file at once.  */
  obj_raw_syment_count (abfd) = 0;
  obj_raw_syment_count (abfd) = 0;
 
 
  if (coff_backend_info (abfd)->_bfd_coff_start_final_link)
  if (coff_backend_info (abfd)->_bfd_coff_start_final_link)
    {
    {
      if (! bfd_coff_start_final_link (abfd, info))
      if (! bfd_coff_start_final_link (abfd, info))
        goto error_return;
        goto error_return;
    }
    }
 
 
  for (o = abfd->sections; o != NULL; o = o->next)
  for (o = abfd->sections; o != NULL; o = o->next)
    {
    {
      for (p = o->map_head.link_order; p != NULL; p = p->next)
      for (p = o->map_head.link_order; p != NULL; p = p->next)
        {
        {
          if (p->type == bfd_indirect_link_order
          if (p->type == bfd_indirect_link_order
              && bfd_family_coff (p->u.indirect.section->owner))
              && bfd_family_coff (p->u.indirect.section->owner))
            {
            {
              sub = p->u.indirect.section->owner;
              sub = p->u.indirect.section->owner;
              if (! bfd_coff_link_output_has_begun (sub, & finfo))
              if (! bfd_coff_link_output_has_begun (sub, & finfo))
                {
                {
                  if (! _bfd_coff_link_input_bfd (&finfo, sub))
                  if (! _bfd_coff_link_input_bfd (&finfo, sub))
                    goto error_return;
                    goto error_return;
                  sub->output_has_begun = TRUE;
                  sub->output_has_begun = TRUE;
                }
                }
            }
            }
          else if (p->type == bfd_section_reloc_link_order
          else if (p->type == bfd_section_reloc_link_order
                   || p->type == bfd_symbol_reloc_link_order)
                   || p->type == bfd_symbol_reloc_link_order)
            {
            {
              if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p))
              if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p))
                goto error_return;
                goto error_return;
            }
            }
          else
          else
            {
            {
              if (! _bfd_default_link_order (abfd, info, o, p))
              if (! _bfd_default_link_order (abfd, info, o, p))
                goto error_return;
                goto error_return;
            }
            }
        }
        }
    }
    }
 
 
  if (! bfd_coff_final_link_postscript (abfd, & finfo))
  if (! bfd_coff_final_link_postscript (abfd, & finfo))
    goto error_return;
    goto error_return;
 
 
  /* Free up the buffers used by _bfd_coff_link_input_bfd.  */
  /* Free up the buffers used by _bfd_coff_link_input_bfd.  */
 
 
  coff_debug_merge_hash_table_free (&finfo.debug_merge);
  coff_debug_merge_hash_table_free (&finfo.debug_merge);
  debug_merge_allocated = FALSE;
  debug_merge_allocated = FALSE;
 
 
  if (finfo.internal_syms != NULL)
  if (finfo.internal_syms != NULL)
    {
    {
      free (finfo.internal_syms);
      free (finfo.internal_syms);
      finfo.internal_syms = NULL;
      finfo.internal_syms = NULL;
    }
    }
  if (finfo.sec_ptrs != NULL)
  if (finfo.sec_ptrs != NULL)
    {
    {
      free (finfo.sec_ptrs);
      free (finfo.sec_ptrs);
      finfo.sec_ptrs = NULL;
      finfo.sec_ptrs = NULL;
    }
    }
  if (finfo.sym_indices != NULL)
  if (finfo.sym_indices != NULL)
    {
    {
      free (finfo.sym_indices);
      free (finfo.sym_indices);
      finfo.sym_indices = NULL;
      finfo.sym_indices = NULL;
    }
    }
  if (finfo.linenos != NULL)
  if (finfo.linenos != NULL)
    {
    {
      free (finfo.linenos);
      free (finfo.linenos);
      finfo.linenos = NULL;
      finfo.linenos = NULL;
    }
    }
  if (finfo.contents != NULL)
  if (finfo.contents != NULL)
    {
    {
      free (finfo.contents);
      free (finfo.contents);
      finfo.contents = NULL;
      finfo.contents = NULL;
    }
    }
  if (finfo.external_relocs != NULL)
  if (finfo.external_relocs != NULL)
    {
    {
      free (finfo.external_relocs);
      free (finfo.external_relocs);
      finfo.external_relocs = NULL;
      finfo.external_relocs = NULL;
    }
    }
  if (finfo.internal_relocs != NULL)
  if (finfo.internal_relocs != NULL)
    {
    {
      free (finfo.internal_relocs);
      free (finfo.internal_relocs);
      finfo.internal_relocs = NULL;
      finfo.internal_relocs = NULL;
    }
    }
 
 
  /* The value of the last C_FILE symbol is supposed to be the symbol
  /* The value of the last C_FILE symbol is supposed to be the symbol
     index of the first external symbol.  Write it out again if
     index of the first external symbol.  Write it out again if
     necessary.  */
     necessary.  */
  if (finfo.last_file_index != -1
  if (finfo.last_file_index != -1
      && (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd))
      && (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd))
    {
    {
      file_ptr pos;
      file_ptr pos;
 
 
      finfo.last_file.n_value = obj_raw_syment_count (abfd);
      finfo.last_file.n_value = obj_raw_syment_count (abfd);
      bfd_coff_swap_sym_out (abfd, &finfo.last_file,
      bfd_coff_swap_sym_out (abfd, &finfo.last_file,
                             finfo.outsyms);
                             finfo.outsyms);
 
 
      pos = obj_sym_filepos (abfd) + finfo.last_file_index * symesz;
      pos = obj_sym_filepos (abfd) + finfo.last_file_index * symesz;
      if (bfd_seek (abfd, pos, SEEK_SET) != 0
      if (bfd_seek (abfd, pos, SEEK_SET) != 0
          || bfd_bwrite (finfo.outsyms, symesz, abfd) != symesz)
          || bfd_bwrite (finfo.outsyms, symesz, abfd) != symesz)
        return FALSE;
        return FALSE;
    }
    }
 
 
  /* If doing task linking (ld --task-link) then make a pass through the
  /* If doing task linking (ld --task-link) then make a pass through the
     global symbols, writing out any that are defined, and making them
     global symbols, writing out any that are defined, and making them
     static.  */
     static.  */
  if (info->task_link)
  if (info->task_link)
    {
    {
      finfo.failed = FALSE;
      finfo.failed = FALSE;
      coff_link_hash_traverse (coff_hash_table (info),
      coff_link_hash_traverse (coff_hash_table (info),
                               _bfd_coff_write_task_globals, &finfo);
                               _bfd_coff_write_task_globals, &finfo);
      if (finfo.failed)
      if (finfo.failed)
        goto error_return;
        goto error_return;
    }
    }
 
 
  /* Write out the global symbols.  */
  /* Write out the global symbols.  */
  finfo.failed = FALSE;
  finfo.failed = FALSE;
  coff_link_hash_traverse (coff_hash_table (info),
  coff_link_hash_traverse (coff_hash_table (info),
                           _bfd_coff_write_global_sym, &finfo);
                           _bfd_coff_write_global_sym, &finfo);
  if (finfo.failed)
  if (finfo.failed)
    goto error_return;
    goto error_return;
 
 
  /* The outsyms buffer is used by _bfd_coff_write_global_sym.  */
  /* The outsyms buffer is used by _bfd_coff_write_global_sym.  */
  if (finfo.outsyms != NULL)
  if (finfo.outsyms != NULL)
    {
    {
      free (finfo.outsyms);
      free (finfo.outsyms);
      finfo.outsyms = NULL;
      finfo.outsyms = NULL;
    }
    }
 
 
  if (info->relocatable && max_output_reloc_count > 0)
  if (info->relocatable && max_output_reloc_count > 0)
    {
    {
      /* Now that we have written out all the global symbols, we know
      /* Now that we have written out all the global symbols, we know
         the symbol indices to use for relocs against them, and we can
         the symbol indices to use for relocs against them, and we can
         finally write out the relocs.  */
         finally write out the relocs.  */
      amt = max_output_reloc_count * relsz;
      amt = max_output_reloc_count * relsz;
      external_relocs = (bfd_byte *) bfd_malloc (amt);
      external_relocs = (bfd_byte *) bfd_malloc (amt);
      if (external_relocs == NULL)
      if (external_relocs == NULL)
        goto error_return;
        goto error_return;
 
 
      for (o = abfd->sections; o != NULL; o = o->next)
      for (o = abfd->sections; o != NULL; o = o->next)
        {
        {
          struct internal_reloc *irel;
          struct internal_reloc *irel;
          struct internal_reloc *irelend;
          struct internal_reloc *irelend;
          struct coff_link_hash_entry **rel_hash;
          struct coff_link_hash_entry **rel_hash;
          bfd_byte *erel;
          bfd_byte *erel;
 
 
          if (o->reloc_count == 0)
          if (o->reloc_count == 0)
            continue;
            continue;
 
 
          irel = finfo.section_info[o->target_index].relocs;
          irel = finfo.section_info[o->target_index].relocs;
          irelend = irel + o->reloc_count;
          irelend = irel + o->reloc_count;
          rel_hash = finfo.section_info[o->target_index].rel_hashes;
          rel_hash = finfo.section_info[o->target_index].rel_hashes;
          erel = external_relocs;
          erel = external_relocs;
          for (; irel < irelend; irel++, rel_hash++, erel += relsz)
          for (; irel < irelend; irel++, rel_hash++, erel += relsz)
            {
            {
              if (*rel_hash != NULL)
              if (*rel_hash != NULL)
                {
                {
                  BFD_ASSERT ((*rel_hash)->indx >= 0);
                  BFD_ASSERT ((*rel_hash)->indx >= 0);
                  irel->r_symndx = (*rel_hash)->indx;
                  irel->r_symndx = (*rel_hash)->indx;
                }
                }
              bfd_coff_swap_reloc_out (abfd, irel, erel);
              bfd_coff_swap_reloc_out (abfd, irel, erel);
            }
            }
 
 
          if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0)
          if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0)
            goto error_return;
            goto error_return;
          if (obj_pe (abfd) && o->reloc_count >= 0xffff)
          if (obj_pe (abfd) && o->reloc_count >= 0xffff)
            {
            {
              /* In PE COFF, write the count of relocs as the first
              /* In PE COFF, write the count of relocs as the first
                 reloc.  The header overflow bit will be set
                 reloc.  The header overflow bit will be set
                 elsewhere. */
                 elsewhere. */
              struct internal_reloc incount;
              struct internal_reloc incount;
              bfd_byte *excount = (bfd_byte *)bfd_malloc (relsz);
              bfd_byte *excount = (bfd_byte *)bfd_malloc (relsz);
 
 
              memset (&incount, 0, sizeof (incount));
              memset (&incount, 0, sizeof (incount));
              incount.r_vaddr = o->reloc_count + 1;
              incount.r_vaddr = o->reloc_count + 1;
              bfd_coff_swap_reloc_out (abfd, (PTR) &incount, (PTR) excount);
              bfd_coff_swap_reloc_out (abfd, (PTR) &incount, (PTR) excount);
              if (bfd_bwrite (excount, relsz, abfd) != relsz)
              if (bfd_bwrite (excount, relsz, abfd) != relsz)
                /* We'll leak, but it's an error anyway. */
                /* We'll leak, but it's an error anyway. */
                goto error_return;
                goto error_return;
              free (excount);
              free (excount);
            }
            }
          if (bfd_bwrite (external_relocs,
          if (bfd_bwrite (external_relocs,
                          (bfd_size_type) relsz * o->reloc_count, abfd)
                          (bfd_size_type) relsz * o->reloc_count, abfd)
              != (bfd_size_type) relsz * o->reloc_count)
              != (bfd_size_type) relsz * o->reloc_count)
            goto error_return;
            goto error_return;
        }
        }
 
 
      free (external_relocs);
      free (external_relocs);
      external_relocs = NULL;
      external_relocs = NULL;
    }
    }
 
 
  /* Free up the section information.  */
  /* Free up the section information.  */
  if (finfo.section_info != NULL)
  if (finfo.section_info != NULL)
    {
    {
      unsigned int i;
      unsigned int i;
 
 
      for (i = 0; i < abfd->section_count; i++)
      for (i = 0; i < abfd->section_count; i++)
        {
        {
          if (finfo.section_info[i].relocs != NULL)
          if (finfo.section_info[i].relocs != NULL)
            free (finfo.section_info[i].relocs);
            free (finfo.section_info[i].relocs);
          if (finfo.section_info[i].rel_hashes != NULL)
          if (finfo.section_info[i].rel_hashes != NULL)
            free (finfo.section_info[i].rel_hashes);
            free (finfo.section_info[i].rel_hashes);
        }
        }
      free (finfo.section_info);
      free (finfo.section_info);
      finfo.section_info = NULL;
      finfo.section_info = NULL;
    }
    }
 
 
  /* If we have optimized stabs strings, output them.  */
  /* If we have optimized stabs strings, output them.  */
  if (coff_hash_table (info)->stab_info.stabstr != NULL)
  if (coff_hash_table (info)->stab_info.stabstr != NULL)
    {
    {
      if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info))
      if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info))
        return FALSE;
        return FALSE;
    }
    }
 
 
  /* Write out the string table.  */
  /* Write out the string table.  */
  if (obj_raw_syment_count (abfd) != 0 || long_section_names)
  if (obj_raw_syment_count (abfd) != 0 || long_section_names)
    {
    {
      file_ptr pos;
      file_ptr pos;
 
 
      pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd) * symesz;
      pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd) * symesz;
      if (bfd_seek (abfd, pos, SEEK_SET) != 0)
      if (bfd_seek (abfd, pos, SEEK_SET) != 0)
        return FALSE;
        return FALSE;
 
 
#if STRING_SIZE_SIZE == 4
#if STRING_SIZE_SIZE == 4
      H_PUT_32 (abfd,
      H_PUT_32 (abfd,
                _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
                _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
                strbuf);
                strbuf);
#else
#else
 #error Change H_PUT_32 above
 #error Change H_PUT_32 above
#endif
#endif
 
 
      if (bfd_bwrite (strbuf, (bfd_size_type) STRING_SIZE_SIZE, abfd)
      if (bfd_bwrite (strbuf, (bfd_size_type) STRING_SIZE_SIZE, abfd)
          != STRING_SIZE_SIZE)
          != STRING_SIZE_SIZE)
        return FALSE;
        return FALSE;
 
 
      if (! _bfd_stringtab_emit (abfd, finfo.strtab))
      if (! _bfd_stringtab_emit (abfd, finfo.strtab))
        return FALSE;
        return FALSE;
 
 
      obj_coff_strings_written (abfd) = TRUE;
      obj_coff_strings_written (abfd) = TRUE;
    }
    }
 
 
  _bfd_stringtab_free (finfo.strtab);
  _bfd_stringtab_free (finfo.strtab);
 
 
  /* Setting bfd_get_symcount to 0 will cause write_object_contents to
  /* Setting bfd_get_symcount to 0 will cause write_object_contents to
     not try to write out the symbols.  */
     not try to write out the symbols.  */
  bfd_get_symcount (abfd) = 0;
  bfd_get_symcount (abfd) = 0;
 
 
  return TRUE;
  return TRUE;
 
 
 error_return:
 error_return:
  if (debug_merge_allocated)
  if (debug_merge_allocated)
    coff_debug_merge_hash_table_free (&finfo.debug_merge);
    coff_debug_merge_hash_table_free (&finfo.debug_merge);
  if (finfo.strtab != NULL)
  if (finfo.strtab != NULL)
    _bfd_stringtab_free (finfo.strtab);
    _bfd_stringtab_free (finfo.strtab);
  if (finfo.section_info != NULL)
  if (finfo.section_info != NULL)
    {
    {
      unsigned int i;
      unsigned int i;
 
 
      for (i = 0; i < abfd->section_count; i++)
      for (i = 0; i < abfd->section_count; i++)
        {
        {
          if (finfo.section_info[i].relocs != NULL)
          if (finfo.section_info[i].relocs != NULL)
            free (finfo.section_info[i].relocs);
            free (finfo.section_info[i].relocs);
          if (finfo.section_info[i].rel_hashes != NULL)
          if (finfo.section_info[i].rel_hashes != NULL)
            free (finfo.section_info[i].rel_hashes);
            free (finfo.section_info[i].rel_hashes);
        }
        }
      free (finfo.section_info);
      free (finfo.section_info);
    }
    }
  if (finfo.internal_syms != NULL)
  if (finfo.internal_syms != NULL)
    free (finfo.internal_syms);
    free (finfo.internal_syms);
  if (finfo.sec_ptrs != NULL)
  if (finfo.sec_ptrs != NULL)
    free (finfo.sec_ptrs);
    free (finfo.sec_ptrs);
  if (finfo.sym_indices != NULL)
  if (finfo.sym_indices != NULL)
    free (finfo.sym_indices);
    free (finfo.sym_indices);
  if (finfo.outsyms != NULL)
  if (finfo.outsyms != NULL)
    free (finfo.outsyms);
    free (finfo.outsyms);
  if (finfo.linenos != NULL)
  if (finfo.linenos != NULL)
    free (finfo.linenos);
    free (finfo.linenos);
  if (finfo.contents != NULL)
  if (finfo.contents != NULL)
    free (finfo.contents);
    free (finfo.contents);
  if (finfo.external_relocs != NULL)
  if (finfo.external_relocs != NULL)
    free (finfo.external_relocs);
    free (finfo.external_relocs);
  if (finfo.internal_relocs != NULL)
  if (finfo.internal_relocs != NULL)
    free (finfo.internal_relocs);
    free (finfo.internal_relocs);
  if (external_relocs != NULL)
  if (external_relocs != NULL)
    free (external_relocs);
    free (external_relocs);
  return FALSE;
  return FALSE;
}
}
 
 
/* Parse out a -heap <reserved>,<commit> line.  */
/* Parse out a -heap <reserved>,<commit> line.  */
 
 
static char *
static char *
dores_com (char *ptr, bfd *output_bfd, int heap)
dores_com (char *ptr, bfd *output_bfd, int heap)
{
{
  if (coff_data(output_bfd)->pe)
  if (coff_data(output_bfd)->pe)
    {
    {
      int val = strtoul (ptr, &ptr, 0);
      int val = strtoul (ptr, &ptr, 0);
 
 
      if (heap)
      if (heap)
        pe_data(output_bfd)->pe_opthdr.SizeOfHeapReserve = val;
        pe_data(output_bfd)->pe_opthdr.SizeOfHeapReserve = val;
      else
      else
        pe_data(output_bfd)->pe_opthdr.SizeOfStackReserve = val;
        pe_data(output_bfd)->pe_opthdr.SizeOfStackReserve = val;
 
 
      if (ptr[0] == ',')
      if (ptr[0] == ',')
        {
        {
          val = strtoul (ptr+1, &ptr, 0);
          val = strtoul (ptr+1, &ptr, 0);
          if (heap)
          if (heap)
            pe_data(output_bfd)->pe_opthdr.SizeOfHeapCommit = val;
            pe_data(output_bfd)->pe_opthdr.SizeOfHeapCommit = val;
          else
          else
            pe_data(output_bfd)->pe_opthdr.SizeOfStackCommit = val;
            pe_data(output_bfd)->pe_opthdr.SizeOfStackCommit = val;
        }
        }
    }
    }
  return ptr;
  return ptr;
}
}
 
 
static char *
static char *
get_name (char *ptr, char **dst)
get_name (char *ptr, char **dst)
{
{
  while (*ptr == ' ')
  while (*ptr == ' ')
    ptr++;
    ptr++;
  *dst = ptr;
  *dst = ptr;
  while (*ptr && *ptr != ' ')
  while (*ptr && *ptr != ' ')
    ptr++;
    ptr++;
  *ptr = 0;
  *ptr = 0;
  return ptr+1;
  return ptr+1;
}
}
 
 
/* Process any magic embedded commands in a section called .drectve.  */
/* Process any magic embedded commands in a section called .drectve.  */
 
 
static int
static int
process_embedded_commands (bfd *output_bfd,
process_embedded_commands (bfd *output_bfd,
                           struct bfd_link_info *info ATTRIBUTE_UNUSED,
                           struct bfd_link_info *info ATTRIBUTE_UNUSED,
                           bfd *abfd)
                           bfd *abfd)
{
{
  asection *sec = bfd_get_section_by_name (abfd, ".drectve");
  asection *sec = bfd_get_section_by_name (abfd, ".drectve");
  char *s;
  char *s;
  char *e;
  char *e;
  bfd_byte *copy;
  bfd_byte *copy;
 
 
  if (!sec)
  if (!sec)
    return 1;
    return 1;
 
 
  if (!bfd_malloc_and_get_section (abfd, sec, &copy))
  if (!bfd_malloc_and_get_section (abfd, sec, &copy))
    {
    {
      if (copy != NULL)
      if (copy != NULL)
        free (copy);
        free (copy);
      return 0;
      return 0;
    }
    }
  e = (char *) copy + sec->size;
  e = (char *) copy + sec->size;
 
 
  for (s = (char *) copy; s < e ; )
  for (s = (char *) copy; s < e ; )
    {
    {
      if (s[0] != '-')
      if (s[0] != '-')
        {
        {
          s++;
          s++;
          continue;
          continue;
        }
        }
      if (CONST_STRNEQ (s, "-attr"))
      if (CONST_STRNEQ (s, "-attr"))
        {
        {
          char *name;
          char *name;
          char *attribs;
          char *attribs;
          asection *asec;
          asection *asec;
          int loop = 1;
          int loop = 1;
          int had_write = 0;
          int had_write = 0;
          int had_exec= 0;
          int had_exec= 0;
 
 
          s += 5;
          s += 5;
          s = get_name (s, &name);
          s = get_name (s, &name);
          s = get_name (s, &attribs);
          s = get_name (s, &attribs);
 
 
          while (loop)
          while (loop)
            {
            {
              switch (*attribs++)
              switch (*attribs++)
                {
                {
                case 'W':
                case 'W':
                  had_write = 1;
                  had_write = 1;
                  break;
                  break;
                case 'R':
                case 'R':
                  break;
                  break;
                case 'S':
                case 'S':
                  break;
                  break;
                case 'X':
                case 'X':
                  had_exec = 1;
                  had_exec = 1;
                  break;
                  break;
                default:
                default:
                  loop = 0;
                  loop = 0;
                }
                }
            }
            }
          asec = bfd_get_section_by_name (abfd, name);
          asec = bfd_get_section_by_name (abfd, name);
          if (asec)
          if (asec)
            {
            {
              if (had_exec)
              if (had_exec)
                asec->flags |= SEC_CODE;
                asec->flags |= SEC_CODE;
              if (!had_write)
              if (!had_write)
                asec->flags |= SEC_READONLY;
                asec->flags |= SEC_READONLY;
            }
            }
        }
        }
      else if (CONST_STRNEQ (s, "-heap"))
      else if (CONST_STRNEQ (s, "-heap"))
        s = dores_com (s + 5, output_bfd, 1);
        s = dores_com (s + 5, output_bfd, 1);
 
 
      else if (CONST_STRNEQ (s, "-stack"))
      else if (CONST_STRNEQ (s, "-stack"))
        s = dores_com (s + 6, output_bfd, 0);
        s = dores_com (s + 6, output_bfd, 0);
 
 
      /* GNU extension for aligned commons.  */
      /* GNU extension for aligned commons.  */
      else if (CONST_STRNEQ (s, "-aligncomm:"))
      else if (CONST_STRNEQ (s, "-aligncomm:"))
        {
        {
          /* Common symbols must be aligned on reading, as it
          /* Common symbols must be aligned on reading, as it
          is too late to do anything here, after they have
          is too late to do anything here, after they have
          already been allocated, so just skip the directive.  */
          already been allocated, so just skip the directive.  */
          s += 11;
          s += 11;
        }
        }
 
 
      else
      else
        s++;
        s++;
    }
    }
  free (copy);
  free (copy);
  return 1;
  return 1;
}
}
 
 
/* Place a marker against all symbols which are used by relocations.
/* Place a marker against all symbols which are used by relocations.
   This marker can be picked up by the 'do we skip this symbol ?'
   This marker can be picked up by the 'do we skip this symbol ?'
   loop in _bfd_coff_link_input_bfd() and used to prevent skipping
   loop in _bfd_coff_link_input_bfd() and used to prevent skipping
   that symbol.  */
   that symbol.  */
 
 
static void
static void
mark_relocs (struct coff_final_link_info *finfo, bfd *input_bfd)
mark_relocs (struct coff_final_link_info *finfo, bfd *input_bfd)
{
{
  asection * a;
  asection * a;
 
 
  if ((bfd_get_file_flags (input_bfd) & HAS_SYMS) == 0)
  if ((bfd_get_file_flags (input_bfd) & HAS_SYMS) == 0)
    return;
    return;
 
 
  for (a = input_bfd->sections; a != (asection *) NULL; a = a->next)
  for (a = input_bfd->sections; a != (asection *) NULL; a = a->next)
    {
    {
      struct internal_reloc *   internal_relocs;
      struct internal_reloc *   internal_relocs;
      struct internal_reloc *   irel;
      struct internal_reloc *   irel;
      struct internal_reloc *   irelend;
      struct internal_reloc *   irelend;
 
 
      if ((a->flags & SEC_RELOC) == 0 || a->reloc_count  < 1)
      if ((a->flags & SEC_RELOC) == 0 || a->reloc_count  < 1)
        continue;
        continue;
      /* Don't mark relocs in excluded sections.  */
      /* Don't mark relocs in excluded sections.  */
      if (a->output_section == bfd_abs_section_ptr)
      if (a->output_section == bfd_abs_section_ptr)
        continue;
        continue;
 
 
      /* Read in the relocs.  */
      /* Read in the relocs.  */
      internal_relocs = _bfd_coff_read_internal_relocs
      internal_relocs = _bfd_coff_read_internal_relocs
        (input_bfd, a, FALSE,
        (input_bfd, a, FALSE,
         finfo->external_relocs,
         finfo->external_relocs,
         finfo->info->relocatable,
         finfo->info->relocatable,
         (finfo->info->relocatable
         (finfo->info->relocatable
          ? (finfo->section_info[ a->output_section->target_index ].relocs + a->output_section->reloc_count)
          ? (finfo->section_info[ a->output_section->target_index ].relocs + a->output_section->reloc_count)
          : finfo->internal_relocs)
          : finfo->internal_relocs)
        );
        );
 
 
      if (internal_relocs == NULL)
      if (internal_relocs == NULL)
        continue;
        continue;
 
 
      irel     = internal_relocs;
      irel     = internal_relocs;
      irelend  = irel + a->reloc_count;
      irelend  = irel + a->reloc_count;
 
 
      /* Place a mark in the sym_indices array (whose entries have
      /* Place a mark in the sym_indices array (whose entries have
         been initialised to 0) for all of the symbols that are used
         been initialised to 0) for all of the symbols that are used
         in the relocation table.  This will then be picked up in the
         in the relocation table.  This will then be picked up in the
         skip/don't-skip pass.  */
         skip/don't-skip pass.  */
      for (; irel < irelend; irel++)
      for (; irel < irelend; irel++)
        finfo->sym_indices[ irel->r_symndx ] = -1;
        finfo->sym_indices[ irel->r_symndx ] = -1;
    }
    }
}
}
 
 
/* Link an input file into the linker output file.  This function
/* Link an input file into the linker output file.  This function
   handles all the sections and relocations of the input file at once.  */
   handles all the sections and relocations of the input file at once.  */
 
 
bfd_boolean
bfd_boolean
_bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
_bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
{
{
  unsigned int n_tmask = coff_data (input_bfd)->local_n_tmask;
  unsigned int n_tmask = coff_data (input_bfd)->local_n_tmask;
  unsigned int n_btshft = coff_data (input_bfd)->local_n_btshft;
  unsigned int n_btshft = coff_data (input_bfd)->local_n_btshft;
  bfd_boolean (*adjust_symndx)
  bfd_boolean (*adjust_symndx)
    (bfd *, struct bfd_link_info *, bfd *, asection *,
    (bfd *, struct bfd_link_info *, bfd *, asection *,
     struct internal_reloc *, bfd_boolean *);
     struct internal_reloc *, bfd_boolean *);
  bfd *output_bfd;
  bfd *output_bfd;
  const char *strings;
  const char *strings;
  bfd_size_type syment_base;
  bfd_size_type syment_base;
  bfd_boolean copy, hash;
  bfd_boolean copy, hash;
  bfd_size_type isymesz;
  bfd_size_type isymesz;
  bfd_size_type osymesz;
  bfd_size_type osymesz;
  bfd_size_type linesz;
  bfd_size_type linesz;
  bfd_byte *esym;
  bfd_byte *esym;
  bfd_byte *esym_end;
  bfd_byte *esym_end;
  struct internal_syment *isymp;
  struct internal_syment *isymp;
  asection **secpp;
  asection **secpp;
  long *indexp;
  long *indexp;
  unsigned long output_index;
  unsigned long output_index;
  bfd_byte *outsym;
  bfd_byte *outsym;
  struct coff_link_hash_entry **sym_hash;
  struct coff_link_hash_entry **sym_hash;
  asection *o;
  asection *o;
 
 
  /* Move all the symbols to the output file.  */
  /* Move all the symbols to the output file.  */
 
 
  output_bfd = finfo->output_bfd;
  output_bfd = finfo->output_bfd;
  strings = NULL;
  strings = NULL;
  syment_base = obj_raw_syment_count (output_bfd);
  syment_base = obj_raw_syment_count (output_bfd);
  isymesz = bfd_coff_symesz (input_bfd);
  isymesz = bfd_coff_symesz (input_bfd);
  osymesz = bfd_coff_symesz (output_bfd);
  osymesz = bfd_coff_symesz (output_bfd);
  linesz = bfd_coff_linesz (input_bfd);
  linesz = bfd_coff_linesz (input_bfd);
  BFD_ASSERT (linesz == bfd_coff_linesz (output_bfd));
  BFD_ASSERT (linesz == bfd_coff_linesz (output_bfd));
 
 
  copy = FALSE;
  copy = FALSE;
  if (! finfo->info->keep_memory)
  if (! finfo->info->keep_memory)
    copy = TRUE;
    copy = TRUE;
  hash = TRUE;
  hash = TRUE;
  if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
  if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
    hash = FALSE;
    hash = FALSE;
 
 
  if (! _bfd_coff_get_external_symbols (input_bfd))
  if (! _bfd_coff_get_external_symbols (input_bfd))
    return FALSE;
    return FALSE;
 
 
  esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
  esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
  esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
  esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
  isymp = finfo->internal_syms;
  isymp = finfo->internal_syms;
  secpp = finfo->sec_ptrs;
  secpp = finfo->sec_ptrs;
  indexp = finfo->sym_indices;
  indexp = finfo->sym_indices;
  output_index = syment_base;
  output_index = syment_base;
  outsym = finfo->outsyms;
  outsym = finfo->outsyms;
 
 
  if (coff_data (output_bfd)->pe
  if (coff_data (output_bfd)->pe
      && ! process_embedded_commands (output_bfd, finfo->info, input_bfd))
      && ! process_embedded_commands (output_bfd, finfo->info, input_bfd))
    return FALSE;
    return FALSE;
 
 
  /* If we are going to perform relocations and also strip/discard some
  /* If we are going to perform relocations and also strip/discard some
     symbols then we must make sure that we do not strip/discard those
     symbols then we must make sure that we do not strip/discard those
     symbols that are going to be involved in the relocations.  */
     symbols that are going to be involved in the relocations.  */
  if ((   finfo->info->strip   != strip_none
  if ((   finfo->info->strip   != strip_none
       || finfo->info->discard != discard_none)
       || finfo->info->discard != discard_none)
      && finfo->info->relocatable)
      && finfo->info->relocatable)
    {
    {
      /* Mark the symbol array as 'not-used'.  */
      /* Mark the symbol array as 'not-used'.  */
      memset (indexp, 0, obj_raw_syment_count (input_bfd) * sizeof * indexp);
      memset (indexp, 0, obj_raw_syment_count (input_bfd) * sizeof * indexp);
 
 
      mark_relocs (finfo, input_bfd);
      mark_relocs (finfo, input_bfd);
    }
    }
 
 
  while (esym < esym_end)
  while (esym < esym_end)
    {
    {
      struct internal_syment isym;
      struct internal_syment isym;
      enum coff_symbol_classification classification;
      enum coff_symbol_classification classification;
      bfd_boolean skip;
      bfd_boolean skip;
      bfd_boolean global;
      bfd_boolean global;
      bfd_boolean dont_skip_symbol;
      bfd_boolean dont_skip_symbol;
      int add;
      int add;
 
 
      bfd_coff_swap_sym_in (input_bfd, esym, isymp);
      bfd_coff_swap_sym_in (input_bfd, esym, isymp);
 
 
      /* Make a copy of *isymp so that the relocate_section function
      /* Make a copy of *isymp so that the relocate_section function
         always sees the original values.  This is more reliable than
         always sees the original values.  This is more reliable than
         always recomputing the symbol value even if we are stripping
         always recomputing the symbol value even if we are stripping
         the symbol.  */
         the symbol.  */
      isym = *isymp;
      isym = *isymp;
 
 
      classification = bfd_coff_classify_symbol (input_bfd, &isym);
      classification = bfd_coff_classify_symbol (input_bfd, &isym);
      switch (classification)
      switch (classification)
        {
        {
        default:
        default:
          abort ();
          abort ();
        case COFF_SYMBOL_GLOBAL:
        case COFF_SYMBOL_GLOBAL:
        case COFF_SYMBOL_PE_SECTION:
        case COFF_SYMBOL_PE_SECTION:
        case COFF_SYMBOL_LOCAL:
        case COFF_SYMBOL_LOCAL:
          *secpp = coff_section_from_bfd_index (input_bfd, isym.n_scnum);
          *secpp = coff_section_from_bfd_index (input_bfd, isym.n_scnum);
          break;
          break;
        case COFF_SYMBOL_COMMON:
        case COFF_SYMBOL_COMMON:
          *secpp = bfd_com_section_ptr;
          *secpp = bfd_com_section_ptr;
          break;
          break;
        case COFF_SYMBOL_UNDEFINED:
        case COFF_SYMBOL_UNDEFINED:
          *secpp = bfd_und_section_ptr;
          *secpp = bfd_und_section_ptr;
          break;
          break;
        }
        }
 
 
      /* Extract the flag indicating if this symbol is used by a
      /* Extract the flag indicating if this symbol is used by a
         relocation.  */
         relocation.  */
      if ((finfo->info->strip != strip_none
      if ((finfo->info->strip != strip_none
           || finfo->info->discard != discard_none)
           || finfo->info->discard != discard_none)
          && finfo->info->relocatable)
          && finfo->info->relocatable)
        dont_skip_symbol = *indexp;
        dont_skip_symbol = *indexp;
      else
      else
        dont_skip_symbol = FALSE;
        dont_skip_symbol = FALSE;
 
 
      *indexp = -1;
      *indexp = -1;
 
 
      skip = FALSE;
      skip = FALSE;
      global = FALSE;
      global = FALSE;
      add = 1 + isym.n_numaux;
      add = 1 + isym.n_numaux;
 
 
      /* If we are stripping all symbols, we want to skip this one.  */
      /* If we are stripping all symbols, we want to skip this one.  */
      if (finfo->info->strip == strip_all && ! dont_skip_symbol)
      if (finfo->info->strip == strip_all && ! dont_skip_symbol)
        skip = TRUE;
        skip = TRUE;
 
 
      if (! skip)
      if (! skip)
        {
        {
          switch (classification)
          switch (classification)
            {
            {
            default:
            default:
              abort ();
              abort ();
            case COFF_SYMBOL_GLOBAL:
            case COFF_SYMBOL_GLOBAL:
            case COFF_SYMBOL_COMMON:
            case COFF_SYMBOL_COMMON:
            case COFF_SYMBOL_PE_SECTION:
            case COFF_SYMBOL_PE_SECTION:
              /* This is a global symbol.  Global symbols come at the
              /* This is a global symbol.  Global symbols come at the
                 end of the symbol table, so skip them for now.
                 end of the symbol table, so skip them for now.
                 Locally defined function symbols, however, are an
                 Locally defined function symbols, however, are an
                 exception, and are not moved to the end.  */
                 exception, and are not moved to the end.  */
              global = TRUE;
              global = TRUE;
              if (! ISFCN (isym.n_type))
              if (! ISFCN (isym.n_type))
                skip = TRUE;
                skip = TRUE;
              break;
              break;
 
 
            case COFF_SYMBOL_UNDEFINED:
            case COFF_SYMBOL_UNDEFINED:
              /* Undefined symbols are left for the end.  */
              /* Undefined symbols are left for the end.  */
              global = TRUE;
              global = TRUE;
              skip = TRUE;
              skip = TRUE;
              break;
              break;
 
 
            case COFF_SYMBOL_LOCAL:
            case COFF_SYMBOL_LOCAL:
              /* This is a local symbol.  Skip it if we are discarding
              /* This is a local symbol.  Skip it if we are discarding
                 local symbols.  */
                 local symbols.  */
              if (finfo->info->discard == discard_all && ! dont_skip_symbol)
              if (finfo->info->discard == discard_all && ! dont_skip_symbol)
                skip = TRUE;
                skip = TRUE;
              break;
              break;
            }
            }
        }
        }
 
 
#ifndef COFF_WITH_PE
#ifndef COFF_WITH_PE
      /* Skip section symbols for sections which are not going to be
      /* Skip section symbols for sections which are not going to be
         emitted.  */
         emitted.  */
      if (!skip
      if (!skip
          && !dont_skip_symbol
          && !dont_skip_symbol
          && isym.n_sclass == C_STAT
          && isym.n_sclass == C_STAT
          && isym.n_type == T_NULL
          && isym.n_type == T_NULL
          && isym.n_numaux > 0
          && isym.n_numaux > 0
          && ((*secpp)->output_section == bfd_abs_section_ptr
          && ((*secpp)->output_section == bfd_abs_section_ptr
              || bfd_section_removed_from_list (output_bfd,
              || bfd_section_removed_from_list (output_bfd,
                                                (*secpp)->output_section)))
                                                (*secpp)->output_section)))
        skip = TRUE;
        skip = TRUE;
#endif
#endif
 
 
      /* If we stripping debugging symbols, and this is a debugging
      /* If we stripping debugging symbols, and this is a debugging
         symbol, then skip it.  FIXME: gas sets the section to N_ABS
         symbol, then skip it.  FIXME: gas sets the section to N_ABS
         for some types of debugging symbols; I don't know if this is
         for some types of debugging symbols; I don't know if this is
         a bug or not.  In any case, we handle it here.  */
         a bug or not.  In any case, we handle it here.  */
      if (! skip
      if (! skip
          && finfo->info->strip == strip_debugger
          && finfo->info->strip == strip_debugger
          && ! dont_skip_symbol
          && ! dont_skip_symbol
          && (isym.n_scnum == N_DEBUG
          && (isym.n_scnum == N_DEBUG
              || (isym.n_scnum == N_ABS
              || (isym.n_scnum == N_ABS
                  && (isym.n_sclass == C_AUTO
                  && (isym.n_sclass == C_AUTO
                      || isym.n_sclass == C_REG
                      || isym.n_sclass == C_REG
                      || isym.n_sclass == C_MOS
                      || isym.n_sclass == C_MOS
                      || isym.n_sclass == C_MOE
                      || isym.n_sclass == C_MOE
                      || isym.n_sclass == C_MOU
                      || isym.n_sclass == C_MOU
                      || isym.n_sclass == C_ARG
                      || isym.n_sclass == C_ARG
                      || isym.n_sclass == C_REGPARM
                      || isym.n_sclass == C_REGPARM
                      || isym.n_sclass == C_FIELD
                      || isym.n_sclass == C_FIELD
                      || isym.n_sclass == C_EOS))))
                      || isym.n_sclass == C_EOS))))
        skip = TRUE;
        skip = TRUE;
 
 
      /* If some symbols are stripped based on the name, work out the
      /* If some symbols are stripped based on the name, work out the
         name and decide whether to skip this symbol.  */
         name and decide whether to skip this symbol.  */
      if (! skip
      if (! skip
          && (finfo->info->strip == strip_some
          && (finfo->info->strip == strip_some
              || finfo->info->discard == discard_l))
              || finfo->info->discard == discard_l))
        {
        {
          const char *name;
          const char *name;
          char buf[SYMNMLEN + 1];
          char buf[SYMNMLEN + 1];
 
 
          name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
          name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
          if (name == NULL)
          if (name == NULL)
            return FALSE;
            return FALSE;
 
 
          if (! dont_skip_symbol
          if (! dont_skip_symbol
              && ((finfo->info->strip == strip_some
              && ((finfo->info->strip == strip_some
                   && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE,
                   && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE,
                                    FALSE) == NULL))
                                    FALSE) == NULL))
                   || (! global
                   || (! global
                       && finfo->info->discard == discard_l
                       && finfo->info->discard == discard_l
                       && bfd_is_local_label_name (input_bfd, name))))
                       && bfd_is_local_label_name (input_bfd, name))))
            skip = TRUE;
            skip = TRUE;
        }
        }
 
 
      /* If this is an enum, struct, or union tag, see if we have
      /* If this is an enum, struct, or union tag, see if we have
         already output an identical type.  */
         already output an identical type.  */
      if (! skip
      if (! skip
          && (finfo->output_bfd->flags & BFD_TRADITIONAL_FORMAT) == 0
          && (finfo->output_bfd->flags & BFD_TRADITIONAL_FORMAT) == 0
          && (isym.n_sclass == C_ENTAG
          && (isym.n_sclass == C_ENTAG
              || isym.n_sclass == C_STRTAG
              || isym.n_sclass == C_STRTAG
              || isym.n_sclass == C_UNTAG)
              || isym.n_sclass == C_UNTAG)
          && isym.n_numaux == 1)
          && isym.n_numaux == 1)
        {
        {
          const char *name;
          const char *name;
          char buf[SYMNMLEN + 1];
          char buf[SYMNMLEN + 1];
          struct coff_debug_merge_hash_entry *mh;
          struct coff_debug_merge_hash_entry *mh;
          struct coff_debug_merge_type *mt;
          struct coff_debug_merge_type *mt;
          union internal_auxent aux;
          union internal_auxent aux;
          struct coff_debug_merge_element **epp;
          struct coff_debug_merge_element **epp;
          bfd_byte *esl, *eslend;
          bfd_byte *esl, *eslend;
          struct internal_syment *islp;
          struct internal_syment *islp;
          bfd_size_type amt;
          bfd_size_type amt;
 
 
          name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
          name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
          if (name == NULL)
          if (name == NULL)
            return FALSE;
            return FALSE;
 
 
          /* Ignore fake names invented by compiler; treat them all as
          /* Ignore fake names invented by compiler; treat them all as
             the same name.  */
             the same name.  */
          if (*name == '~' || *name == '.' || *name == '$'
          if (*name == '~' || *name == '.' || *name == '$'
              || (*name == bfd_get_symbol_leading_char (input_bfd)
              || (*name == bfd_get_symbol_leading_char (input_bfd)
                  && (name[1] == '~' || name[1] == '.' || name[1] == '$')))
                  && (name[1] == '~' || name[1] == '.' || name[1] == '$')))
            name = "";
            name = "";
 
 
          mh = coff_debug_merge_hash_lookup (&finfo->debug_merge, name,
          mh = coff_debug_merge_hash_lookup (&finfo->debug_merge, name,
                                             TRUE, TRUE);
                                             TRUE, TRUE);
          if (mh == NULL)
          if (mh == NULL)
            return FALSE;
            return FALSE;
 
 
          /* Allocate memory to hold type information.  If this turns
          /* Allocate memory to hold type information.  If this turns
             out to be a duplicate, we pass this address to
             out to be a duplicate, we pass this address to
             bfd_release.  */
             bfd_release.  */
          amt = sizeof (struct coff_debug_merge_type);
          amt = sizeof (struct coff_debug_merge_type);
          mt = (struct coff_debug_merge_type *) bfd_alloc (input_bfd, amt);
          mt = (struct coff_debug_merge_type *) bfd_alloc (input_bfd, amt);
          if (mt == NULL)
          if (mt == NULL)
            return FALSE;
            return FALSE;
          mt->type_class = isym.n_sclass;
          mt->type_class = isym.n_sclass;
 
 
          /* Pick up the aux entry, which points to the end of the tag
          /* Pick up the aux entry, which points to the end of the tag
             entries.  */
             entries.  */
          bfd_coff_swap_aux_in (input_bfd, (esym + isymesz),
          bfd_coff_swap_aux_in (input_bfd, (esym + isymesz),
                                isym.n_type, isym.n_sclass, 0, isym.n_numaux,
                                isym.n_type, isym.n_sclass, 0, isym.n_numaux,
                                &aux);
                                &aux);
 
 
          /* Gather the elements.  */
          /* Gather the elements.  */
          epp = &mt->elements;
          epp = &mt->elements;
          mt->elements = NULL;
          mt->elements = NULL;
          islp = isymp + 2;
          islp = isymp + 2;
          esl = esym + 2 * isymesz;
          esl = esym + 2 * isymesz;
          eslend = ((bfd_byte *) obj_coff_external_syms (input_bfd)
          eslend = ((bfd_byte *) obj_coff_external_syms (input_bfd)
                    + aux.x_sym.x_fcnary.x_fcn.x_endndx.l * isymesz);
                    + aux.x_sym.x_fcnary.x_fcn.x_endndx.l * isymesz);
          while (esl < eslend)
          while (esl < eslend)
            {
            {
              const char *elename;
              const char *elename;
              char elebuf[SYMNMLEN + 1];
              char elebuf[SYMNMLEN + 1];
              char *name_copy;
              char *name_copy;
 
 
              bfd_coff_swap_sym_in (input_bfd, esl, islp);
              bfd_coff_swap_sym_in (input_bfd, esl, islp);
 
 
              amt = sizeof (struct coff_debug_merge_element);
              amt = sizeof (struct coff_debug_merge_element);
              *epp = (struct coff_debug_merge_element *)
              *epp = (struct coff_debug_merge_element *)
                  bfd_alloc (input_bfd, amt);
                  bfd_alloc (input_bfd, amt);
              if (*epp == NULL)
              if (*epp == NULL)
                return FALSE;
                return FALSE;
 
 
              elename = _bfd_coff_internal_syment_name (input_bfd, islp,
              elename = _bfd_coff_internal_syment_name (input_bfd, islp,
                                                        elebuf);
                                                        elebuf);
              if (elename == NULL)
              if (elename == NULL)
                return FALSE;
                return FALSE;
 
 
              amt = strlen (elename) + 1;
              amt = strlen (elename) + 1;
              name_copy = (char *) bfd_alloc (input_bfd, amt);
              name_copy = (char *) bfd_alloc (input_bfd, amt);
              if (name_copy == NULL)
              if (name_copy == NULL)
                return FALSE;
                return FALSE;
              strcpy (name_copy, elename);
              strcpy (name_copy, elename);
 
 
              (*epp)->name = name_copy;
              (*epp)->name = name_copy;
              (*epp)->type = islp->n_type;
              (*epp)->type = islp->n_type;
              (*epp)->tagndx = 0;
              (*epp)->tagndx = 0;
              if (islp->n_numaux >= 1
              if (islp->n_numaux >= 1
                  && islp->n_type != T_NULL
                  && islp->n_type != T_NULL
                  && islp->n_sclass != C_EOS)
                  && islp->n_sclass != C_EOS)
                {
                {
                  union internal_auxent eleaux;
                  union internal_auxent eleaux;
                  long indx;
                  long indx;
 
 
                  bfd_coff_swap_aux_in (input_bfd, (esl + isymesz),
                  bfd_coff_swap_aux_in (input_bfd, (esl + isymesz),
                                        islp->n_type, islp->n_sclass, 0,
                                        islp->n_type, islp->n_sclass, 0,
                                        islp->n_numaux, &eleaux);
                                        islp->n_numaux, &eleaux);
                  indx = eleaux.x_sym.x_tagndx.l;
                  indx = eleaux.x_sym.x_tagndx.l;
 
 
                  /* FIXME: If this tagndx entry refers to a symbol
                  /* FIXME: If this tagndx entry refers to a symbol
                     defined later in this file, we just ignore it.
                     defined later in this file, we just ignore it.
                     Handling this correctly would be tedious, and may
                     Handling this correctly would be tedious, and may
                     not be required.  */
                     not be required.  */
                  if (indx > 0
                  if (indx > 0
                      && (indx
                      && (indx
                          < ((esym -
                          < ((esym -
                              (bfd_byte *) obj_coff_external_syms (input_bfd))
                              (bfd_byte *) obj_coff_external_syms (input_bfd))
                             / (long) isymesz)))
                             / (long) isymesz)))
                    {
                    {
                      (*epp)->tagndx = finfo->sym_indices[indx];
                      (*epp)->tagndx = finfo->sym_indices[indx];
                      if ((*epp)->tagndx < 0)
                      if ((*epp)->tagndx < 0)
                        (*epp)->tagndx = 0;
                        (*epp)->tagndx = 0;
                    }
                    }
                }
                }
              epp = &(*epp)->next;
              epp = &(*epp)->next;
              *epp = NULL;
              *epp = NULL;
 
 
              esl += (islp->n_numaux + 1) * isymesz;
              esl += (islp->n_numaux + 1) * isymesz;
              islp += islp->n_numaux + 1;
              islp += islp->n_numaux + 1;
            }
            }
 
 
          /* See if we already have a definition which matches this
          /* See if we already have a definition which matches this
             type.  We always output the type if it has no elements,
             type.  We always output the type if it has no elements,
             for simplicity.  */
             for simplicity.  */
          if (mt->elements == NULL)
          if (mt->elements == NULL)
            bfd_release (input_bfd, mt);
            bfd_release (input_bfd, mt);
          else
          else
            {
            {
              struct coff_debug_merge_type *mtl;
              struct coff_debug_merge_type *mtl;
 
 
              for (mtl = mh->types; mtl != NULL; mtl = mtl->next)
              for (mtl = mh->types; mtl != NULL; mtl = mtl->next)
                {
                {
                  struct coff_debug_merge_element *me, *mel;
                  struct coff_debug_merge_element *me, *mel;
 
 
                  if (mtl->type_class != mt->type_class)
                  if (mtl->type_class != mt->type_class)
                    continue;
                    continue;
 
 
                  for (me = mt->elements, mel = mtl->elements;
                  for (me = mt->elements, mel = mtl->elements;
                       me != NULL && mel != NULL;
                       me != NULL && mel != NULL;
                       me = me->next, mel = mel->next)
                       me = me->next, mel = mel->next)
                    {
                    {
                      if (strcmp (me->name, mel->name) != 0
                      if (strcmp (me->name, mel->name) != 0
                          || me->type != mel->type
                          || me->type != mel->type
                          || me->tagndx != mel->tagndx)
                          || me->tagndx != mel->tagndx)
                        break;
                        break;
                    }
                    }
 
 
                  if (me == NULL && mel == NULL)
                  if (me == NULL && mel == NULL)
                    break;
                    break;
                }
                }
 
 
              if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base)
              if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base)
                {
                {
                  /* This is the first definition of this type.  */
                  /* This is the first definition of this type.  */
                  mt->indx = output_index;
                  mt->indx = output_index;
                  mt->next = mh->types;
                  mt->next = mh->types;
                  mh->types = mt;
                  mh->types = mt;
                }
                }
              else
              else
                {
                {
                  /* This is a redefinition which can be merged.  */
                  /* This is a redefinition which can be merged.  */
                  bfd_release (input_bfd, mt);
                  bfd_release (input_bfd, mt);
                  *indexp = mtl->indx;
                  *indexp = mtl->indx;
                  add = (eslend - esym) / isymesz;
                  add = (eslend - esym) / isymesz;
                  skip = TRUE;
                  skip = TRUE;
                }
                }
            }
            }
        }
        }
 
 
      /* We now know whether we are to skip this symbol or not.  */
      /* We now know whether we are to skip this symbol or not.  */
      if (! skip)
      if (! skip)
        {
        {
          /* Adjust the symbol in order to output it.  */
          /* Adjust the symbol in order to output it.  */
 
 
          if (isym._n._n_n._n_zeroes == 0
          if (isym._n._n_n._n_zeroes == 0
              && isym._n._n_n._n_offset != 0)
              && isym._n._n_n._n_offset != 0)
            {
            {
              const char *name;
              const char *name;
              bfd_size_type indx;
              bfd_size_type indx;
 
 
              /* This symbol has a long name.  Enter it in the string
              /* This symbol has a long name.  Enter it in the string
                 table we are building.  Note that we do not check
                 table we are building.  Note that we do not check
                 bfd_coff_symname_in_debug.  That is only true for
                 bfd_coff_symname_in_debug.  That is only true for
                 XCOFF, and XCOFF requires different linking code
                 XCOFF, and XCOFF requires different linking code
                 anyhow.  */
                 anyhow.  */
              name = _bfd_coff_internal_syment_name (input_bfd, &isym, NULL);
              name = _bfd_coff_internal_syment_name (input_bfd, &isym, NULL);
              if (name == NULL)
              if (name == NULL)
                return FALSE;
                return FALSE;
              indx = _bfd_stringtab_add (finfo->strtab, name, hash, copy);
              indx = _bfd_stringtab_add (finfo->strtab, name, hash, copy);
              if (indx == (bfd_size_type) -1)
              if (indx == (bfd_size_type) -1)
                return FALSE;
                return FALSE;
              isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
              isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
            }
            }
 
 
          switch (isym.n_sclass)
          switch (isym.n_sclass)
            {
            {
            case C_AUTO:
            case C_AUTO:
            case C_MOS:
            case C_MOS:
            case C_EOS:
            case C_EOS:
            case C_MOE:
            case C_MOE:
            case C_MOU:
            case C_MOU:
            case C_UNTAG:
            case C_UNTAG:
            case C_STRTAG:
            case C_STRTAG:
            case C_ENTAG:
            case C_ENTAG:
            case C_TPDEF:
            case C_TPDEF:
            case C_ARG:
            case C_ARG:
            case C_USTATIC:
            case C_USTATIC:
            case C_REG:
            case C_REG:
            case C_REGPARM:
            case C_REGPARM:
            case C_FIELD:
            case C_FIELD:
              /* The symbol value should not be modified.  */
              /* The symbol value should not be modified.  */
              break;
              break;
 
 
            case C_FCN:
            case C_FCN:
              if (obj_pe (input_bfd)
              if (obj_pe (input_bfd)
                  && strcmp (isym.n_name, ".bf") != 0
                  && strcmp (isym.n_name, ".bf") != 0
                  && isym.n_scnum > 0)
                  && isym.n_scnum > 0)
                {
                {
                  /* For PE, .lf and .ef get their value left alone,
                  /* For PE, .lf and .ef get their value left alone,
                     while .bf gets relocated.  However, they all have
                     while .bf gets relocated.  However, they all have
                     "real" section numbers, and need to be moved into
                     "real" section numbers, and need to be moved into
                     the new section.  */
                     the new section.  */
                  isym.n_scnum = (*secpp)->output_section->target_index;
                  isym.n_scnum = (*secpp)->output_section->target_index;
                  break;
                  break;
                }
                }
              /* Fall through.  */
              /* Fall through.  */
            default:
            default:
            case C_LABEL:  /* Not completely sure about these 2 */
            case C_LABEL:  /* Not completely sure about these 2 */
            case C_EXTDEF:
            case C_EXTDEF:
            case C_BLOCK:
            case C_BLOCK:
            case C_EFCN:
            case C_EFCN:
            case C_NULL:
            case C_NULL:
            case C_EXT:
            case C_EXT:
            case C_STAT:
            case C_STAT:
            case C_SECTION:
            case C_SECTION:
            case C_NT_WEAK:
            case C_NT_WEAK:
              /* Compute new symbol location.  */
              /* Compute new symbol location.  */
            if (isym.n_scnum > 0)
            if (isym.n_scnum > 0)
              {
              {
                isym.n_scnum = (*secpp)->output_section->target_index;
                isym.n_scnum = (*secpp)->output_section->target_index;
                isym.n_value += (*secpp)->output_offset;
                isym.n_value += (*secpp)->output_offset;
                if (! obj_pe (input_bfd))
                if (! obj_pe (input_bfd))
                  isym.n_value -= (*secpp)->vma;
                  isym.n_value -= (*secpp)->vma;
                if (! obj_pe (finfo->output_bfd))
                if (! obj_pe (finfo->output_bfd))
                  isym.n_value += (*secpp)->output_section->vma;
                  isym.n_value += (*secpp)->output_section->vma;
              }
              }
            break;
            break;
 
 
            case C_FILE:
            case C_FILE:
              /* The value of a C_FILE symbol is the symbol index of
              /* The value of a C_FILE symbol is the symbol index of
                 the next C_FILE symbol.  The value of the last C_FILE
                 the next C_FILE symbol.  The value of the last C_FILE
                 symbol is the symbol index to the first external
                 symbol is the symbol index to the first external
                 symbol (actually, coff_renumber_symbols does not get
                 symbol (actually, coff_renumber_symbols does not get
                 this right--it just sets the value of the last C_FILE
                 this right--it just sets the value of the last C_FILE
                 symbol to zero--and nobody has ever complained about
                 symbol to zero--and nobody has ever complained about
                 it).  We try to get this right, below, just before we
                 it).  We try to get this right, below, just before we
                 write the symbols out, but in the general case we may
                 write the symbols out, but in the general case we may
                 have to write the symbol out twice.  */
                 have to write the symbol out twice.  */
              if (finfo->last_file_index != -1
              if (finfo->last_file_index != -1
                  && finfo->last_file.n_value != (bfd_vma) output_index)
                  && finfo->last_file.n_value != (bfd_vma) output_index)
                {
                {
                  /* We must correct the value of the last C_FILE
                  /* We must correct the value of the last C_FILE
                     entry.  */
                     entry.  */
                  finfo->last_file.n_value = output_index;
                  finfo->last_file.n_value = output_index;
                  if ((bfd_size_type) finfo->last_file_index >= syment_base)
                  if ((bfd_size_type) finfo->last_file_index >= syment_base)
                    {
                    {
                      /* The last C_FILE symbol is in this input file.  */
                      /* The last C_FILE symbol is in this input file.  */
                      bfd_coff_swap_sym_out (output_bfd,
                      bfd_coff_swap_sym_out (output_bfd,
                                             &finfo->last_file,
                                             &finfo->last_file,
                                             (finfo->outsyms
                                             (finfo->outsyms
                                              + ((finfo->last_file_index
                                              + ((finfo->last_file_index
                                                  - syment_base)
                                                  - syment_base)
                                                 * osymesz)));
                                                 * osymesz)));
                    }
                    }
                  else
                  else
                    {
                    {
                      file_ptr pos;
                      file_ptr pos;
 
 
                      /* We have already written out the last C_FILE
                      /* We have already written out the last C_FILE
                         symbol.  We need to write it out again.  We
                         symbol.  We need to write it out again.  We
                         borrow *outsym temporarily.  */
                         borrow *outsym temporarily.  */
                      bfd_coff_swap_sym_out (output_bfd,
                      bfd_coff_swap_sym_out (output_bfd,
                                             &finfo->last_file, outsym);
                                             &finfo->last_file, outsym);
                      pos = obj_sym_filepos (output_bfd);
                      pos = obj_sym_filepos (output_bfd);
                      pos += finfo->last_file_index * osymesz;
                      pos += finfo->last_file_index * osymesz;
                      if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
                      if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
                          || bfd_bwrite (outsym, osymesz, output_bfd) != osymesz)
                          || bfd_bwrite (outsym, osymesz, output_bfd) != osymesz)
                        return FALSE;
                        return FALSE;
                    }
                    }
                }
                }
 
 
              finfo->last_file_index = output_index;
              finfo->last_file_index = output_index;
              finfo->last_file = isym;
              finfo->last_file = isym;
              break;
              break;
            }
            }
 
 
          /* If doing task linking, convert normal global function symbols to
          /* If doing task linking, convert normal global function symbols to
             static functions.  */
             static functions.  */
          if (finfo->info->task_link && IS_EXTERNAL (input_bfd, isym))
          if (finfo->info->task_link && IS_EXTERNAL (input_bfd, isym))
            isym.n_sclass = C_STAT;
            isym.n_sclass = C_STAT;
 
 
          /* Output the symbol.  */
          /* Output the symbol.  */
          bfd_coff_swap_sym_out (output_bfd, &isym, outsym);
          bfd_coff_swap_sym_out (output_bfd, &isym, outsym);
 
 
          *indexp = output_index;
          *indexp = output_index;
 
 
          if (global)
          if (global)
            {
            {
              long indx;
              long indx;
              struct coff_link_hash_entry *h;
              struct coff_link_hash_entry *h;
 
 
              indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd))
              indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd))
                      / isymesz);
                      / isymesz);
              h = obj_coff_sym_hashes (input_bfd)[indx];
              h = obj_coff_sym_hashes (input_bfd)[indx];
              if (h == NULL)
              if (h == NULL)
                {
                {
                  /* This can happen if there were errors earlier in
                  /* This can happen if there were errors earlier in
                     the link.  */
                     the link.  */
                  bfd_set_error (bfd_error_bad_value);
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
                  return FALSE;
                }
                }
              h->indx = output_index;
              h->indx = output_index;
            }
            }
 
 
          output_index += add;
          output_index += add;
          outsym += add * osymesz;
          outsym += add * osymesz;
        }
        }
 
 
      esym += add * isymesz;
      esym += add * isymesz;
      isymp += add;
      isymp += add;
      ++secpp;
      ++secpp;
      ++indexp;
      ++indexp;
      for (--add; add > 0; --add)
      for (--add; add > 0; --add)
        {
        {
          *secpp++ = NULL;
          *secpp++ = NULL;
          *indexp++ = -1;
          *indexp++ = -1;
        }
        }
    }
    }
 
 
  /* Fix up the aux entries.  This must be done in a separate pass,
  /* Fix up the aux entries.  This must be done in a separate pass,
     because we don't know the correct symbol indices until we have
     because we don't know the correct symbol indices until we have
     already decided which symbols we are going to keep.  */
     already decided which symbols we are going to keep.  */
  esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
  esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
  esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
  esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
  isymp = finfo->internal_syms;
  isymp = finfo->internal_syms;
  indexp = finfo->sym_indices;
  indexp = finfo->sym_indices;
  sym_hash = obj_coff_sym_hashes (input_bfd);
  sym_hash = obj_coff_sym_hashes (input_bfd);
  outsym = finfo->outsyms;
  outsym = finfo->outsyms;
 
 
  while (esym < esym_end)
  while (esym < esym_end)
    {
    {
      int add;
      int add;
 
 
      add = 1 + isymp->n_numaux;
      add = 1 + isymp->n_numaux;
 
 
      if ((*indexp < 0
      if ((*indexp < 0
           || (bfd_size_type) *indexp < syment_base)
           || (bfd_size_type) *indexp < syment_base)
          && (*sym_hash == NULL
          && (*sym_hash == NULL
              || (*sym_hash)->auxbfd != input_bfd))
              || (*sym_hash)->auxbfd != input_bfd))
        esym += add * isymesz;
        esym += add * isymesz;
      else
      else
        {
        {
          struct coff_link_hash_entry *h;
          struct coff_link_hash_entry *h;
          int i;
          int i;
 
 
          h = NULL;
          h = NULL;
          if (*indexp < 0)
          if (*indexp < 0)
            {
            {
              h = *sym_hash;
              h = *sym_hash;
 
 
              /* The m68k-motorola-sysv assembler will sometimes
              /* The m68k-motorola-sysv assembler will sometimes
                 generate two symbols with the same name, but only one
                 generate two symbols with the same name, but only one
                 will have aux entries.  */
                 will have aux entries.  */
              BFD_ASSERT (isymp->n_numaux == 0
              BFD_ASSERT (isymp->n_numaux == 0
                          || h->numaux == 0
                          || h->numaux == 0
                          || h->numaux == isymp->n_numaux);
                          || h->numaux == isymp->n_numaux);
            }
            }
 
 
          esym += isymesz;
          esym += isymesz;
 
 
          if (h == NULL)
          if (h == NULL)
            outsym += osymesz;
            outsym += osymesz;
 
 
          /* Handle the aux entries.  This handling is based on
          /* Handle the aux entries.  This handling is based on
             coff_pointerize_aux.  I don't know if it always correct.  */
             coff_pointerize_aux.  I don't know if it always correct.  */
          for (i = 0; i < isymp->n_numaux && esym < esym_end; i++)
          for (i = 0; i < isymp->n_numaux && esym < esym_end; i++)
            {
            {
              union internal_auxent aux;
              union internal_auxent aux;
              union internal_auxent *auxp;
              union internal_auxent *auxp;
 
 
              if (h != NULL && h->aux != NULL && (h->numaux > i))
              if (h != NULL && h->aux != NULL && (h->numaux > i))
                auxp = h->aux + i;
                auxp = h->aux + i;
              else
              else
                {
                {
                  bfd_coff_swap_aux_in (input_bfd, esym, isymp->n_type,
                  bfd_coff_swap_aux_in (input_bfd, esym, isymp->n_type,
                                        isymp->n_sclass, i, isymp->n_numaux, &aux);
                                        isymp->n_sclass, i, isymp->n_numaux, &aux);
                  auxp = &aux;
                  auxp = &aux;
                }
                }
 
 
              if (isymp->n_sclass == C_FILE)
              if (isymp->n_sclass == C_FILE)
                {
                {
                  /* If this is a long filename, we must put it in the
                  /* If this is a long filename, we must put it in the
                     string table.  */
                     string table.  */
                  if (auxp->x_file.x_n.x_zeroes == 0
                  if (auxp->x_file.x_n.x_zeroes == 0
                      && auxp->x_file.x_n.x_offset != 0)
                      && auxp->x_file.x_n.x_offset != 0)
                    {
                    {
                      const char *filename;
                      const char *filename;
                      bfd_size_type indx;
                      bfd_size_type indx;
 
 
                      BFD_ASSERT (auxp->x_file.x_n.x_offset
                      BFD_ASSERT (auxp->x_file.x_n.x_offset
                                  >= STRING_SIZE_SIZE);
                                  >= STRING_SIZE_SIZE);
                      if (strings == NULL)
                      if (strings == NULL)
                        {
                        {
                          strings = _bfd_coff_read_string_table (input_bfd);
                          strings = _bfd_coff_read_string_table (input_bfd);
                          if (strings == NULL)
                          if (strings == NULL)
                            return FALSE;
                            return FALSE;
                        }
                        }
                      filename = strings + auxp->x_file.x_n.x_offset;
                      filename = strings + auxp->x_file.x_n.x_offset;
                      indx = _bfd_stringtab_add (finfo->strtab, filename,
                      indx = _bfd_stringtab_add (finfo->strtab, filename,
                                                 hash, copy);
                                                 hash, copy);
                      if (indx == (bfd_size_type) -1)
                      if (indx == (bfd_size_type) -1)
                        return FALSE;
                        return FALSE;
                      auxp->x_file.x_n.x_offset = STRING_SIZE_SIZE + indx;
                      auxp->x_file.x_n.x_offset = STRING_SIZE_SIZE + indx;
                    }
                    }
                }
                }
              else if ((isymp->n_sclass != C_STAT || isymp->n_type != T_NULL)
              else if ((isymp->n_sclass != C_STAT || isymp->n_type != T_NULL)
                       && isymp->n_sclass != C_NT_WEAK)
                       && isymp->n_sclass != C_NT_WEAK)
                {
                {
                  unsigned long indx;
                  unsigned long indx;
 
 
                  if (ISFCN (isymp->n_type)
                  if (ISFCN (isymp->n_type)
                      || ISTAG (isymp->n_sclass)
                      || ISTAG (isymp->n_sclass)
                      || isymp->n_sclass == C_BLOCK
                      || isymp->n_sclass == C_BLOCK
                      || isymp->n_sclass == C_FCN)
                      || isymp->n_sclass == C_FCN)
                    {
                    {
                      indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l;
                      indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l;
                      if (indx > 0
                      if (indx > 0
                          && indx < obj_raw_syment_count (input_bfd))
                          && indx < obj_raw_syment_count (input_bfd))
                        {
                        {
                          /* We look forward through the symbol for
                          /* We look forward through the symbol for
                             the index of the next symbol we are going
                             the index of the next symbol we are going
                             to include.  I don't know if this is
                             to include.  I don't know if this is
                             entirely right.  */
                             entirely right.  */
                          while ((finfo->sym_indices[indx] < 0
                          while ((finfo->sym_indices[indx] < 0
                                  || ((bfd_size_type) finfo->sym_indices[indx]
                                  || ((bfd_size_type) finfo->sym_indices[indx]
                                      < syment_base))
                                      < syment_base))
                                 && indx < obj_raw_syment_count (input_bfd))
                                 && indx < obj_raw_syment_count (input_bfd))
                            ++indx;
                            ++indx;
                          if (indx >= obj_raw_syment_count (input_bfd))
                          if (indx >= obj_raw_syment_count (input_bfd))
                            indx = output_index;
                            indx = output_index;
                          else
                          else
                            indx = finfo->sym_indices[indx];
                            indx = finfo->sym_indices[indx];
                          auxp->x_sym.x_fcnary.x_fcn.x_endndx.l = indx;
                          auxp->x_sym.x_fcnary.x_fcn.x_endndx.l = indx;
                        }
                        }
                    }
                    }
 
 
                  indx = auxp->x_sym.x_tagndx.l;
                  indx = auxp->x_sym.x_tagndx.l;
                  if (indx > 0 && indx < obj_raw_syment_count (input_bfd))
                  if (indx > 0 && indx < obj_raw_syment_count (input_bfd))
                    {
                    {
                      long symindx;
                      long symindx;
 
 
                      symindx = finfo->sym_indices[indx];
                      symindx = finfo->sym_indices[indx];
                      if (symindx < 0)
                      if (symindx < 0)
                        auxp->x_sym.x_tagndx.l = 0;
                        auxp->x_sym.x_tagndx.l = 0;
                      else
                      else
                        auxp->x_sym.x_tagndx.l = symindx;
                        auxp->x_sym.x_tagndx.l = symindx;
                    }
                    }
 
 
                  /* The .bf symbols are supposed to be linked through
                  /* The .bf symbols are supposed to be linked through
                     the endndx field.  We need to carry this list
                     the endndx field.  We need to carry this list
                     across object files.  */
                     across object files.  */
                  if (i == 0
                  if (i == 0
                      && h == NULL
                      && h == NULL
                      && isymp->n_sclass == C_FCN
                      && isymp->n_sclass == C_FCN
                      && (isymp->_n._n_n._n_zeroes != 0
                      && (isymp->_n._n_n._n_zeroes != 0
                          || isymp->_n._n_n._n_offset == 0)
                          || isymp->_n._n_n._n_offset == 0)
                      && isymp->_n._n_name[0] == '.'
                      && isymp->_n._n_name[0] == '.'
                      && isymp->_n._n_name[1] == 'b'
                      && isymp->_n._n_name[1] == 'b'
                      && isymp->_n._n_name[2] == 'f'
                      && isymp->_n._n_name[2] == 'f'
                      && isymp->_n._n_name[3] == '\0')
                      && isymp->_n._n_name[3] == '\0')
                    {
                    {
                      if (finfo->last_bf_index != -1)
                      if (finfo->last_bf_index != -1)
                        {
                        {
                          finfo->last_bf.x_sym.x_fcnary.x_fcn.x_endndx.l =
                          finfo->last_bf.x_sym.x_fcnary.x_fcn.x_endndx.l =
                            *indexp;
                            *indexp;
 
 
                          if ((bfd_size_type) finfo->last_bf_index
                          if ((bfd_size_type) finfo->last_bf_index
                              >= syment_base)
                              >= syment_base)
                            {
                            {
                              void *auxout;
                              void *auxout;
 
 
                              /* The last .bf symbol is in this input
                              /* The last .bf symbol is in this input
                                 file.  This will only happen if the
                                 file.  This will only happen if the
                                 assembler did not set up the .bf
                                 assembler did not set up the .bf
                                 endndx symbols correctly.  */
                                 endndx symbols correctly.  */
                              auxout = (finfo->outsyms
                              auxout = (finfo->outsyms
                                        + ((finfo->last_bf_index
                                        + ((finfo->last_bf_index
                                            - syment_base)
                                            - syment_base)
                                           * osymesz));
                                           * osymesz));
 
 
                              bfd_coff_swap_aux_out (output_bfd,
                              bfd_coff_swap_aux_out (output_bfd,
                                                     &finfo->last_bf,
                                                     &finfo->last_bf,
                                                     isymp->n_type,
                                                     isymp->n_type,
                                                     isymp->n_sclass,
                                                     isymp->n_sclass,
                                                     0, isymp->n_numaux,
                                                     0, isymp->n_numaux,
                                                     auxout);
                                                     auxout);
                            }
                            }
                          else
                          else
                            {
                            {
                              file_ptr pos;
                              file_ptr pos;
 
 
                              /* We have already written out the last
                              /* We have already written out the last
                                 .bf aux entry.  We need to write it
                                 .bf aux entry.  We need to write it
                                 out again.  We borrow *outsym
                                 out again.  We borrow *outsym
                                 temporarily.  FIXME: This case should
                                 temporarily.  FIXME: This case should
                                 be made faster.  */
                                 be made faster.  */
                              bfd_coff_swap_aux_out (output_bfd,
                              bfd_coff_swap_aux_out (output_bfd,
                                                     &finfo->last_bf,
                                                     &finfo->last_bf,
                                                     isymp->n_type,
                                                     isymp->n_type,
                                                     isymp->n_sclass,
                                                     isymp->n_sclass,
                                                     0, isymp->n_numaux,
                                                     0, isymp->n_numaux,
                                                     outsym);
                                                     outsym);
                              pos = obj_sym_filepos (output_bfd);
                              pos = obj_sym_filepos (output_bfd);
                              pos += finfo->last_bf_index * osymesz;
                              pos += finfo->last_bf_index * osymesz;
                              if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
                              if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
                                  || (bfd_bwrite (outsym, osymesz, output_bfd)
                                  || (bfd_bwrite (outsym, osymesz, output_bfd)
                                      != osymesz))
                                      != osymesz))
                                return FALSE;
                                return FALSE;
                            }
                            }
                        }
                        }
 
 
                      if (auxp->x_sym.x_fcnary.x_fcn.x_endndx.l != 0)
                      if (auxp->x_sym.x_fcnary.x_fcn.x_endndx.l != 0)
                        finfo->last_bf_index = -1;
                        finfo->last_bf_index = -1;
                      else
                      else
                        {
                        {
                          /* The endndx field of this aux entry must
                          /* The endndx field of this aux entry must
                             be updated with the symbol number of the
                             be updated with the symbol number of the
                             next .bf symbol.  */
                             next .bf symbol.  */
                          finfo->last_bf = *auxp;
                          finfo->last_bf = *auxp;
                          finfo->last_bf_index = (((outsym - finfo->outsyms)
                          finfo->last_bf_index = (((outsym - finfo->outsyms)
                                                   / osymesz)
                                                   / osymesz)
                                                  + syment_base);
                                                  + syment_base);
                        }
                        }
                    }
                    }
                }
                }
 
 
              if (h == NULL)
              if (h == NULL)
                {
                {
                  bfd_coff_swap_aux_out (output_bfd, auxp, isymp->n_type,
                  bfd_coff_swap_aux_out (output_bfd, auxp, isymp->n_type,
                                         isymp->n_sclass, i, isymp->n_numaux,
                                         isymp->n_sclass, i, isymp->n_numaux,
                                         outsym);
                                         outsym);
                  outsym += osymesz;
                  outsym += osymesz;
                }
                }
 
 
              esym += isymesz;
              esym += isymesz;
            }
            }
        }
        }
 
 
      indexp += add;
      indexp += add;
      isymp += add;
      isymp += add;
      sym_hash += add;
      sym_hash += add;
    }
    }
 
 
  /* Relocate the line numbers, unless we are stripping them.  */
  /* Relocate the line numbers, unless we are stripping them.  */
  if (finfo->info->strip == strip_none
  if (finfo->info->strip == strip_none
      || finfo->info->strip == strip_some)
      || finfo->info->strip == strip_some)
    {
    {
      for (o = input_bfd->sections; o != NULL; o = o->next)
      for (o = input_bfd->sections; o != NULL; o = o->next)
        {
        {
          bfd_vma offset;
          bfd_vma offset;
          bfd_byte *eline;
          bfd_byte *eline;
          bfd_byte *elineend;
          bfd_byte *elineend;
          bfd_byte *oeline;
          bfd_byte *oeline;
          bfd_boolean skipping;
          bfd_boolean skipping;
          file_ptr pos;
          file_ptr pos;
          bfd_size_type amt;
          bfd_size_type amt;
 
 
          /* FIXME: If SEC_HAS_CONTENTS is not for the section, then
          /* FIXME: If SEC_HAS_CONTENTS is not for the section, then
             build_link_order in ldwrite.c will not have created a
             build_link_order in ldwrite.c will not have created a
             link order, which means that we will not have seen this
             link order, which means that we will not have seen this
             input section in _bfd_coff_final_link, which means that
             input section in _bfd_coff_final_link, which means that
             we will not have allocated space for the line numbers of
             we will not have allocated space for the line numbers of
             this section.  I don't think line numbers can be
             this section.  I don't think line numbers can be
             meaningful for a section which does not have
             meaningful for a section which does not have
             SEC_HAS_CONTENTS set, but, if they do, this must be
             SEC_HAS_CONTENTS set, but, if they do, this must be
             changed.  */
             changed.  */
          if (o->lineno_count == 0
          if (o->lineno_count == 0
              || (o->output_section->flags & SEC_HAS_CONTENTS) == 0)
              || (o->output_section->flags & SEC_HAS_CONTENTS) == 0)
            continue;
            continue;
 
 
          if (bfd_seek (input_bfd, o->line_filepos, SEEK_SET) != 0
          if (bfd_seek (input_bfd, o->line_filepos, SEEK_SET) != 0
              || bfd_bread (finfo->linenos, linesz * o->lineno_count,
              || bfd_bread (finfo->linenos, linesz * o->lineno_count,
                           input_bfd) != linesz * o->lineno_count)
                           input_bfd) != linesz * o->lineno_count)
            return FALSE;
            return FALSE;
 
 
          offset = o->output_section->vma + o->output_offset - o->vma;
          offset = o->output_section->vma + o->output_offset - o->vma;
          eline = finfo->linenos;
          eline = finfo->linenos;
          oeline = finfo->linenos;
          oeline = finfo->linenos;
          elineend = eline + linesz * o->lineno_count;
          elineend = eline + linesz * o->lineno_count;
          skipping = FALSE;
          skipping = FALSE;
          for (; eline < elineend; eline += linesz)
          for (; eline < elineend; eline += linesz)
            {
            {
              struct internal_lineno iline;
              struct internal_lineno iline;
 
 
              bfd_coff_swap_lineno_in (input_bfd, eline, &iline);
              bfd_coff_swap_lineno_in (input_bfd, eline, &iline);
 
 
              if (iline.l_lnno != 0)
              if (iline.l_lnno != 0)
                iline.l_addr.l_paddr += offset;
                iline.l_addr.l_paddr += offset;
              else if (iline.l_addr.l_symndx >= 0
              else if (iline.l_addr.l_symndx >= 0
                       && ((unsigned long) iline.l_addr.l_symndx
                       && ((unsigned long) iline.l_addr.l_symndx
                           < obj_raw_syment_count (input_bfd)))
                           < obj_raw_syment_count (input_bfd)))
                {
                {
                  long indx;
                  long indx;
 
 
                  indx = finfo->sym_indices[iline.l_addr.l_symndx];
                  indx = finfo->sym_indices[iline.l_addr.l_symndx];
 
 
                  if (indx < 0)
                  if (indx < 0)
                    {
                    {
                      /* These line numbers are attached to a symbol
                      /* These line numbers are attached to a symbol
                         which we are stripping.  We must discard the
                         which we are stripping.  We must discard the
                         line numbers because reading them back with
                         line numbers because reading them back with
                         no associated symbol (or associating them all
                         no associated symbol (or associating them all
                         with symbol #0) will fail.  We can't regain
                         with symbol #0) will fail.  We can't regain
                         the space in the output file, but at least
                         the space in the output file, but at least
                         they're dense.  */
                         they're dense.  */
                      skipping = TRUE;
                      skipping = TRUE;
                    }
                    }
                  else
                  else
                    {
                    {
                      struct internal_syment is;
                      struct internal_syment is;
                      union internal_auxent ia;
                      union internal_auxent ia;
 
 
                      /* Fix up the lnnoptr field in the aux entry of
                      /* Fix up the lnnoptr field in the aux entry of
                         the symbol.  It turns out that we can't do
                         the symbol.  It turns out that we can't do
                         this when we modify the symbol aux entries,
                         this when we modify the symbol aux entries,
                         because gas sometimes screws up the lnnoptr
                         because gas sometimes screws up the lnnoptr
                         field and makes it an offset from the start
                         field and makes it an offset from the start
                         of the line numbers rather than an absolute
                         of the line numbers rather than an absolute
                         file index.  */
                         file index.  */
                      bfd_coff_swap_sym_in (output_bfd,
                      bfd_coff_swap_sym_in (output_bfd,
                                            (finfo->outsyms
                                            (finfo->outsyms
                                             + ((indx - syment_base)
                                             + ((indx - syment_base)
                                                * osymesz)), &is);
                                                * osymesz)), &is);
                      if ((ISFCN (is.n_type)
                      if ((ISFCN (is.n_type)
                           || is.n_sclass == C_BLOCK)
                           || is.n_sclass == C_BLOCK)
                          && is.n_numaux >= 1)
                          && is.n_numaux >= 1)
                        {
                        {
                          void *auxptr;
                          void *auxptr;
 
 
                          auxptr = (finfo->outsyms
                          auxptr = (finfo->outsyms
                                    + ((indx - syment_base + 1)
                                    + ((indx - syment_base + 1)
                                       * osymesz));
                                       * osymesz));
                          bfd_coff_swap_aux_in (output_bfd, auxptr,
                          bfd_coff_swap_aux_in (output_bfd, auxptr,
                                                is.n_type, is.n_sclass,
                                                is.n_type, is.n_sclass,
                                                0, is.n_numaux, &ia);
                                                0, is.n_numaux, &ia);
                          ia.x_sym.x_fcnary.x_fcn.x_lnnoptr =
                          ia.x_sym.x_fcnary.x_fcn.x_lnnoptr =
                            (o->output_section->line_filepos
                            (o->output_section->line_filepos
                             + o->output_section->lineno_count * linesz
                             + o->output_section->lineno_count * linesz
                             + eline - finfo->linenos);
                             + eline - finfo->linenos);
                          bfd_coff_swap_aux_out (output_bfd, &ia,
                          bfd_coff_swap_aux_out (output_bfd, &ia,
                                                 is.n_type, is.n_sclass, 0,
                                                 is.n_type, is.n_sclass, 0,
                                                 is.n_numaux, auxptr);
                                                 is.n_numaux, auxptr);
                        }
                        }
 
 
                      skipping = FALSE;
                      skipping = FALSE;
                    }
                    }
 
 
                  iline.l_addr.l_symndx = indx;
                  iline.l_addr.l_symndx = indx;
                }
                }
 
 
              if (!skipping)
              if (!skipping)
                {
                {
                  bfd_coff_swap_lineno_out (output_bfd, &iline, oeline);
                  bfd_coff_swap_lineno_out (output_bfd, &iline, oeline);
                  oeline += linesz;
                  oeline += linesz;
                }
                }
            }
            }
 
 
          pos = o->output_section->line_filepos;
          pos = o->output_section->line_filepos;
          pos += o->output_section->lineno_count * linesz;
          pos += o->output_section->lineno_count * linesz;
          amt = oeline - finfo->linenos;
          amt = oeline - finfo->linenos;
          if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
          if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
              || bfd_bwrite (finfo->linenos, amt, output_bfd) != amt)
              || bfd_bwrite (finfo->linenos, amt, output_bfd) != amt)
            return FALSE;
            return FALSE;
 
 
          o->output_section->lineno_count += amt / linesz;
          o->output_section->lineno_count += amt / linesz;
        }
        }
    }
    }
 
 
  /* If we swapped out a C_FILE symbol, guess that the next C_FILE
  /* If we swapped out a C_FILE symbol, guess that the next C_FILE
     symbol will be the first symbol in the next input file.  In the
     symbol will be the first symbol in the next input file.  In the
     normal case, this will save us from writing out the C_FILE symbol
     normal case, this will save us from writing out the C_FILE symbol
     again.  */
     again.  */
  if (finfo->last_file_index != -1
  if (finfo->last_file_index != -1
      && (bfd_size_type) finfo->last_file_index >= syment_base)
      && (bfd_size_type) finfo->last_file_index >= syment_base)
    {
    {
      finfo->last_file.n_value = output_index;
      finfo->last_file.n_value = output_index;
      bfd_coff_swap_sym_out (output_bfd, &finfo->last_file,
      bfd_coff_swap_sym_out (output_bfd, &finfo->last_file,
                             (finfo->outsyms
                             (finfo->outsyms
                              + ((finfo->last_file_index - syment_base)
                              + ((finfo->last_file_index - syment_base)
                                 * osymesz)));
                                 * osymesz)));
    }
    }
 
 
  /* Write the modified symbols to the output file.  */
  /* Write the modified symbols to the output file.  */
  if (outsym > finfo->outsyms)
  if (outsym > finfo->outsyms)
    {
    {
      file_ptr pos;
      file_ptr pos;
      bfd_size_type amt;
      bfd_size_type amt;
 
 
      pos = obj_sym_filepos (output_bfd) + syment_base * osymesz;
      pos = obj_sym_filepos (output_bfd) + syment_base * osymesz;
      amt = outsym - finfo->outsyms;
      amt = outsym - finfo->outsyms;
      if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
      if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
          || bfd_bwrite (finfo->outsyms, amt, output_bfd) != amt)
          || bfd_bwrite (finfo->outsyms, amt, output_bfd) != amt)
        return FALSE;
        return FALSE;
 
 
      BFD_ASSERT ((obj_raw_syment_count (output_bfd)
      BFD_ASSERT ((obj_raw_syment_count (output_bfd)
                   + (outsym - finfo->outsyms) / osymesz)
                   + (outsym - finfo->outsyms) / osymesz)
                  == output_index);
                  == output_index);
 
 
      obj_raw_syment_count (output_bfd) = output_index;
      obj_raw_syment_count (output_bfd) = output_index;
    }
    }
 
 
  /* Relocate the contents of each section.  */
  /* Relocate the contents of each section.  */
  adjust_symndx = coff_backend_info (input_bfd)->_bfd_coff_adjust_symndx;
  adjust_symndx = coff_backend_info (input_bfd)->_bfd_coff_adjust_symndx;
  for (o = input_bfd->sections; o != NULL; o = o->next)
  for (o = input_bfd->sections; o != NULL; o = o->next)
    {
    {
      bfd_byte *contents;
      bfd_byte *contents;
      struct coff_section_tdata *secdata;
      struct coff_section_tdata *secdata;
 
 
      if (! o->linker_mark)
      if (! o->linker_mark)
        /* This section was omitted from the link.  */
        /* This section was omitted from the link.  */
        continue;
        continue;
 
 
      if ((o->flags & SEC_LINKER_CREATED) != 0)
      if ((o->flags & SEC_LINKER_CREATED) != 0)
        continue;
        continue;
 
 
      if ((o->flags & SEC_HAS_CONTENTS) == 0
      if ((o->flags & SEC_HAS_CONTENTS) == 0
          || (o->size == 0 && (o->flags & SEC_RELOC) == 0))
          || (o->size == 0 && (o->flags & SEC_RELOC) == 0))
        {
        {
          if ((o->flags & SEC_RELOC) != 0
          if ((o->flags & SEC_RELOC) != 0
              && o->reloc_count != 0)
              && o->reloc_count != 0)
            {
            {
              (*_bfd_error_handler)
              (*_bfd_error_handler)
                (_("%B: relocs in section `%A', but it has no contents"),
                (_("%B: relocs in section `%A', but it has no contents"),
                 input_bfd, o);
                 input_bfd, o);
              bfd_set_error (bfd_error_no_contents);
              bfd_set_error (bfd_error_no_contents);
              return FALSE;
              return FALSE;
            }
            }
 
 
          continue;
          continue;
        }
        }
 
 
      secdata = coff_section_data (input_bfd, o);
      secdata = coff_section_data (input_bfd, o);
      if (secdata != NULL && secdata->contents != NULL)
      if (secdata != NULL && secdata->contents != NULL)
        contents = secdata->contents;
        contents = secdata->contents;
      else
      else
        {
        {
          bfd_size_type x = o->rawsize ? o->rawsize : o->size;
          bfd_size_type x = o->rawsize ? o->rawsize : o->size;
          if (! bfd_get_section_contents (input_bfd, o, finfo->contents, 0, x))
          if (! bfd_get_section_contents (input_bfd, o, finfo->contents, 0, x))
            return FALSE;
            return FALSE;
          contents = finfo->contents;
          contents = finfo->contents;
        }
        }
 
 
      if ((o->flags & SEC_RELOC) != 0)
      if ((o->flags & SEC_RELOC) != 0)
        {
        {
          int target_index;
          int target_index;
          struct internal_reloc *internal_relocs;
          struct internal_reloc *internal_relocs;
          struct internal_reloc *irel;
          struct internal_reloc *irel;
 
 
          /* Read in the relocs.  */
          /* Read in the relocs.  */
          target_index = o->output_section->target_index;
          target_index = o->output_section->target_index;
          internal_relocs = (_bfd_coff_read_internal_relocs
          internal_relocs = (_bfd_coff_read_internal_relocs
                             (input_bfd, o, FALSE, finfo->external_relocs,
                             (input_bfd, o, FALSE, finfo->external_relocs,
                              finfo->info->relocatable,
                              finfo->info->relocatable,
                              (finfo->info->relocatable
                              (finfo->info->relocatable
                               ? (finfo->section_info[target_index].relocs
                               ? (finfo->section_info[target_index].relocs
                                  + o->output_section->reloc_count)
                                  + o->output_section->reloc_count)
                               : finfo->internal_relocs)));
                               : finfo->internal_relocs)));
          if (internal_relocs == NULL)
          if (internal_relocs == NULL)
            return FALSE;
            return FALSE;
 
 
          /* Call processor specific code to relocate the section
          /* Call processor specific code to relocate the section
             contents.  */
             contents.  */
          if (! bfd_coff_relocate_section (output_bfd, finfo->info,
          if (! bfd_coff_relocate_section (output_bfd, finfo->info,
                                           input_bfd, o,
                                           input_bfd, o,
                                           contents,
                                           contents,
                                           internal_relocs,
                                           internal_relocs,
                                           finfo->internal_syms,
                                           finfo->internal_syms,
                                           finfo->sec_ptrs))
                                           finfo->sec_ptrs))
            return FALSE;
            return FALSE;
 
 
          if (finfo->info->relocatable)
          if (finfo->info->relocatable)
            {
            {
              bfd_vma offset;
              bfd_vma offset;
              struct internal_reloc *irelend;
              struct internal_reloc *irelend;
              struct coff_link_hash_entry **rel_hash;
              struct coff_link_hash_entry **rel_hash;
 
 
              offset = o->output_section->vma + o->output_offset - o->vma;
              offset = o->output_section->vma + o->output_offset - o->vma;
              irel = internal_relocs;
              irel = internal_relocs;
              irelend = irel + o->reloc_count;
              irelend = irel + o->reloc_count;
              rel_hash = (finfo->section_info[target_index].rel_hashes
              rel_hash = (finfo->section_info[target_index].rel_hashes
                          + o->output_section->reloc_count);
                          + o->output_section->reloc_count);
              for (; irel < irelend; irel++, rel_hash++)
              for (; irel < irelend; irel++, rel_hash++)
                {
                {
                  struct coff_link_hash_entry *h;
                  struct coff_link_hash_entry *h;
                  bfd_boolean adjusted;
                  bfd_boolean adjusted;
 
 
                  *rel_hash = NULL;
                  *rel_hash = NULL;
 
 
                  /* Adjust the reloc address and symbol index.  */
                  /* Adjust the reloc address and symbol index.  */
                  irel->r_vaddr += offset;
                  irel->r_vaddr += offset;
 
 
                  if (irel->r_symndx == -1)
                  if (irel->r_symndx == -1)
                    continue;
                    continue;
 
 
                  if (adjust_symndx)
                  if (adjust_symndx)
                    {
                    {
                      if (! (*adjust_symndx) (output_bfd, finfo->info,
                      if (! (*adjust_symndx) (output_bfd, finfo->info,
                                              input_bfd, o, irel,
                                              input_bfd, o, irel,
                                              &adjusted))
                                              &adjusted))
                        return FALSE;
                        return FALSE;
                      if (adjusted)
                      if (adjusted)
                        continue;
                        continue;
                    }
                    }
 
 
                  h = obj_coff_sym_hashes (input_bfd)[irel->r_symndx];
                  h = obj_coff_sym_hashes (input_bfd)[irel->r_symndx];
                  if (h != NULL)
                  if (h != NULL)
                    {
                    {
                      /* This is a global symbol.  */
                      /* This is a global symbol.  */
                      if (h->indx >= 0)
                      if (h->indx >= 0)
                        irel->r_symndx = h->indx;
                        irel->r_symndx = h->indx;
                      else
                      else
                        {
                        {
                          /* This symbol is being written at the end
                          /* This symbol is being written at the end
                             of the file, and we do not yet know the
                             of the file, and we do not yet know the
                             symbol index.  We save the pointer to the
                             symbol index.  We save the pointer to the
                             hash table entry in the rel_hash list.
                             hash table entry in the rel_hash list.
                             We set the indx field to -2 to indicate
                             We set the indx field to -2 to indicate
                             that this symbol must not be stripped.  */
                             that this symbol must not be stripped.  */
                          *rel_hash = h;
                          *rel_hash = h;
                          h->indx = -2;
                          h->indx = -2;
                        }
                        }
                    }
                    }
                  else
                  else
                    {
                    {
                      long indx;
                      long indx;
 
 
                      indx = finfo->sym_indices[irel->r_symndx];
                      indx = finfo->sym_indices[irel->r_symndx];
                      if (indx != -1)
                      if (indx != -1)
                        irel->r_symndx = indx;
                        irel->r_symndx = indx;
                      else
                      else
                        {
                        {
                          struct internal_syment *is;
                          struct internal_syment *is;
                          const char *name;
                          const char *name;
                          char buf[SYMNMLEN + 1];
                          char buf[SYMNMLEN + 1];
 
 
                          /* This reloc is against a symbol we are
                          /* This reloc is against a symbol we are
                             stripping.  This should have been handled
                             stripping.  This should have been handled
                             by the 'dont_skip_symbol' code in the while
                             by the 'dont_skip_symbol' code in the while
                             loop at the top of this function.  */
                             loop at the top of this function.  */
                          is = finfo->internal_syms + irel->r_symndx;
                          is = finfo->internal_syms + irel->r_symndx;
 
 
                          name = (_bfd_coff_internal_syment_name
                          name = (_bfd_coff_internal_syment_name
                                  (input_bfd, is, buf));
                                  (input_bfd, is, buf));
                          if (name == NULL)
                          if (name == NULL)
                            return FALSE;
                            return FALSE;
 
 
                          if (! ((*finfo->info->callbacks->unattached_reloc)
                          if (! ((*finfo->info->callbacks->unattached_reloc)
                                 (finfo->info, name, input_bfd, o,
                                 (finfo->info, name, input_bfd, o,
                                  irel->r_vaddr)))
                                  irel->r_vaddr)))
                            return FALSE;
                            return FALSE;
                        }
                        }
                    }
                    }
                }
                }
 
 
              o->output_section->reloc_count += o->reloc_count;
              o->output_section->reloc_count += o->reloc_count;
            }
            }
        }
        }
 
 
      /* Write out the modified section contents.  */
      /* Write out the modified section contents.  */
      if (secdata == NULL || secdata->stab_info == NULL)
      if (secdata == NULL || secdata->stab_info == NULL)
        {
        {
          file_ptr loc = o->output_offset * bfd_octets_per_byte (output_bfd);
          file_ptr loc = o->output_offset * bfd_octets_per_byte (output_bfd);
          if (! bfd_set_section_contents (output_bfd, o->output_section,
          if (! bfd_set_section_contents (output_bfd, o->output_section,
                                          contents, loc, o->size))
                                          contents, loc, o->size))
            return FALSE;
            return FALSE;
        }
        }
      else
      else
        {
        {
          if (! (_bfd_write_section_stabs
          if (! (_bfd_write_section_stabs
                 (output_bfd, &coff_hash_table (finfo->info)->stab_info,
                 (output_bfd, &coff_hash_table (finfo->info)->stab_info,
                  o, &secdata->stab_info, contents)))
                  o, &secdata->stab_info, contents)))
            return FALSE;
            return FALSE;
        }
        }
    }
    }
 
 
  if (! finfo->info->keep_memory
  if (! finfo->info->keep_memory
      && ! _bfd_coff_free_symbols (input_bfd))
      && ! _bfd_coff_free_symbols (input_bfd))
    return FALSE;
    return FALSE;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Write out a global symbol.  Called via coff_link_hash_traverse.  */
/* Write out a global symbol.  Called via coff_link_hash_traverse.  */
 
 
bfd_boolean
bfd_boolean
_bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
_bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
{
{
  struct coff_final_link_info *finfo = (struct coff_final_link_info *) data;
  struct coff_final_link_info *finfo = (struct coff_final_link_info *) data;
  bfd *output_bfd;
  bfd *output_bfd;
  struct internal_syment isym;
  struct internal_syment isym;
  bfd_size_type symesz;
  bfd_size_type symesz;
  unsigned int i;
  unsigned int i;
  file_ptr pos;
  file_ptr pos;
 
 
  output_bfd = finfo->output_bfd;
  output_bfd = finfo->output_bfd;
 
 
  if (h->root.type == bfd_link_hash_warning)
  if (h->root.type == bfd_link_hash_warning)
    {
    {
      h = (struct coff_link_hash_entry *) h->root.u.i.link;
      h = (struct coff_link_hash_entry *) h->root.u.i.link;
      if (h->root.type == bfd_link_hash_new)
      if (h->root.type == bfd_link_hash_new)
        return TRUE;
        return TRUE;
    }
    }
 
 
  if (h->indx >= 0)
  if (h->indx >= 0)
    return TRUE;
    return TRUE;
 
 
  if (h->indx != -2
  if (h->indx != -2
      && (finfo->info->strip == strip_all
      && (finfo->info->strip == strip_all
          || (finfo->info->strip == strip_some
          || (finfo->info->strip == strip_some
              && (bfd_hash_lookup (finfo->info->keep_hash,
              && (bfd_hash_lookup (finfo->info->keep_hash,
                                   h->root.root.string, FALSE, FALSE)
                                   h->root.root.string, FALSE, FALSE)
                  == NULL))))
                  == NULL))))
    return TRUE;
    return TRUE;
 
 
  switch (h->root.type)
  switch (h->root.type)
    {
    {
    default:
    default:
    case bfd_link_hash_new:
    case bfd_link_hash_new:
    case bfd_link_hash_warning:
    case bfd_link_hash_warning:
      abort ();
      abort ();
      return FALSE;
      return FALSE;
 
 
    case bfd_link_hash_undefined:
    case bfd_link_hash_undefined:
    case bfd_link_hash_undefweak:
    case bfd_link_hash_undefweak:
      isym.n_scnum = N_UNDEF;
      isym.n_scnum = N_UNDEF;
      isym.n_value = 0;
      isym.n_value = 0;
      break;
      break;
 
 
    case bfd_link_hash_defined:
    case bfd_link_hash_defined:
    case bfd_link_hash_defweak:
    case bfd_link_hash_defweak:
      {
      {
        asection *sec;
        asection *sec;
 
 
        sec = h->root.u.def.section->output_section;
        sec = h->root.u.def.section->output_section;
        if (bfd_is_abs_section (sec))
        if (bfd_is_abs_section (sec))
          isym.n_scnum = N_ABS;
          isym.n_scnum = N_ABS;
        else
        else
          isym.n_scnum = sec->target_index;
          isym.n_scnum = sec->target_index;
        isym.n_value = (h->root.u.def.value
        isym.n_value = (h->root.u.def.value
                        + h->root.u.def.section->output_offset);
                        + h->root.u.def.section->output_offset);
        if (! obj_pe (finfo->output_bfd))
        if (! obj_pe (finfo->output_bfd))
          isym.n_value += sec->vma;
          isym.n_value += sec->vma;
      }
      }
      break;
      break;
 
 
    case bfd_link_hash_common:
    case bfd_link_hash_common:
      isym.n_scnum = N_UNDEF;
      isym.n_scnum = N_UNDEF;
      isym.n_value = h->root.u.c.size;
      isym.n_value = h->root.u.c.size;
      break;
      break;
 
 
    case bfd_link_hash_indirect:
    case bfd_link_hash_indirect:
      /* Just ignore these.  They can't be handled anyhow.  */
      /* Just ignore these.  They can't be handled anyhow.  */
      return TRUE;
      return TRUE;
    }
    }
 
 
  if (strlen (h->root.root.string) <= SYMNMLEN)
  if (strlen (h->root.root.string) <= SYMNMLEN)
    strncpy (isym._n._n_name, h->root.root.string, SYMNMLEN);
    strncpy (isym._n._n_name, h->root.root.string, SYMNMLEN);
  else
  else
    {
    {
      bfd_boolean hash;
      bfd_boolean hash;
      bfd_size_type indx;
      bfd_size_type indx;
 
 
      hash = TRUE;
      hash = TRUE;
      if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
      if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
        hash = FALSE;
        hash = FALSE;
      indx = _bfd_stringtab_add (finfo->strtab, h->root.root.string, hash,
      indx = _bfd_stringtab_add (finfo->strtab, h->root.root.string, hash,
                                 FALSE);
                                 FALSE);
      if (indx == (bfd_size_type) -1)
      if (indx == (bfd_size_type) -1)
        {
        {
          finfo->failed = TRUE;
          finfo->failed = TRUE;
          return FALSE;
          return FALSE;
        }
        }
      isym._n._n_n._n_zeroes = 0;
      isym._n._n_n._n_zeroes = 0;
      isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
      isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
    }
    }
 
 
  isym.n_sclass = h->symbol_class;
  isym.n_sclass = h->symbol_class;
  isym.n_type = h->type;
  isym.n_type = h->type;
 
 
  if (isym.n_sclass == C_NULL)
  if (isym.n_sclass == C_NULL)
    isym.n_sclass = C_EXT;
    isym.n_sclass = C_EXT;
 
 
  /* If doing task linking and this is the pass where we convert
  /* If doing task linking and this is the pass where we convert
     defined globals to statics, then do that conversion now.  If the
     defined globals to statics, then do that conversion now.  If the
     symbol is not being converted, just ignore it and it will be
     symbol is not being converted, just ignore it and it will be
     output during a later pass.  */
     output during a later pass.  */
  if (finfo->global_to_static)
  if (finfo->global_to_static)
    {
    {
      if (! IS_EXTERNAL (output_bfd, isym))
      if (! IS_EXTERNAL (output_bfd, isym))
        return TRUE;
        return TRUE;
 
 
      isym.n_sclass = C_STAT;
      isym.n_sclass = C_STAT;
    }
    }
 
 
  /* When a weak symbol is not overridden by a strong one,
  /* When a weak symbol is not overridden by a strong one,
     turn it into an external symbol when not building a
     turn it into an external symbol when not building a
     shared or relocatable object.  */
     shared or relocatable object.  */
  if (! finfo->info->shared
  if (! finfo->info->shared
      && ! finfo->info->relocatable
      && ! finfo->info->relocatable
      && IS_WEAK_EXTERNAL (finfo->output_bfd, isym))
      && IS_WEAK_EXTERNAL (finfo->output_bfd, isym))
    isym.n_sclass = C_EXT;
    isym.n_sclass = C_EXT;
 
 
  isym.n_numaux = h->numaux;
  isym.n_numaux = h->numaux;
 
 
  bfd_coff_swap_sym_out (output_bfd, &isym, finfo->outsyms);
  bfd_coff_swap_sym_out (output_bfd, &isym, finfo->outsyms);
 
 
  symesz = bfd_coff_symesz (output_bfd);
  symesz = bfd_coff_symesz (output_bfd);
 
 
  pos = obj_sym_filepos (output_bfd);
  pos = obj_sym_filepos (output_bfd);
  pos += obj_raw_syment_count (output_bfd) * symesz;
  pos += obj_raw_syment_count (output_bfd) * symesz;
  if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
  if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
      || bfd_bwrite (finfo->outsyms, symesz, output_bfd) != symesz)
      || bfd_bwrite (finfo->outsyms, symesz, output_bfd) != symesz)
    {
    {
      finfo->failed = TRUE;
      finfo->failed = TRUE;
      return FALSE;
      return FALSE;
    }
    }
 
 
  h->indx = obj_raw_syment_count (output_bfd);
  h->indx = obj_raw_syment_count (output_bfd);
 
 
  ++obj_raw_syment_count (output_bfd);
  ++obj_raw_syment_count (output_bfd);
 
 
  /* Write out any associated aux entries.  Most of the aux entries
  /* Write out any associated aux entries.  Most of the aux entries
     will have been modified in _bfd_coff_link_input_bfd.  We have to
     will have been modified in _bfd_coff_link_input_bfd.  We have to
     handle section aux entries here, now that we have the final
     handle section aux entries here, now that we have the final
     relocation and line number counts.  */
     relocation and line number counts.  */
  for (i = 0; i < isym.n_numaux; i++)
  for (i = 0; i < isym.n_numaux; i++)
    {
    {
      union internal_auxent *auxp;
      union internal_auxent *auxp;
 
 
      auxp = h->aux + i;
      auxp = h->aux + i;
 
 
      /* Look for a section aux entry here using the same tests that
      /* Look for a section aux entry here using the same tests that
         coff_swap_aux_out uses.  */
         coff_swap_aux_out uses.  */
      if (i == 0
      if (i == 0
          && (isym.n_sclass == C_STAT
          && (isym.n_sclass == C_STAT
              || isym.n_sclass == C_HIDDEN)
              || isym.n_sclass == C_HIDDEN)
          && isym.n_type == T_NULL
          && isym.n_type == T_NULL
          && (h->root.type == bfd_link_hash_defined
          && (h->root.type == bfd_link_hash_defined
              || h->root.type == bfd_link_hash_defweak))
              || h->root.type == bfd_link_hash_defweak))
        {
        {
          asection *sec;
          asection *sec;
 
 
          sec = h->root.u.def.section->output_section;
          sec = h->root.u.def.section->output_section;
          if (sec != NULL)
          if (sec != NULL)
            {
            {
              auxp->x_scn.x_scnlen = sec->size;
              auxp->x_scn.x_scnlen = sec->size;
 
 
              /* For PE, an overflow on the final link reportedly does
              /* For PE, an overflow on the final link reportedly does
                 not matter.  FIXME: Why not?  */
                 not matter.  FIXME: Why not?  */
              if (sec->reloc_count > 0xffff
              if (sec->reloc_count > 0xffff
                  && (! obj_pe (output_bfd)
                  && (! obj_pe (output_bfd)
                      || finfo->info->relocatable))
                      || finfo->info->relocatable))
                (*_bfd_error_handler)
                (*_bfd_error_handler)
                  (_("%s: %s: reloc overflow: 0x%lx > 0xffff"),
                  (_("%s: %s: reloc overflow: 0x%lx > 0xffff"),
                   bfd_get_filename (output_bfd),
                   bfd_get_filename (output_bfd),
                   bfd_get_section_name (output_bfd, sec),
                   bfd_get_section_name (output_bfd, sec),
                   sec->reloc_count);
                   sec->reloc_count);
 
 
              if (sec->lineno_count > 0xffff
              if (sec->lineno_count > 0xffff
                  && (! obj_pe (output_bfd)
                  && (! obj_pe (output_bfd)
                      || finfo->info->relocatable))
                      || finfo->info->relocatable))
                (*_bfd_error_handler)
                (*_bfd_error_handler)
                  (_("%s: warning: %s: line number overflow: 0x%lx > 0xffff"),
                  (_("%s: warning: %s: line number overflow: 0x%lx > 0xffff"),
                   bfd_get_filename (output_bfd),
                   bfd_get_filename (output_bfd),
                   bfd_get_section_name (output_bfd, sec),
                   bfd_get_section_name (output_bfd, sec),
                   sec->lineno_count);
                   sec->lineno_count);
 
 
              auxp->x_scn.x_nreloc = sec->reloc_count;
              auxp->x_scn.x_nreloc = sec->reloc_count;
              auxp->x_scn.x_nlinno = sec->lineno_count;
              auxp->x_scn.x_nlinno = sec->lineno_count;
              auxp->x_scn.x_checksum = 0;
              auxp->x_scn.x_checksum = 0;
              auxp->x_scn.x_associated = 0;
              auxp->x_scn.x_associated = 0;
              auxp->x_scn.x_comdat = 0;
              auxp->x_scn.x_comdat = 0;
            }
            }
        }
        }
 
 
      bfd_coff_swap_aux_out (output_bfd, auxp, isym.n_type,
      bfd_coff_swap_aux_out (output_bfd, auxp, isym.n_type,
                             isym.n_sclass, (int) i, isym.n_numaux,
                             isym.n_sclass, (int) i, isym.n_numaux,
                             finfo->outsyms);
                             finfo->outsyms);
      if (bfd_bwrite (finfo->outsyms, symesz, output_bfd) != symesz)
      if (bfd_bwrite (finfo->outsyms, symesz, output_bfd) != symesz)
        {
        {
          finfo->failed = TRUE;
          finfo->failed = TRUE;
          return FALSE;
          return FALSE;
        }
        }
      ++obj_raw_syment_count (output_bfd);
      ++obj_raw_syment_count (output_bfd);
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Write out task global symbols, converting them to statics.  Called
/* Write out task global symbols, converting them to statics.  Called
   via coff_link_hash_traverse.  Calls bfd_coff_write_global_sym to do
   via coff_link_hash_traverse.  Calls bfd_coff_write_global_sym to do
   the dirty work, if the symbol we are processing needs conversion.  */
   the dirty work, if the symbol we are processing needs conversion.  */
 
 
bfd_boolean
bfd_boolean
_bfd_coff_write_task_globals (struct coff_link_hash_entry *h, void *data)
_bfd_coff_write_task_globals (struct coff_link_hash_entry *h, void *data)
{
{
  struct coff_final_link_info *finfo = (struct coff_final_link_info *) data;
  struct coff_final_link_info *finfo = (struct coff_final_link_info *) data;
  bfd_boolean rtnval = TRUE;
  bfd_boolean rtnval = TRUE;
  bfd_boolean save_global_to_static;
  bfd_boolean save_global_to_static;
 
 
  if (h->root.type == bfd_link_hash_warning)
  if (h->root.type == bfd_link_hash_warning)
    h = (struct coff_link_hash_entry *) h->root.u.i.link;
    h = (struct coff_link_hash_entry *) h->root.u.i.link;
 
 
  if (h->indx < 0)
  if (h->indx < 0)
    {
    {
      switch (h->root.type)
      switch (h->root.type)
        {
        {
        case bfd_link_hash_defined:
        case bfd_link_hash_defined:
        case bfd_link_hash_defweak:
        case bfd_link_hash_defweak:
          save_global_to_static = finfo->global_to_static;
          save_global_to_static = finfo->global_to_static;
          finfo->global_to_static = TRUE;
          finfo->global_to_static = TRUE;
          rtnval = _bfd_coff_write_global_sym (h, data);
          rtnval = _bfd_coff_write_global_sym (h, data);
          finfo->global_to_static = save_global_to_static;
          finfo->global_to_static = save_global_to_static;
          break;
          break;
        default:
        default:
          break;
          break;
        }
        }
    }
    }
  return (rtnval);
  return (rtnval);
}
}
 
 
/* Handle a link order which is supposed to generate a reloc.  */
/* Handle a link order which is supposed to generate a reloc.  */
 
 
bfd_boolean
bfd_boolean
_bfd_coff_reloc_link_order (bfd *output_bfd,
_bfd_coff_reloc_link_order (bfd *output_bfd,
                            struct coff_final_link_info *finfo,
                            struct coff_final_link_info *finfo,
                            asection *output_section,
                            asection *output_section,
                            struct bfd_link_order *link_order)
                            struct bfd_link_order *link_order)
{
{
  reloc_howto_type *howto;
  reloc_howto_type *howto;
  struct internal_reloc *irel;
  struct internal_reloc *irel;
  struct coff_link_hash_entry **rel_hash_ptr;
  struct coff_link_hash_entry **rel_hash_ptr;
 
 
  howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
  howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
  if (howto == NULL)
  if (howto == NULL)
    {
    {
      bfd_set_error (bfd_error_bad_value);
      bfd_set_error (bfd_error_bad_value);
      return FALSE;
      return FALSE;
    }
    }
 
 
  if (link_order->u.reloc.p->addend != 0)
  if (link_order->u.reloc.p->addend != 0)
    {
    {
      bfd_size_type size;
      bfd_size_type size;
      bfd_byte *buf;
      bfd_byte *buf;
      bfd_reloc_status_type rstat;
      bfd_reloc_status_type rstat;
      bfd_boolean ok;
      bfd_boolean ok;
      file_ptr loc;
      file_ptr loc;
 
 
      size = bfd_get_reloc_size (howto);
      size = bfd_get_reloc_size (howto);
      buf = (bfd_byte *) bfd_zmalloc (size);
      buf = (bfd_byte *) bfd_zmalloc (size);
      if (buf == NULL)
      if (buf == NULL)
        return FALSE;
        return FALSE;
 
 
      rstat = _bfd_relocate_contents (howto, output_bfd,
      rstat = _bfd_relocate_contents (howto, output_bfd,
                                      (bfd_vma) link_order->u.reloc.p->addend,\
                                      (bfd_vma) link_order->u.reloc.p->addend,\
                                      buf);
                                      buf);
      switch (rstat)
      switch (rstat)
        {
        {
        case bfd_reloc_ok:
        case bfd_reloc_ok:
          break;
          break;
        default:
        default:
        case bfd_reloc_outofrange:
        case bfd_reloc_outofrange:
          abort ();
          abort ();
        case bfd_reloc_overflow:
        case bfd_reloc_overflow:
          if (! ((*finfo->info->callbacks->reloc_overflow)
          if (! ((*finfo->info->callbacks->reloc_overflow)
                 (finfo->info, NULL,
                 (finfo->info, NULL,
                  (link_order->type == bfd_section_reloc_link_order
                  (link_order->type == bfd_section_reloc_link_order
                   ? bfd_section_name (output_bfd,
                   ? bfd_section_name (output_bfd,
                                       link_order->u.reloc.p->u.section)
                                       link_order->u.reloc.p->u.section)
                   : link_order->u.reloc.p->u.name),
                   : link_order->u.reloc.p->u.name),
                  howto->name, link_order->u.reloc.p->addend,
                  howto->name, link_order->u.reloc.p->addend,
                  (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
                  (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
            {
            {
              free (buf);
              free (buf);
              return FALSE;
              return FALSE;
            }
            }
          break;
          break;
        }
        }
      loc = link_order->offset * bfd_octets_per_byte (output_bfd);
      loc = link_order->offset * bfd_octets_per_byte (output_bfd);
      ok = bfd_set_section_contents (output_bfd, output_section, buf,
      ok = bfd_set_section_contents (output_bfd, output_section, buf,
                                     loc, size);
                                     loc, size);
      free (buf);
      free (buf);
      if (! ok)
      if (! ok)
        return FALSE;
        return FALSE;
    }
    }
 
 
  /* Store the reloc information in the right place.  It will get
  /* Store the reloc information in the right place.  It will get
     swapped and written out at the end of the final_link routine.  */
     swapped and written out at the end of the final_link routine.  */
  irel = (finfo->section_info[output_section->target_index].relocs
  irel = (finfo->section_info[output_section->target_index].relocs
          + output_section->reloc_count);
          + output_section->reloc_count);
  rel_hash_ptr = (finfo->section_info[output_section->target_index].rel_hashes
  rel_hash_ptr = (finfo->section_info[output_section->target_index].rel_hashes
                  + output_section->reloc_count);
                  + output_section->reloc_count);
 
 
  memset (irel, 0, sizeof (struct internal_reloc));
  memset (irel, 0, sizeof (struct internal_reloc));
  *rel_hash_ptr = NULL;
  *rel_hash_ptr = NULL;
 
 
  irel->r_vaddr = output_section->vma + link_order->offset;
  irel->r_vaddr = output_section->vma + link_order->offset;
 
 
  if (link_order->type == bfd_section_reloc_link_order)
  if (link_order->type == bfd_section_reloc_link_order)
    {
    {
      /* We need to somehow locate a symbol in the right section.  The
      /* We need to somehow locate a symbol in the right section.  The
         symbol must either have a value of zero, or we must adjust
         symbol must either have a value of zero, or we must adjust
         the addend by the value of the symbol.  FIXME: Write this
         the addend by the value of the symbol.  FIXME: Write this
         when we need it.  The old linker couldn't handle this anyhow.  */
         when we need it.  The old linker couldn't handle this anyhow.  */
      abort ();
      abort ();
      *rel_hash_ptr = NULL;
      *rel_hash_ptr = NULL;
      irel->r_symndx = 0;
      irel->r_symndx = 0;
    }
    }
  else
  else
    {
    {
      struct coff_link_hash_entry *h;
      struct coff_link_hash_entry *h;
 
 
      h = ((struct coff_link_hash_entry *)
      h = ((struct coff_link_hash_entry *)
           bfd_wrapped_link_hash_lookup (output_bfd, finfo->info,
           bfd_wrapped_link_hash_lookup (output_bfd, finfo->info,
                                         link_order->u.reloc.p->u.name,
                                         link_order->u.reloc.p->u.name,
                                         FALSE, FALSE, TRUE));
                                         FALSE, FALSE, TRUE));
      if (h != NULL)
      if (h != NULL)
        {
        {
          if (h->indx >= 0)
          if (h->indx >= 0)
            irel->r_symndx = h->indx;
            irel->r_symndx = h->indx;
          else
          else
            {
            {
              /* Set the index to -2 to force this symbol to get
              /* Set the index to -2 to force this symbol to get
                 written out.  */
                 written out.  */
              h->indx = -2;
              h->indx = -2;
              *rel_hash_ptr = h;
              *rel_hash_ptr = h;
              irel->r_symndx = 0;
              irel->r_symndx = 0;
            }
            }
        }
        }
      else
      else
        {
        {
          if (! ((*finfo->info->callbacks->unattached_reloc)
          if (! ((*finfo->info->callbacks->unattached_reloc)
                 (finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL,
                 (finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL,
                  (asection *) NULL, (bfd_vma) 0)))
                  (asection *) NULL, (bfd_vma) 0)))
            return FALSE;
            return FALSE;
          irel->r_symndx = 0;
          irel->r_symndx = 0;
        }
        }
    }
    }
 
 
  /* FIXME: Is this always right?  */
  /* FIXME: Is this always right?  */
  irel->r_type = howto->type;
  irel->r_type = howto->type;
 
 
  /* r_size is only used on the RS/6000, which needs its own linker
  /* r_size is only used on the RS/6000, which needs its own linker
     routines anyhow.  r_extern is only used for ECOFF.  */
     routines anyhow.  r_extern is only used for ECOFF.  */
 
 
  /* FIXME: What is the right value for r_offset?  Is zero OK?  */
  /* FIXME: What is the right value for r_offset?  Is zero OK?  */
  ++output_section->reloc_count;
  ++output_section->reloc_count;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* A basic reloc handling routine which may be used by processors with
/* A basic reloc handling routine which may be used by processors with
   simple relocs.  */
   simple relocs.  */
 
 
bfd_boolean
bfd_boolean
_bfd_coff_generic_relocate_section (bfd *output_bfd,
_bfd_coff_generic_relocate_section (bfd *output_bfd,
                                    struct bfd_link_info *info,
                                    struct bfd_link_info *info,
                                    bfd *input_bfd,
                                    bfd *input_bfd,
                                    asection *input_section,
                                    asection *input_section,
                                    bfd_byte *contents,
                                    bfd_byte *contents,
                                    struct internal_reloc *relocs,
                                    struct internal_reloc *relocs,
                                    struct internal_syment *syms,
                                    struct internal_syment *syms,
                                    asection **sections)
                                    asection **sections)
{
{
  struct internal_reloc *rel;
  struct internal_reloc *rel;
  struct internal_reloc *relend;
  struct internal_reloc *relend;
 
 
  rel = relocs;
  rel = relocs;
  relend = rel + input_section->reloc_count;
  relend = rel + input_section->reloc_count;
  for (; rel < relend; rel++)
  for (; rel < relend; rel++)
    {
    {
      long symndx;
      long symndx;
      struct coff_link_hash_entry *h;
      struct coff_link_hash_entry *h;
      struct internal_syment *sym;
      struct internal_syment *sym;
      bfd_vma addend;
      bfd_vma addend;
      bfd_vma val;
      bfd_vma val;
      reloc_howto_type *howto;
      reloc_howto_type *howto;
      bfd_reloc_status_type rstat;
      bfd_reloc_status_type rstat;
 
 
      symndx = rel->r_symndx;
      symndx = rel->r_symndx;
 
 
      if (symndx == -1)
      if (symndx == -1)
        {
        {
          h = NULL;
          h = NULL;
          sym = NULL;
          sym = NULL;
        }
        }
      else if (symndx < 0
      else if (symndx < 0
               || (unsigned long) symndx >= obj_raw_syment_count (input_bfd))
               || (unsigned long) symndx >= obj_raw_syment_count (input_bfd))
        {
        {
          (*_bfd_error_handler)
          (*_bfd_error_handler)
            ("%B: illegal symbol index %ld in relocs", input_bfd, symndx);
            ("%B: illegal symbol index %ld in relocs", input_bfd, symndx);
          return FALSE;
          return FALSE;
        }
        }
      else
      else
        {
        {
          h = obj_coff_sym_hashes (input_bfd)[symndx];
          h = obj_coff_sym_hashes (input_bfd)[symndx];
          sym = syms + symndx;
          sym = syms + symndx;
        }
        }
 
 
      /* COFF treats common symbols in one of two ways.  Either the
      /* COFF treats common symbols in one of two ways.  Either the
         size of the symbol is included in the section contents, or it
         size of the symbol is included in the section contents, or it
         is not.  We assume that the size is not included, and force
         is not.  We assume that the size is not included, and force
         the rtype_to_howto function to adjust the addend as needed.  */
         the rtype_to_howto function to adjust the addend as needed.  */
      if (sym != NULL && sym->n_scnum != 0)
      if (sym != NULL && sym->n_scnum != 0)
        addend = - sym->n_value;
        addend = - sym->n_value;
      else
      else
        addend = 0;
        addend = 0;
 
 
      howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
      howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
                                       sym, &addend);
                                       sym, &addend);
      if (howto == NULL)
      if (howto == NULL)
        return FALSE;
        return FALSE;
 
 
      /* If we are doing a relocatable link, then we can just ignore
      /* If we are doing a relocatable link, then we can just ignore
         a PC relative reloc that is pcrel_offset.  It will already
         a PC relative reloc that is pcrel_offset.  It will already
         have the correct value.  If this is not a relocatable link,
         have the correct value.  If this is not a relocatable link,
         then we should ignore the symbol value.  */
         then we should ignore the symbol value.  */
      if (howto->pc_relative && howto->pcrel_offset)
      if (howto->pc_relative && howto->pcrel_offset)
        {
        {
          if (info->relocatable)
          if (info->relocatable)
            continue;
            continue;
          if (sym != NULL && sym->n_scnum != 0)
          if (sym != NULL && sym->n_scnum != 0)
            addend += sym->n_value;
            addend += sym->n_value;
        }
        }
 
 
      val = 0;
      val = 0;
 
 
      if (h == NULL)
      if (h == NULL)
        {
        {
          asection *sec;
          asection *sec;
 
 
          if (symndx == -1)
          if (symndx == -1)
            {
            {
              sec = bfd_abs_section_ptr;
              sec = bfd_abs_section_ptr;
              val = 0;
              val = 0;
            }
            }
          else
          else
            {
            {
              sec = sections[symndx];
              sec = sections[symndx];
              val = (sec->output_section->vma
              val = (sec->output_section->vma
                     + sec->output_offset
                     + sec->output_offset
                     + sym->n_value);
                     + sym->n_value);
              if (! obj_pe (input_bfd))
              if (! obj_pe (input_bfd))
                val -= sec->vma;
                val -= sec->vma;
            }
            }
        }
        }
      else
      else
        {
        {
          if (h->root.type == bfd_link_hash_defined
          if (h->root.type == bfd_link_hash_defined
              || h->root.type == bfd_link_hash_defweak)
              || h->root.type == bfd_link_hash_defweak)
            {
            {
              /* Defined weak symbols are a GNU extension. */
              /* Defined weak symbols are a GNU extension. */
              asection *sec;
              asection *sec;
 
 
              sec = h->root.u.def.section;
              sec = h->root.u.def.section;
              val = (h->root.u.def.value
              val = (h->root.u.def.value
                     + sec->output_section->vma
                     + sec->output_section->vma
                     + sec->output_offset);
                     + sec->output_offset);
            }
            }
 
 
          else if (h->root.type == bfd_link_hash_undefweak)
          else if (h->root.type == bfd_link_hash_undefweak)
            {
            {
              if (h->symbol_class == C_NT_WEAK && h->numaux == 1)
              if (h->symbol_class == C_NT_WEAK && h->numaux == 1)
                {
                {
                  /* See _Microsoft Portable Executable and Common Object
                  /* See _Microsoft Portable Executable and Common Object
                     File Format Specification_, section 5.5.3.
                     File Format Specification_, section 5.5.3.
                     Note that weak symbols without aux records are a GNU
                     Note that weak symbols without aux records are a GNU
                     extension.
                     extension.
                     FIXME: All weak externals are treated as having
                     FIXME: All weak externals are treated as having
                     characteristic IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY (1).
                     characteristic IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY (1).
                     These behave as per SVR4 ABI:  A library member
                     These behave as per SVR4 ABI:  A library member
                     will resolve a weak external only if a normal
                     will resolve a weak external only if a normal
                     external causes the library member to be linked.
                     external causes the library member to be linked.
                     See also linker.c: generic_link_check_archive_element. */
                     See also linker.c: generic_link_check_archive_element. */
                  asection *sec;
                  asection *sec;
                  struct coff_link_hash_entry *h2 =
                  struct coff_link_hash_entry *h2 =
                    h->auxbfd->tdata.coff_obj_data->sym_hashes[
                    h->auxbfd->tdata.coff_obj_data->sym_hashes[
                    h->aux->x_sym.x_tagndx.l];
                    h->aux->x_sym.x_tagndx.l];
 
 
                  if (!h2 || h2->root.type == bfd_link_hash_undefined)
                  if (!h2 || h2->root.type == bfd_link_hash_undefined)
                    {
                    {
                      sec = bfd_abs_section_ptr;
                      sec = bfd_abs_section_ptr;
                      val = 0;
                      val = 0;
                    }
                    }
                  else
                  else
                    {
                    {
                      sec = h2->root.u.def.section;
                      sec = h2->root.u.def.section;
                      val = h2->root.u.def.value
                      val = h2->root.u.def.value
                        + sec->output_section->vma + sec->output_offset;
                        + sec->output_section->vma + sec->output_offset;
                    }
                    }
                }
                }
              else
              else
                /* This is a GNU extension.  */
                /* This is a GNU extension.  */
                val = 0;
                val = 0;
            }
            }
 
 
          else if (! info->relocatable)
          else if (! info->relocatable)
            {
            {
              if (! ((*info->callbacks->undefined_symbol)
              if (! ((*info->callbacks->undefined_symbol)
                     (info, h->root.root.string, input_bfd, input_section,
                     (info, h->root.root.string, input_bfd, input_section,
                      rel->r_vaddr - input_section->vma, TRUE)))
                      rel->r_vaddr - input_section->vma, TRUE)))
                return FALSE;
                return FALSE;
            }
            }
        }
        }
 
 
      if (info->base_file)
      if (info->base_file)
        {
        {
          /* Emit a reloc if the backend thinks it needs it.  */
          /* Emit a reloc if the backend thinks it needs it.  */
          if (sym && pe_data (output_bfd)->in_reloc_p (output_bfd, howto))
          if (sym && pe_data (output_bfd)->in_reloc_p (output_bfd, howto))
            {
            {
              /* Relocation to a symbol in a section which isn't
              /* Relocation to a symbol in a section which isn't
                 absolute.  We output the address here to a file.
                 absolute.  We output the address here to a file.
                 This file is then read by dlltool when generating the
                 This file is then read by dlltool when generating the
                 reloc section.  Note that the base file is not
                 reloc section.  Note that the base file is not
                 portable between systems.  We write out a bfd_vma here,
                 portable between systems.  We write out a bfd_vma here,
                 and dlltool reads in a bfd_vma.  */
                 and dlltool reads in a bfd_vma.  */
              bfd_vma addr = (rel->r_vaddr
              bfd_vma addr = (rel->r_vaddr
                           - input_section->vma
                           - input_section->vma
                           + input_section->output_offset
                           + input_section->output_offset
                           + input_section->output_section->vma);
                           + input_section->output_section->vma);
              if (coff_data (output_bfd)->pe)
              if (coff_data (output_bfd)->pe)
                addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
                addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
              if (fwrite (&addr, 1, sizeof (bfd_vma), (FILE *) info->base_file)
              if (fwrite (&addr, 1, sizeof (bfd_vma), (FILE *) info->base_file)
                  != sizeof (bfd_vma))
                  != sizeof (bfd_vma))
                {
                {
                  bfd_set_error (bfd_error_system_call);
                  bfd_set_error (bfd_error_system_call);
                  return FALSE;
                  return FALSE;
                }
                }
            }
            }
        }
        }
 
 
      rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
      rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                        contents,
                                        contents,
                                        rel->r_vaddr - input_section->vma,
                                        rel->r_vaddr - input_section->vma,
                                        val, addend);
                                        val, addend);
 
 
      switch (rstat)
      switch (rstat)
        {
        {
        default:
        default:
          abort ();
          abort ();
        case bfd_reloc_ok:
        case bfd_reloc_ok:
          break;
          break;
        case bfd_reloc_outofrange:
        case bfd_reloc_outofrange:
          (*_bfd_error_handler)
          (*_bfd_error_handler)
            (_("%B: bad reloc address 0x%lx in section `%A'"),
            (_("%B: bad reloc address 0x%lx in section `%A'"),
             input_bfd, input_section, (unsigned long) rel->r_vaddr);
             input_bfd, input_section, (unsigned long) rel->r_vaddr);
          return FALSE;
          return FALSE;
        case bfd_reloc_overflow:
        case bfd_reloc_overflow:
          {
          {
            const char *name;
            const char *name;
            char buf[SYMNMLEN + 1];
            char buf[SYMNMLEN + 1];
 
 
            if (symndx == -1)
            if (symndx == -1)
              name = "*ABS*";
              name = "*ABS*";
            else if (h != NULL)
            else if (h != NULL)
              name = NULL;
              name = NULL;
            else
            else
              {
              {
                name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
                name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
                if (name == NULL)
                if (name == NULL)
                  return FALSE;
                  return FALSE;
              }
              }
 
 
            if (! ((*info->callbacks->reloc_overflow)
            if (! ((*info->callbacks->reloc_overflow)
                   (info, (h ? &h->root : NULL), name, howto->name,
                   (info, (h ? &h->root : NULL), name, howto->name,
                    (bfd_vma) 0, input_bfd, input_section,
                    (bfd_vma) 0, input_bfd, input_section,
                    rel->r_vaddr - input_section->vma)))
                    rel->r_vaddr - input_section->vma)))
              return FALSE;
              return FALSE;
          }
          }
        }
        }
    }
    }
  return TRUE;
  return TRUE;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.