OSDN Git Service

Add WinCE support.
[pf3gnuchains/pf3gnuchains3x.git] / bfd / peigen.c
index 8d623bd..639ea89 100644 (file)
@@ -78,7 +78,10 @@ PE/PEI rearrangement (and code added): Donn Terry
    anybody wants to revive the code, you will have to figure out how
    to handle those issues.  */
 
-boolean in_reloc_p PARAMS((bfd *, reloc_howto_type *));
+static void add_data_entry
+  PARAMS ((bfd *, struct internal_extra_pe_aouthdr *, int, char *, bfd_vma));
+static boolean pe_print_pdata PARAMS ((bfd *, PTR));
+static boolean pe_print_reloc PARAMS ((bfd *, PTR));
 
 /**********************************************************************/
 
@@ -497,7 +500,10 @@ _bfd_pei_swap_aouthdr_in (abfd, aouthdr_ext1, aouthdr_int1)
 
 }
 
-static void add_data_entry (abfd, aout, idx, name, base)
+/* A support function for below.  */
+
+static void
+add_data_entry (abfd, aout, idx, name, base)
      bfd *abfd;
      struct internal_extra_pe_aouthdr *aout;
      int idx;
@@ -560,31 +566,27 @@ _bfd_pei_swap_aouthdr_out (abfd, in, out)
   /* first null out all data directory entries .. */
   memset (extra->DataDirectory, sizeof (extra->DataDirectory), 0);
 
-  add_data_entry (abfd, extra, 0, ".edata", ib);
-  add_data_entry (abfd, extra, 1, ".idata", ib);
-  add_data_entry (abfd, extra, 2, ".rsrc" ,ib);
+  add_data_entry (abfd, extra, 0, ".edata", 0);
 
-#ifdef POWERPC_LE_PE
-  /* FIXME: do other PE platforms use this? */
-  add_data_entry (abfd, extra, 3, ".pdata" ,ib);
-#endif
+  /* Don't call add_data_entry for .idata$2 or .idata$5.  It's done in
+     bfd_coff_final_link where all the required information is
+     available.  */
 
-  add_data_entry (abfd, extra, 5, ".reloc", ib);
+  /* However, until other .idata fixes are made (pending patch), the
+     entry for .idata is needed for backwards compatability.  FIXME.  */
+  add_data_entry (abfd, extra, 1, ".idata" ,0);
 
-#ifdef POWERPC_LE_PE
-  /* On the PPC NT system, this field is set up as follows. It is not
-     an "officially" reserved field, so it currently has no title.
-     first_thunk_address is idata$5, and the thunk_size is the size of
-     the idata$5 chunk of the idata section.  */
-  extra->DataDirectory[12].VirtualAddress = first_thunk_address;
-  extra->DataDirectory[12].Size = thunk_size;
-
-  /* On the PPC NT system, the size of the directory entry is not the
-     size of the entire section. It's actually offset to the end of
-     the idata$3 component of the idata section. This is the size of
-     the entire import table. (also known as the start of idata$4).  */
-  extra->DataDirectory[1].Size = import_table_size;
-#endif
+  add_data_entry (abfd, extra, 2, ".rsrc" ,0);
+
+  add_data_entry (abfd, extra, 3, ".pdata", 0);
+
+  /* For some reason, the virtual size (which is what's set by
+     add_data_entry) for .reloc is not the same as the size recorded
+     in this slot by MSVC; it doesn't seem to cause problems (so far),
+     but since it's the best we've got, use it.  It does do the right
+     thing for .pdata.  */
+  if (pe_data (abfd)->has_reloc_section)
+    add_data_entry (abfd, extra, 5, ".reloc", 0);
 
   {
     asection *sec;
@@ -600,7 +602,12 @@ _bfd_pei_swap_aouthdr_out (abfd, in, out)
          dsize += rounded;
        if (sec->flags & SEC_CODE)
          tsize += rounded;
-       isize += SA(rounded);
+       /* The image size is the total VIRTUAL size (which is what is
+          in the virt_size field).  Files have been seen (from MSVC
+          5.0 link.exe) where the file size of the .data segment is
+          quite small compared to the virtual size.  Without this
+          fix, strip munges the file.  */
+       isize += SA (FA (pei_section_data (abfd, sec)->virt_size));
       }
 
     aouthdr_in->dsize = dsize;
