Arm specific code changed to conform to BFD coding conventions.
[deliverable/binutils-gdb.git] / bfd / cofflink.c
index 1e3d33e1caa8fb6a220a8fbaaaa1841aa5a0f0b9..2f19641289a578381411d52a54f50d02b0a8c843 100644 (file)
@@ -1,5 +1,5 @@
 /* COFF specific linker code.
 /* COFF specific linker code.
-   Copyright 1994, 1995 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
    Written by Ian Lance Taylor, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -16,7 +16,7 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* This file contains the COFF backend linker code.  */
 
 
 /* This file contains the COFF backend linker code.  */
 
@@ -27,125 +27,23 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "coff/internal.h"
 #include "libcoff.h"
 
 #include "coff/internal.h"
 #include "libcoff.h"
 
-#define STRING_SIZE_SIZE (4)
-
-/* Information we keep for each section in the output file when doing
-   a relocateable link.  */
-
-struct coff_link_section_info
-{
-  /* The relocs to be output.  */
-  struct internal_reloc *relocs;
-  /* For each reloc against a global symbol whose index was not known
-     when the reloc was handled, the global hash table entry.  */
-  struct coff_link_hash_entry **rel_hashes;
-};
-
-/* Information that we pass around while doing the final link step.  */
-
-struct coff_final_link_info
-{
-  /* General link information.  */
-  struct bfd_link_info *info;
-  /* Output BFD.  */
-  bfd *output_bfd;
-  /* Used to indicate failure in traversal routine.  */
-  boolean failed;
-  /* Hash table for long symbol name.  */
-  struct bfd_strtab_hash *strtab;
-  /* When doing a relocateable link, an array of information kept for
-     each output section, indexed by the target_index field.  */
-  struct coff_link_section_info *section_info;
-  /* Symbol index of last C_FILE symbol (-1 if none).  */
-  long last_file_index;
-  /* Contents of last C_FILE symbol.  */
-  struct internal_syment last_file;
-  /* Buffer large enough to hold swapped symbols of any input file.  */
-  struct internal_syment *internal_syms;
-  /* Buffer large enough to hold sections of symbols of any input file.  */
-  asection **sec_ptrs;
-  /* Buffer large enough to hold output indices of symbols of any
-     input file.  */
-  long *sym_indices;
-  /* Buffer large enough to hold output symbols for any input file.  */
-  bfd_byte *outsyms;
-  /* Buffer large enough to hold external line numbers for any input
-     section.  */
-  bfd_byte *linenos;
-  /* Buffer large enough to hold any input section.  */
-  bfd_byte *contents;
-  /* Buffer large enough to hold external relocs of any input section.  */
-  bfd_byte *external_relocs;
-  /* Buffer large enough to hold swapped relocs of any input section.  */
-  struct internal_reloc *internal_relocs;
-
-enum   bfd_link_subsystem  subsystem;
-bfd_link_stack_heap stack_heap_parameters;
-};
-
-static struct bfd_hash_entry *coff_link_hash_newfunc
-  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
 static boolean coff_link_add_object_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean coff_link_check_archive_element
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static boolean coff_link_add_object_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean coff_link_check_archive_element
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
-static boolean coff_link_get_symbols PARAMS ((bfd *));
-static const char *coff_read_string_table PARAMS ((bfd *));
-static boolean coff_link_free_symbols PARAMS ((bfd *));
 static boolean coff_link_check_ar_symbols
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
 static boolean coff_link_check_ar_symbols
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
-static boolean coff_link_input_bfd
-  PARAMS ((struct coff_final_link_info *, bfd *));
-static boolean coff_write_global_sym
-  PARAMS ((struct coff_link_hash_entry *, PTR));
-static boolean coff_reloc_link_order
-  PARAMS ((bfd *, struct coff_final_link_info *, asection *,
-          struct bfd_link_order *));
-
-
-/* These new data and data types are used to keep track of the .idata$4 and
-   .idata$5 relocations which are put into the .idata section for all of the
-   *.dll input libraries linked in.  This is not a great solution, and may
-   break in the future if MS changes the format of its libraries, but it
-   does work for the collection of mstools libraries we are currently working
-   with.  The main problem is that there are some new majic symbols defined
-   in the libraries which are non-standard coff and simply aren't handled 
-   completely by ld.  What has been included here will help finish up the job.
-     Basically, during the link, .idata$4 and .idata$5 pointers are correctly
-   relocated to the image.  At the very end of the link, the .idata$2
-   information is written.  This data appears at the beginning of the .idata
-   section and a 'set' of information appears for each *.dll passed in.
-   Each set of information consists of 3 addresses, a pointer to the .idata$4
-   start, a pointer to .idata$6 (which has the name of the dll), and a pointer
-   to .idata$5 start.  The idata$4 and 5 information is a list of pointers
-   which appear to point to the name of various functions found within the dll.
-   When invoked, the loader will write over these names with the correct
-   addresses to use for these functions.  
-     Without this 'fix', all information appears correctly except for the
-   addresses of the .idata$4 and 5 starts within the .idata$2 portion of the
-   .idata section.  What we will do is to keep track of the dll's processed
-   and the number of functions needed from each dll.  From this information
-   we can correctly compute the start of the idata$4 and 5 lists for each
-   dll in the idata section */
-static int num_DLLs_done = 0;
-static int num_DLLs      = 0;
-static int all_entries   = 0;
-struct DLL_struct {
-  const char * DLL_name;
-  int          num_entries;
-};
-struct DLL_struct MS_DLL[10];
-static bfd_vma idata_4_prev = 0;
-static bfd_vma idata_5_prev = 0;
-static bfd_vma add_to_val   = 0;
-
-
+static char *dores_com PARAMS ((char *, bfd *, int));
+static char *get_name PARAMS ((char *, char **));
+static int process_embedded_commands
+  PARAMS ((bfd *, struct bfd_link_info *, bfd *));
+static void mark_relocs PARAMS ((struct coff_final_link_info *, bfd *));
 
 /* Create an entry in a COFF linker hash table.  */
 
 
 /* Create an entry in a COFF linker hash table.  */
 
-static struct bfd_hash_entry *
-coff_link_hash_newfunc (entry, table, string)
+struct bfd_hash_entry *
+_bfd_coff_link_hash_newfunc (entry, table, string)
      struct bfd_hash_entry *entry;
      struct bfd_hash_table *table;
      const char *string;
      struct bfd_hash_entry *entry;
      struct bfd_hash_table *table;
      const char *string;
@@ -158,10 +56,7 @@ coff_link_hash_newfunc (entry, table, string)
     ret = ((struct coff_link_hash_entry *)
           bfd_hash_allocate (table, sizeof (struct coff_link_hash_entry)));
   if (ret == (struct coff_link_hash_entry *) NULL)
     ret = ((struct coff_link_hash_entry *)
           bfd_hash_allocate (table, sizeof (struct coff_link_hash_entry)));
   if (ret == (struct coff_link_hash_entry *) NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return (struct bfd_hash_entry *) ret;
-    }
+    return (struct bfd_hash_entry *) ret;
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct coff_link_hash_entry *)
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct coff_link_hash_entry *)
@@ -181,6 +76,20 @@ coff_link_hash_newfunc (entry, table, string)
   return (struct bfd_hash_entry *) ret;
 }
 
   return (struct bfd_hash_entry *) ret;
 }
 
+/* Initialize a COFF linker hash table.  */
+
+boolean
+_bfd_coff_link_hash_table_init (table, abfd, newfunc)
+     struct coff_link_hash_table *table;
+     bfd *abfd;
+     struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+                                               struct bfd_hash_table *,
+                                               const char *));
+{
+  table->stab_info = NULL;
+  return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
+}
+
 /* Create a COFF linker hash table.  */
 
 struct bfd_link_hash_table *
 /* Create a COFF linker hash table.  */
 
 struct bfd_link_hash_table *
@@ -190,21 +99,50 @@ _bfd_coff_link_hash_table_create (abfd)
   struct coff_link_hash_table *ret;
 
   ret = ((struct coff_link_hash_table *)
   struct coff_link_hash_table *ret;
 
   ret = ((struct coff_link_hash_table *)
-        malloc (sizeof (struct coff_link_hash_table)));
+        bfd_alloc (abfd, sizeof (struct coff_link_hash_table)));
   if (ret == NULL)
   if (ret == NULL)
+    return NULL;
+  if (! _bfd_coff_link_hash_table_init (ret, abfd,
+                                       _bfd_coff_link_hash_newfunc))
     {
     {
-      bfd_set_error (bfd_error_no_memory);
-      return NULL;
-    }
-  if (! _bfd_link_hash_table_init (&ret->root, abfd,
-                                  coff_link_hash_newfunc))
-    {
-      free (ret);
+      bfd_release (abfd, ret);
       return (struct bfd_link_hash_table *) NULL;
     }
   return &ret->root;
 }
 
       return (struct bfd_link_hash_table *) NULL;
     }
   return &ret->root;
 }
 
