diff --git a/bfd/cofflink.c b/bfd/cofflink.c
index 87769648c27..2e6fe26bec0 100644
--- a/bfd/cofflink.c
+++ b/bfd/cofflink.c
@@ -1,5 +1,5 @@
 /* COFF specific linker code.
-   Copyright 1994 Free Software Foundation, Inc.
+   Copyright 1994, 1995 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -78,6 +78,9 @@ 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
@@ -100,6 +103,45 @@ 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 *
@@ -304,7 +346,7 @@ coff_read_string_table (abfd)
   else
     {
 #if STRING_SIZE_SIZE == 4
-      strsize = bfd_h_get_32 (abfd, extstrsize);
+      strsize = bfd_h_get_32 (abfd, (bfd_byte *) extstrsize);
 #else
  #error Change bfd_h_get_32
 #endif
@@ -566,9 +608,10 @@ coff_link_add_symbols (abfd, info)
 		      bfd_byte *eaux;
 		      union internal_auxent *iaux;
 
-		      alloc = bfd_hash_allocate (&info->hash->table,
-						 (sym.n_numaux
-						  * sizeof (*alloc)));
+		      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);
@@ -593,6 +636,126 @@ 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 (!s) 
+    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;
+}
 /* Do the final link step.  */
 
 boolean
@@ -633,6 +796,15 @@ _bfd_coff_final_link (abfd, info)
   finfo.external_relocs = NULL;
   finfo.internal_relocs = NULL;
 
+  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;
+    }
+
   finfo.strtab = _bfd_stringtab_init ();
   if (finfo.strtab == NULL)
     goto error_return;
@@ -989,7 +1161,7 @@ _bfd_coff_final_link (abfd, info)
 #if STRING_SIZE_SIZE == 4
   bfd_h_put_32 (abfd,
 		_bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
-		strbuf);
+		(bfd_byte *) strbuf);
 #else
  #error Change bfd_h_put_32
 #endif
@@ -1054,6 +1226,9 @@ coff_link_input_bfd (finfo, input_bfd)
      bfd *input_bfd;
 {
   boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *));
+  boolean (*adjust_symndx) PARAMS ((bfd *, struct bfd_link_info *, bfd *,
+				    asection *, struct internal_reloc *,
+				    boolean *));
   bfd *output_bfd;
   const char *strings;
   bfd_size_type syment_base;
@@ -1109,6 +1284,13 @@ coff_link_input_bfd (finfo, input_bfd)
   indexp = finfo->sym_indices;
   output_index = syment_base;
   outsym = finfo->outsyms;
+
+  if (obj_pe (output_bfd))
+      {
+	if (!process_embedded_commands (input_bfd))
+	  return false;
+      }
+
   while (esym < esym_end)
     {
       struct internal_syment isym;
@@ -1387,7 +1569,8 @@ coff_link_input_bfd (finfo, input_bfd)
 		{
 		  /* If this is a long filename, we must put it in the
 		     string table.  */
-		  if (auxp->x_file.x_n.x_zeroes == 0)
+		  if (auxp->x_file.x_n.x_zeroes == 0
+		      && auxp->x_file.x_n.x_offset != 0)
 		    {
 		      const char *filename;
 		      bfd_size_type indx;
@@ -1570,13 +1753,14 @@ coff_link_input_bfd (finfo, input_bfd)
      symbol will be the first symbol in the next input file.  In the
      normal case, this will save us from writing out the C_FILE symbol
      again.  */
-  if (finfo->last_file_index >= syment_base)
+  if (finfo->last_file_index != -1
+      && finfo->last_file_index >= syment_base)
     {
       finfo->last_file.n_value = output_index;
       bfd_coff_swap_sym_out (output_bfd, (PTR) &finfo->last_file,
 			     (PTR) (finfo->outsyms
-				    + ((finfo->last_file_index - syment_base)
-				       * osymesz)));
+ 				    + ((finfo->last_file_index - syment_base)
+ 				       * osymesz)));
     }
 
   /* Write the modified symbols to the output file.  */
@@ -1598,6 +1782,7 @@ 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)
     {
       if ((o->flags & SEC_HAS_CONTENTS) == 0)
@@ -1605,7 +1790,7 @@ coff_link_input_bfd (finfo, input_bfd)
 
       if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
 				      (file_ptr) 0, o->_raw_size))