@@ -611,13 +618,13 @@ _bfd_pei_swap_aouthdr_out (abfd, in, out)
   extra->SizeOfHeaders = abfd->sections->filepos;
   bfd_h_put_16(abfd, aouthdr_in->magic, (bfd_byte *) aouthdr_out->standard.magic);
 
-#ifdef POWERPC_LE_PE
-  /* this little piece of magic sets the "linker version" field to 2.60 */
-  bfd_h_put_16(abfd, 2  + 60 * 256, (bfd_byte *) aouthdr_out->standard.vstamp);
-#else
-  /* this little piece of magic sets the "linker version" field to 2.55 */
-  bfd_h_put_16(abfd, 2  + 55 * 256, (bfd_byte *) aouthdr_out->standard.vstamp);
-#endif
+#define LINKER_VERSION 256 /* That is, 2.56 */
+
+  /* This piece of magic sets the "linker version" field to
+     LINKER_VERSION.  */
+  bfd_h_put_16 (abfd,
+               LINKER_VERSION / 100 + (LINKER_VERSION % 100) * 256,
+               (bfd_byte *) aouthdr_out->standard.vstamp);
 
   PUT_AOUTHDR_TSIZE (abfd, aouthdr_in->tsize, (bfd_byte *) aouthdr_out->standard.tsize);
   PUT_AOUTHDR_DSIZE (abfd, aouthdr_in->dsize, (bfd_byte *) aouthdr_out->standard.dsize);
@@ -855,11 +862,11 @@ _bfd_pei_swap_scnhdr_out (abfd, in, out)
                     & 0xffffffff),
                    (bfd_byte *) scnhdr_ext->s_vaddr);
 
-  /* NT wants the size data to be rounded up to the next NT_FILE_ALIGNMENT
-     value except for the BSS section, its s_size should be 0 */
+  /* NT wants the size data to be rounded up to the next
+     NT_FILE_ALIGNMENT, but zero if it has no content (as in .bss,
+     sometimes).  */
 
