First round ld support for PPC PE
[deliverable/binutils-gdb.git] / bfd / cofflink.c
index efc830517833f68da263ab47c9f5d1e962cfbcef..99b5f301db32c0dd017c1570a2e6cf11d38ff74a 100644 (file)
@@ -29,6 +29,77 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #define STRING_SIZE_SIZE (4)
 
+/* We use a hash table to merge identical enum, struct, and union
+   definitions in the linker.  */
+
+/* Information we keep for a single element (an enum value, a
+   structure or union field) in the debug merge hash table.  */
+
+struct coff_debug_merge_element
+{
+  /* Next element.  */
+  struct coff_debug_merge_element *next;
+
+  /* Name.  */
+  const char *name;
+
+  /* Type.  */
+  unsigned int type;
+
+  /* Symbol index for complex type.  */
+  long tagndx;
+};
+
+/* A linked list of debug merge entries for a given name.  */
+
+struct coff_debug_merge_type
+{
+  /* Next type with the same name.  */
+  struct coff_debug_merge_type *next;
+
+  /* Class of type.  */
+  int class;
+
+  /* Symbol index where this type is defined.  */
+  long indx;
+
+  /* List of elements.  */
+  struct coff_debug_merge_element *elements;
+};
+
+/* Information we store in the debug merge hash table.  */
+
+struct coff_debug_merge_hash_entry
+{
+  struct bfd_hash_entry root;
+
+  /* A list of types with this name.  */
+  struct coff_debug_merge_type *types;
+};
+
+/* The debug merge hash table.  */
+
+struct coff_debug_merge_hash_table
+{
+  struct bfd_hash_table root;
+};
+
+/* Initialize a COFF debug merge hash table.  */
+
+#define coff_debug_merge_hash_table_init(table) \
+  (bfd_hash_table_init (&(table)->root, coff_debug_merge_hash_newfunc))
+
+/* Free a COFF debug merge hash table.  */
+
+#define coff_debug_merge_hash_table_free(table) \
+  (bfd_hash_table_free (&(table)->root))
+
+/* Look up an entry in a COFF debug merge hash table.  */
+
+#define coff_debug_merge_hash_lookup(table, string, create, copy) \
+  ((struct coff_debug_merge_hash_entry *) \
+   bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
+
 /* Information we keep for each section in the output file when doing
    a relocateable link.  */
 
@@ -51,7 +122,7 @@ struct coff_final_link_info
   bfd *output_bfd;
   /* Used to indicate failure in traversal routine.  */
   boolean failed;
-  /* Hash table for long symbol name.  */
+  /* Hash table for long symbol names.  */
   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.  */
@@ -60,6 +131,8 @@ struct coff_final_link_info
   long last_file_index;
   /* Contents of last C_FILE symbol.  */
   struct internal_syment last_file;
+  /* Hash table used to merge debug information.  */
+  struct coff_debug_merge_hash_table debug_merge;
   /* 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.  */
@@ -78,20 +151,14 @@ struct coff_final_link_info
   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
+static struct bfd_hash_entry *coff_debug_merge_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_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 *));
@@ -103,49 +170,10 @@ 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;
-
-
-
 /* 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;
@@ -176,11 +204,25 @@ coff_link_hash_newfunc (entry, table, string)
       ret->numaux = 0;
       ret->auxbfd = NULL;
       ret->aux = NULL;
+      ret->toc_offset = 1; /* invalid toc address, sets the high bit */
     }
 
   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 *));
+{
+  return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
+}
+
 /* Create a COFF linker hash table.  */
 
 struct bfd_link_hash_table *
@@ -190,21 +232,56 @@ _bfd_coff_link_hash_table_create (abfd)
   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)
     {
       bfd_set_error (bfd_error_no_memory);
       return NULL;
     }