+/* Create an entry in a COFF debug merge hash table.  */
+
+struct bfd_hash_entry *
+_bfd_coff_debug_merge_hash_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  struct coff_debug_merge_hash_entry *ret =
+    (struct coff_debug_merge_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == (struct coff_debug_merge_hash_entry *) NULL)
+    ret = ((struct coff_debug_merge_hash_entry *)
+          bfd_hash_allocate (table,
+                             sizeof (struct coff_debug_merge_hash_entry)));
+  if (ret == (struct coff_debug_merge_hash_entry *) NULL)
+    return (struct bfd_hash_entry *) ret;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct coff_debug_merge_hash_entry *)
+        bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+  if (ret != (struct coff_debug_merge_hash_entry *) NULL)
+    {
+      /* Set local fields.  */
+      ret->types = NULL;
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
+
 /* Given a COFF BFD, add symbols to the global hash table as
    appropriate.  */
 
 /* Given a COFF BFD, add symbols to the global hash table as
    appropriate.  */
 
@@ -233,13 +171,14 @@ coff_link_add_object_symbols (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
      bfd *abfd;
      struct bfd_link_info *info;
 {
-  if (! coff_link_get_symbols (abfd))
+  if (! _bfd_coff_get_external_symbols (abfd))
     return false;
   if (! coff_link_add_symbols (abfd, info))
     return false;
     return false;
   if (! coff_link_add_symbols (abfd, info))
     return false;
+
   if (! info->keep_memory)
     {
   if (! info->keep_memory)
     {
-      if (! coff_link_free_symbols (abfd))
+      if (! _bfd_coff_free_symbols (abfd))
        return false;
     }
   return true;
        return false;
     }
   return true;
@@ -256,7 +195,7 @@ coff_link_check_archive_element (abfd, info, pneeded)
      struct bfd_link_info *info;
      boolean *pneeded;
 {
      struct bfd_link_info *info;
      boolean *pneeded;
 {
-  if (! coff_link_get_symbols (abfd))
+  if (! _bfd_coff_get_external_symbols (abfd))
     return false;
 
   if (! coff_link_check_ar_symbols (abfd, info, pneeded))
     return false;
 
   if (! coff_link_check_ar_symbols (abfd, info, pneeded))
@@ -270,127 +209,13 @@ coff_link_check_archive_element (abfd, info, pneeded)
 
   if (! info->keep_memory || ! *pneeded)
     {
 
   if (! info->keep_memory || ! *pneeded)
     {
-      if (! coff_link_free_symbols (abfd))
+      if (! _bfd_coff_free_symbols (abfd))
        return false;
     }
 
   return true;
 }
 
        return false;
     }
 
   return true;
 }
 
-/* Read in the external symbols.  */
-
-static boolean
-coff_link_get_symbols (abfd)
-     bfd *abfd;
-{
-  bfd_size_type symesz;
-  size_t size;
-  PTR syms;
-
-  if (obj_coff_external_syms (abfd) != NULL)
-    return true;
-
-  symesz = bfd_coff_symesz (abfd);
-
-  size = obj_raw_syment_count (abfd) * symesz;
-
-  syms = malloc (size);
-  if (syms == NULL && size != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
-
-  if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
-      || bfd_read (syms, size, 1, abfd) != size)
-    {
-      if (syms != NULL)
-       free (syms);
-      return false;
-    }
-
-  obj_coff_external_syms (abfd) = syms;
-
-  return true;
-}
-
-/* Read in the external strings.  The strings are not loaded until
-   they are needed.  This is because we have no simple way of
-   detecting a missing string table in an archive.  */
-
-static const char *
-coff_read_string_table (abfd)
-     bfd *abfd;
-{
-  char extstrsize[STRING_SIZE_SIZE];
-  size_t strsize;
-  char *strings;
-
-  if (obj_coff_strings (abfd) != NULL)
-    return obj_coff_strings (abfd);
-
-  if (bfd_seek (abfd,
-               (obj_sym_filepos (abfd)
-                + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd)),
-               SEEK_SET) != 0)
-    return NULL;
-    
-  if (bfd_read (extstrsize, sizeof extstrsize, 1, abfd) != sizeof extstrsize)
-    {
-      if (bfd_get_error () != bfd_error_file_truncated)
-       return NULL;
-
-      /* There is no string table.  */
-      strsize = STRING_SIZE_SIZE;
-    }
-  else
-    {
-#if STRING_SIZE_SIZE == 4
-      strsize = bfd_h_get_32 (abfd, (bfd_byte *) extstrsize);
-#else
- #error Change bfd_h_get_32
-#endif
-    }
-
-  strings = malloc (strsize);
-  if (strings == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return NULL;
-    }
-
-  if (bfd_read (strings + STRING_SIZE_SIZE,
-               strsize - STRING_SIZE_SIZE, 1, abfd)
-      != strsize - STRING_SIZE_SIZE)
-    {
-      free (strings);
-      return NULL;
-    }
-
-  obj_coff_strings (abfd) = strings;
-
-  return strings;
-}
-
-/* Free up the external symbols and strings read from a COFF file.  */
-
-static boolean
-coff_link_free_symbols (abfd)
-     bfd *abfd;
-{
-  if (obj_coff_external_syms (abfd) != NULL)
-    {
-      free (obj_coff_external_syms (abfd));
-      obj_coff_external_syms (abfd) = NULL;
-    }
-  if (obj_coff_strings (abfd) != NULL)
-    {
-      free (obj_coff_strings (abfd));
-      obj_coff_strings (abfd) = NULL;
-    }
-  return true;
-}
-
 /* Look through the symbols to see if this object file should be
    included in the link.  */
 
 /* Look through the symbols to see if this object file should be
    included in the link.  */
 
@@ -401,7 +226,6 @@ coff_link_check_ar_symbols (abfd, info, pneeded)
      boolean *pneeded;
 {
   boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
      boolean *pneeded;
 {
   boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
-  const char *strings;
   bfd_size_type symesz;
   bfd_byte *esym;
   bfd_byte *esym_end;
   bfd_size_type symesz;
   bfd_byte *esym;
   bfd_byte *esym_end;
@@ -409,7 +233,6 @@ coff_link_check_ar_symbols (abfd, info, pneeded)
   *pneeded = false;
 
   sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
   *pneeded = false;
 
   sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
-  strings = NULL;
 
   symesz = bfd_coff_symesz (abfd);
   esym = (bfd_byte *) obj_coff_external_syms (abfd);
 
   symesz = bfd_coff_symesz (abfd);
   esym = (bfd_byte *) obj_coff_external_syms (abfd);
@@ -421,6 +244,9 @@ coff_link_check_ar_symbols (abfd, info, pneeded)
       bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
 
       if ((sym.n_sclass == C_EXT
       bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
 
       if ((sym.n_sclass == C_EXT
+#ifdef C_SYSTEM
+          || sym.n_sclass == C_SYSTEM
+#endif
           || (sym_is_global && (*sym_is_global) (abfd, &sym)))
          && (sym.n_scnum != 0 || sym.n_value != 0))
        {
           || (sym_is_global && (*sym_is_global) (abfd, &sym)))
          && (sym.n_scnum != 0 || sym.n_value != 0))
        {
@@ -431,27 +257,9 @@ coff_link_check_ar_symbols (abfd, info, pneeded)
          /* This symbol is externally visible, and is defined by this
              object file.  */
 
          /* This symbol is externally visible, and is defined by this
              object file.  */
 
-         /* FIXME: It's not clear this will work correctly if sizeof
-             (_n_zeroes) != 4.  */
-         if (sym._n._n_n._n_zeroes != 0
-             || sym._n._n_n._n_offset == 0)
-           {
-             memcpy (buf, sym._n._n_name, SYMNMLEN);
-             buf[SYMNMLEN] = '\0';
-             name = buf;
-           }
-         else
-           {
-             BFD_ASSERT (sym._n._n_n._n_offset >= STRING_SIZE_SIZE);
-             if (strings == NULL)
-               {
-                 strings = coff_read_string_table (abfd);
-                 if (strings == NULL)
-                   return false;
-               }
-             name = strings + sym._n._n_n._n_offset;
-           }
-
+         name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
+         if (name == NULL)
+           return false;
          h = bfd_link_hash_lookup (info->hash, name, false, false, true);
 
          /* We are only interested in symbols that are currently
          h = bfd_link_hash_lookup (info->hash, name, false, false, true);
 
          /* We are only interested in symbols that are currently
@@ -483,7 +291,7 @@ coff_link_add_symbols (abfd, info)
      struct bfd_link_info *info;
 {
   boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
      struct bfd_link_info *info;
 {
   boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
-  const char *strings;
+  boolean keep_syms;
   boolean default_copy;
   bfd_size_type symcount;
   struct coff_link_hash_entry **sym_hash;
   boolean default_copy;
   bfd_size_type symcount;
   struct coff_link_hash_entry **sym_hash;
@@ -491,8 +299,12 @@ coff_link_add_symbols (abfd, info)
   bfd_byte *esym;
   bfd_byte *esym_end;
 
   bfd_byte *esym;
   bfd_byte *esym_end;
 
+  /* Keep the symbols during this function, in case the linker needs
+     to read the generic symbols in order to report an error message.  */
+  keep_syms = obj_coff_keep_syms (abfd);
+  obj_coff_keep_syms (abfd) = true;
+
   sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
   sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
-  strings = NULL;
 
   if (info->keep_memory)
     default_copy = false;
 
   if (info->keep_memory)
     default_copy = false;
@@ -508,10 +320,7 @@ coff_link_add_symbols (abfd, info)
                         ((size_t) symcount
                          * sizeof (struct coff_link_hash_entry *))));
   if (sym_hash == NULL && symcount != 0)
                         ((size_t) symcount
                          * sizeof (struct coff_link_hash_entry *))));
   if (sym_hash == NULL && symcount != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    goto error_return;
   obj_coff_sym_hashes (abfd) = sym_hash;
   memset (sym_hash, 0,
          (size_t) symcount * sizeof (struct coff_link_hash_entry *));
   obj_coff_sym_hashes (abfd) = sym_hash;
   memset (sym_hash, 0,
          (size_t) symcount * sizeof (struct coff_link_hash_entry *));
@@ -528,6 +337,9 @@ coff_link_add_symbols (abfd, info)
       bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
 
       if (sym.n_sclass == C_EXT
       bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
 
       if (sym.n_sclass == C_EXT
+#ifdef C_SYSTEM
+         || sym.n_sclass == C_SYSTEM
+#endif
          || (sym_is_global && (*sym_is_global) (abfd, &sym)))
        {
          const char *name;
          || (sym_is_global && (*sym_is_global) (abfd, &sym)))
        {
          const char *name;
@@ -538,28 +350,16 @@ coff_link_add_symbols (abfd, info)
 
          /* This symbol is externally visible.  */
 
 
          /* This symbol is externally visible.  */
 
-         /* FIXME: It's not clear this will work correctly if sizeof
-             (_n_zeroes) != 4.  */
+         name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
+         if (name == NULL)
+           goto error_return;
+
+         /* We must copy the name into memory if we got it from the
+             syment itself, rather than the string table.  */
          copy = default_copy;
          copy = default_copy;
-         if (sym._n._n_n._n_zeroes == 0
-             && sym._n._n_n._n_offset != 0)
-           {
-             BFD_ASSERT (sym._n._n_n._n_offset >= STRING_SIZE_SIZE);
-             if (strings == NULL)
-               {
-                 strings = coff_read_string_table (abfd);
-                 if (strings == NULL)
-                   return false;
-               }
-             name = strings + sym._n._n_n._n_offset;
-           }
-         else
-           {
-             memcpy (buf, sym._n._n_name, SYMNMLEN);
-             buf[SYMNMLEN] = '\0';
-             name = buf;
-             copy = true;
-           }
+         if (sym._n._n_n._n_zeroes != 0
+             || sym._n._n_n._n_offset == 0)
+           copy = true;
 
          value = sym.n_value;
 
 
          value = sym.n_value;
 
@@ -580,14 +380,22 @@ coff_link_add_symbols (abfd, info)
            {
              flags = BSF_EXPORT | BSF_GLOBAL;
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
            {
              flags = BSF_EXPORT | BSF_GLOBAL;
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
-             value -= section->vma;
+             if (! obj_pe (abfd))
+               value -= section->vma;
            }
 
            }
 
-         if (! (_bfd_generic_link_add_one_symbol
+         if (! (bfd_coff_link_add_one_symbol
                 (info, abfd, name, flags, section, value,
                  (const char *) NULL, copy, false,
                  (struct bfd_link_hash_entry **) sym_hash)))
                 (info, abfd, name, flags, section, value,
                  (const char *) NULL, copy, false,
                  (struct bfd_link_hash_entry **) sym_hash)))
-           return false;
+           goto error_return;
+
+         if (section == bfd_com_section_ptr
+             && (*sym_hash)->root.type == bfd_link_hash_common
+             && ((*sym_hash)->root.u.c.p->alignment_power
+                 > bfd_coff_default_section_alignment_power (abfd)))
+           (*sym_hash)->root.u.c.p->alignment_power
+             = bfd_coff_default_section_alignment_power (abfd);
 
          if (info->hash->creator->flavour == bfd_get_flavour (abfd))
            {
 
          if (info->hash->creator->flavour == bfd_get_flavour (abfd))
            {
@@ -598,8 +406,16 @@ coff_link_add_symbols (abfd, info)
                      && (*sym_hash)->root.type != bfd_link_hash_defined))
                {
                  (*sym_hash)->class = sym.n_sclass;
                      && (*sym_hash)->root.type != bfd_link_hash_defined))
                {
                  (*sym_hash)->class = sym.n_sclass;
-                 (*sym_hash)->type = sym.n_type;
-                 (*sym_hash)->numaux = sym.n_numaux;
+                 if (sym.n_type != T_NULL)
+                   {
+                     if ((*sym_hash)->type != T_NULL
+                         && (*sym_hash)->type != sym.n_type)
+                       (*_bfd_error_handler)
+                         ("Warning: type of symbol `%s' changed from %d to %d in %s",
+                          name, (*sym_hash)->type, sym.n_type,
+                          bfd_get_filename (abfd));
+                     (*sym_hash)->type = sym.n_type;
+                   }
                  (*sym_hash)->auxbfd = abfd;
                  if (sym.n_numaux != 0)
                    {
                  (*sym_hash)->auxbfd = abfd;
                  if (sym.n_numaux != 0)
                    {
@@ -608,15 +424,13 @@ coff_link_add_symbols (abfd, info)
                      bfd_byte *eaux;
                      union internal_auxent *iaux;
 
                      bfd_byte *eaux;
                      union internal_auxent *iaux;
 
+                     (*sym_hash)->numaux = sym.n_numaux;
                      alloc = ((union internal_auxent *)
                               bfd_hash_allocate (&info->hash->table,
                                                  (sym.n_numaux
                                                   * sizeof (*alloc))));
                      if (alloc == NULL)
                      alloc = ((union internal_auxent *)
                               bfd_hash_allocate (&info->hash->table,
                                                  (sym.n_numaux
                                                   * sizeof (*alloc))));
                      if (alloc == NULL)
-                       {
-                         bfd_set_error (bfd_error_no_memory);
-                         return false;
-                       }
+                       goto error_return;
                      for (i = 0, eaux = esym + symesz, iaux = alloc;
                           i < sym.n_numaux;
                           i++, eaux += symesz, iaux++)
                      for (i = 0, eaux = esym + symesz, iaux = alloc;
                           i < sym.n_numaux;
                           i++, eaux += symesz, iaux++)
@@ -633,129 +447,55 @@ coff_link_add_symbols (abfd, info)
       sym_hash += sym.n_numaux + 1;
     }
 
       sym_hash += sym.n_numaux + 1;
     }
 
-  return true;
-}
+  /* If this is a non-traditional, non-relocateable link, try to
+     optimize the handling of any .stab/.stabstr sections.  */
+  if (! info->relocateable
+      && ! info->traditional_format
+      && info->hash->creator->flavour == bfd_get_flavour (abfd)
+      && (info->strip != strip_all && info->strip != strip_debugger))
+    {
+      asection *stab, *stabstr;
 
 
-/* parse out a -heap <reserved>,<commit> line */
+      stab = bfd_get_section_by_name (abfd, ".stab");
+      if (stab != NULL)
+       {
+         stabstr = bfd_get_section_by_name (abfd, ".stabstr");
 
 
-static char *
-dores_com (ptr, def,res, com)
-     char *ptr;
-     int *def;
-     int *res;
-     int *com;
-{
-  *def = 1;
-  *res = strtoul (ptr, &ptr, 0);
-  if (ptr[0] == ',')
-    *com = strtoul (ptr+1, &ptr, 0);
-  return ptr;
-}
+         if (stabstr != NULL)
+           {
+             struct coff_link_hash_table *table;
+             struct coff_section_tdata *secdata;
 
 
-static char *get_name(ptr, dst)
-char *ptr;
-char **dst;
-{
-  while (*ptr == ' ')
-    ptr++;
-  *dst = ptr;
-  while (*ptr && *ptr != ' ')
-    ptr++;
-  *ptr = 0;
-  return ptr+1;
-}
-/* Process any magic embedded commands in a section called .drectve */
-                       
-static int
-process_embedded_commands (abfd)
-     bfd *abfd;
-{
-  asection *sec = bfd_get_section_by_name (abfd, ".drectve");
-  char *s;
-  char *e;
-  char *copy;
-  if (!sec) 
-    return 1;
-  
-  copy = malloc (sec->_raw_size);
-  if (!copy) 
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return 0;
-    }
-  if (! bfd_get_section_contents(abfd, sec, copy, 0, sec->_raw_size)) 
-    {
-      free (copy);
-      return 0;
-    }
-  e = copy + sec->_raw_size;
-  for (s = copy;  s < e ; ) 
-    {
-      if (s[0]!= '-') {
-       s++;
-       continue;
-      }
-      if (strncmp (s,"-attr", 5) == 0)
-       {
-         char *name;
-         char *attribs;
-         asection *asec;
+             secdata = coff_section_data (abfd, stab);
+             if (secdata == NULL)
+               {
+                 stab->used_by_bfd =
+                   (PTR) bfd_zalloc (abfd,
+                                     sizeof (struct coff_section_tdata));
+                 if (stab->used_by_bfd == NULL)
+                   goto error_return;
+                 secdata = coff_section_data (abfd, stab);
+               }
 
 
-         int loop = 1;
-         int had_write = 0;
-         int had_read = 0;
-         int had_exec= 0;
-         int had_shared= 0;
-         s += 5;
-         s = get_name(s, &name);
-         s = get_name(s, &attribs);
-         while (loop) {
-           switch (*attribs++) 
-             {
-             case 'W':
-               had_write = 1;
-               break;
-             case 'R':
-               had_read = 1;
-               break;
-             case 'S':
-               had_shared = 1;
-               break;
-             case 'X':
-               had_exec = 1;
-               break;
-             default:
-               loop = 0;
-             }
-         }
-         asec = bfd_get_section_by_name (abfd, name);
-         if (asec) {
-           if (had_exec)
-             asec->flags |= SEC_CODE;
-           if (!had_write)
-             asec->flags |= SEC_READONLY;
-         }
-       }
-      else if (strncmp (s,"-heap", 5) == 0)
-       {
-         s = dores_com (s+5, 
-                        &NT_stack_heap.heap_defined,
-                        &NT_stack_heap.heap_reserve,
-                        &NT_stack_heap.heap_commit);
-       }
-      else if (strncmp (s,"-stack", 6) == 0)
-       {
-         s = dores_com (s+6,
-                        &NT_stack_heap.heap_defined,
-                        &NT_stack_heap.heap_reserve,
-                        &NT_stack_heap.heap_commit);
+             table = coff_hash_table (info);
+
+             if (! _bfd_link_section_stabs (abfd, &table->stab_info,
+                                            stab, stabstr,
+                                            &secdata->stab_info))
+               goto error_return;
+           }
        }
        }
-      else 
-       s++;
     }
     }
-  free (copy);
-  return 1;
+
+  obj_coff_keep_syms (abfd) = keep_syms;
+
+  return true;
+
+ error_return:
+  obj_coff_keep_syms (abfd) = keep_syms;
+  return false;
 }
 }
+\f
 /* Do the final link step.  */
 
 boolean
 /* Do the final link step.  */
 
 boolean
@@ -765,13 +505,15 @@ _bfd_coff_final_link (abfd, info)
 {
   bfd_size_type symesz;
   struct coff_final_link_info finfo;
 {
   bfd_size_type symesz;
   struct coff_final_link_info finfo;
+  boolean debug_merge_allocated;
+  boolean long_section_names;
   asection *o;
   struct bfd_link_order *p;
   asection *o;
   struct bfd_link_order *p;
-  size_t max_contents_size;
   size_t max_sym_count;
   size_t max_lineno_count;
   size_t max_reloc_count;
   size_t max_output_reloc_count;
   size_t max_sym_count;
   size_t max_lineno_count;
   size_t max_reloc_count;
   size_t max_output_reloc_count;
+  size_t max_contents_size;
   file_ptr rel_filepos;
   unsigned int relsz;
   file_ptr line_filepos;
   file_ptr rel_filepos;
   unsigned int relsz;
   file_ptr line_filepos;
@@ -787,6 +529,7 @@ _bfd_coff_final_link (abfd, info)
   finfo.strtab = NULL;
   finfo.section_info = NULL;
   finfo.last_file_index = -1;
   finfo.strtab = NULL;
   finfo.section_info = NULL;
   finfo.last_file_index = -1;
+  finfo.last_bf_index = -1;
   finfo.internal_syms = NULL;
   finfo.sec_ptrs = NULL;
   finfo.sym_indices = NULL;
   finfo.internal_syms = NULL;
   finfo.sec_ptrs = NULL;
   finfo.sym_indices = NULL;
@@ -795,23 +538,25 @@ _bfd_coff_final_link (abfd, info)
   finfo.contents = NULL;
   finfo.external_relocs = NULL;
   finfo.internal_relocs = NULL;
   finfo.contents = NULL;
   finfo.external_relocs = NULL;
   finfo.internal_relocs = NULL;
+  finfo.global_to_static = false;
+  debug_merge_allocated = false;
 
 
-  if (obj_pe(abfd))
-    {
-      /* store the subsystem, stack and heap parameters in variables defined
-        in internal.h so that when they are needed to write the NT optional
-        file header (coffcode.h), they will be available */
-      NT_subsystem  = info->subsystem;
-      NT_stack_heap = info->stack_heap_parameters;
-    }
+  coff_data (abfd)->link_info = info;
 
   finfo.strtab = _bfd_stringtab_init ();
   if (finfo.strtab == NULL)
     goto error_return;
 
 
   finfo.strtab = _bfd_stringtab_init ();
   if (finfo.strtab == NULL)
     goto error_return;
 
+  if (! coff_debug_merge_hash_table_init (&finfo.debug_merge))
+    goto error_return;
+  debug_merge_allocated = true;
+
   /* Compute the file positions for all the sections.  */
   if (! abfd->output_has_begun)
   /* Compute the file positions for all the sections.  */
   if (! abfd->output_has_begun)
-    bfd_coff_compute_section_file_positions (abfd);
+    {
+      if (! bfd_coff_compute_section_file_positions (abfd))
+       goto error_return;
+    }
 
   /* Count the line numbers and relocation entries required for the
      output file.  Set the file positions for the relocs.  */
 
   /* Count the line numbers and relocation entries required for the
      output file.  Set the file positions for the relocs.  */
@@ -820,6 +565,8 @@ _bfd_coff_final_link (abfd, info)
   max_contents_size = 0;
   max_lineno_count = 0;
   max_reloc_count = 0;
   max_contents_size = 0;
   max_lineno_count = 0;
   max_reloc_count = 0;
+
+  long_section_names = false;
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       o->reloc_count = 0;
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       o->reloc_count = 0;
@@ -832,6 +579,12 @@ _bfd_coff_final_link (abfd, info)
 
              sec = p->u.indirect.section;
 
 
              sec = p->u.indirect.section;
 
+             /* Mark all sections which are to be included in the
+                link.  This will normally be every section.  We need
+                to do this so that we can identify any sections which
+                the linker has decided to not include.  */
+             sec->linker_mark = true;
+
              if (info->strip == strip_none
                  || info->strip == strip_some)
                o->lineno_count += sec->lineno_count;
              if (info->strip == strip_none
                  || info->strip == strip_some)
                o->lineno_count += sec->lineno_count;
@@ -859,6 +612,20 @@ _bfd_coff_final_link (abfd, info)
          o->rel_filepos = rel_filepos;
          rel_filepos += o->reloc_count * relsz;
        }
          o->rel_filepos = rel_filepos;
          rel_filepos += o->reloc_count * relsz;
        }
+
+      if (bfd_coff_long_section_names (abfd)
+         && strlen (o->name) > SCNNMLEN)
+       {
+         /* This section has a long name which must go in the string
+             table.  This must correspond to the code in
+             coff_write_object_contents which puts the string index
+             into the s_name field of the section header.  That is why
+             we pass hash as false.  */
+         if (_bfd_stringtab_add (finfo.strtab, o->name, false, false)
+             == (bfd_size_type) -1)
+           goto error_return;
+         long_section_names = true;
+       }
     }
 
   /* If doing a relocateable link, allocate space for the pointers we
     }
 
   /* If doing a relocateable link, allocate space for the pointers we
@@ -869,14 +636,12 @@ _bfd_coff_final_link (abfd, info)
 
       /* We use section_count + 1, rather than section_count, because
          the target_index fields are 1 based.  */
 
       /* We use section_count + 1, rather than section_count, because
          the target_index fields are 1 based.  */
-      finfo.section_info = ((struct coff_link_section_info *)
-                           malloc ((abfd->section_count + 1)
-                                   * sizeof (struct coff_link_section_info)));
+      finfo.section_info =
+       ((struct coff_link_section_info *)
+        bfd_malloc ((abfd->section_count + 1)
+                    * sizeof (struct coff_link_section_info)));
       if (finfo.section_info == NULL)
       if (finfo.section_info == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         goto error_return;
-       }
+       goto error_return;
       for (i = 0; i <= abfd->section_count; i++)
        {
          finfo.section_info[i].relocs = NULL;
       for (i = 0; i <= abfd->section_count; i++)
        {
          finfo.section_info[i].relocs = NULL;
@@ -917,17 +682,14 @@ _bfd_coff_final_link (abfd, info)
          BFD_ASSERT (info->relocateable);
          finfo.section_info[o->target_index].relocs =
            ((struct internal_reloc *)
          BFD_ASSERT (info->relocateable);
          finfo.section_info[o->target_index].relocs =
            ((struct internal_reloc *)
-            malloc (o->reloc_count * sizeof (struct internal_reloc)));
+            bfd_malloc (o->reloc_count * sizeof (struct internal_reloc)));
          finfo.section_info[o->target_index].rel_hashes =
            ((struct coff_link_hash_entry **)
          finfo.section_info[o->target_index].rel_hashes =
            ((struct coff_link_hash_entry **)
-            malloc (o->reloc_count
+            bfd_malloc (o->reloc_count
                     * sizeof (struct coff_link_hash_entry *)));
          if (finfo.section_info[o->target_index].relocs == NULL
              || finfo.section_info[o->target_index].rel_hashes == NULL)
                     * sizeof (struct coff_link_hash_entry *)));
          if (finfo.section_info[o->target_index].relocs == NULL
              || finfo.section_info[o->target_index].rel_hashes == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             goto error_return;
-           }
+           goto error_return;
 
          if (o->reloc_count > max_output_reloc_count)
            max_output_reloc_count = o->reloc_count;
 
          if (o->reloc_count > max_output_reloc_count)
            max_output_reloc_count = o->reloc_count;
@@ -957,19 +719,21 @@ _bfd_coff_final_link (abfd, info)
 
   /* Allocate some buffers used while linking.  */
   finfo.internal_syms = ((struct internal_syment *)
 
   /* Allocate some buffers used while linking.  */
   finfo.internal_syms = ((struct internal_syment *)
-                        malloc (max_sym_count
-                                * sizeof (struct internal_syment)));
-  finfo.sec_ptrs = (asection **) malloc (max_sym_count * sizeof (asection *));
-  finfo.sym_indices = (long *) malloc (max_sym_count * sizeof (long));
-  finfo.outsyms = (bfd_byte *) malloc ((max_sym_count + 1) * symesz);
-  finfo.linenos = (bfd_byte *) malloc (max_lineno_count
+                        bfd_malloc (max_sym_count
+                                    * sizeof (struct internal_syment)));
+  finfo.sec_ptrs = (asection **) bfd_malloc (max_sym_count
+                                            * sizeof (asection *));
+  finfo.sym_indices = (long *) bfd_malloc (max_sym_count * sizeof (long));
+  finfo.outsyms = ((bfd_byte *)
+                  bfd_malloc ((size_t) ((max_sym_count + 1) * symesz)));
+  finfo.linenos = (bfd_byte *) bfd_malloc (max_lineno_count
                                       * bfd_coff_linesz (abfd));
                                       * bfd_coff_linesz (abfd));
-  finfo.contents = (bfd_byte *) malloc (max_contents_size);
-  finfo.external_relocs = (bfd_byte *) malloc (max_reloc_count * relsz);
+  finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+  finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz);
   if (! info->relocateable)
     finfo.internal_relocs = ((struct internal_reloc *)
   if (! info->relocateable)
     finfo.internal_relocs = ((struct internal_reloc *)
-                            malloc (max_reloc_count
-                                    * sizeof (struct internal_reloc)));
+                            bfd_malloc (max_reloc_count
+                                        * sizeof (struct internal_reloc)));
   if ((finfo.internal_syms == NULL && max_sym_count > 0)
       || (finfo.sec_ptrs == NULL && max_sym_count > 0)
       || (finfo.sym_indices == NULL && max_sym_count > 0)
   if ((finfo.internal_syms == NULL && max_sym_count > 0)
       || (finfo.sec_ptrs == NULL && max_sym_count > 0)
       || (finfo.sym_indices == NULL && max_sym_count > 0)
@@ -980,10 +744,7 @@ _bfd_coff_final_link (abfd, info)
       || (! info->relocateable
          && finfo.internal_relocs == NULL
          && max_reloc_count > 0))
       || (! info->relocateable
          && finfo.internal_relocs == NULL
          && max_reloc_count > 0))
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   /* 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 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
@@ -991,6 +752,13 @@ _bfd_coff_final_link (abfd, info)
      table in memory as we go along.  We process all the relocations
      for a single input file at once.  */
   obj_raw_syment_count (abfd) = 0;
      table in memory as we go along.  We process all the relocations
      for a single input file at once.  */
   obj_raw_syment_count (abfd) = 0;
+
+  if (coff_backend_info (abfd)->_bfd_coff_start_final_link)
+    {
+      if (! bfd_coff_start_final_link (abfd, info))
+       goto error_return;
+    }
+
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       for (p = o->link_order_head; p != NULL; p = p->next)
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       for (p = o->link_order_head; p != NULL; p = p->next)
@@ -1000,9 +768,9 @@ _bfd_coff_final_link (abfd, info)
                  == bfd_target_coff_flavour))
            {
              sub = p->u.indirect.section->owner;
                  == bfd_target_coff_flavour))
            {
              sub = p->u.indirect.section->owner;
-             if (! sub->output_has_begun)
+             if (! bfd_coff_link_output_has_begun (sub, & finfo))
                {
                {
-                 if (! coff_link_input_bfd (&finfo, sub))
+                 if (! _bfd_coff_link_input_bfd (&finfo, sub))
                    goto error_return;
                  sub->output_has_begun = true;
                }
                    goto error_return;
                  sub->output_has_begun = true;
                }
@@ -1010,7 +778,7 @@ _bfd_coff_final_link (abfd, info)
          else if (p->type == bfd_section_reloc_link_order
                   || p->type == bfd_symbol_reloc_link_order)
            {
          else if (p->type == bfd_section_reloc_link_order
                   || p->type == bfd_symbol_reloc_link_order)
            {
-             if (! coff_reloc_link_order (abfd, &finfo, o, p))
+             if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p))
                goto error_return;
            }
          else
                goto error_return;
            }
          else