-
-  if (strcmp (scnhdr_int->s_name, _BSS) == 0) 
+  if ((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0)
     {
       ps = scnhdr_int->s_size;
       ss = 0;
@@ -874,6 +881,7 @@ _bfd_pei_swap_scnhdr_out (abfd, in, out)
                   (bfd_byte *) scnhdr_ext->s_size);
 
 
+  /* s_paddr in PE is really the virtual size.  */
   PUT_SCNHDR_PADDR (abfd, ps, (bfd_byte *) scnhdr_ext->s_paddr);
 
   PUT_SCNHDR_SCNPTR (abfd, scnhdr_int->s_scnptr,
@@ -897,76 +905,55 @@ _bfd_pei_swap_scnhdr_out (abfd, in, out)
   /* FIXME: even worse, I don't see how to get the original alignment field*/
   /*        back...                                                        */
 
-  /* FIXME: Basing this on section names is bogus.  Also, this should
-     be in sec_to_styp_flags.  */
-
   {
     int flags = scnhdr_int->s_flags;
-    if (strcmp (scnhdr_int->s_name, ".data")  == 0 ||
-       strcmp (scnhdr_int->s_name, ".CRT")   == 0 ||
-       strcmp (scnhdr_int->s_name, ".bss")   == 0)
-      flags |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
-    else if (strcmp (scnhdr_int->s_name, ".text") == 0)
-      flags |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
-    else if (strcmp (scnhdr_int->s_name, ".reloc") == 0)
-      flags = (SEC_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
-              | IMAGE_SCN_MEM_SHARED);
-    else if (strcmp (scnhdr_int->s_name, ".idata") == 0)
-      flags = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | SEC_DATA;     
-    else if (strcmp (scnhdr_int->s_name, ".rdata") == 0
-            || strcmp (scnhdr_int->s_name, ".edata") == 0)
-      flags =  IMAGE_SCN_MEM_READ | SEC_DATA;     
-    else if (strcmp (scnhdr_int->s_name, ".pdata") == 0)
-      flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES |
-                         IMAGE_SCN_MEM_READ ;
-    /* Remember this field is a max of 8 chars, so the null is _not_ there
-       for an 8 character name like ".reldata". (yep. Stupid bug) */
-    else if (strncmp (scnhdr_int->s_name, ".reldata", 8) == 0)
-      flags =  IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_8BYTES |
-              IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE ;
-    else if (strcmp (scnhdr_int->s_name, ".ydata") == 0)
-      flags =  IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_8BYTES |
-              IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE ;
-    else if (strncmp (scnhdr_int->s_name, ".drectve", 8) == 0)
-      flags =  IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE ;
-    else if (strncmp (scnhdr_int->s_name, ".stab", 5) == 0)
-      flags |= (IMAGE_SCN_LNK_INFO | IMAGE_SCN_MEM_DISCARDABLE
-               | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ);
-    else if (strcmp (scnhdr_int->s_name, ".rsrc")  == 0)
-      flags |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED;
-    else
-      {
-       flags |= IMAGE_SCN_MEM_READ;
-       if (! (flags & SEC_READONLY))
-         flags |= IMAGE_SCN_MEM_WRITE;
-       if (flags & SEC_SHARED)
-         flags |= IMAGE_SCN_MEM_SHARED;
-      }
-
     bfd_h_put_32(abfd, flags, (bfd_byte *) scnhdr_ext->s_flags);
   }
 
-  if (scnhdr_int->s_nlnno <= 0xffff)
-    bfd_h_put_16(abfd, scnhdr_int->s_nlnno, (bfd_byte *) scnhdr_ext->s_nlnno);
-  else
+  if (coff_data (abfd)->link_info
+      && ! coff_data (abfd)->link_info->relocateable
+      && ! coff_data (abfd)->link_info->shared
+      && strcmp (scnhdr_int->s_name, ".text") == 0)
     {
-      (*_bfd_error_handler) (_("%s: line number overflow: 0x%lx > 0xffff"),
-                            bfd_get_filename (abfd),
-                            scnhdr_int->s_nlnno);
-      bfd_set_error (bfd_error_file_truncated);
-      bfd_h_put_16 (abfd, 0xffff, (bfd_byte *) scnhdr_ext->s_nlnno);
-      ret = 0;
+      /* By inference from looking at MS output, the 32 bit field
+        which is the combintion of the number_of_relocs and
+        number_of_linenos is used for the line number count in
+        executables.  A 16-bit field won't do for cc1.  The MS
+        document says that the number of relocs is zero for
+        executables, but the 17-th bit has been observed to be there.
+        Overflow is not an issue: a 4G-line program will overflow a
+        bunch of other fields long before this!  */
+      bfd_h_put_16 (abfd, scnhdr_int->s_nlnno & 0xffff,
+                   (bfd_byte *) scnhdr_ext->s_nlnno);
+      bfd_h_put_16 (abfd, scnhdr_int->s_nlnno >> 16,
+                   (bfd_byte *) scnhdr_ext->s_nreloc);
     }
-  if (scnhdr_int->s_nreloc <= 0xffff)
-    bfd_h_put_16(abfd, scnhdr_int->s_nreloc, (bfd_byte *) scnhdr_ext->s_nreloc);
   else
     {
-      (*_bfd_error_handler) (_("%s: reloc overflow: 0x%lx > 0xffff"),
-                            bfd_get_filename (abfd),
-                            scnhdr_int->s_nreloc);
-      bfd_set_error (bfd_error_file_truncated);
-      bfd_h_put_16 (abfd, 0xffff, (bfd_byte *) scnhdr_ext->s_nreloc);
-      ret = 0;
+      if (scnhdr_int->s_nlnno <= 0xffff)
+       bfd_h_put_16 (abfd, scnhdr_int->s_nlnno,
+                     (bfd_byte *) scnhdr_ext->s_nlnno);
+      else
+       {
+         (*_bfd_error_handler) (_("%s: line number overflow: 0x%lx > 0xffff"),
+                                bfd_get_filename (abfd),
+                                scnhdr_int->s_nlnno);
+         bfd_set_error (bfd_error_file_truncated);
+         bfd_h_put_16 (abfd, 0xffff, (bfd_byte *) scnhdr_ext->s_nlnno);
+         ret = 0;
+       }
+      if (scnhdr_int->s_nreloc <= 0xffff)
+       bfd_h_put_16 (abfd, scnhdr_int->s_nreloc,
+                     (bfd_byte *) scnhdr_ext->s_nreloc);
+      else
+       {
+         (*_bfd_error_handler) (_("%s: reloc overflow: 0x%lx > 0xffff"),
+                                bfd_get_filename (abfd),
+                                scnhdr_int->s_nreloc);
+         bfd_set_error (bfd_error_file_truncated);
+         bfd_h_put_16 (abfd, 0xffff, (bfd_byte *) scnhdr_ext->s_nreloc);
+         ret = 0;
+       }
     }
   return ret;
 }
@@ -1002,7 +989,7 @@ static char * dir_names[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] =
 
 /**********************************************************************/
 static boolean
-pe_print_idata(abfd, vfile)
+pe_print_idata (abfd, vfile)
      bfd *abfd;
      PTR vfile;
 {
@@ -1019,7 +1006,6 @@ pe_print_idata(abfd, vfile)
   bfd_size_type dataoff;
   bfd_size_type secsize;
   bfd_size_type i;
-  bfd_size_type start, stop;
   int onaline = 20;
 
   pe_data_type *pe = pe_data (abfd);
@@ -1032,9 +1018,12 @@ pe_print_idata(abfd, vfile)
 
       if (datasize == 0)
        return true;
+
+      fprintf (file, _("\nThe import table is the .idata section\n"));
     }
   else
     {
+      /* idata buried in some other section: e.g. KERNEL32.DLL.  */
       bfd_vma addr, size;
 
       addr = extra->DataDirectory[1].VirtualAddress;
@@ -1045,19 +1034,21 @@ pe_print_idata(abfd, vfile)
 
       for (section = abfd->sections; section != NULL; section = section->next)
        {
-         if (section->vma - extra->ImageBase <= addr
-             && ((section->vma - extra->ImageBase
-                  + bfd_section_size (abfd, section))
-                 >= addr + size))
-           break;
+          if (addr >= section->vma
+              && addr < section->vma + bfd_section_size(abfd,section))
+                break;
        }
       if (section == NULL)
-       return true;
+       {
+          fprintf (file,
+                   _("\nThere is an import table, but the section containing it could not be found\n"));
+          return true;
+       }
 
-      /* For some reason the import table size is not reliable.  The
-         import data will extend past the indicated size, and before
-         the indicated address.  */
-      dataoff = addr - (section->vma - extra->ImageBase);
+      fprintf (file, _("\nThere is an import table in %s at 0x%lx\n"),
+              section->name, (unsigned long)addr);
+
+      dataoff = addr - section->vma;
       datasize = size;
     }
 
@@ -1123,11 +1114,9 @@ pe_print_idata(abfd, vfile)
   if (! bfd_get_section_contents (abfd, section, (PTR) data, 0, secsize))
     return false;
 
-  adj = (extra->ImageBase - section->vma) & 0xffffffff;
+  adj = - section->vma;
 
-  start = dataoff;
-  stop = dataoff + datasize;
-  for (i = start; i < stop; i += onaline)
+  for (i = 0; i < datasize; i += onaline)
     {
       bfd_vma hint_addr;
       bfd_vma time_stamp;
@@ -1142,30 +1131,29 @@ pe_print_idata(abfd, vfile)
               " %08lx\t",
               (unsigned long int) (i + section->vma + dataoff));
       
-      if (i+20 > stop)
+      if (i + 20 > datasize)
        {
          /* check stuff */
          ;
        }
-      
-      hint_addr = bfd_get_32(abfd, data+i);
-      time_stamp = bfd_get_32(abfd, data+i+4);
-      forward_chain = bfd_get_32(abfd, data+i+8);
-      dll_name = bfd_get_32(abfd, data+i+12);
-      first_thunk = bfd_get_32(abfd, data+i+16);
-      
-      fprintf(file, "%08lx %08lx %08lx %08lx %08lx\n",
-             hint_addr,
-             time_stamp,
-             forward_chain,
-             dll_name,
-             first_thunk);
+
+      hint_addr = bfd_get_32 (abfd, data + i + dataoff);
+      time_stamp = bfd_get_32 (abfd, data + i + 4 + dataoff);
+      forward_chain = bfd_get_32 (abfd, data + i + 8 + dataoff);
+      dll_name = bfd_get_32 (abfd, data + i + 12 + dataoff);
+      first_thunk = bfd_get_32 (abfd, data + i + 16 + dataoff);
+
+      fprintf (file, "%08lx %08lx %08lx %08lx %08lx\n",
+              hint_addr,
+              time_stamp,
+              forward_chain,
+              dll_name,
+              first_thunk);
 
       if (hint_addr == 0 && first_thunk == 0)
        break;
 
-      /* the image base is present in the section->vma */
-      dll = (char *) data + dll_name + adj;
+      dll = (char *) data + dll_name - section->vma + dataoff;
       fprintf(file, _("\n\tDLL Name: %s\n"), dll);
 
       if (hint_addr != 0)
@@ -1174,7 +1162,7 @@ pe_print_idata(abfd, vfile)
 
          idx = hint_addr + adj;
 
-         for (j = 0; j < stop; j += 4)
+         for (j = 0; j < datasize; j += 4)
            {
              unsigned long member = bfd_get_32 (abfd, data + idx + j);
 
@@ -1213,7 +1201,7 @@ pe_print_idata(abfd, vfile)
 
          idx2 = first_thunk + adj;
 
-         for (j=0;j<stop;j+=4)
+         for (j = 0; j < datasize; j += 4)
            {
              int ordinal;
              char *member_name;
@@ -1306,9 +1294,11 @@ pe_print_edata (abfd, vfile)
     {
       datasize = bfd_section_size (abfd, section);
       dataoff = 0;
+      fprintf (file, _("\nThe export table is the .edata section\n"));
     }
   else
     {
+      /* edata is buried in some other section: e.g. NTDLL.DLL.  */
       bfd_vma addr, size;
 
       addr = extra->DataDirectory[0].VirtualAddress;
@@ -1319,17 +1309,22 @@ pe_print_edata (abfd, vfile)
 
       for (section = abfd->sections; section != NULL; section = section->next)
        {
-         if (section->vma - extra->ImageBase <= addr
-             && ((section->vma - extra->ImageBase
-                  + bfd_section_size (abfd, section))
-                 >= addr + size))
-            break;
+          if (addr >= section->vma
+              && addr < section->vma + bfd_section_size (abfd, section))
+            break;
        }
       if (section == NULL)
-       return true;
+       {
+          fprintf (file,
+                   _("\nThere is an export table, but the section containing it could not be found\n"));
+          return true;
+       }
+
+      fprintf (file, _("\nThere is an export table in %s at 0x%lx\n"),
+              section->name, (unsigned long) addr);
 
       datasize = size;
-      dataoff = addr - (section->vma - extra->ImageBase);
+      dataoff = addr - section->vma;
     }
 
   data = (bfd_byte *) bfd_malloc (datasize);
@@ -1353,7 +1348,7 @@ pe_print_edata (abfd, vfile)
   edt.npt_addr       = bfd_get_32(abfd, data+32);
   edt.ot_addr        = bfd_get_32(abfd, data+36);
 
-  adj = (extra->ImageBase - (section->vma + dataoff)) & 0xffffffff;
+  adj = - (section->vma + dataoff);
 
   /* Dump the EDT first first */
   fprintf(file,
@@ -1406,7 +1401,7 @@ pe_print_edata (abfd, vfile)
   fprintf (file, "\n");
 
   
-  /* The next table to find si the Export Address Table. It's basically
+  /* The next table to find is the Export Address Table. It's basically
      a list of pointers that either locate a function in this dll, or
      forward the call to another dll. Something like:
       typedef union
@@ -1424,8 +1419,8 @@ pe_print_edata (abfd, vfile)
     {
       bfd_vma eat_member = bfd_get_32 (abfd,
                                       data + edt.eat_addr + (i * 4) + adj);
-      bfd_vma eat_actual = (extra->ImageBase + eat_member) & 0xffffffff;
-      bfd_vma edata_start = bfd_get_section_vma (abfd,section) + dataoff;
+      bfd_vma eat_actual = eat_member;
+      bfd_vma edata_start = bfd_get_section_vma (abfd, section);
       bfd_vma edata_end = edata_start + datasize;
 
       if (eat_member == 0)
@@ -1435,17 +1430,18 @@ pe_print_edata (abfd, vfile)
        {
          /* this rva is to a name (forwarding function) in our section */
          /* Should locate a function descriptor */
-         fprintf(file,
-                 "\t[%4ld] +base[%4ld] %04lx %s -- %s\n",
-                 (long) i, (long) (i + edt.base), eat_member,
-                 "Forwarder RVA", data + eat_member + adj);
+         fprintf (file,
+                  "\t[%4ld] +base[%4ld] %04lx %s -- %s\n",
+                  (long) i, (long) (i + edt.base), eat_member,
+                  _("Forwarder RVA"), data + eat_member + adj);
        }
       else
        {
          /* Should locate a function descriptor in the reldata section */
-         fprintf(file,
-                 "\t[%4ld] +base[%4ld] %04lx %s\n",
-                 (long) i, (long) (i + edt.base), eat_member, "Export RVA");
+         fprintf (file,
+                  "\t[%4ld] +base[%4ld] %04lx %s\n",
+                  (long) i, (long) (i + edt.base), eat_member,
+                  _("Export RVA"));
        }
     }
 
@@ -1490,20 +1486,22 @@ pe_print_pdata (abfd, vfile)
   bfd_size_type start, stop;
   int onaline = 20;
 
-  if (section == 0)
-    return true;
+  if (section == NULL
+      || coff_section_data (abfd, section) == NULL
+      || pei_section_data (abfd, section) == NULL)
+     return true;
 
-  stop = bfd_section_size (abfd, section);
+  stop = pei_section_data (abfd, section)->virt_size;
   if ((stop % onaline) != 0)
     fprintf (file, _("Warning, .pdata section size (%ld) is not a multiple of %d\n"),
             (long)stop, onaline);
 
-  fprintf(file,
-         _("\nThe Function Table (interpreted .pdata section contents)\n"));
-  fprintf(file,
-         _(" vma:\t\tBegin    End      EH       EH       PrologEnd\n"));
-  fprintf(file,
-         _("     \t\tAddress  Address  Handler  Data     Address\n"));
+  fprintf (file,
+          _("\nThe Function Table (interpreted .pdata section contents)\n"));
+  fprintf (file,
+          _(" vma:\t\tBegin    End      EH       EH       PrologEnd  Exception\n"));
+  fprintf (file,
+          _("     \t\tAddress  Address  Handler  Data     Address    Mask\n"));
 
   if (bfd_section_size (abfd, section) == 0)
     return true;
@@ -1527,10 +1525,11 @@ pe_print_pdata (abfd, vfile)
       bfd_vma eh_handler;
       bfd_vma eh_data;
       bfd_vma prolog_end_addr;
+      int em_data;
 
-      if (i+20 > stop)
+      if (i + 20 > stop)
        break;
-      
+
       begin_addr = bfd_get_32(abfd, data+i);
       end_addr = bfd_get_32(abfd, data+i+4);
       eh_handler = bfd_get_32(abfd, data+i+8);
@@ -1548,12 +1547,17 @@ pe_print_pdata (abfd, vfile)
               " %08lx\t",
               (unsigned long int) (i + section->vma));
 
-      fprintf(file, "%08lx %08lx %08lx %08lx %08lx",
-             begin_addr,
-             end_addr,
-             eh_handler,
-             eh_data,
-             prolog_end_addr);
+      em_data = ((eh_handler & 0x1) << 2) | (prolog_end_addr & 0x3);
+      eh_handler &= 0xfffffffc;
+      prolog_end_addr &= 0xfffffffc;
+
+      fprintf (file, "%08lx %08lx %08lx %08lx %08lx   %x",
+              begin_addr,
+              end_addr,
+              eh_handler,
+              eh_data,
+              prolog_end_addr,
+              em_data);
 
 #ifdef POWERPC_LE_PE
       if (eh_handler == 0 && eh_data != 0)
@@ -1590,14 +1594,16 @@ pe_print_pdata (abfd, vfile)
   return true;
 }
 