-  if (! _bfd_link_hash_table_init (&ret->root, abfd,
-                                  coff_link_hash_newfunc))
+  if (! _bfd_coff_link_hash_table_init (ret, abfd,
+                                       _bfd_coff_link_hash_newfunc))
     {
-      free (ret);
+      bfd_release (abfd, ret);
       return (struct bfd_link_hash_table *) NULL;
     }
   return &ret->root;
 }
 
+/* Create an entry in a COFF debug merge hash table.  */
+
+static struct bfd_hash_entry *
+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)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      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.  */
 
@@ -233,13 +310,14 @@ coff_link_add_object_symbols (abfd, 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;
+
   if (! info->keep_memory)
     {
-      if (! coff_link_free_symbols (abfd))
+      if (! _bfd_coff_free_symbols (abfd))
        return false;
     }
   return true;
@@ -256,7 +334,7 @@ coff_link_check_archive_element (abfd, info, 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))
@@ -270,127 +348,13 @@ coff_link_check_archive_element (abfd, info, pneeded)
 
   if (! info->keep_memory || ! *pneeded)
     {
-      if (! coff_link_free_symbols (abfd))
+      if (! _bfd_coff_free_symbols (abfd))
        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.  */
 
@@ -401,7 +365,6 @@ coff_link_check_ar_symbols (abfd, info, pneeded)
      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;
@@ -409,7 +372,6 @@ coff_link_check_ar_symbols (abfd, info, pneeded)
   *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);
@@ -431,27 +393,9 @@ coff_link_check_ar_symbols (abfd, info, pneeded)
          /* 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
@@ -483,7 +427,6 @@ coff_link_add_symbols (abfd, info)
      struct bfd_link_info *info;
 {
   boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
-  const char *strings;
   boolean default_copy;
   bfd_size_type symcount;
   struct coff_link_hash_entry **sym_hash;
@@ -492,7 +435,6 @@ coff_link_add_symbols (abfd, info)
   bfd_byte *esym_end;
 
   sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global;
-  strings = NULL;
 
   if (info->keep_memory)
     default_copy = false;
@@ -538,28 +480,16 @@ coff_link_add_symbols (abfd, info)
 
          /* 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)
+           return false;
+
+         /* We must copy the name into memory if we got it from the
+             syment itself, rather than the string table.  */
          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;
 
@@ -601,6 +531,7 @@ coff_link_add_symbols (abfd, info)
                  (*sym_hash)->type = sym.n_type;
                  (*sym_hash)->numaux = sym.n_numaux;
                  (*sym_hash)->auxbfd = abfd;
+                 (*sym_hash)->toc_offset = 1;
                  if (sym.n_numaux != 0)
                    {
                      union internal_auxent *alloc;
@@ -635,127 +566,7 @@ coff_link_add_symbols (abfd, info)
 
   return true;
 }
-
-/* parse out a -heap <reserved>,<commit> line */
-
-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;
-}
-
-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;
-
-         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);
-       }
-      else 
-       s++;
-    }
-  free (copy);
-  return 1;
-}
+\f
 /* Do the final link step.  */
 
 boolean
@@ -765,6 +576,7 @@ _bfd_coff_final_link (abfd, info)
 {
   bfd_size_type symesz;
   struct coff_final_link_info finfo;
+  boolean debug_merge_allocated;
   asection *o;
   struct bfd_link_order *p;
   size_t max_contents_size;
@@ -795,20 +607,18 @@ _bfd_coff_final_link (abfd, info)
   finfo.contents = NULL;
   finfo.external_relocs = NULL;
   finfo.internal_relocs = NULL;
+  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;
 
+  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)
     bfd_coff_compute_section_file_positions (abfd);
@@ -961,7 +771,8 @@ _bfd_coff_final_link (abfd, info)
                                 * 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.outsyms = ((bfd_byte *)
+                  malloc ((size_t) ((max_sym_count + 1) * symesz)));
   finfo.linenos = (bfd_byte *) malloc (max_lineno_count
                                       * bfd_coff_linesz (abfd));
   finfo.contents = (bfd_byte *) malloc (max_contents_size);