-	return false;
+ 	return false;
 
       if ((o->flags & SEC_RELOC) != 0)
 	{
@@ -1655,7 +1840,6 @@ coff_link_input_bfd (finfo, input_bfd)
 	      struct coff_link_hash_entry **rel_hash;
 
 	      offset = o->output_section->vma + o->output_offset - o->vma;
-
 	      irel = internal_relocs;
 	      irelend = irel + o->reloc_count;
 	      rel_hash = (finfo->section_info[target_index].rel_hashes
@@ -1663,6 +1847,7 @@ coff_link_input_bfd (finfo, input_bfd)
 	      for (; irel < irelend; irel++, rel_hash++)
 		{
 		  struct coff_link_hash_entry *h;
+		  boolean adjusted;
 
 		  *rel_hash = NULL;
 
@@ -1673,6 +1858,16 @@ coff_link_input_bfd (finfo, input_bfd)
 		  if (irel->r_symndx == -1)
 		    continue;
 
+		  if (adjust_symndx)
+		    {
+		      if (! (*adjust_symndx) (output_bfd, finfo->info,
+					      input_bfd, o, irel,
+					      &adjusted))
+			return false;
+		      if (adjusted)
+			continue;
+		    }
+
 		  h = obj_coff_sym_hashes (input_bfd)[irel->r_symndx];
 		  if (h != NULL)
 		    {
@@ -1792,12 +1987,13 @@ coff_write_global_sym (h, data)
       return false;
 
     case bfd_link_hash_undefined:
-    case bfd_link_hash_weak:
+    case bfd_link_hash_undefweak:
       isym.n_scnum = N_UNDEF;
       isym.n_value = 0;
       break;
 
     case bfd_link_hash_defined:
+    case bfd_link_hash_defweak:
       {
 	asection *sec;
 
@@ -1897,7 +2093,7 @@ coff_reloc_link_order (output_bfd, finfo, output_section, link_order)
      asection *output_section;
      struct bfd_link_order *link_order;
 {
-  const reloc_howto_type *howto;
+  reloc_howto_type *howto;
   struct internal_reloc *irel;
   struct coff_link_hash_entry **rel_hash_ptr;
 
@@ -2039,6 +2235,7 @@ _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++)
@@ -2048,7 +2245,7 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
       struct internal_syment *sym;
       bfd_vma addend;
       bfd_vma val;
-      const reloc_howto_type *howto;
+      reloc_howto_type *howto;
       bfd_reloc_status_type rstat;
 
       symndx = rel->r_symndx;
@@ -2068,21 +2265,33 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
          size of the symbol is included in the section contents, or it
          is not.  We assume that the size is not included, and force
          the rtype_to_howto function to adjust the addend as needed.  */
+
       if (sym != NULL && sym->n_scnum != 0)
 	addend = - sym->n_value;
       else
 	addend = 0;
 
+
       howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
 				       sym, &addend);
       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)
 	    {
@@ -2092,15 +2301,30 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
 	  else
 	    {
 	      sec = sections[symndx];
-	      val = (sec->output_section->vma
+              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;
+		    else if (strncmp (sec->name, ".rsrc$", 6) == 0) 
+		      {
+			val -= NT_IMAGE_BASE;
+			val += sec->vma;
+		      }
+		  }
+	      }
 	    }
 	}
       else
 	{
-	  if (h->root.type == bfd_link_hash_defined)
+	  if (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
 	    {
 	      asection *sec;
 
@@ -2108,6 +2332,20 @@ _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
+		   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, ".rsrc$", 6) == 0) 
+		      {
+			val -= NT_IMAGE_BASE;
+			val += sec->vma;
+		      }
+		  }
+	      }
 	    }
 	  else if (! info->relocateable)
 	    {
@@ -2118,6 +2356,102 @@ _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;
+       
+      }
+  
       rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
 					contents,
 					rel->r_vaddr - input_section->vma,