-static const char *tbl[6] =
+#define IMAGE_REL_BASED_HIGHADJ 4
+static const char * const tbl[] =
 {
 "ABSOLUTE",
 "HIGH",
 "LOW",
 "HIGHLOW",
 "HIGHADJ",
-"MIPS_JMPADDR"
+"MIPS_JMPADDR",
+"UNKNOWN",   /* MUST be last */
 };
 
 static boolean
@@ -1612,14 +1618,14 @@ pe_print_reloc (abfd, vfile)
   bfd_size_type i;
   bfd_size_type start, stop;
 
-  if (section == 0)
+  if (section == NULL)
     return true;
 
   if (bfd_section_size (abfd, section) == 0)
     return true;
 
-  fprintf(file,
-         _("\n\nPE File Base Relocations (interpreted .reloc section contents)\n"));
+  fprintf (file,
+          _("\n\nPE File Base Relocations (interpreted .reloc section contents)\n"));
 
   data = (bfd_byte *) bfd_malloc ((size_t) bfd_section_size (abfd, section));
   datasize = bfd_section_size (abfd, section);
@@ -1659,17 +1665,28 @@ pe_print_reloc (abfd, vfile)
 
       for (j = 0; j < number; ++j)
        {
-         unsigned short e = bfd_get_16(abfd, data + i + 8 + j*2);
-         int t =   (e & 0xF000) >> 12;
+         unsigned short e = bfd_get_16 (abfd, data + i + 8 + j * 2);
+         unsigned int t = (e & 0xF000) >> 12;
          int off = e & 0x0FFF;
 
-         if (t > 5) 
-           abort();
+         if (t >= sizeof (tbl) / sizeof (tbl[0]))
+           t = (sizeof (tbl) / sizeof (tbl[0])) - 1;
 
-         fprintf(file,
-                 _("\treloc %4d offset %4x [%4lx] %s\n"), 
-                 j, off, (long) (off + virtual_address), tbl[t]);
+         fprintf (file,
+                  _("\treloc %4d offset %4x [%4lx] %s"),
+                  j, off, (long) (off + virtual_address), tbl[t]);
 
+         /* HIGHADJ takes an argument, - the next record *is* the
+            low 16 bits of addend.  */ 
+         if (t == IMAGE_REL_BASED_HIGHADJ)
+           {
+              fprintf (file, " (%4x)",
+                       ((unsigned int)
+                        bfd_get_16 (abfd, data + i + 8 + j * 2 + 2)));
+              j++;
+           }
+         
+         fprintf (file, "\n");
        }
       i += size;
     }