@@ -991,6 +802,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;
+
+  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)
@@ -1022,6 +840,10 @@ _bfd_coff_final_link (abfd, info)
     }
 
   /* Free up the buffers used by 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);
@@ -1062,7 +884,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
-      && 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,
@@ -1181,6 +1003,8 @@ _bfd_coff_final_link (abfd, info)
   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)
@@ -1217,6 +1041,136 @@ _bfd_coff_final_link (abfd, info)
   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 = malloc ((size_t) 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;
+
+         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);
+       }
+      else 
+       s++;
+    }
+  free (copy);
+  return 1;
+}
+
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.  */
 
@@ -1243,10 +1197,9 @@ coff_link_input_bfd (finfo, input_bfd)
   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_size_type relsz;
   asection *o;
 
   /* Move all the symbols to the output file.  */
@@ -1274,7 +1227,7 @@ coff_link_input_bfd (finfo, input_bfd)
   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);
@@ -1285,9 +1238,9 @@ coff_link_input_bfd (finfo, input_bfd)
   output_index = syment_base;
   outsym = finfo->outsyms;
 
-  if (obj_pe (output_bfd))
+  if (coff_data(output_bfd)->pe)
       {
-       if (!process_embedded_commands (input_bfd))
+       if (!process_embedded_commands (output_bfd, finfo->info, input_bfd))
          return false;
       }
 
@@ -1364,23 +1317,9 @@ coff_link_input_bfd (finfo, input_bfd)
          const char *name;
          char buf[SYMNMLEN + 1];
 
-         if (isym._n._n_n._n_zeroes == 0
-             && isym._n._n_n._n_offset != 0)
-           {
-             if (strings == NULL)
-               {
-                 strings = coff_read_string_table (input_bfd);
-                 if (strings == NULL)
-                   return false;
-               }
-             name = strings + isym._n._n_n._n_offset;
-           }
-         else
-           {
-             memcpy (buf, isym._n._n_name, SYMNMLEN);
-             buf[SYMNMLEN] = '\0';
-             name = buf;
-           }
+         name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
+         if (name == NULL)
+           return false;
 
          if ((finfo->info->strip == strip_some
               && (bfd_hash_lookup (finfo->info->keep_hash, name, false,
@@ -1392,6 +1331,175 @@ coff_link_input_bfd (finfo, input_bfd)
            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;
+         struct coff_debug_merge_type *mtl;
+
+         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 == bfd_get_symbol_leading_char (input_bfd)
+                 && (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)
+           {
+             bfd_set_error (bfd_error_no_memory);
+             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)
+           {
+             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)
+               {
+                 bfd_set_error (bfd_error_no_memory);
+                 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)
+               {
+                 bfd_set_error (bfd_error_no_memory);
+                 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)
+               {
+                 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;
+                   }
+               }
+             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.  */
+         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.  */
       if (! skip)
        {
@@ -1408,14 +1516,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_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;
@@ -1442,11 +1546,11 @@ coff_link_input_bfd (finfo, input_bfd)
          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;
-                 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,
@@ -1527,7 +1631,8 @@ coff_link_input_bfd (finfo, input_bfd)
 
       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;
@@ -1579,7 +1684,7 @@ coff_link_input_bfd (finfo, input_bfd)
                                  >= 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;
                        }
@@ -1593,7 +1698,7 @@ coff_link_input_bfd (finfo, input_bfd)
                }
              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)
@@ -1621,11 +1726,13 @@ 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 = 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 = indx;
+                       auxp->x_sym.x_tagndx.l = symindx;
                    }
                }
 
@@ -1656,7 +1763,17 @@ coff_link_input_bfd (finfo, input_bfd)
          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