@@ -1021,7 +789,14 @@ _bfd_coff_final_link (abfd, info)
        }
     }
 
        }
     }
 
-  /* Free up the buffers used by coff_link_input_bfd.  */
+  if (! bfd_coff_final_link_postscript (abfd, & finfo))
+    goto error_return;
+  
+  /* Free up the buffers used by _bfd_coff_link_input_bfd.  */
+
+  coff_debug_merge_hash_table_free (&finfo.debug_merge);
+  debug_merge_allocated = false;
+
   if (finfo.internal_syms != NULL)
     {
       free (finfo.internal_syms);
   if (finfo.internal_syms != NULL)
     {
       free (finfo.internal_syms);
@@ -1062,7 +837,7 @@ _bfd_coff_final_link (abfd, info)
      index of the first external symbol.  Write it out again if
      necessary.  */
   if (finfo.last_file_index != -1
      index of the first external symbol.  Write it out again if
      necessary.  */
   if (finfo.last_file_index != -1
-      && finfo.last_file.n_value != obj_raw_syment_count (abfd))
+      && (unsigned int) 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, (PTR) &finfo.last_file,
     {
       finfo.last_file.n_value = obj_raw_syment_count (abfd);
       bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file,
@@ -1075,31 +850,41 @@ _bfd_coff_final_link (abfd, info)
        return false;
     }
 
        return false;
     }
 
+  /* If doing task linking (ld --task-link) then make a pass through the
+     global symbols, writing out any that are defined, and making them
+     static. */
+  if (info->task_link)
+    {
+      finfo.failed = false;
+      coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_task_globals,
+                              (PTR) &finfo);
+      if (finfo.failed)
+       goto error_return;
+    }
+
   /* Write out the global symbols.  */
   finfo.failed = false;
   /* Write out the global symbols.  */
   finfo.failed = false;
-  coff_link_hash_traverse (coff_hash_table (info), coff_write_global_sym,
+  coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_global_sym,
                           (PTR) &finfo);
   if (finfo.failed)
     goto error_return;
 
                           (PTR) &finfo);
   if (finfo.failed)
     goto error_return;
 