@@ -1709,6 +1726,8 @@ _bfd_pe_print_private_bfd_data_common (abfd, vfile)
   PF (0x8000, "big endian");
 #undef PF
 
+  /* ctime implies '\n'.  */
+  fprintf (file, "\nTime/Date\t\t%s", ctime (&pe->coff.timestamp));
   fprintf (file,"\nImageBase\t\t");
   fprintf_vma (file, i->ImageBase);
   fprintf (file,"\nSectionAlignment\t");
@@ -1770,6 +1789,13 @@ _bfd_pe_bfd_copy_private_bfd_data_common (ibfd, obfd)
   pe_data (obfd)->pe_opthdr = pe_data (ibfd)->pe_opthdr;
   pe_data (obfd)->dll = pe_data (ibfd)->dll;
 
+  /* for strip: if we removed .reloc, we'll make a real mess of things
+     if we don't remove this entry as well.  */
+  if (! pe_data (obfd)->has_reloc_section)
+    {
+      pe_data(obfd)->pe_opthdr.DataDirectory[5].VirtualAddress = 0;
+      pe_data(obfd)->pe_opthdr.DataDirectory[5].Size = 0;
+    }
   return true;
 }
 
@@ -1804,6 +1830,8 @@ _bfd_pe_bfd_copy_private_section_data (ibfd, isec, obfd, osec)
        }
       pei_section_data (obfd, osec)->virt_size =
        pei_section_data (ibfd, isec)->virt_size;