@@ -1676,7 +1793,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
-                      && (iline.l_addr.l_symndx
+                      && ((unsigned long) iline.l_addr.l_symndx
                           < obj_raw_syment_count (input_bfd)))
                {
                  long indx;
@@ -1754,7 +1871,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
-      && 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,
@@ -1769,8 +1886,9 @@ coff_link_input_bfd (finfo, input_bfd)
       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)
@@ -1781,53 +1899,61 @@ coff_link_input_bfd (finfo, input_bfd)
     }
 
   /* 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)
     {
+      bfd_byte *contents;
+
       if ((o->flags & SEC_HAS_CONTENTS) == 0)
-       continue;
+       {
+         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;
+           }
 
-      if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
-                                     (file_ptr) 0, o->_raw_size))
-       return false;
+         continue;
+       }
+
+      if (coff_section_data (input_bfd, o) != NULL
+         && coff_section_data (input_bfd, o)->contents != NULL)
+       contents = coff_section_data (input_bfd, o)->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;
-         bfd_byte *erel;
-         bfd_byte *erel_end;
          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;
-         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,
-                                          finfo->contents,
+                                          contents,
                                           internal_relocs,
                                           finfo->internal_syms,
                                           finfo->sec_ptrs))
@@ -1905,23 +2031,10 @@ coff_link_input_bfd (finfo, input_bfd)
                              worth it.  */
                          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,
@@ -1937,7 +2050,7 @@ coff_link_input_bfd (finfo, input_bfd)
 
       /* Write out the modified section contents.  */
       if (! bfd_set_section_contents (output_bfd, o->output_section,
-                                     finfo->contents, o->output_offset,
+                                     contents, o->output_offset,
                                      (o->_cooked_size != 0
                                       ? o->_cooked_size
                                       : o->_raw_size)))
@@ -1946,7 +2059,7 @@ coff_link_input_bfd (finfo, input_bfd)
 
   if (! finfo->info->keep_memory)
     {
-      if (! coff_link_free_symbols (input_bfd))
+      if (! _bfd_coff_free_symbols (input_bfd))
        return false;
     }
 
@@ -2235,7 +2348,6 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
   struct internal_reloc *rel;
   struct internal_reloc *relend;
 
-
   rel = relocs;
   relend = rel + input_section->reloc_count;
   for (; rel < relend; rel++)
@@ -2277,21 +2389,11 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
       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.  */
-
       val = 0;
 
       if (h == NULL)
        {
          asection *sec;
-          int i;
 
          if (symndx == -1)
            {
@@ -2305,23 +2407,6 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
                     + 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$nnn
-                  or .idata$nnn or reloc or edata */
-               if (strcmp (input_section->name, ".text") != 0)
-                 {
-                   if (strncmp (sec->name, ".idata$", 7) == 0
-                       || strcmp (sec->name, ".reloc") == 0
-                       || strcmp (sec->name, ".edata") == 0)
-                     val -= NT_IMAGE_BASE;
-                   else if (strncmp (sec->name, ".rsrc$", 6) == 0) 
-                     {
-                       val -= NT_IMAGE_BASE;
-                       val += sec->vma;
-                     }
-                 }
-             }
            }
        }
       else
@@ -2335,23 +2420,8 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
              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$nnn
-                  or .idata$nnnn or reloc or edata. */
-               if (strcmp (input_section->name, ".text") != 0)
-                 {
-                   if (strncmp (sec->name, ".idata$", 7) == 0
-                       || strcmp (sec->name, ".reloc") == 0
-                       || strcmp (sec->name, ".edata") == 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)
@@ -2361,116 +2431,20 @@ _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)
        {
-         /* 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->vma 
                + input_section->output_offset 
                  + input_section->output_section->vma;
+             if (coff_data(output_bfd)->pe)
+               addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
              fwrite (&addr, 1,4, (FILE *) info->base_file);
            }
        }
@@ -2495,14 +2469,11 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
              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
              {
-               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)
@@ -2512,6 +2483,6 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
          }
        }
     }
-
   return true;
 }
+
This page took 0.073662 seconds and 4 git commands to generate.