-  /* The outsyms buffer is used by coff_write_global_sym.  */
+  /* The outsyms buffer is used by _bfd_coff_write_global_sym.  */
   if (finfo.outsyms != NULL)
     {
       free (finfo.outsyms);
       finfo.outsyms = NULL;
     }
 
   if (finfo.outsyms != NULL)
     {
       free (finfo.outsyms);
       finfo.outsyms = NULL;
     }
 
-  if (info->relocateable)
+  if (info->relocateable && max_output_reloc_count > 0)
     {
       /* Now that we have written out all the global symbols, we know
         the symbol indices to use for relocs against them, and we can
         finally write out the relocs.  */
     {
       /* Now that we have written out all the global symbols, we know
         the symbol indices to use for relocs against them, and we can
         finally write out the relocs.  */
-      external_relocs = (bfd_byte *) malloc (max_output_reloc_count * relsz);
+      external_relocs = ((bfd_byte *)
+                        bfd_malloc (max_output_reloc_count * relsz));
       if (external_relocs == NULL)
       if (external_relocs == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         goto error_return;
-       }
+       goto error_return;
 
       for (o = abfd->sections; o != NULL; o = o->next)
        {
 
       for (o = abfd->sections; o != NULL; o = o->next)
        {
@@ -1142,86 +927,279 @@ _bfd_coff_final_link (abfd, info)
 
       for (i = 0; i < abfd->section_count; i++)
        {
 
       for (i = 0; i < abfd->section_count; i++)
        {
-         if (finfo.section_info[i].relocs != NULL)
-           free (finfo.section_info[i].relocs);
-         if (finfo.section_info[i].rel_hashes != NULL)
-           free (finfo.section_info[i].rel_hashes);
+         if (finfo.section_info[i].relocs != NULL)
+           free (finfo.section_info[i].relocs);
+         if (finfo.section_info[i].rel_hashes != NULL)
+           free (finfo.section_info[i].rel_hashes);
+       }
+      free (finfo.section_info);
+      finfo.section_info = NULL;
+    }
+
+  /* If we have optimized stabs strings, output them.  */
+  if (coff_hash_table (info)->stab_info != NULL)
+    {
+      if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info))
+       return false;
+    }
+
+  /* Write out the string table.  */
+  if (obj_raw_syment_count (abfd) != 0 || long_section_names)
+    {
+      if (bfd_seek (abfd,
+                   (obj_sym_filepos (abfd)
+                    + obj_raw_syment_count (abfd) * symesz),
+                   SEEK_SET) != 0)
+       return false;
+
+#if STRING_SIZE_SIZE == 4
+      bfd_h_put_32 (abfd,
+                   _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
+                   (bfd_byte *) strbuf);
+#else
+ #error Change bfd_h_put_32
+#endif
+
+      if (bfd_write (strbuf, 1, STRING_SIZE_SIZE, abfd) != STRING_SIZE_SIZE)
+       return false;
+
+      if (! _bfd_stringtab_emit (abfd, finfo.strtab))
+       return false;
+    }
+
+  _bfd_stringtab_free (finfo.strtab);
+
+  /* Setting bfd_get_symcount to 0 will cause write_object_contents to
+     not try to write out the symbols.  */
+  bfd_get_symcount (abfd) = 0;
+
+  return true;
+
+ error_return:
+  if (debug_merge_allocated)
+    coff_debug_merge_hash_table_free (&finfo.debug_merge);
+  if (finfo.strtab != NULL)
+    _bfd_stringtab_free (finfo.strtab);
+  if (finfo.section_info != NULL)
+    {
+      unsigned int i;
+
+      for (i = 0; i < abfd->section_count; i++)
+       {
+         if (finfo.section_info[i].relocs != NULL)
+           free (finfo.section_info[i].relocs);
+         if (finfo.section_info[i].rel_hashes != NULL)
+           free (finfo.section_info[i].rel_hashes);
+       }
+      free (finfo.section_info);
+    }
+  if (finfo.internal_syms != NULL)
+    free (finfo.internal_syms);
+  if (finfo.sec_ptrs != NULL)
+    free (finfo.sec_ptrs);
+  if (finfo.sym_indices != NULL)
+    free (finfo.sym_indices);
+  if (finfo.outsyms != NULL)
+    free (finfo.outsyms);
+  if (finfo.linenos != NULL)
+    free (finfo.linenos);
+  if (finfo.contents != NULL)
+    free (finfo.contents);
+  if (finfo.external_relocs != NULL)
+    free (finfo.external_relocs);
+  if (finfo.internal_relocs != NULL)
+    free (finfo.internal_relocs);
+  if (external_relocs != NULL)
+    free (external_relocs);
+  return false;
+}
+
+/* parse out a -heap <reserved>,<commit> line */
+
+static char *
+dores_com (ptr, output_bfd, heap)
+     char *ptr;
+     bfd *output_bfd;
+     int heap;
+{
+  if (coff_data(output_bfd)->pe) 
+    {
+      int val = strtoul (ptr, &ptr, 0);
+      if (heap)
+       pe_data(output_bfd)->pe_opthdr.SizeOfHeapReserve =val;
+      else
+       pe_data(output_bfd)->pe_opthdr.SizeOfStackReserve =val;
+
+      if (ptr[0] == ',') 
+       {
+         int val = strtoul (ptr+1, &ptr, 0);
+         if (heap)
+           pe_data(output_bfd)->pe_opthdr.SizeOfHeapCommit =val;
+         else
+           pe_data(output_bfd)->pe_opthdr.SizeOfStackCommit =val;
+       }
+    }
+  return ptr;
+}
+
+static char *get_name(ptr, dst)
+char *ptr;
+char **dst;
+{
+  while (*ptr == ' ')
+    ptr++;
+  *dst = ptr;
+  while (*ptr && *ptr != ' ')
+    ptr++;
+  *ptr = 0;
+  return ptr+1;
+}
+
+/* Process any magic embedded commands in a section called .drectve */
+                       
+static int
+process_embedded_commands (output_bfd, info,  abfd)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     bfd *abfd;
+{
+  asection *sec = bfd_get_section_by_name (abfd, ".drectve");
+  char *s;
+  char *e;
+  char *copy;
+  if (!sec) 
+    return 1;
+  
+  copy = bfd_malloc ((size_t) sec->_raw_size);
+  if (!copy) 
+    return 0;
+  if (! bfd_get_section_contents(abfd, sec, copy, 0, sec->_raw_size)) 
+    {
+      free (copy);
+      return 0;
+    }
+  e = copy + sec->_raw_size;
+  for (s = copy;  s < e ; ) 
+    {
+      if (s[0]!= '-') {
+       s++;
+       continue;
+      }
+      if (strncmp (s,"-attr", 5) == 0)
+       {
+         char *name;
+         char *attribs;
+         asection *asec;
+
+         int loop = 1;
+         int had_write = 0;
+         int had_read = 0;
+         int had_exec= 0;
+         int had_shared= 0;
+         s += 5;
+         s = get_name(s, &name);
+         s = get_name(s, &attribs);
+         while (loop) {
+           switch (*attribs++) 
+             {
+             case 'W':
+               had_write = 1;
+               break;
+             case 'R':
+               had_read = 1;
+               break;
+             case 'S':
+               had_shared = 1;
+               break;
+             case 'X':
+               had_exec = 1;
+               break;
+             default:
+               loop = 0;
+             }
+         }
+         asec = bfd_get_section_by_name (abfd, name);
+         if (asec) {
+           if (had_exec)
+             asec->flags |= SEC_CODE;
+           if (!had_write)
+             asec->flags |= SEC_READONLY;
+         }
+       }
+      else if (strncmp (s,"-heap", 5) == 0)
+       {
+         s = dores_com (s+5, output_bfd, 1);
+       }
+      else if (strncmp (s,"-stack", 6) == 0)
+       {
+         s = dores_com (s+6, output_bfd, 0);
        }
        }
-      free (finfo.section_info);
-      finfo.section_info = NULL;
+      else 
+       s++;
     }
     }