+      pei_section_data (obfd, osec)->pe_flags =
+        pei_section_data (ibfd, isec)->pe_flags;
     }
 
   return true;
@@ -1823,3 +1851,61 @@ _bfd_pe_get_symbol_info (abfd, symbol, ret)
       && ! bfd_is_abs_section (symbol->section))
     ret->value += pe_data (abfd)->pe_opthdr.ImageBase;
 }
+
+/* Handle the .idata section and other things that need symbol table
+   access.  */
+
+boolean
+_bfd_pei_final_link_postscript (abfd, pfinfo)
+     bfd *abfd;
+     struct coff_final_link_info *pfinfo;
+{
+  struct coff_link_hash_entry *h1;
+  struct bfd_link_info *info = pfinfo->info;
+
+  /* There are a few fields that need to be filled in now while we
+     have symbol table access.
+
+     The .idata subsections aren't directly available as sections, but
+     they are in the symbol table, so get them from there.  */
+
+  /* The import directory.  This is the address of .idata$2, with size
+     of .idata$2 + .idata$3.  */
+  h1 = coff_link_hash_lookup (coff_hash_table (info),
+                             ".idata$2", false, false, true);
+  if (h1 != NULL)
+    {
+      pe_data(abfd)->pe_opthdr.DataDirectory[1].VirtualAddress =
+       (h1->root.u.def.value
+        + h1->root.u.def.section->output_section->vma
+        + h1->root.u.def.section->output_offset);
+      h1 = coff_link_hash_lookup (coff_hash_table (info),
+                                 ".idata$4", false, false, true);
+      pe_data (abfd)->pe_opthdr.DataDirectory[1].Size =
+       ((h1->root.u.def.value
+         + h1->root.u.def.section->output_section->vma
+         + h1->root.u.def.section->output_offset)
+        - pe_data(abfd)->pe_opthdr.DataDirectory[1].VirtualAddress);
+
+      /* The import address table.  This is the size/address of
+         .idata$5.  */
+      h1 = coff_link_hash_lookup (coff_hash_table (info),
+                                 ".idata$5", false, false, true);
+      pe_data (abfd)->pe_opthdr.DataDirectory[12].VirtualAddress =
+       (h1->root.u.def.value
+        + h1->root.u.def.section->output_section->vma
+        + h1->root.u.def.section->output_offset);
+      h1 = coff_link_hash_lookup (coff_hash_table (info),
+                                 ".idata$6", false, false, true);
+      pe_data (abfd)->pe_opthdr.DataDirectory[12].Size =
+       ((h1->root.u.def.value
+         + h1->root.u.def.section->output_section->vma
+         + h1->root.u.def.section->output_offset)
+        - pe_data(abfd)->pe_opthdr.DataDirectory[12].VirtualAddress);
+    }
+
+  /* If we couldn't find idata$2, we either have an excessively
+     trivial program or are in DEEP trouble; we have to assume trivial
+     program....  */
+  return true;
+}