+  free (copy);
+  return 1;
+}
 
 
-  /* Write out the string table.  */
-  if (bfd_seek (abfd,
-               (obj_sym_filepos (abfd)
-                + obj_raw_syment_count (abfd) * symesz),
-               SEEK_SET) != 0)
-    return false;
-
-#if STRING_SIZE_SIZE == 4
-  bfd_h_put_32 (abfd,
-               _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
-               (bfd_byte *) strbuf);
-#else
- #error Change bfd_h_put_32
-#endif
-
-  if (bfd_write (strbuf, 1, STRING_SIZE_SIZE, abfd) != STRING_SIZE_SIZE)
-    return false;
+/* Place a marker against all symbols which are used by relocations.
+   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
+   that symbol. 
+   */
 
 
-  if (! _bfd_stringtab_emit (abfd, finfo.strtab))
-    return false;
+static void
+mark_relocs (finfo, input_bfd)
+     struct coff_final_link_info *     finfo;
+     bfd *                             input_bfd;
+{
+  asection * a;
 
 
-  _bfd_stringtab_free (finfo.strtab);
+  if ((bfd_get_file_flags (input_bfd) & HAS_SYMS) == 0)
+    return;
+  
+  for (a = input_bfd->sections; a != (asection *) NULL; a = a->next)
+    {
+      struct internal_reloc *  internal_relocs;
+      struct internal_reloc *  irel;
+      struct internal_reloc *  irelend;
 
 
-  /* Setting bfd_get_symcount to 0 will cause write_object_contents to
-     not try to write out the symbols.  */
-  bfd_get_symcount (abfd) = 0;
+      
+      if ((a->flags & SEC_RELOC) == 0 || a->reloc_count  < 1)
+       continue;
 
 
-  return true;
+      /* Read in the relocs.  */
+      internal_relocs = _bfd_coff_read_internal_relocs
+       (input_bfd, a, false,
+        finfo->external_relocs,
+        finfo->info->relocateable,
+        (finfo->info->relocateable
+         ? (finfo->section_info[ a->output_section->target_index ].relocs + a->output_section->reloc_count)
+         : finfo->internal_relocs)
+       );
+      
+      if (internal_relocs == NULL)
+       continue;
 
 
- error_return:
-  if (finfo.strtab != NULL)
-    _bfd_stringtab_free (finfo.strtab);
-  if (finfo.section_info != NULL)
-    {
-      unsigned int i;
+      irel     = internal_relocs;
+      irelend  = irel + a->reloc_count;
 
 
-      for (i = 0; i < abfd->section_count; i++)
+      /* Place a mark in the sym_indices array (whose entries have
+        been initialised to 0) for all of the symbols that are used
+        in the relocation table.  This will then be picked up in the
+        skip/don't pass */
+      
+      for (; irel < irelend; irel++)
        {
        {
-         if (finfo.section_info[i].relocs != NULL)
-           free (finfo.section_info[i].relocs);
-         if (finfo.section_info[i].rel_hashes != NULL)
-           free (finfo.section_info[i].rel_hashes);
+         finfo->sym_indices[ irel->r_symndx ] = -1;
        }
        }
-      free (finfo.section_info);
     }
     }
-  if (finfo.internal_syms != NULL)
-    free (finfo.internal_syms);
-  if (finfo.sec_ptrs != NULL)
-    free (finfo.sec_ptrs);
-  if (finfo.sym_indices != NULL)
-    free (finfo.sym_indices);
-  if (finfo.outsyms != NULL)
-    free (finfo.outsyms);
-  if (finfo.linenos != NULL)
-    free (finfo.linenos);
-  if (finfo.contents != NULL)
-    free (finfo.contents);
-  if (finfo.external_relocs != NULL)
-    free (finfo.external_relocs);
-  if (finfo.internal_relocs != NULL)
-    free (finfo.internal_relocs);
-  if (external_relocs != NULL)
-    free (external_relocs);
-  return false;
 }
 
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.  */
 
 }
 
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.  */
 
-static boolean
-coff_link_input_bfd (finfo, input_bfd)
+boolean
+_bfd_coff_link_input_bfd (finfo, input_bfd)
      struct coff_final_link_info *finfo;
      bfd *input_bfd;
 {
      struct coff_final_link_info *finfo;
      bfd *input_bfd;
 {
@@ -1243,10 +1221,9 @@ coff_link_input_bfd (finfo, input_bfd)
   struct internal_syment *isymp;
   asection **secpp;
   long *indexp;
   struct internal_syment *isymp;
   asection **secpp;
   long *indexp;
-  long output_index;
+  unsigned long output_index;
   bfd_byte *outsym;
   struct coff_link_hash_entry **sym_hash;
   bfd_byte *outsym;
   struct coff_link_hash_entry **sym_hash;
-  bfd_size_type relsz;
   asection *o;
 
   /* Move all the symbols to the output file.  */
   asection *o;
 
   /* Move all the symbols to the output file.  */
@@ -1274,7 +1251,7 @@ coff_link_input_bfd (finfo, input_bfd)
   if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
     hash = false;
 
   if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
     hash = false;
 
-  if (! coff_link_get_symbols (input_bfd))
+  if (! _bfd_coff_get_external_symbols (input_bfd))
     return false;
 
   esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
     return false;
 
   esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
@@ -1285,17 +1262,31 @@ coff_link_input_bfd (finfo, input_bfd)
   output_index = syment_base;
   outsym = finfo->outsyms;
 
   output_index = syment_base;
   outsym = finfo->outsyms;
 
-  if (obj_pe (output_bfd))
-      {
-       if (!process_embedded_commands (input_bfd))
-         return false;
-      }
+  if (coff_data (output_bfd)->pe)
+    {
+      if (! process_embedded_commands (output_bfd, finfo->info, input_bfd))
+       return false;
+    }
+
+  /* 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 that are
+     going to be involved in the relocations */
+  if ((   finfo->info->strip   != strip_none
+       || finfo->info->discard != discard_none)
+      && finfo->info->relocateable)
+    {
+      /* mark the symbol array as 'not-used' */
+      memset (indexp, 0, obj_raw_syment_count (input_bfd) * sizeof * indexp); 
+       
+      mark_relocs (finfo, input_bfd);
+    }
 
   while (esym < esym_end)
     {
       struct internal_syment isym;
       boolean skip;
       boolean global;
 
   while (esym < esym_end)
     {
       struct internal_syment isym;
       boolean skip;
       boolean global;
+      boolean dont_skip_symbol;
       int add;
 
       bfd_coff_swap_sym_in (input_bfd, (PTR) esym, (PTR) isymp);
       int add;
 
       bfd_coff_swap_sym_in (input_bfd, (PTR) esym, (PTR) isymp);
@@ -1316,6 +1307,15 @@ coff_link_input_bfd (finfo, input_bfd)
            *secpp = bfd_com_section_ptr;
        }
 
            *secpp = bfd_com_section_ptr;
        }
 
+      /* Extract the flag indicating if this symbol is used by a
+         relocation.  */
+      if ((finfo->info->strip != strip_none
+          || finfo->info->discard != discard_none)
+         && finfo->info->relocateable)
+       dont_skip_symbol = *indexp;
+      else
+       dont_skip_symbol = false;
+      
       *indexp = -1;
 
       skip = false;
       *indexp = -1;
 
       skip = false;
@@ -1323,12 +1323,15 @@ coff_link_input_bfd (finfo, input_bfd)
       add = 1 + isym.n_numaux;
 
       /* If we are stripping all symbols, we want to skip this one.  */
       add = 1 + isym.n_numaux;
 
       /* If we are stripping all symbols, we want to skip this one.  */
-      if (finfo->info->strip == strip_all)
+      if (finfo->info->strip == strip_all && ! dont_skip_symbol)
        skip = true;
 
       if (! skip)
        {
          if (isym.n_sclass == C_EXT
        skip = true;
 
       if (! skip)
        {
          if (isym.n_sclass == C_EXT
+#ifdef C_SYSTEM
+             || isym.n_sclass == C_SYSTEM
+#endif
              || (sym_is_global && (*sym_is_global) (input_bfd, &isym)))
            {
              /* This is a global symbol.  Global symbols come at the
              || (sym_is_global && (*sym_is_global) (input_bfd, &isym)))
            {
              /* This is a global symbol.  Global symbols come at the
@@ -1343,16 +1346,29 @@ coff_link_input_bfd (finfo, input_bfd)
            {
              /* This is a local symbol.  Skip it if we are discarding
                  local symbols.  */
            {
              /* This is a local symbol.  Skip it if we are discarding
                  local symbols.  */
-             if (finfo->info->discard == discard_all)
+             if (finfo->info->discard == discard_all && ! dont_skip_symbol)
                skip = true;
            }
        }
 
       /* If we stripping debugging symbols, and this is a debugging
                skip = true;
            }
        }
 
       /* If we stripping debugging symbols, and this is a debugging
-         symbol, then skip it.  */
+         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
+         a bug or not.  In any case, we handle it here.  */
       if (! skip
          && finfo->info->strip == strip_debugger
       if (! skip
          && finfo->info->strip == strip_debugger
-         && isym.n_scnum == N_DEBUG)
+         && ! dont_skip_symbol
+         && (isym.n_scnum == N_DEBUG
+             || (isym.n_scnum == N_ABS
+                 && (isym.n_sclass == C_AUTO
+                     || isym.n_sclass == C_REG
+                     || isym.n_sclass == C_MOS
+                     || isym.n_sclass == C_MOE
+                     || isym.n_sclass == C_MOU
+                     || isym.n_sclass == C_ARG
+                     || isym.n_sclass == C_REGPARM
+                     || isym.n_sclass == C_FIELD
+                     || isym.n_sclass == C_EOS))))
        skip = true;
 
       /* If some symbols are stripped based on the name, work out the
        skip = true;
 
       /* If some symbols are stripped based on the name, work out the
@@ -1364,32 +1380,185 @@ coff_link_input_bfd (finfo, input_bfd)
          const char *name;
          char buf[SYMNMLEN + 1];
 
          const char *name;
          char buf[SYMNMLEN + 1];
 
-         if (isym._n._n_n._n_zeroes == 0
-             && isym._n._n_n._n_offset != 0)
+         name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
+         if (name == NULL)
+           return false;
+
+         if (! dont_skip_symbol
+             && ((finfo->info->strip == strip_some
+                  && (bfd_hash_lookup (finfo->info->keep_hash, name, false,
+                                   false) == NULL))
+                  || (! global
+                      && finfo->info->discard == discard_l
+                      && bfd_is_local_label_name (input_bfd, name))))
+           skip = true;
+       }
+
+      /* If this is an enum, struct, or union tag, see if we have
+         already output an identical type.  */
+      if (! skip
+         && (finfo->output_bfd->flags & BFD_TRADITIONAL_FORMAT) == 0
+         && (isym.n_sclass == C_ENTAG
+             || isym.n_sclass == C_STRTAG
+             || isym.n_sclass == C_UNTAG)
+         && isym.n_numaux == 1)
+       {
+         const char *name;
+         char buf[SYMNMLEN + 1];
+         struct coff_debug_merge_hash_entry *mh;
+         struct coff_debug_merge_type *mt;
+         union internal_auxent aux;
+         struct coff_debug_merge_element **epp;
+         bfd_byte *esl, *eslend;
+         struct internal_syment *islp;
+
+         name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
+         if (name == NULL)
+           return false;
+
+         /* Ignore fake names invented by compiler; treat them all as
+             the same name.  */
+         if (*name == '~' || *name == '.' || *name == '$'
+             || (*name == bfd_get_symbol_leading_char (input_bfd)
+                 && (name[1] == '~' || name[1] == '.' || name[1] == '$')))
+           name = "";
+
+         mh = coff_debug_merge_hash_lookup (&finfo->debug_merge, name,
+                                            true, true);
+         if (mh == NULL)
+           return false;
+
+         /* Allocate memory to hold type information.  If this turns
+             out to be a duplicate, we pass this address to
+             bfd_release.  */
+         mt = ((struct coff_debug_merge_type *)
+               bfd_alloc (input_bfd,
+                          sizeof (struct coff_debug_merge_type)));
+         if (mt == NULL)
+           return false;
+         mt->class = isym.n_sclass;
+
+         /* Pick up the aux entry, which points to the end of the tag
+             entries.  */
+         bfd_coff_swap_aux_in (input_bfd, (PTR) (esym + isymesz),
+                               isym.n_type, isym.n_sclass, 0, isym.n_numaux,
+                               (PTR) &aux);
+
+         /* Gather the elements.  */
+         epp = &mt->elements;
+         mt->elements = NULL;
+         islp = isymp + 2;
+         esl = esym + 2 * isymesz;
+         eslend = ((bfd_byte *) obj_coff_external_syms (input_bfd)
+                   + aux.x_sym.x_fcnary.x_fcn.x_endndx.l * isymesz);
+         while (esl < eslend)
            {
            {
-             if (strings == NULL)
+             const char *elename;
+             char elebuf[SYMNMLEN + 1];
+             char *copy;
+
+             bfd_coff_swap_sym_in (input_bfd, (PTR) esl, (PTR) islp);
+
+             *epp = ((struct coff_debug_merge_element *)
+                     bfd_alloc (input_bfd,
+                                sizeof (struct coff_debug_merge_element)));
+             if (*epp == NULL)
+               return false;
+
+             elename = _bfd_coff_internal_syment_name (input_bfd, islp,
+                                                       elebuf);
+             if (elename == NULL)
+               return false;
+
+             copy = (char *) bfd_alloc (input_bfd, strlen (elename) + 1);
+             if (copy == NULL)
+               return false;
+             strcpy (copy, elename);
+
+             (*epp)->name = copy;
+             (*epp)->type = islp->n_type;
+             (*epp)->tagndx = 0;
+             if (islp->n_numaux >= 1
+                 && islp->n_type != T_NULL
+                 && islp->n_sclass != C_EOS)
                {
                {
-                 strings = coff_read_string_table (input_bfd);
-                 if (strings == NULL)
-                   return false;
+                 union internal_auxent eleaux;
+                 long indx;
+
+                 bfd_coff_swap_aux_in (input_bfd, (PTR) (esl + isymesz),
+                                       islp->n_type, islp->n_sclass, 0,
+                                       islp->n_numaux, (PTR) &eleaux);
+                 indx = eleaux.x_sym.x_tagndx.l;
+
+                 /* FIXME: If this tagndx entry refers to a symbol
+                    defined later in this file, we just ignore it.
+                    Handling this correctly would be tedious, and may
+                    not be required.  */
+
+                 if (indx > 0
+                     && (indx
+                         < ((esym -
+                             (bfd_byte *) obj_coff_external_syms (input_bfd))
+                            / (long) isymesz)))
+                   {
+                     (*epp)->tagndx = finfo->sym_indices[indx];
+                     if ((*epp)->tagndx < 0)
+                       (*epp)->tagndx = 0;
+                   }
                }
                }
-             name = strings + isym._n._n_n._n_offset;
+             epp = &(*epp)->next;
+             *epp = NULL;
+
+             esl += (islp->n_numaux + 1) * isymesz;
+             islp += islp->n_numaux + 1;
            }
            }
+
+         /* See if we already have a definition which matches this
+             type.  We always output the type if it has no elements,
+             for simplicity.  */
+         if (mt->elements == NULL)
+           bfd_release (input_bfd, (PTR) mt);
          else
            {
          else
            {
-             memcpy (buf, isym._n._n_name, SYMNMLEN);
-             buf[SYMNMLEN] = '\0';
-             name = buf;
-           }
+             struct coff_debug_merge_type *mtl;
 
 
-         if ((finfo->info->strip == strip_some
-              && (bfd_hash_lookup (finfo->info->keep_hash, name, false,
-                                   false) == NULL))
-             || (! global
-                 && finfo->info->discard == discard_l
-                 && strncmp (name, finfo->info->lprefix,
-                             finfo->info->lprefix_len) == 0))
-           skip = true;
+             for (mtl = mh->types; mtl != NULL; mtl = mtl->next)
+               {
+                 struct coff_debug_merge_element *me, *mel;
+
+                 if (mtl->class != mt->class)
+                   continue;
+
+                 for (me = mt->elements, mel = mtl->elements;
+                      me != NULL && mel != NULL;
+                      me = me->next, mel = mel->next)
+                   {
+                     if (strcmp (me->name, mel->name) != 0
+                         || me->type != mel->type
+                         || me->tagndx != mel->tagndx)
+                       break;
+                   }
+
+                 if (me == NULL && mel == NULL)
+                   break;
+               }
+
+             if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base)
+               {
+                 /* This is the first definition of this type.  */
+                 mt->indx = output_index;
+                 mt->next = mh->types;
+                 mh->types = mt;
+               }
+             else
+               {
+                 /* This is a redefinition which can be merged.  */
+                 bfd_release (input_bfd, (PTR) mt);
+                 *indexp = mtl->indx;
+                 add = (eslend - esym) / isymesz;
+                 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.  */
@@ -1408,14 +1577,10 @@ coff_link_input_bfd (finfo, input_bfd)
                 bfd_coff_symname_in_debug.  That is only true for
                 XCOFF, and XCOFF requires different linking code
                 anyhow.  */
                 bfd_coff_symname_in_debug.  That is only true for
                 XCOFF, and XCOFF requires different linking code
                 anyhow.  */
-             BFD_ASSERT (isym._n._n_n._n_offset >= STRING_SIZE_SIZE);
-             if (strings == NULL)
-               {
-                 strings = coff_read_string_table (input_bfd);
-                 if (strings == NULL)
-                   return false;
-               }
-             name = strings + isym._n._n_n._n_offset;
+             name = _bfd_coff_internal_syment_name (input_bfd, &isym,
+                                                    (char *) NULL);
+             if (name == NULL)
+               return false;
              indx = _bfd_stringtab_add (finfo->strtab, name, hash, copy);
              if (indx == (bfd_size_type) -1)
                return false;
              indx = _bfd_stringtab_add (finfo->strtab, name, hash, copy);
              if (indx == (bfd_size_type) -1)
                return false;
@@ -1425,9 +1590,11 @@ coff_link_input_bfd (finfo, input_bfd)
          if (isym.n_scnum > 0)
            {
              isym.n_scnum = (*secpp)->output_section->target_index;
          if (isym.n_scnum > 0)
            {
              isym.n_scnum = (*secpp)->output_section->target_index;
-             isym.n_value += ((*secpp)->output_section->vma
-                              + (*secpp)->output_offset
-                              - (*secpp)->vma);
+             isym.n_value += (*secpp)->output_offset;
+             if (! obj_pe (input_bfd))
+               isym.n_value -= (*secpp)->vma;
+             if (! obj_pe (finfo->output_bfd))
+               isym.n_value += (*secpp)->output_section->vma;
            }
 
          /* The value of a C_FILE symbol is the symbol index of the
            }
 
          /* The value of a C_FILE symbol is the symbol index of the
@@ -1442,11 +1609,11 @@ coff_link_input_bfd (finfo, input_bfd)
          if (isym.n_sclass == C_FILE)
            {
              if (finfo->last_file_index != -1
          if (isym.n_sclass == C_FILE)
            {
              if (finfo->last_file_index != -1
-                 && finfo->last_file.n_value != output_index)
+                 && finfo->last_file.n_value != (long) output_index)
                {
                  /* We must correct the value of the last C_FILE entry.  */
                  finfo->last_file.n_value = output_index;
                {
                  /* We must correct the value of the last C_FILE entry.  */
                  finfo->last_file.n_value = output_index;
-                 if (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.  */
                      bfd_coff_swap_sym_out (output_bfd,
                    {
                      /* The last C_FILE symbol is in this input file.  */
                      bfd_coff_swap_sym_out (output_bfd,
@@ -1478,6 +1645,12 @@ coff_link_input_bfd (finfo, input_bfd)
              finfo->last_file = isym;
            }
 
              finfo->last_file = isym;
            }
 
+         /* If doing task linking, convert normal global function symbols to
+            static functions. */
+
+         if (finfo->info->task_link && isym.n_sclass == C_EXT)
+           isym.n_sclass = C_STAT;
+
          /* Output the symbol.  */
 
          bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) outsym);
          /* Output the symbol.  */
 
          bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) outsym);
@@ -1492,7 +1665,13 @@ coff_link_input_bfd (finfo, input_bfd)
              indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd))
                      / isymesz);
              h = obj_coff_sym_hashes (input_bfd)[indx];
              indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd))
                      / isymesz);
              h = obj_coff_sym_hashes (input_bfd)[indx];
-             BFD_ASSERT (h != NULL);
+             if (h == NULL)
+               {
+                 /* This can happen if there were errors earlier in
+                     the link.  */
+                 bfd_set_error (bfd_error_bad_value);
+                 return false;
+               }
              h->indx = output_index;
            }
 
              h->indx = output_index;
            }
 
@@ -1527,7 +1706,8 @@ coff_link_input_bfd (finfo, input_bfd)
 
       add = 1 + isymp->n_numaux;
 
 
       add = 1 + isymp->n_numaux;
 
-      if (*indexp < 0
+      if ((*indexp < 0
+          || (bfd_size_type) *indexp < syment_base)
          && (*sym_hash == NULL
              || (*sym_hash)->auxbfd != input_bfd))
        esym += add * isymesz;
          && (*sym_hash == NULL
              || (*sym_hash)->auxbfd != input_bfd))
        esym += add * isymesz;
@@ -1540,7 +1720,12 @@ coff_link_input_bfd (finfo, input_bfd)
          if (*indexp < 0)
            {
              h = *sym_hash;
          if (*indexp < 0)
            {
              h = *sym_hash;
-             BFD_ASSERT (h->numaux == isymp->n_numaux);
+
+             /* The m68k-motorola-sysv assembler will sometimes
+                 generate two symbols with the same name, but only one
+                 will have aux entries.  */
+             BFD_ASSERT (isymp->n_numaux == 0
+                         || h->numaux == isymp->n_numaux);
            }
 
          esym += isymesz;
            }
 
          esym += isymesz;
@@ -1579,7 +1764,7 @@ coff_link_input_bfd (finfo, input_bfd)
                                  >= STRING_SIZE_SIZE);
                      if (strings == NULL)
                        {
                                  >= STRING_SIZE_SIZE);
                      if (strings == NULL)
                        {
-                         strings = coff_read_string_table (input_bfd);
+                         strings = _bfd_coff_read_string_table (input_bfd);
                          if (strings == NULL)
                            return false;
                        }
                          if (strings == NULL)
                            return false;
                        }
@@ -1593,11 +1778,12 @@ coff_link_input_bfd (finfo, input_bfd)
                }
              else if (isymp->n_sclass != C_STAT || isymp->n_type != T_NULL)
                {
                }
              else if (isymp->n_sclass != C_STAT || isymp->n_type != T_NULL)
                {
-                 long indx;
+                 unsigned long indx;
 
                  if (ISFCN (isymp->n_type)
                      || ISTAG (isymp->n_sclass)
 
                  if (ISFCN (isymp->n_type)
                      || ISTAG (isymp->n_sclass)
-                     || isymp->n_sclass == C_BLOCK)
+                     || isymp->n_sclass == C_BLOCK
+                     || isymp->n_sclass == C_FCN)
                    {
                      indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l;
                      if (indx > 0
                    {
                      indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l;
                      if (indx > 0
@@ -1607,7 +1793,9 @@ coff_link_input_bfd (finfo, input_bfd)
                              the index of the next symbol we are going
                              to include.  I don't know if this is
                              entirely right.  */
                              the index of the next symbol we are going
                              to include.  I don't know if this is
                              entirely right.  */
-                         while (finfo->sym_indices[indx] < 0
+                         while ((finfo->sym_indices[indx] < 0
+                                 || ((bfd_size_type) finfo->sym_indices[indx]
+                                     < syment_base))
                                 && indx < obj_raw_syment_count (input_bfd))
                            ++indx;
                          if (indx >= obj_raw_syment_count (input_bfd))
                                 && indx < obj_raw_syment_count (input_bfd))
                            ++indx;
                          if (indx >= obj_raw_syment_count (input_bfd))
@@ -1621,11 +1809,88 @@ coff_link_input_bfd (finfo, input_bfd)
                  indx = auxp->x_sym.x_tagndx.l;
                  if (indx > 0 && indx < obj_raw_syment_count (input_bfd))
                    {
                  indx = auxp->x_sym.x_tagndx.l;
                  if (indx > 0 && indx < obj_raw_syment_count (input_bfd))
                    {
-                     indx = finfo->sym_indices[indx];
-                     if (indx < 0)
+                     long symindx;
+
+                     symindx = finfo->sym_indices[indx];
+                     if (symindx < 0)
                        auxp->x_sym.x_tagndx.l = 0;
                      else
                        auxp->x_sym.x_tagndx.l = 0;
                      else
-                       auxp->x_sym.x_tagndx.l = indx;
+                       auxp->x_sym.x_tagndx.l = symindx;
+                   }
+
+                 /* The .bf symbols are supposed to be linked through
+                    the endndx field.  We need to carry this list
+                    across object files.  */
+                 if (i == 0
+                     && h == NULL
+                     && isymp->n_sclass == C_FCN
+                     && (isymp->_n._n_n._n_zeroes != 0
+                         || isymp->_n._n_n._n_offset == 0)
+                     && isymp->_n._n_name[0] == '.'
+                     && isymp->_n._n_name[1] == 'b'
+                     && isymp->_n._n_name[2] == 'f'
+                     && isymp->_n._n_name[3] == '\0')
+                   {
+                     if (finfo->last_bf_index != -1)
+                       {
+                         finfo->last_bf.x_sym.x_fcnary.x_fcn.x_endndx.l =
+                           *indexp;
+
+                         if ((bfd_size_type) finfo->last_bf_index
+                             >= syment_base)
+                           {
+                             PTR auxout;
+
+                             /* The last .bf symbol is in this input
+                                file.  This will only happen if the
+                                assembler did not set up the .bf
+                                endndx symbols correctly.  */
+                             auxout = (PTR) (finfo->outsyms
+                                             + ((finfo->last_bf_index
+                                                 - syment_base)
+                                                * osymesz));
+                             bfd_coff_swap_aux_out (output_bfd,
+                                                    (PTR) &finfo->last_bf,
+                                                    isymp->n_type,
+                                                    isymp->n_sclass,
+                                                    0, isymp->n_numaux,
+                                                    auxout);
+                           }
+                         else
+                           {
+                             /* We have already written out the last
+                                 .bf aux entry.  We need to write it
+                                 out again.  We borrow *outsym
+                                 temporarily.  FIXME: This case should
+                                 be made faster.  */
+                             bfd_coff_swap_aux_out (output_bfd,
+                                                    (PTR) &finfo->last_bf,
+                                                    isymp->n_type,
+                                                    isymp->n_sclass,
+                                                    0, isymp->n_numaux,
+                                                    (PTR) outsym);
+                             if (bfd_seek (output_bfd,
+                                           (obj_sym_filepos (output_bfd)
+                                            + finfo->last_bf_index * osymesz),
+                                           SEEK_SET) != 0
+                                 || bfd_write (outsym, osymesz, 1,
+                                               output_bfd) != osymesz)
+                               return false;
+                           }
+                       }
+
+                     if (auxp->x_sym.x_fcnary.x_fcn.x_endndx.l != 0)
+                       finfo->last_bf_index = -1;
+                     else
+                       {
+                         /* The endndx field of this aux entry must
+                             be updated with the symbol number of the
+                             next .bf symbol.  */
+                         finfo->last_bf = *auxp;
+                         finfo->last_bf_index = (((outsym - finfo->outsyms)
+                                                  / osymesz)
+                                                 + syment_base);
+                       }
                    }
                }
 
                    }
                }
 
@@ -1656,7 +1921,17 @@ coff_link_input_bfd (finfo, input_bfd)
          bfd_byte *eline;
          bfd_byte *elineend;
 
          bfd_byte *eline;
          bfd_byte *elineend;
 
-         if (o->lineno_count == 0)
+         /* FIXME: If SEC_HAS_CONTENTS is not for the section, then
+            build_link_order in ldwrite.c will not have created a
+            link order, which means that we will not have seen this
+            input section in _bfd_coff_final_link, which means that
+            we will not have allocated space for the line numbers of
+            this section.  I don't think line numbers can be
+            meaningful for a section which does not have
+            SEC_HAS_CONTENTS set, but, if they do, this must be
+            changed.  */
+         if (o->lineno_count == 0
+             || (o->output_section->flags & SEC_HAS_CONTENTS) == 0)
            continue;
 
          if (bfd_seek (input_bfd, o->line_filepos, SEEK_SET) != 0
            continue;
 
          if (bfd_seek (input_bfd, o->line_filepos, SEEK_SET) != 0
@@ -1676,7 +1951,7 @@ coff_link_input_bfd (finfo, input_bfd)
              if (iline.l_lnno != 0)
                iline.l_addr.l_paddr += offset;
              else if (iline.l_addr.l_symndx >= 0
              if (iline.l_lnno != 0)
                iline.l_addr.l_paddr += offset;
              else if (iline.l_addr.l_symndx >= 0
-                      && (iline.l_addr.l_symndx
+                      && ((unsigned long) iline.l_addr.l_symndx
                           < obj_raw_syment_count (input_bfd)))
                {
                  long indx;
                           < obj_raw_syment_count (input_bfd)))
                {
                  long indx;
@@ -1754,7 +2029,7 @@ coff_link_input_bfd (finfo, input_bfd)
      normal case, this will save us from writing out the C_FILE symbol
      again.  */
   if (finfo->last_file_index != -1
      normal case, this will save us from writing out the C_FILE symbol
      again.  */
   if (finfo->last_file_index != -1
-      && finfo->last_file_index >= syment_base)
+      && (bfd_size_type) finfo->last_file_index >= syment_base)
     {
       finfo->last_file.n_value = output_index;
       bfd_coff_swap_sym_out (output_bfd, (PTR) &finfo->last_file,
     {
       finfo->last_file.n_value = output_index;
       bfd_coff_swap_sym_out (output_bfd, (PTR) &finfo->last_file,
@@ -1769,8 +2044,9 @@ coff_link_input_bfd (finfo, input_bfd)
       if (bfd_seek (output_bfd,
                    obj_sym_filepos (output_bfd) + syment_base * osymesz,
                    SEEK_SET) != 0
       if (bfd_seek (output_bfd,
                    obj_sym_filepos (output_bfd) + syment_base * osymesz,
                    SEEK_SET) != 0
-         || bfd_write (finfo->outsyms, outsym - finfo->outsyms, 1,
-                       output_bfd) != outsym - finfo->outsyms)
+         || (bfd_write (finfo->outsyms, outsym - finfo->outsyms, 1,
+                       output_bfd)
+             != (bfd_size_type) (outsym - finfo->outsyms)))
        return false;
 
       BFD_ASSERT ((obj_raw_syment_count (output_bfd)
        return false;
 
       BFD_ASSERT ((obj_raw_syment_count (output_bfd)
@@ -1781,53 +2057,69 @@ coff_link_input_bfd (finfo, input_bfd)
     }
 
   /* Relocate the contents of each section.  */
     }
 
   /* Relocate the contents of each section.  */
-  relsz = bfd_coff_relsz (input_bfd);
   adjust_symndx = coff_backend_info (input_bfd)->_bfd_coff_adjust_symndx;
   for (o = input_bfd->sections; o != NULL; o = o->next)
     {
   adjust_symndx = coff_backend_info (input_bfd)->_bfd_coff_adjust_symndx;
   for (o = input_bfd->sections; o != NULL; o = o->next)
     {
-      if ((o->flags & SEC_HAS_CONTENTS) == 0)
-       continue;
+      bfd_byte *contents;
+      struct coff_section_tdata *secdata;
+
+      if (! o->linker_mark)
+       {
+         /* This section was omitted from the link.  */
+         continue;
+       }
+
+      if ((o->flags & SEC_HAS_CONTENTS) == 0
+         || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0))
+       {
+         if ((o->flags & SEC_RELOC) != 0
+             && o->reloc_count != 0)
+           {
+             ((*_bfd_error_handler)
+              ("%s: relocs in section `%s', but it has no contents",
+               bfd_get_filename (input_bfd),
+               bfd_get_section_name (input_bfd, o)));
+             bfd_set_error (bfd_error_no_contents);
+             return false;
+           }
+
+         continue;
+       }
 
 
-      if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
-                                     (file_ptr) 0, o->_raw_size))
-       return false;
+      secdata = coff_section_data (input_bfd, o);
+      if (secdata != NULL && secdata->contents != NULL)
+       contents = secdata->contents;
+      else
+       {
+         if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
+                                         (file_ptr) 0, o->_raw_size))
+           return false;
+         contents = finfo->contents;
+       }
 
       if ((o->flags & SEC_RELOC) != 0)
        {
          int target_index;
          struct internal_reloc *internal_relocs;
 
       if ((o->flags & SEC_RELOC) != 0)
        {
          int target_index;
          struct internal_reloc *internal_relocs;
-         bfd_byte *erel;
-         bfd_byte *erel_end;
          struct internal_reloc *irel;
 
          /* Read in the relocs.  */
          struct internal_reloc *irel;
 
          /* Read in the relocs.  */
-         if (bfd_seek (input_bfd, o->rel_filepos, SEEK_SET) != 0
-             || (bfd_read (finfo->external_relocs, relsz, o->reloc_count,
-                           input_bfd) != relsz * o->reloc_count))
-           return false;
-
-         /* If we are doing a relocateable link, we keep the swapped
-            in relocs in memory, and don't write them out until the
-            end of the link.  */
          target_index = o->output_section->target_index;
          target_index = o->output_section->target_index;
-         if (! finfo->info->relocateable)
-           internal_relocs = finfo->internal_relocs;
-         else
-           internal_relocs = (finfo->section_info[target_index].relocs
-                              + o->output_section->reloc_count);
-
-         /* Swap in the relocs.  */
-         erel = finfo->external_relocs;
-         erel_end = erel + relsz * o->reloc_count;
-         irel = internal_relocs;
-         for (; erel < erel_end; erel += relsz, irel++)
-           bfd_coff_swap_reloc_in (input_bfd, (PTR) erel, (PTR) irel);
+         internal_relocs = (_bfd_coff_read_internal_relocs
+                            (input_bfd, o, false, finfo->external_relocs,
+                             finfo->info->relocateable,
+                             (finfo->info->relocateable
+                              ? (finfo->section_info[target_index].relocs
+                                 + o->output_section->reloc_count)
+                              : finfo->internal_relocs)));
+         if (internal_relocs == NULL)
+           return false;
 
          /* Call processor specific code to relocate the section
              contents.  */
          if (! bfd_coff_relocate_section (output_bfd, finfo->info,
                                           input_bfd, o,
 
          /* Call processor specific code to relocate the section
              contents.  */
          if (! bfd_coff_relocate_section (output_bfd, finfo->info,
                                           input_bfd, o,
-                                          finfo->contents,
+                                          contents,
                                           internal_relocs,
                                           finfo->internal_syms,
                                           finfo->sec_ptrs))
                                           internal_relocs,
                                           finfo->internal_syms,
                                           finfo->sec_ptrs))
@@ -1900,28 +2192,16 @@ coff_link_input_bfd (finfo, input_bfd)
                          char buf[SYMNMLEN + 1];
 
                          /* This reloc is against a symbol we are
                          char buf[SYMNMLEN + 1];
 
                          /* This reloc is against a symbol we are
-                             stripping.  It would be possible to
-                             handle this case, but I don't think it's
-                             worth it.  */
+                             stripping.  This should have been handled
+                            by the 'dont_skip_symbol' code in the while
+                            loop at the top of this function. */
+                         
                          is = finfo->internal_syms + irel->r_symndx;
 
                          is = finfo->internal_syms + irel->r_symndx;
 
-                         if (is->_n._n_n._n_zeroes == 0
-                             && is->_n._n_n._n_offset != 0)
-                           {
-                             if (strings == NULL)
-                               {
-                                 strings = coff_read_string_table (input_bfd);
-                                 if (strings == NULL)
-                                   return false;
-                               }
-                             name = strings + is->_n._n_n._n_offset;
-                           }
-                         else
-                           {
-                             memcpy (buf, is->_n._n_name, SYMNMLEN);
-                             buf[SYMNMLEN] = '\0';
-                             name = buf;
-                           }
+                         name = (_bfd_coff_internal_syment_name
+                                 (input_bfd, is, buf));
+                         if (name == NULL)
+                           return false;
 
                          if (! ((*finfo->info->callbacks->unattached_reloc)
                                 (finfo->info, name, input_bfd, o,
 
                          if (! ((*finfo->info->callbacks->unattached_reloc)
                                 (finfo->info, name, input_bfd, o,
@@ -1936,17 +2216,27 @@ coff_link_input_bfd (finfo, input_bfd)
        }
 
       /* Write out the modified section contents.  */
        }
 
       /* Write out the modified section contents.  */
-      if (! bfd_set_section_contents (output_bfd, o->output_section,
-                                     finfo->contents, o->output_offset,
-                                     (o->_cooked_size != 0
-                                      ? o->_cooked_size
-                                      : o->_raw_size)))
-       return false;
+      if (secdata == NULL || secdata->stab_info == NULL)
+       {
+         if (! bfd_set_section_contents (output_bfd, o->output_section,
+                                         contents, o->output_offset,
+                                         (o->_cooked_size != 0
+                                          ? o->_cooked_size
+                                          : o->_raw_size)))
+           return false;
+       }
+      else
+       {
+         if (! (_bfd_write_section_stabs
+                (output_bfd, &coff_hash_table (finfo->info)->stab_info,
+                 o, &secdata->stab_info, contents)))
+           return false;
+       }
     }
 
   if (! finfo->info->keep_memory)
     {
     }
 
   if (! finfo->info->keep_memory)
     {
-      if (! coff_link_free_symbols (input_bfd))
+      if (! _bfd_coff_free_symbols (input_bfd))
        return false;
     }
 
        return false;
     }
 
@@ -1955,8 +2245,8 @@ coff_link_input_bfd (finfo, input_bfd)
 
 /* Write out a global symbol.  Called via coff_link_hash_traverse.  */
 
 
 /* Write out a global symbol.  Called via coff_link_hash_traverse.  */
 
-static boolean
-coff_write_global_sym (h, data)
+boolean
+_bfd_coff_write_global_sym (h, data)
      struct coff_link_hash_entry *h;
      PTR data;
 {
      struct coff_link_hash_entry *h;
      PTR data;
 {
@@ -2003,8 +2293,9 @@ coff_write_global_sym (h, data)
        else
          isym.n_scnum = sec->target_index;
        isym.n_value = (h->root.u.def.value
        else
          isym.n_scnum = sec->target_index;
        isym.n_value = (h->root.u.def.value
-                       + sec->vma
                        + h->root.u.def.section->output_offset);
                        + h->root.u.def.section->output_offset);
+       if (! obj_pe (finfo->output_bfd))
+         isym.n_value += sec->vma;
       }
       break;
 
       }
       break;
 
@@ -2046,6 +2337,18 @@ coff_write_global_sym (h, data)
   if (isym.n_sclass == C_NULL)
     isym.n_sclass = C_EXT;
 
   if (isym.n_sclass == C_NULL)
     isym.n_sclass = C_EXT;
 
+  /* If doing task linking and this is the pass where we convert defined globals to
+     statics, then do that conversion now.  If the symbol is not being converted,
+     just ignore it and it will be output during a later pass. */
+  if (finfo->global_to_static)
+    {
+      if (isym.n_sclass != C_EXT)
+       {
+         return true;
+       }
+      isym.n_sclass = C_STAT;
+    }
+
   isym.n_numaux = h->numaux;
   
   bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) finfo->outsyms);
   isym.n_numaux = h->numaux;
   
   bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) finfo->outsyms);
@@ -2084,10 +2387,41 @@ coff_write_global_sym (h, data)
   return true;
 }
 
   return true;
 }
 
+/* Write out task global symbols, converting them to statics.  Called
+   via coff_link_hash_traverse.  Calls bfd_coff_write_global_sym to do
+   the dirty work, if the symbol we are processing needs conversion. */
+
+boolean
+_bfd_coff_write_task_globals (h, data)
+     struct coff_link_hash_entry *h;
+     PTR data;
+{
+  struct coff_final_link_info *finfo = (struct coff_final_link_info *) data;
+  boolean rtnval = true;
+  boolean save_global_to_static;
+
+  if (h->indx < 0)
+    {
+      switch (h->root.type)
+       {
+       case bfd_link_hash_defined:
+       case bfd_link_hash_defweak:
+         save_global_to_static = finfo->global_to_static;
+         finfo->global_to_static = true;
+         rtnval = _bfd_coff_write_global_sym (h, data);
+         finfo->global_to_static = save_global_to_static;
+         break;
+       default:
+         break;
+       }
+    }
+  return (rtnval);
+}
+
 /* Handle a link order which is supposed to generate a reloc.  */
 
 /* Handle a link order which is supposed to generate a reloc.  */
 
-static boolean
-coff_reloc_link_order (output_bfd, finfo, output_section, link_order)
+boolean
+_bfd_coff_reloc_link_order (output_bfd, finfo, output_section, link_order)
      bfd *output_bfd;
      struct coff_final_link_info *finfo;
      asection *output_section;
      bfd *output_bfd;
      struct coff_final_link_info *finfo;
      asection *output_section;
@@ -2114,10 +2448,7 @@ coff_reloc_link_order (output_bfd, finfo, output_section, link_order)
       size = bfd_get_reloc_size (howto);
       buf = (bfd_byte *) bfd_zmalloc (size);
       if (buf == NULL)
       size = bfd_get_reloc_size (howto);
       buf = (bfd_byte *) bfd_zmalloc (size);
       if (buf == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
 
       rstat = _bfd_relocate_contents (howto, output_bfd,
                                      link_order->u.reloc.p->addend, buf);
 
       rstat = _bfd_relocate_contents (howto, output_bfd,
                                      link_order->u.reloc.p->addend, buf);
@@ -2177,9 +2508,10 @@ coff_reloc_link_order (output_bfd, finfo, output_section, link_order)
     {
       struct coff_link_hash_entry *h;
 
     {
       struct coff_link_hash_entry *h;
 
-      h = coff_link_hash_lookup (coff_hash_table (finfo->info),
-                                link_order->u.reloc.p->u.name,
-                                false, false, true);
+      h = ((struct coff_link_hash_entry *)
+          bfd_wrapped_link_hash_lookup (output_bfd, finfo->info,
+                                        link_order->u.reloc.p->u.name,
+                                        false, false, true));
       if (h != NULL)
        {
          if (h->indx >= 0)
       if (h != NULL)
        {
          if (h->indx >= 0)
@@ -2235,7 +2567,6 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
   struct internal_reloc *rel;
   struct internal_reloc *relend;
 
   struct internal_reloc *rel;
   struct internal_reloc *relend;
 
-
   rel = relocs;
   relend = rel + input_section->reloc_count;
   for (; rel < relend; rel++)
   rel = relocs;
   relend = rel + input_section->reloc_count;
   for (; rel < relend; rel++)
@@ -2277,21 +2608,23 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
       if (howto == NULL)
        return false;
 
       if (howto == NULL)
        return false;
 
-      /* WINDOWS_NT; in this next section, the value of 'val' will be computed.
-         With respect to the .idata and .rsrc sections, the NT_IMAGE_BASE
-         must be removed from the value that is to be relocated (NT_IMAGE_BASE
-         is currently defined in internal.h and has value 400000).  Now this
-         value should only be removed from addresses being relocated in the
-         .idata and .rsrc sections, not the .text section which should have
-         the 'real' address.  In addition, the .rsrc val's must also be
-         adjusted by the input_section->vma.  */
+      /* If we are doing a relocateable link, then we can just ignore
+         a PC relative reloc that is pcrel_offset.  It will already
+         have the correct value.  If this is not a relocateable link,
+         then we should ignore the symbol value.  */
+      if (howto->pc_relative && howto->pcrel_offset)
+       {
+         if (info->relocateable)
+           continue;
+         if (sym != NULL && sym->n_scnum != 0)
+           addend += sym->n_value;
+       }
 
       val = 0;
 
       if (h == NULL)
        {
          asection *sec;
 
       val = 0;
 
       if (h == NULL)
        {
          asection *sec;
-          int i;
 
          if (symndx == -1)
            {
 
          if (symndx == -1)
            {
@@ -2303,26 +2636,9 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
              sec = sections[symndx];
               val = (sec->output_section->vma
                     + sec->output_offset
              sec = sections[symndx];
               val = (sec->output_section->vma
                     + sec->output_offset
-                    + sym->n_value
-                    - sec->vma);
-             if (obj_pe(output_bfd)) {
-               /* Make a correction here to val if the sec is either .rsrc
-                  or .idata */
-               if (strcmp (input_section->name, ".text") != 0)
-                 {
-                   if (strncmp (sec->name, ".idata$", 7) == 0)
-                     val -= NT_IMAGE_BASE;
-                   if (strncmp (sec->name, ".reloc", 6) == 0)
-                     val -= NT_IMAGE_BASE;
-                   else if (strncmp (sec->name, ".edata", 5) == 0)
-                     val -= NT_IMAGE_BASE;
-                   else if (strncmp (sec->name, ".rsrc$", 6) == 0) 
-                     {
-                       val -= NT_IMAGE_BASE;
-                       val += sec->vma;
-                     }
-                 }
-             }
+                    + sym->n_value);
+             if (! obj_pe (input_bfd))
+               val -= sec->vma;
            }
        }
       else
            }
        }
       else
@@ -2336,25 +2652,8 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
              val = (h->root.u.def.value
                     + sec->output_section->vma
                     + sec->output_offset);
              val = (h->root.u.def.value
                     + sec->output_section->vma
                     + sec->output_offset);
-             if (obj_pe (output_bfd)) {
-               /* Make a correction here to val if the sec is either .rsrc
-                  or .idata */
-               if (strcmp (input_section->name, ".text") != 0)
-                 {
-                   if (strncmp (sec->name, ".idata$", 7) == 0)
-                     val -= NT_IMAGE_BASE;
-                   else if (strncmp (sec->name, ".reloc", 5) == 0)
-                     val -= NT_IMAGE_BASE;
-                   else if (strncmp (sec->name, ".edata", 5) == 0)
-                     val -= NT_IMAGE_BASE;
-                   else if (strncmp (sec->name, ".rsrc$", 6) == 0) 
-                     {
-                       val -= NT_IMAGE_BASE;
-                       val += sec->vma;
-                     }
-                 }
              }
              }
-           }
+
          else if (! info->relocateable)
            {
              if (! ((*info->callbacks->undefined_symbol)
          else if (! info->relocateable)
            {
              if (! ((*info->callbacks->undefined_symbol)
@@ -2364,117 +2663,29 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
            }
        }
 
            }
        }
 
-      if (obj_pe (output_bfd)) {
-
-       /* Here's where we will collect the information about the dll .idata$4 
-          and 5 entries and fix up the vals for .idata$2 information.  When
-          we encounter processing for .idata$5 (this could also be done for
-          .idata$4) we will keep track of the number of entries made for a
-          particular dll.  Now if we are processing .idata$2 input_section,
-          then we know how many entries have been made from each dll and we
-          have to fix up the .idata$2 start addresses for .idata$4 and 
-          .idata$5. */
-       add_to_val = 0;
-       if (strncmp (input_section->name, ".idata$5", 8) == 0)
-         {
-           if (num_DLLs == 0)  /* this is the first one */
-             {
-               num_DLLs += 1;
-               MS_DLL[num_DLLs].DLL_name = input_bfd->filename;
-               MS_DLL[num_DLLs].num_entries += 1;
-             }
-           else if (!strcmp (input_bfd->filename, MS_DLL[num_DLLs].DLL_name))
-             {
-               /* this is just another entry */
-               MS_DLL[num_DLLs].num_entries += 1;
-             }
-           else
-             {
-               /* This is a new DLL */
-               num_DLLs += 1;
-               MS_DLL[num_DLLs].DLL_name = input_bfd->filename;
-               MS_DLL[num_DLLs].num_entries += 1; 
-             }
-           all_entries += 1;
-         }
-
-       else if (strncmp (input_section->name, ".idata$2", 8) == 0)
-         {
-           /* All information about the number of entries needed from each
-              DLL has been collected at this point.  Now we actually want to
-              make and adjustment to the val's for .idata$4 and .idata$5
-              which are part of the .idata$2 section. */
-           /* first we have to get the symbol name from sym.  This will be
-              either .idata$4, .idata$5 or .idata$6.  A 'fixup' is computed for
-              .idata$4 and .idata$5 but not for .idata$6 (this value is handled
-              correctly already and doesn't have to be fixed) */
-           const char *name;
-           char buf[SYMNMLEN + 1];
-
-           if (sym->_n._n_n._n_zeroes == 0 && sym->_n._n_n._n_offset != 0)
-             name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
-           else
-             {
-               strncpy (buf, sym->_n._n_name, SYMNMLEN);
-               buf[SYMNMLEN] = '\0';
-               name = buf;
-             }
-
-           if (num_DLLs_done)
-             {
-               /* we have done at least one.  The val fixups are based on the
-                  previous fixups */
-               if (strncmp (name, ".idata$4", 8) == 0)
-                 {
-                   add_to_val = idata_4_prev +
-                     ((MS_DLL[num_DLLs_done].num_entries + 1) * 4);
-                   idata_4_prev = add_to_val;
-                 }
-               else if (strncmp (name, ".idata$5", 8) == 0)
-                 {
-                   add_to_val = idata_5_prev +
-                     ((MS_DLL[num_DLLs_done].num_entries + 1) * 4);
-                   idata_5_prev = add_to_val;
-                   num_DLLs_done += 1; /* assuming that idata$5 is done after $4*/
-                 }
-             }
-           else
-             {
-               /* This is the first one.  The other idata$4 and 5 entries will be
-                  computed from these */
-               if (strncmp (name, ".idata$4", 8) == 0)
-                 {
-                   add_to_val = ((num_DLLs - 1) * 0x14) + 0x28;
-                   idata_4_prev = add_to_val;
-                 }
-               else if (strncmp (name, ".idata$5", 8) == 0)
-                 {
-                   add_to_val = idata_4_prev + (all_entries + num_DLLs) * 4;
-                   idata_5_prev = add_to_val;
-                   num_DLLs_done += 1; /* assuming that idata$5 is done after $4*/
-                 }
-            
-             }
-         }
-       val = val + add_to_val;
-       
-      }
-
       if (info->base_file)
        {
       if (info->base_file)
        {
-         /* So if this is non pcrelative, and is referenced
-            to a section or a common symbol, then it needs a reloc */
-         if (!howto->pc_relative
-             && (sym->n_scnum
-                 || sym->n_value))
+         /* Emit a reloc if the backend thinks it needs it. */
+         if (sym && pe_data (output_bfd)->in_reloc_p (output_bfd, howto))
            {
            {
-             /* relocation to a symbol in a section which
-                isn't absolute - we output the address here 
-                to a file */
-             bfd_vma addr = rel->r_vaddr +
-               + input_section->output_offset 
-                 + input_section->output_section->vma;
-             fwrite (&addr, 1,4, info->base_file);
+             /* Relocation to a symbol in a section which isn't
+                absolute.  We output the address here to a file.
+                This file is then read by dlltool when generating the
+                reloc section.  Note that the base file is not
+                portable between systems.  We write out a long here,
+                and dlltool reads in a long.  */
+             long addr = (rel->r_vaddr 
+                          - input_section->vma 
+                          + input_section->output_offset 
+                          + input_section->output_section->vma);
+             if (coff_data (output_bfd)->pe)
+               addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
+             if (fwrite (&addr, 1, sizeof (long), (FILE *) info->base_file)
+                 != sizeof (long))
+               {
+                 bfd_set_error (bfd_error_system_call);
+                 return false;
+               }
            }
        }
   
            }
        }
   
@@ -2489,6 +2700,13 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
          abort ();
        case bfd_reloc_ok:
          break;
          abort ();
        case bfd_reloc_ok:
          break;
+       case bfd_reloc_outofrange:
+         (*_bfd_error_handler)
+           ("%s: bad reloc address 0x%lx in section `%s'",
+            bfd_get_filename (input_bfd),
+            (unsigned long) rel->r_vaddr,
+            bfd_get_section_name (input_bfd, input_section));
+         return false;
        case bfd_reloc_overflow:
          {
            const char *name;
        case bfd_reloc_overflow:
          {
            const char *name;
@@ -2498,14 +2716,11 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
              name = "*ABS*";
            else if (h != NULL)
              name = h->root.root.string;
              name = "*ABS*";
            else if (h != NULL)
              name = h->root.root.string;
-           else if (sym->_n._n_n._n_zeroes == 0
-                    && sym->_n._n_n._n_offset != 0)
-             name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
            else
              {
            else
              {
-               strncpy (buf, sym->_n._n_name, SYMNMLEN);
-               buf[SYMNMLEN] = '\0';
-               name = buf;
+               name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
+               if (name == NULL)
+                 return false;
              }
 
            if (! ((*info->callbacks->reloc_overflow)
              }
 
            if (! ((*info->callbacks->reloc_overflow)
@@ -2515,6 +2730,6 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
          }
        }
     }
          }
        }
     }
-
   return true;
 }
   return true;
 }
+
This page took 0.052156 seconds and 4 git commands to generate.