NDS32/bfd: Add one more argument to control contents cache.
[deliverable/binutils-gdb.git] / bfd / peXXigen.c
index 3848f53dea85b84202180ceb5b589b789edf8bec..122ddf125643e1a66bfd1d396a8110791540bc97 100644 (file)
@@ -1,13 +1,12 @@
 /* Support for the generic parts of PE/PEI; the common executable parts.
 /* Support for the generic parts of PE/PEI; the common executable parts.
-   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1995-2015 Free Software Foundation, Inc.
    Written by Cygnus Solutions.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Written by Cygnus Solutions.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -17,7 +16,9 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
 
 /* Most of this hacked by Steve Chamberlain <sac@cygnus.com>.
 
 
 /* Most of this hacked by Steve Chamberlain <sac@cygnus.com>.
 
    depending on whether we're compiling for straight PE or PE+.  */
 #define COFF_WITH_XX
 
    depending on whether we're compiling for straight PE or PE+.  */
 #define COFF_WITH_XX
 
-#include "bfd.h"
 #include "sysdep.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "libbfd.h"
 #include "coff/internal.h"
 #include "libbfd.h"
 #include "coff/internal.h"
+#include "bfdver.h"
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#endif
 
 /* NOTE: it's strange to be including an architecture specific header
    in what's supposed to be general (to PE/PEI) code.  However, that's
 
 /* NOTE: it's strange to be including an architecture specific header
    in what's supposed to be general (to PE/PEI) code.  However, that's
@@ -78,6 +83,7 @@
 #include "coff/pe.h"
 #include "libcoff.h"
 #include "libpei.h"
 #include "coff/pe.h"
 #include "libcoff.h"
 #include "libpei.h"
+#include "safe-ctype.h"
 
 #if defined COFF_WITH_pep || defined COFF_WITH_pex64
 # undef AOUTSZ
 
 #if defined COFF_WITH_pep || defined COFF_WITH_pex64
 # undef AOUTSZ
 # define PEAOUTHDR     PEPAOUTHDR
 #endif
 
 # define PEAOUTHDR     PEPAOUTHDR
 #endif
 
+#define HighBitSet(val)      ((val) & 0x80000000)
+#define SetHighBit(val)      ((val) | 0x80000000)
+#define WithoutHighBit(val)  ((val) & 0x7fffffff)
+
 /* FIXME: This file has various tests of POWERPC_LE_PE.  Those tests
    worked when the code was in peicode.h, but no longer work now that
    the code is in peigen.c.  PowerPC NT is said to be dead.  If
 /* FIXME: This file has various tests of POWERPC_LE_PE.  Those tests
    worked when the code was in peicode.h, but no longer work now that
    the code is in peigen.c.  PowerPC NT is said to be dead.  If
@@ -127,6 +137,9 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
      they will be handled somewhat correctly in the bfd code.  */
   if (in->n_sclass == C_SECTION)
     {
      they will be handled somewhat correctly in the bfd code.  */
   if (in->n_sclass == C_SECTION)
     {
+      char namebuf[SYMNMLEN + 1];
+      const char *name = NULL;
+
       in->n_value = 0x0;
 
       /* Create synthetic empty sections as needed.  DJ */
       in->n_value = 0x0;
 
       /* Create synthetic empty sections as needed.  DJ */
@@ -134,33 +147,50 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
        {
          asection *sec;
 
        {
          asection *sec;
 
-         for (sec = abfd->sections; sec; sec = sec->next)
+         name = _bfd_coff_internal_syment_name (abfd, in, namebuf);
+         if (name == NULL)
            {
            {
-             if (strcmp (sec->name, in->n_name) == 0)
-               {
-                 in->n_scnum = sec->target_index;
-                 break;
-               }
+             _bfd_error_handler (_("%B: unable to find name for empty section"),
+                                 abfd);
+             bfd_set_error (bfd_error_invalid_target);
+             return;
            }
            }
+
+         sec = bfd_get_section_by_name (abfd, name);
+         if (sec != NULL)
+           in->n_scnum = sec->target_index;
        }
 
       if (in->n_scnum == 0)
        {
          int unused_section_number = 0;
          asection *sec;
        }
 
       if (in->n_scnum == 0)
        {
          int unused_section_number = 0;
          asection *sec;
-         char *name;
          flagword flags;
 
          for (sec = abfd->sections; sec; sec = sec->next)
            if (unused_section_number <= sec->target_index)
              unused_section_number = sec->target_index + 1;
 
          flagword flags;
 
          for (sec = abfd->sections; sec; sec = sec->next)
            if (unused_section_number <= sec->target_index)
              unused_section_number = sec->target_index + 1;
 
-         name = bfd_alloc (abfd, (bfd_size_type) strlen (in->n_name) + 10);
-         if (name == NULL)
-           return;
-         strcpy (name, in->n_name);
+         if (name == namebuf)
+           {
+             name = (const char *) bfd_alloc (abfd, strlen (namebuf) + 1);
+             if (name == NULL)
+               {
+                 _bfd_error_handler (_("%B: out of memory creating name for empty section"),
+                                     abfd);
+                 return;
+               }
+             strcpy ((char *) name, namebuf);
+           }
+
          flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_DATA | SEC_LOAD;
          sec = bfd_make_section_anyway_with_flags (abfd, name, flags);
          flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_DATA | SEC_LOAD;
          sec = bfd_make_section_anyway_with_flags (abfd, name, flags);
+         if (sec == NULL)
+           {
+             _bfd_error_handler (_("%B: unable to create fake empty section"),
+                                 abfd);
+             return;
+           }
 
          sec->vma = 0;
          sec->lma = 0;
 
          sec->vma = 0;
          sec->lma = 0;
@@ -189,6 +219,14 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
 #endif
 }
 
 #endif
 }
 
+static bfd_boolean
+abs_finder (bfd * abfd ATTRIBUTE_UNUSED, asection * sec, void * data)
+{
+  bfd_vma abs_val = * (bfd_vma *) data;
+
+  return (sec->vma <= abs_val) && ((sec->vma + (1ULL << 32)) > abs_val);
+}
+
 unsigned int
 _bfd_XXi_swap_sym_out (bfd * abfd, void * inp, void * extp)
 {
 unsigned int
 _bfd_XXi_swap_sym_out (bfd * abfd, void * inp, void * extp)
 {
@@ -203,6 +241,34 @@ _bfd_XXi_swap_sym_out (bfd * abfd, void * inp, void * extp)
   else
     memcpy (ext->e.e_name, in->_n._n_name, SYMNMLEN);
 
   else
     memcpy (ext->e.e_name, in->_n._n_name, SYMNMLEN);
 
+  /* The PE32 and PE32+ formats only use 4 bytes to hold the value of a
+     symbol.  This is a problem on 64-bit targets where we can generate
+     absolute symbols with values >= 1^32.  We try to work around this
+     problem by finding a section whose base address is sufficient to
+     reduce the absolute value to < 1^32, and then transforming the
+     symbol into a section relative symbol.  This of course is a hack.  */
+  if (sizeof (in->n_value) > 4
+      /* The strange computation of the shift amount is here in order to
+        avoid a compile time warning about the comparison always being
+        false.  It does not matter if this test fails to work as expected
+        as the worst that can happen is that some absolute symbols are
+        needlessly converted into section relative symbols.  */
+      && in->n_value > ((1ULL << (sizeof (in->n_value) > 4 ? 32 : 31)) - 1)
+      && in->n_scnum == -1)
+    {
+      asection * sec;
+
+      sec = bfd_sections_find_if (abfd, abs_finder, & in->n_value);
+      if (sec)
+       {
+         in->n_value -= sec->vma;
+         in->n_scnum = sec->target_index;
+       }
+      /* else: FIXME: The value is outside the range of any section.  This
+        happens for __image_base__ and __ImageBase and maybe some other
+        symbols as well.  We should find a way to handle these values.  */
+    }
+
   H_PUT_32 (abfd, in->n_value, ext->e_value);
   H_PUT_16 (abfd, in->n_scnum, ext->e_scnum);
 
   H_PUT_32 (abfd, in->n_value, ext->e_value);
   H_PUT_16 (abfd, in->n_scnum, ext->e_scnum);
 
@@ -221,7 +287,7 @@ void
 _bfd_XXi_swap_aux_in (bfd *    abfd,
                      void *    ext1,
                      int       type,
 _bfd_XXi_swap_aux_in (bfd *    abfd,
                      void *    ext1,
                      int       type,
-                     int       class,
+                     int       in_class,
                      int       indx ATTRIBUTE_UNUSED,
                      int       numaux ATTRIBUTE_UNUSED,
                      void *    in1)
                      int       indx ATTRIBUTE_UNUSED,
                      int       numaux ATTRIBUTE_UNUSED,
                      void *    in1)
@@ -229,7 +295,10 @@ _bfd_XXi_swap_aux_in (bfd *        abfd,
   AUXENT *ext = (AUXENT *) ext1;
   union internal_auxent *in = (union internal_auxent *) in1;
 
   AUXENT *ext = (AUXENT *) ext1;
   union internal_auxent *in = (union internal_auxent *) in1;
 
-  switch (class)
+  /* PR 17521: Make sure that all fields in the aux structure
+     are initialised.  */
+  memset (in, 0, sizeof * in);
+  switch (in_class)
     {
     case C_FILE:
       if (ext->x_file.x_fname[0] == 0)
     {
     case C_FILE:
       if (ext->x_file.x_fname[0] == 0)
@@ -260,7 +329,8 @@ _bfd_XXi_swap_aux_in (bfd * abfd,
   in->x_sym.x_tagndx.l = H_GET_32 (abfd, ext->x_sym.x_tagndx);
   in->x_sym.x_tvndx = H_GET_16 (abfd, ext->x_sym.x_tvndx);
 
   in->x_sym.x_tagndx.l = H_GET_32 (abfd, ext->x_sym.x_tagndx);
   in->x_sym.x_tvndx = H_GET_16 (abfd, ext->x_sym.x_tvndx);
 
-  if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
+  if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type)
+      || ISTAG (in_class))
     {
       in->x_sym.x_fcnary.x_fcn.x_lnnoptr = GET_FCN_LNNOPTR (abfd, ext);
       in->x_sym.x_fcnary.x_fcn.x_endndx.l = GET_FCN_ENDNDX (abfd, ext);
     {
       in->x_sym.x_fcnary.x_fcn.x_lnnoptr = GET_FCN_LNNOPTR (abfd, ext);
       in->x_sym.x_fcnary.x_fcn.x_endndx.l = GET_FCN_ENDNDX (abfd, ext);
@@ -292,7 +362,7 @@ unsigned int
 _bfd_XXi_swap_aux_out (bfd *  abfd,
                       void * inp,
                       int    type,
 _bfd_XXi_swap_aux_out (bfd *  abfd,
                       void * inp,
                       int    type,
-                      int    class,
+                      int    in_class,
                       int    indx ATTRIBUTE_UNUSED,
                       int    numaux ATTRIBUTE_UNUSED,
                       void * extp)
                       int    indx ATTRIBUTE_UNUSED,
                       int    numaux ATTRIBUTE_UNUSED,
                       void * extp)
@@ -302,7 +372,7 @@ _bfd_XXi_swap_aux_out (bfd *  abfd,
 
   memset (ext, 0, AUXESZ);
 
 
   memset (ext, 0, AUXESZ);
 
-  switch (class)
+  switch (in_class)
     {
     case C_FILE:
       if (in->x_file.x_fname[0] == 0)
     {
     case C_FILE:
       if (in->x_file.x_fname[0] == 0)
@@ -334,7 +404,8 @@ _bfd_XXi_swap_aux_out (bfd *  abfd,
   H_PUT_32 (abfd, in->x_sym.x_tagndx.l, ext->x_sym.x_tagndx);
   H_PUT_16 (abfd, in->x_sym.x_tvndx, ext->x_sym.x_tvndx);
 
   H_PUT_32 (abfd, in->x_sym.x_tagndx.l, ext->x_sym.x_tagndx);
   H_PUT_16 (abfd, in->x_sym.x_tvndx, ext->x_sym.x_tvndx);
 
-  if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
+  if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type)
+      || ISTAG (in_class))
     {
       PUT_FCN_LNNOPTR (abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr,  ext);
       PUT_FCN_ENDNDX  (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, ext);
     {
       PUT_FCN_LNNOPTR (abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr,  ext);
       PUT_FCN_ENDNDX  (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, ext);
@@ -388,10 +459,11 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
                          void * aouthdr_ext1,
                          void * aouthdr_int1)
 {
                          void * aouthdr_ext1,
                          void * aouthdr_int1)
 {
-  struct internal_extra_pe_aouthdr *a;
-  PEAOUTHDR * src = (PEAOUTHDR *) (aouthdr_ext1);
+  PEAOUTHDR * src = (PEAOUTHDR *) aouthdr_ext1;
   AOUTHDR * aouthdr_ext = (AOUTHDR *) aouthdr_ext1;
   AOUTHDR * aouthdr_ext = (AOUTHDR *) aouthdr_ext1;
-  struct internal_aouthdr *aouthdr_int = (struct internal_aouthdr *)aouthdr_int1;
+  struct internal_aouthdr *aouthdr_int
+    = (struct internal_aouthdr *) aouthdr_int1;
+  struct internal_extra_pe_aouthdr *a = &aouthdr_int->pe;
 
   aouthdr_int->magic = H_GET_16 (abfd, aouthdr_ext->magic);
   aouthdr_int->vstamp = H_GET_16 (abfd, aouthdr_ext->vstamp);
 
   aouthdr_int->magic = H_GET_16 (abfd, aouthdr_ext->magic);
   aouthdr_int->vstamp = H_GET_16 (abfd, aouthdr_ext->vstamp);
@@ -401,13 +473,22 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
   aouthdr_int->entry = GET_AOUTHDR_ENTRY (abfd, aouthdr_ext->entry);
   aouthdr_int->text_start =
     GET_AOUTHDR_TEXT_START (abfd, aouthdr_ext->text_start);
   aouthdr_int->entry = GET_AOUTHDR_ENTRY (abfd, aouthdr_ext->entry);
   aouthdr_int->text_start =
     GET_AOUTHDR_TEXT_START (abfd, aouthdr_ext->text_start);
+
 #if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64)
   /* PE32+ does not have data_start member!  */
   aouthdr_int->data_start =
     GET_AOUTHDR_DATA_START (abfd, aouthdr_ext->data_start);
 #if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64)
   /* PE32+ does not have data_start member!  */
   aouthdr_int->data_start =
     GET_AOUTHDR_DATA_START (abfd, aouthdr_ext->data_start);
+  a->BaseOfData = aouthdr_int->data_start;
 #endif
 
 #endif
 
-  a = &aouthdr_int->pe;
+  a->Magic = aouthdr_int->magic;
+  a->MajorLinkerVersion = H_GET_8 (abfd, aouthdr_ext->vstamp);
+  a->MinorLinkerVersion = H_GET_8 (abfd, aouthdr_ext->vstamp + 1);
+  a->SizeOfCode = aouthdr_int->tsize ;
+  a->SizeOfInitializedData = aouthdr_int->dsize ;
+  a->SizeOfUninitializedData = aouthdr_int->bsize ;
+  a->AddressOfEntryPoint = aouthdr_int->entry;
+  a->BaseOfCode = aouthdr_int->text_start;
   a->ImageBase = GET_OPTHDR_IMAGE_BASE (abfd, src->ImageBase);
   a->SectionAlignment = H_GET_32 (abfd, src->SectionAlignment);
   a->FileAlignment = H_GET_32 (abfd, src->FileAlignment);
   a->ImageBase = GET_OPTHDR_IMAGE_BASE (abfd, src->ImageBase);
   a->SectionAlignment = H_GET_32 (abfd, src->SectionAlignment);
   a->FileAlignment = H_GET_32 (abfd, src->FileAlignment);
@@ -439,7 +520,20 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
   {
     int idx;
 
   {
     int idx;
 
-    for (idx = 0; idx < 16; idx++)
+    /* PR 17512: Corrupt PE binaries can cause seg-faults.  */
+    if (a->NumberOfRvaAndSizes > IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
+      {
+       (*_bfd_error_handler)
+         (_("%B: aout header specifies an invalid number of data-directory entries: %d"),
+          abfd, a->NumberOfRvaAndSizes);
+       bfd_set_error (bfd_error_bad_value);
+
+       /* Paranoia: If the number is corrupt, then assume that the
+          actual entries themselves might be corrupt as well.  */
+       a->NumberOfRvaAndSizes = 0;
+      }
+
+    for (idx = 0; idx < a->NumberOfRvaAndSizes; idx++)
       {
         /* If data directory is empty, rva also should be 0.  */
        int size =
       {
         /* If data directory is empty, rva also should be 0.  */
        int size =
@@ -453,6 +547,13 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
        else
          a->DataDirectory[idx].VirtualAddress = 0;
       }
        else
          a->DataDirectory[idx].VirtualAddress = 0;
       }
+
+    while (idx < IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
+      {
+       a->DataDirectory[idx].Size = 0;
+       a->DataDirectory[idx].VirtualAddress = 0;
+       idx ++;
+      }
   }
 
   if (aouthdr_int->entry)
   }
 
   if (aouthdr_int->entry)
@@ -528,17 +629,6 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out)
   PEAOUTHDR *aouthdr_out = (PEAOUTHDR *) out;
   bfd_vma sa, fa, ib;
   IMAGE_DATA_DIRECTORY idata2, idata5, tls;
   PEAOUTHDR *aouthdr_out = (PEAOUTHDR *) out;
   bfd_vma sa, fa, ib;
   IMAGE_DATA_DIRECTORY idata2, idata5, tls;
-  
-  if (pe->force_minimum_alignment)
-    {
-      if (!extra->FileAlignment)
-       extra->FileAlignment = PE_DEF_FILE_ALIGNMENT;
-      if (!extra->SectionAlignment)
-       extra->SectionAlignment = PE_DEF_SECTION_ALIGNMENT;
-    }
-
-  if (extra->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
-    extra->Subsystem = pe->target_subsystem;
 
   sa = extra->SectionAlignment;
   fa = extra->FileAlignment;
 
   sa = extra->SectionAlignment;
   fa = extra->FileAlignment;
@@ -547,7 +637,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out)
   idata2 = pe->pe_opthdr.DataDirectory[PE_IMPORT_TABLE];
   idata5 = pe->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE];
   tls = pe->pe_opthdr.DataDirectory[PE_TLS_TABLE];
   idata2 = pe->pe_opthdr.DataDirectory[PE_IMPORT_TABLE];
   idata5 = pe->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE];
   tls = pe->pe_opthdr.DataDirectory[PE_TLS_TABLE];
-  
+
   if (aouthdr_in->tsize)
     {
       aouthdr_in->text_start -= ib;
   if (aouthdr_in->tsize)
     {
       aouthdr_in->text_start -= ib;
@@ -580,9 +670,6 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out)
 
   extra->NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
 
 
   extra->NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
 
-  /* First null out all data directory entries.  */
-  memset (extra->DataDirectory, 0, sizeof (extra->DataDirectory));
-
   add_data_entry (abfd, extra, 0, ".edata", ib);
   add_data_entry (abfd, extra, 2, ".rsrc", ib);
   add_data_entry (abfd, extra, 3, ".pdata", ib);
   add_data_entry (abfd, extra, 0, ".edata", ib);
   add_data_entry (abfd, extra, 2, ".rsrc", ib);
   add_data_entry (abfd, extra, 3, ".pdata", ib);
@@ -604,7 +691,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out)
     /* Until other .idata fixes are made (pending patch), the entry for
        .idata is needed for backwards compatibility.  FIXME.  */
     add_data_entry (abfd, extra, 1, ".idata", ib);
     /* Until other .idata fixes are made (pending patch), the entry for
        .idata is needed for backwards compatibility.  FIXME.  */
     add_data_entry (abfd, extra, 1, ".idata", ib);
-    
+
   /* 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),
   /* 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),
@@ -636,21 +723,28 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out)
           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
           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.  */
+          fix, strip munges the file.
+
+          FIXME: We need to handle holes between sections, which may
+          happpen when we covert from another format.  We just use
+          the virtual address and virtual size of the last section
+          for the image size.  */
        if (coff_section_data (abfd, sec) != NULL
            && pei_section_data (abfd, sec) != NULL)
        if (coff_section_data (abfd, sec) != NULL
            && pei_section_data (abfd, sec) != NULL)
-         isize += SA (FA (pei_section_data (abfd, sec)->virt_size));
+         isize = (sec->vma - extra->ImageBase
+                  + SA (FA (pei_section_data (abfd, sec)->virt_size)));
       }
 
     aouthdr_in->dsize = dsize;
     aouthdr_in->tsize = tsize;
     extra->SizeOfHeaders = hsize;
       }
 
     aouthdr_in->dsize = dsize;
     aouthdr_in->tsize = tsize;
     extra->SizeOfHeaders = hsize;
-    extra->SizeOfImage = SA (hsize) + isize;
+    extra->SizeOfImage = isize;
   }
 
   H_PUT_16 (abfd, aouthdr_in->magic, aouthdr_out->standard.magic);
 
   }
 
   H_PUT_16 (abfd, aouthdr_in->magic, aouthdr_out->standard.magic);
 
-#define LINKER_VERSION 256 /* That is, 2.56 */
+/* e.g. 219510000 is linker version 2.19  */
+#define LINKER_VERSION ((short) (BFD_VERSION / 1000000))
 
   /* This piece of magic sets the "linker version" field to
      LINKER_VERSION.  */
 
   /* This piece of magic sets the "linker version" field to
      LINKER_VERSION.  */
@@ -703,7 +797,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out)
   {
     int idx;
 
   {
     int idx;
 
-    for (idx = 0; idx < 16; idx++)
+    for (idx = 0; idx < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; idx++)
       {
        H_PUT_32 (abfd, extra->DataDirectory[idx].VirtualAddress,
                  aouthdr_out->DataDirectory[idx][0]);
       {
        H_PUT_32 (abfd, extra->DataDirectory[idx].VirtualAddress,
                  aouthdr_out->DataDirectory[idx][0]);
@@ -722,7 +816,8 @@ _bfd_XXi_only_swap_filehdr_out (bfd * abfd, void * in, void * out)
   struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
   struct external_PEI_filehdr *filehdr_out = (struct external_PEI_filehdr *) out;
 
   struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
   struct external_PEI_filehdr *filehdr_out = (struct external_PEI_filehdr *) out;
 
-  if (pe_data (abfd)->has_reloc_section)
+  if (pe_data (abfd)->has_reloc_section
+      || pe_data (abfd)->dont_strip_reloc)
     filehdr_in->f_flags &= ~F_RELFLG;
 
   if (pe_data (abfd)->dll)
     filehdr_in->f_flags &= ~F_RELFLG;
 
   if (pe_data (abfd)->dll)
@@ -777,7 +872,10 @@ _bfd_XXi_only_swap_filehdr_out (bfd * abfd, void * in, void * out)
   H_PUT_16 (abfd, filehdr_in->f_magic, filehdr_out->f_magic);
   H_PUT_16 (abfd, filehdr_in->f_nscns, filehdr_out->f_nscns);
 
   H_PUT_16 (abfd, filehdr_in->f_magic, filehdr_out->f_magic);
   H_PUT_16 (abfd, filehdr_in->f_nscns, filehdr_out->f_nscns);
 
-  H_PUT_32 (abfd, time (0), filehdr_out->f_timdat);
+  /* Only use a real timestamp if the option was chosen.  */
+  if ((pe_data (abfd)->insert_timestamp))
+    H_PUT_32 (abfd, time (0), filehdr_out->f_timdat);
+
   PUT_FILEHDR_SYMPTR (abfd, filehdr_in->f_symptr,
                      filehdr_out->f_symptr);
   H_PUT_32 (abfd, filehdr_in->f_nsyms, filehdr_out->f_nsyms);
   PUT_FILEHDR_SYMPTR (abfd, filehdr_in->f_symptr,
                      filehdr_out->f_symptr);
   H_PUT_32 (abfd, filehdr_in->f_nsyms, filehdr_out->f_nsyms);
@@ -862,7 +960,7 @@ _bfd_XXi_swap_scnhdr_out (bfd * abfd, void * in, void * out)
      sometimes).  */
   if ((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0)
     {
      sometimes).  */
   if ((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0)
     {
-      if (bfd_pe_executable_p (abfd))
+      if (bfd_pei_p (abfd))
        {
          ps = scnhdr_int->s_size;
          ss = 0;
        {
          ps = scnhdr_int->s_size;
          ss = 0;
@@ -875,7 +973,7 @@ _bfd_XXi_swap_scnhdr_out (bfd * abfd, void * in, void * out)
     }
   else
     {
     }
   else
     {
-      if (bfd_pe_executable_p (abfd))
+      if (bfd_pei_p (abfd))
        ps = scnhdr_int->s_paddr;
       else
        ps = 0;
        ps = scnhdr_int->s_paddr;
       else
        ps = 0;
@@ -907,7 +1005,7 @@ _bfd_XXi_swap_scnhdr_out (bfd * abfd, void * in, void * out)
        (0x02000000).  Also, the resource data should also be read and
        writable.  */
 
        (0x02000000).  Also, the resource data should also be read and
        writable.  */
 
-    /* FIXME: Alignment is also encoded in this field, at least on PPC and 
+    /* FIXME: Alignment is also encoded in this field, at least on PPC and
        ARM-WINCE.  Although - how do we get the original alignment field
        back ?  */
 
        ARM-WINCE.  Although - how do we get the original alignment field
        back ?  */
 
@@ -917,7 +1015,7 @@ _bfd_XXi_swap_scnhdr_out (bfd * abfd, void * in, void * out)
       unsigned long    must_have;
     }
     pe_required_section_flags;
       unsigned long    must_have;
     }
     pe_required_section_flags;
-    
+
     pe_required_section_flags known_sections [] =
       {
        { ".arch",  IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_ALIGN_8BYTES },
     pe_required_section_flags known_sections [] =
       {
        { ".arch",  IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_ALIGN_8BYTES },
@@ -1005,6 +1103,121 @@ _bfd_XXi_swap_scnhdr_out (bfd * abfd, void * in, void * out)
   return ret;
 }
 
   return ret;
 }
 
+void
+_bfd_XXi_swap_debugdir_in (bfd * abfd, void * ext1, void * in1)
+{
+  struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *) ext1;
+  struct internal_IMAGE_DEBUG_DIRECTORY *in = (struct internal_IMAGE_DEBUG_DIRECTORY *) in1;
+
+  in->Characteristics = H_GET_32(abfd, ext->Characteristics);
+  in->TimeDateStamp = H_GET_32(abfd, ext->TimeDateStamp);
+  in->MajorVersion = H_GET_16(abfd, ext->MajorVersion);
+  in->MinorVersion = H_GET_16(abfd, ext->MinorVersion);
+  in->Type = H_GET_32(abfd, ext->Type);
+  in->SizeOfData = H_GET_32(abfd, ext->SizeOfData);
+  in->AddressOfRawData = H_GET_32(abfd, ext->AddressOfRawData);
+  in->PointerToRawData = H_GET_32(abfd, ext->PointerToRawData);
+}
+
+unsigned int
+_bfd_XXi_swap_debugdir_out (bfd * abfd, void * inp, void * extp)
+{
+  struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *) extp;
+  struct internal_IMAGE_DEBUG_DIRECTORY *in = (struct internal_IMAGE_DEBUG_DIRECTORY *) inp;
+
+  H_PUT_32(abfd, in->Characteristics, ext->Characteristics);
+  H_PUT_32(abfd, in->TimeDateStamp, ext->TimeDateStamp);
+  H_PUT_16(abfd, in->MajorVersion, ext->MajorVersion);
+  H_PUT_16(abfd, in->MinorVersion, ext->MinorVersion);
+  H_PUT_32(abfd, in->Type, ext->Type);
+  H_PUT_32(abfd, in->SizeOfData, ext->SizeOfData);
+  H_PUT_32(abfd, in->AddressOfRawData, ext->AddressOfRawData);
+  H_PUT_32(abfd, in->PointerToRawData, ext->PointerToRawData);
+
+  return sizeof (struct external_IMAGE_DEBUG_DIRECTORY);
+}
+
+static CODEVIEW_INFO *
+_bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo)
+{
+  char buffer[256+1];
+
+  if (bfd_seek (abfd, where, SEEK_SET) != 0)
+    return NULL;
+
+  if (bfd_bread (buffer, 256, abfd) < 4)
+    return NULL;
+
+  /* Ensure null termination of filename.  */
+  buffer[256] = '\0';
+
+  cvinfo->CVSignature = H_GET_32(abfd, buffer);
+  cvinfo->Age = 0;
+
+  if ((cvinfo->CVSignature == CVINFO_PDB70_CVSIGNATURE)
+      && (length > sizeof (CV_INFO_PDB70)))
+    {
+      CV_INFO_PDB70 *cvinfo70 = (CV_INFO_PDB70 *)(buffer);
+
+      cvinfo->Age = H_GET_32(abfd, cvinfo70->Age);
+
+      /* A GUID consists of 4,2,2 byte values in little-endian order, followed
+         by 8 single bytes.  Byte swap them so we can conveniently treat the GUID
+         as 16 bytes in big-endian order.  */
+      bfd_putb32 (bfd_getl32 (cvinfo70->Signature), cvinfo->Signature);
+      bfd_putb16 (bfd_getl16 (&(cvinfo70->Signature[4])), &(cvinfo->Signature[4]));
+      bfd_putb16 (bfd_getl16 (&(cvinfo70->Signature[6])), &(cvinfo->Signature[6]));
+      memcpy (&(cvinfo->Signature[8]), &(cvinfo70->Signature[8]), 8);
+
+      cvinfo->SignatureLength = CV_INFO_SIGNATURE_LENGTH;
+      // cvinfo->PdbFileName = cvinfo70->PdbFileName;
+
+      return cvinfo;
+    }
+  else if ((cvinfo->CVSignature == CVINFO_PDB20_CVSIGNATURE)
+           && (length > sizeof (CV_INFO_PDB20)))
+    {
+      CV_INFO_PDB20 *cvinfo20 = (CV_INFO_PDB20 *)(buffer);
+      cvinfo->Age = H_GET_32(abfd, cvinfo20->Age);
+      memcpy (cvinfo->Signature, cvinfo20->Signature, 4);
+      cvinfo->SignatureLength = 4;
+      // cvinfo->PdbFileName = cvinfo20->PdbFileName;
+
+      return cvinfo;
+    }
+
+  return NULL;
+}
+
+unsigned int
+_bfd_XXi_write_codeview_record (bfd * abfd, file_ptr where, CODEVIEW_INFO *cvinfo)
+{
+  unsigned int size = sizeof (CV_INFO_PDB70) + 1;
+  CV_INFO_PDB70 *cvinfo70;
+  char buffer[size];
+
+  if (bfd_seek (abfd, where, SEEK_SET) != 0)
+    return 0;
+
+  cvinfo70 = (CV_INFO_PDB70 *) buffer;
+  H_PUT_32 (abfd, CVINFO_PDB70_CVSIGNATURE, cvinfo70->CvSignature);
+
+  /* Byte swap the GUID from 16 bytes in big-endian order to 4,2,2 byte values
+     in little-endian order, followed by 8 single bytes.  */
+  bfd_putl32 (bfd_getb32 (cvinfo->Signature), cvinfo70->Signature);
+  bfd_putl16 (bfd_getb16 (&(cvinfo->Signature[4])), &(cvinfo70->Signature[4]));
+  bfd_putl16 (bfd_getb16 (&(cvinfo->Signature[6])), &(cvinfo70->Signature[6]));
+  memcpy (&(cvinfo70->Signature[8]), &(cvinfo->Signature[8]), 8);
+
+  H_PUT_32 (abfd, cvinfo->Age, cvinfo70->Age);
+  cvinfo70->PdbFileName[0] = '\0';
+
+  if (bfd_bwrite (buffer, size, abfd) != size)
+    return 0;
+
+  return size;
+}
+
 static char * dir_names[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] =
 {
   N_("Export Directory [.edata (or where ever we found it)]"),
 static char * dir_names[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] =
 {
   N_("Export Directory [.edata (or where ever we found it)]"),
@@ -1085,13 +1298,19 @@ pe_print_idata (bfd * abfd, void * vfile)
                   _("\nThere is an import table, but the section containing it could not be found\n"));
          return TRUE;
        }
                   _("\nThere is an import table, but the section containing it could not be found\n"));
          return TRUE;
        }
+      else if (!(section->flags & SEC_HAS_CONTENTS))
+        {
+         fprintf (file,
+                  _("\nThere is an import table in %s, but that section has no contents\n"),
+                  section->name);
+         return TRUE;
+        }
     }
 
   fprintf (file, _("\nThere is an import table in %s at 0x%lx\n"),
           section->name, (unsigned long) addr);
 
   dataoff = addr - section->vma;
     }
 
   fprintf (file, _("\nThere is an import table in %s at 0x%lx\n"),
           section->name, (unsigned long) addr);
 
   dataoff = addr - section->vma;
-  datasize -= dataoff;
 
 #ifdef POWERPC_LE_PE
   if (rel_section != 0 && rel_section->size != 0)
 
 #ifdef POWERPC_LE_PE
   if (rel_section != 0 && rel_section->size != 0)
@@ -1164,7 +1383,7 @@ pe_print_idata (bfd * abfd, void * vfile)
   adj = section->vma - extra->ImageBase;
 
   /* Print all image import descriptors.  */
   adj = section->vma - extra->ImageBase;
 
   /* Print all image import descriptors.  */
-  for (i = 0; i < datasize; i += onaline)
+  for (i = dataoff; i + onaline <= datasize; i += onaline)
     {
       bfd_vma hint_addr;
       bfd_vma time_stamp;
     {
       bfd_vma hint_addr;
       bfd_vma time_stamp;
@@ -1176,12 +1395,12 @@ pe_print_idata (bfd * abfd, void * vfile)
       char *dll;
 
       /* Print (i + extra->DataDirectory[PE_IMPORT_TABLE].VirtualAddress).  */
       char *dll;
 
       /* Print (i + extra->DataDirectory[PE_IMPORT_TABLE].VirtualAddress).  */
-      fprintf (file, " %08lx\t", (unsigned long) (i + adj + dataoff));
-      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\t", (unsigned long) (i + adj));
+      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",
               (unsigned long) hint_addr,
 
       fprintf (file, "%08lx %08lx %08lx %08lx %08lx\n",
               (unsigned long) hint_addr,
@@ -1197,7 +1416,9 @@ pe_print_idata (bfd * abfd, void * vfile)
         break;
 
       dll = (char *) data + dll_name - adj;
         break;
 
       dll = (char *) data + dll_name - adj;
-      fprintf (file, _("\n\tDLL Name: %s\n"), dll);
+      /* PR 17512 file: 078-12277-0.004.  */
+      bfd_size_type maxlen = (char *)(data + datasize) - dll - 1;
+      fprintf (file, _("\n\tDLL Name: %.*s\n"), (int) maxlen, dll);
 
       if (hint_addr != 0)
        {
 
       if (hint_addr != 0)
        {
@@ -1206,16 +1427,17 @@ pe_print_idata (bfd * abfd, void * vfile)
          bfd_vma ft_addr;
          bfd_size_type ft_datasize;
          int ft_idx;
          bfd_vma ft_addr;
          bfd_size_type ft_datasize;
          int ft_idx;
-         int ft_allocated = 0;
+         int ft_allocated;
 
          fprintf (file, _("\tvma:  Hint/Ord Member-Name Bound-To\n"));
 
          idx = hint_addr - adj;
 
          fprintf (file, _("\tvma:  Hint/Ord Member-Name Bound-To\n"));
 
          idx = hint_addr - adj;
-         
+
          ft_addr = first_thunk + extra->ImageBase;
          ft_addr = first_thunk + extra->ImageBase;
-         ft_data = data;
          ft_idx = first_thunk - adj;
          ft_idx = first_thunk - adj;
-         ft_allocated = 0; 
+         ft_data = data + ft_idx;
+         ft_datasize = datasize - ft_idx;
+         ft_allocated = 0;
 
          if (first_thunk != hint_addr)
            {
 
          if (first_thunk != hint_addr)
            {
@@ -1224,9 +1446,8 @@ pe_print_idata (bfd * abfd, void * vfile)
                   ft_section != NULL;
                   ft_section = ft_section->next)
                {
                   ft_section != NULL;
                   ft_section = ft_section->next)
                {
-                 ft_datasize = ft_section->size;
                  if (ft_addr >= ft_section->vma
                  if (ft_addr >= ft_section->vma
-                     && ft_addr < ft_section->vma + ft_datasize)
+                     && ft_addr < ft_section->vma + ft_section->size)
                    break;
                }
 
                    break;
                }
 
@@ -1239,93 +1460,103 @@ pe_print_idata (bfd * abfd, void * vfile)
 
              /* Now check to see if this section is the same as our current
                 section.  If it is not then we will have to load its data in.  */
 
              /* Now check to see if this section is the same as our current
                 section.  If it is not then we will have to load its data in.  */
-             if (ft_section == section)
-               {
-                 ft_data = data;
-                 ft_idx = first_thunk - adj;
-               }
-             else
+             if (ft_section != section)
                {
                  ft_idx = first_thunk - (ft_section->vma - extra->ImageBase);
                {
                  ft_idx = first_thunk - (ft_section->vma - extra->ImageBase);
-                 ft_data = bfd_malloc (datasize);
+                 ft_datasize = ft_section->size - ft_idx;
+                 ft_data = (bfd_byte *) bfd_malloc (ft_datasize);
                  if (ft_data == NULL)
                    continue;
 
                  if (ft_data == NULL)
                    continue;
 
-                 /* Read datasize bfd_bytes starting at offset ft_idx.  */
-                 if (! bfd_get_section_contents
-                     (abfd, ft_section, ft_data, (bfd_vma) ft_idx, datasize))
+                 /* Read ft_datasize bytes starting at offset ft_idx.  */
+                 if (!bfd_get_section_contents (abfd, ft_section, ft_data,
+                                                (bfd_vma) ft_idx, ft_datasize))
                    {
                      free (ft_data);
                      continue;
                    }
                    {
                      free (ft_data);
                      continue;
                    }
-
-                 ft_idx = 0;
                  ft_allocated = 1;
                }
            }
 
          /* Print HintName vector entries.  */
 #ifdef COFF_WITH_pex64
                  ft_allocated = 1;
                }
            }
 
          /* Print HintName vector entries.  */
 #ifdef COFF_WITH_pex64
-         for (j = 0; j < datasize; j += 8)
+         for (j = 0; idx + j + 8 <= datasize; j += 8)
            {
            {
+             bfd_size_type amt;
              unsigned long member = bfd_get_32 (abfd, data + idx + j);
              unsigned long member_high = bfd_get_32 (abfd, data + idx + j + 4);
 
              if (!member && !member_high)
                break;
 
              unsigned long member = bfd_get_32 (abfd, data + idx + j);
              unsigned long member_high = bfd_get_32 (abfd, data + idx + j + 4);
 
              if (!member && !member_high)
                break;
 
-             if (member_high & 0x80000000)
+             amt = member - adj;
+
+             if (HighBitSet (member_high))
                fprintf (file, "\t%lx%08lx\t %4lx%08lx  <none>",
                fprintf (file, "\t%lx%08lx\t %4lx%08lx  <none>",
-                        member_high,member, member_high & 0x7fffffff, member);
+                        member_high, member,
+                        WithoutHighBit (member_high), member);
+             /* PR binutils/17512: Handle corrupt PE data.  */
+             else if (amt + 2 >= datasize)
+               fprintf (file, _("\t<corrupt: 0x%04lx>"), member);
              else
                {
                  int ordinal;
                  char *member_name;
 
              else
                {
                  int ordinal;
                  char *member_name;
 
-                 ordinal = bfd_get_16 (abfd, data + member - adj);
-                 member_name = (char *) data + member - adj + 2;
-                 fprintf (file, "\t%04lx\t %4d  %s",member, ordinal, member_name);
+                 ordinal = bfd_get_16 (abfd, data + amt);
+                 member_name = (char *) data + amt + 2;
+                 fprintf (file, "\t%04lx\t %4d  %.*s",member, ordinal,
+                          (int) (datasize - (amt + 2)), member_name);
                }
 
              /* If the time stamp is not zero, the import address
                 table holds actual addresses.  */
              if (time_stamp != 0
                  && first_thunk != 0
                }
 
              /* If the time stamp is not zero, the import address
                 table holds actual addresses.  */
              if (time_stamp != 0
                  && first_thunk != 0
-                 && first_thunk != hint_addr)
+                 && first_thunk != hint_addr
+                 && j + 4 <= ft_datasize)
                fprintf (file, "\t%04lx",
                fprintf (file, "\t%04lx",
-                        (long) bfd_get_32 (abfd, ft_data + ft_idx + j));
+                        (unsigned long) bfd_get_32 (abfd, ft_data + j));
              fprintf (file, "\n");
            }
 #else
              fprintf (file, "\n");
            }
 #else
-         for (j = 0; j < datasize; j += 4)
+         for (j = 0; idx + j + 4 <= datasize; j += 4)
            {
            {
+             bfd_size_type amt;
              unsigned long member = bfd_get_32 (abfd, data + idx + j);
 
              unsigned long member = bfd_get_32 (abfd, data + idx + j);
 
-             /* Print single IMAGE_IMPORT_BY_NAME vector.  */ 
+             /* Print single IMAGE_IMPORT_BY_NAME vector.  */
              if (member == 0)
                break;
 
              if (member == 0)
                break;
 
-             if (member & 0x80000000)
+             amt = member - adj;
+             if (HighBitSet (member))
                fprintf (file, "\t%04lx\t %4lu  <none>",
                fprintf (file, "\t%04lx\t %4lu  <none>",
-                        member, member & 0x7fffffff);
+                        member, WithoutHighBit (member));
+             /* PR binutils/17512: Handle corrupt PE data.  */
+             else if (amt + 2 >= datasize)
+               fprintf (file, _("\t<corrupt: 0x%04lx>"), member);
              else
                {
                  int ordinal;
                  char *member_name;
 
              else
                {
                  int ordinal;
                  char *member_name;
 
-                 ordinal = bfd_get_16 (abfd, data + member - adj);
-                 member_name = (char *) data + member - adj + 2;
-                 fprintf (file, "\t%04lx\t %4d  %s",
-                          member, ordinal, member_name);
+                 ordinal = bfd_get_16 (abfd, data + amt);
+                 member_name = (char *) data + amt + 2;
+                 fprintf (file, "\t%04lx\t %4d  %.*s",
+                          member, ordinal,
+                          (int) (datasize - (amt + 2)), member_name);
                }
 
              /* If the time stamp is not zero, the import address
                 table holds actual addresses.  */
              if (time_stamp != 0
                  && first_thunk != 0
                }
 
              /* If the time stamp is not zero, the import address
                 table holds actual addresses.  */
              if (time_stamp != 0
                  && first_thunk != 0
-                 && first_thunk != hint_addr)
+                 && first_thunk != hint_addr
+                 && j + 4 <= ft_datasize)
                fprintf (file, "\t%04lx",
                fprintf (file, "\t%04lx",
-                        (long) bfd_get_32 (abfd, ft_data + ft_idx + j));
+                        (unsigned long) bfd_get_32 (abfd, ft_data + j));
 
              fprintf (file, "\n");
            }
 
              fprintf (file, "\n");
            }
@@ -1351,7 +1582,7 @@ pe_print_edata (bfd * abfd, void * vfile)
   bfd_size_type datasize = 0;
   bfd_size_type dataoff;
   bfd_size_type i;
   bfd_size_type datasize = 0;
   bfd_size_type dataoff;
   bfd_size_type i;
-  bfd_signed_vma adj;
+  bfd_vma       adj;
   struct EDT_type
   {
     long export_flags;          /* Reserved - should be zero.  */
   struct EDT_type
   {
     long export_flags;          /* Reserved - should be zero.  */
@@ -1401,6 +1632,13 @@ pe_print_edata (bfd * abfd, void * vfile)
                   _("\nThere is an export table, but the section containing it could not be found\n"));
          return TRUE;
        }
                   _("\nThere is an export table, but the section containing it could not be found\n"));
          return TRUE;
        }
+      else if (!(section->flags & SEC_HAS_CONTENTS))
+        {
+         fprintf (file,
+                  _("\nThere is an export table in %s, but that section has no contents\n"),
+                  section->name);
+         return TRUE;
+        }
 
       dataoff = addr - section->vma;
       datasize = extra->DataDirectory[PE_EXPORT_TABLE].Size;
 
       dataoff = addr - section->vma;
       datasize = extra->DataDirectory[PE_EXPORT_TABLE].Size;
@@ -1413,10 +1651,19 @@ pe_print_edata (bfd * abfd, void * vfile)
        }
     }
 
        }
     }
 
+  /* PR 17512: Handle corrupt PE binaries.  */
+  if (datasize < 36)
+    {
+      fprintf (file,
+              _("\nThere is an export table in %s, but it is too small (%d)\n"),
+              section->name, (int) datasize);
+      return TRUE;
+    }
+
   fprintf (file, _("\nThere is an export table in %s at 0x%lx\n"),
           section->name, (unsigned long) addr);
 
   fprintf (file, _("\nThere is an export table in %s at 0x%lx\n"),
           section->name, (unsigned long) addr);
 
-  data = bfd_malloc (datasize);
+  data = (bfd_byte *) bfd_malloc (datasize);
   if (data == NULL)
     return FALSE;
 
   if (data == NULL)
     return FALSE;
 
@@ -1455,9 +1702,14 @@ pe_print_edata (bfd * abfd, void * vfile)
 
   fprintf (file,
           _("Name \t\t\t\t"));
 
   fprintf (file,
           _("Name \t\t\t\t"));
-  fprintf_vma (file, edt.name);
-  fprintf (file,
-          " %s\n", data + edt.name - adj);
+  bfd_fprintf_vma (abfd, file, edt.name);
+
+  if ((edt.name >= adj) && (edt.name < adj + datasize))
+    fprintf (file, " %.*s\n",
+            (int) (datasize - (edt.name - adj)),
+            data + edt.name - adj);
+  else
+    fprintf (file, "(outside .edata section)\n");
 
   fprintf (file,
           _("Ordinal Base \t\t\t%ld\n"), edt.base);
 
   fprintf (file,
           _("Ordinal Base \t\t\t%ld\n"), edt.base);
@@ -1477,17 +1729,17 @@ pe_print_edata (bfd * abfd, void * vfile)
 
   fprintf (file,
           _("\tExport Address Table \t\t"));
 
   fprintf (file,
           _("\tExport Address Table \t\t"));
-  fprintf_vma (file, edt.eat_addr);
+  bfd_fprintf_vma (abfd, file, edt.eat_addr);
   fprintf (file, "\n");
 
   fprintf (file,
           _("\tName Pointer Table \t\t"));
   fprintf (file, "\n");
 
   fprintf (file,
           _("\tName Pointer Table \t\t"));
-  fprintf_vma (file, edt.npt_addr);
+  bfd_fprintf_vma (abfd, file, edt.npt_addr);
   fprintf (file, "\n");
 
   fprintf (file,
           _("\tOrdinal Table \t\t\t"));
   fprintf (file, "\n");
 
   fprintf (file,
           _("\tOrdinal Table \t\t\t"));
-  fprintf_vma (file, edt.ot_addr);
+  bfd_fprintf_vma (abfd, file, edt.ot_addr);
   fprintf (file, "\n");
 
   /* The next table to find is the Export Address Table. It's basically
   fprintf (file, "\n");
 
   /* The next table to find is the Export Address Table. It's basically
@@ -1503,7 +1755,14 @@ pe_print_edata (bfd * abfd, void * vfile)
          _("\nExport Address Table -- Ordinal Base %ld\n"),
          edt.base);
 
          _("\nExport Address Table -- Ordinal Base %ld\n"),
          edt.base);
 
-  for (i = 0; i < edt.num_functions; ++i)
+  /* PR 17512: Handle corrupt PE binaries.  */
+  if (edt.eat_addr + (edt.num_functions * 4) - adj >= datasize
+      /* PR 17512 file: 140-165018-0.004.  */
+      || data + edt.eat_addr - adj < data)
+    fprintf (file, _("\tInvalid Export Address Table rva (0x%lx) or entry count (0x%lx)\n"),
+            (long) edt.eat_addr,
+            (long) edt.num_functions);
+  else for (i = 0; i < edt.num_functions; ++i)
     {
       bfd_vma eat_member = bfd_get_32 (abfd,
                                       data + edt.eat_addr + (i * 4) - adj);
     {
       bfd_vma eat_member = bfd_get_32 (abfd,
                                       data + edt.eat_addr + (i * 4) - adj);
@@ -1515,11 +1774,12 @@ pe_print_edata (bfd * abfd, void * vfile)
          /* This rva is to a name (forwarding function) in our section.  */
          /* Should locate a function descriptor.  */
          fprintf (file,
          /* 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",
+                  "\t[%4ld] +base[%4ld] %04lx %s -- %.*s\n",
                   (long) i,
                   (long) (i + edt.base),
                   (unsigned long) eat_member,
                   _("Forwarder RVA"),
                   (long) i,
                   (long) (i + edt.base),
                   (unsigned long) eat_member,
                   _("Forwarder RVA"),
+                  (int)(datasize - (eat_member - adj)),
                   data + eat_member - adj);
        }
       else
                   data + eat_member - adj);
        }
       else
@@ -1539,21 +1799,38 @@ pe_print_edata (bfd * abfd, void * vfile)
   fprintf (file,
           _("\n[Ordinal/Name Pointer] Table\n"));
 
   fprintf (file,
           _("\n[Ordinal/Name Pointer] Table\n"));
 
-  for (i = 0; i < edt.num_names; ++i)
+  /* PR 17512: Handle corrupt PE binaries.  */
+  if (edt.npt_addr + (edt.num_names * 4) - adj >= datasize
+      || (data + edt.npt_addr - adj) < data)
+    fprintf (file, _("\tInvalid Name Pointer Table rva (0x%lx) or entry count (0x%lx)\n"),
+            (long) edt.npt_addr,
+            (long) edt.num_names);
+  /* PR 17512: file: 140-147171-0.004.  */
+  else if (edt.ot_addr + (edt.num_names * 2) - adj >= datasize
+          || data + edt.ot_addr - adj < data)
+    fprintf (file, _("\tInvalid Ordinal Table rva (0x%lx) or entry count (0x%lx)\n"),
+            (long) edt.ot_addr,
+            (long) edt.num_names);
+  else for (i = 0; i < edt.num_names; ++i)
     {
     {
-      bfd_vma name_ptr = bfd_get_32 (abfd,
-                                   data +
-                                   edt.npt_addr
-                                   + (i*4) - adj);
+      bfd_vma  name_ptr;
+      bfd_vma  ord;
 
 
-      char *name = (char *) data + name_ptr - adj;
+      ord = bfd_get_16 (abfd, data + edt.ot_addr + (i * 2) - adj);
+      name_ptr = bfd_get_32 (abfd, data + edt.npt_addr + (i * 4) - adj);
 
 
-      bfd_vma ord = bfd_get_16 (abfd,
-                                   data +
-                                   edt.ot_addr
-                                   + (i*2) - adj);
-      fprintf (file,
-             "\t[%4ld] %s\n", (long) ord, name);
+      if ((name_ptr - adj) >= datasize)
+       {
+         fprintf (file, _("\t[%4ld] <corrupt offset: %lx>\n"),
+                  (long) ord, (long) name_ptr);
+       }
+      else
+       {
+         char * name = (char *) data + name_ptr - adj;
+
+         fprintf (file, "\t[%4ld] %.*s\n", (long) ord,
+                  (int)((char *)(data + datasize) - name), name);
+       }
     }
 
   free (data);
     }
 
   free (data);
@@ -1564,7 +1841,14 @@ pe_print_edata (bfd * abfd, void * vfile)
 /* This really is architecture dependent.  On IA-64, a .pdata entry
    consists of three dwords containing relative virtual addresses that
    specify the start and end address of the code range the entry
 /* This really is architecture dependent.  On IA-64, a .pdata entry
    consists of three dwords containing relative virtual addresses that
    specify the start and end address of the code range the entry
-   covers and the address of the corresponding unwind info data.  */
+   covers and the address of the corresponding unwind info data.
+
+   On ARM and SH-4, a compressed PDATA structure is used :
+   _IMAGE_CE_RUNTIME_FUNCTION_ENTRY, whereas MIPS is documented to use
+   _IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY.
+   See http://msdn2.microsoft.com/en-us/library/ms253988(VS.80).aspx .
+
+   This is the version for uncompressed data.  */
 
 static bfd_boolean
 pe_print_pdata (bfd * abfd, void * vfile)
 
 static bfd_boolean
 pe_print_pdata (bfd * abfd, void * vfile)
@@ -1608,6 +1892,14 @@ pe_print_pdata (bfd * abfd, void * vfile)
   if (datasize == 0)
     return TRUE;
 
   if (datasize == 0)
     return TRUE;
 
+  /* PR 17512: file: 002-193900-0.004.  */
+  if (datasize < stop)
+    {
+      fprintf (file, _("Virtual size of .pdata section (%ld) larger than real size (%ld)\n"),
+              (long) stop, (long) datasize);
+      return FALSE;
+    }
+
   if (! bfd_malloc_and_get_section (abfd, section, &data))
     {
       if (data != NULL)
   if (! bfd_malloc_and_get_section (abfd, section, &data))
     {
       if (data != NULL)
@@ -1624,7 +1916,9 @@ pe_print_pdata (bfd * abfd, void * vfile)
       bfd_vma eh_handler;
       bfd_vma eh_data;
       bfd_vma prolog_end_addr;
       bfd_vma eh_handler;
       bfd_vma eh_data;
       bfd_vma prolog_end_addr;
+#if !defined(COFF_WITH_pep) || defined(COFF_WITH_pex64)
       int em_data;
       int em_data;
+#endif
 
       if (i + PDATA_ROW_SIZE > stop)
        break;
 
       if (i + PDATA_ROW_SIZE > stop)
        break;
@@ -1640,19 +1934,21 @@ pe_print_pdata (bfd * abfd, void * vfile)
        /* We are probably into the padding of the section now.  */
        break;
 
        /* We are probably into the padding of the section now.  */
        break;
 
+#if !defined(COFF_WITH_pep) || defined(COFF_WITH_pex64)
       em_data = ((eh_handler & 0x1) << 2) | (prolog_end_addr & 0x3);
       em_data = ((eh_handler & 0x1) << 2) | (prolog_end_addr & 0x3);
+#endif
       eh_handler &= ~(bfd_vma) 0x3;
       prolog_end_addr &= ~(bfd_vma) 0x3;
 
       fputc (' ', file);
       eh_handler &= ~(bfd_vma) 0x3;
       prolog_end_addr &= ~(bfd_vma) 0x3;
 
       fputc (' ', file);
-      fprintf_vma (file, i + section->vma); fputc ('\t', file);
-      fprintf_vma (file, begin_addr); fputc (' ', file);
-      fprintf_vma (file, end_addr); fputc (' ', file);
-      fprintf_vma (file, eh_handler);
+      bfd_fprintf_vma (abfd, file, i + section->vma); fputc ('\t', file);
+      bfd_fprintf_vma (abfd, file, begin_addr); fputc (' ', file);
+      bfd_fprintf_vma (abfd, file, end_addr); fputc (' ', file);
+      bfd_fprintf_vma (abfd, file, eh_handler);
 #if !defined(COFF_WITH_pep) || defined(COFF_WITH_pex64)
       fputc (' ', file);
 #if !defined(COFF_WITH_pep) || defined(COFF_WITH_pex64)
       fputc (' ', file);
-      fprintf_vma (file, eh_data); fputc (' ', file);
-      fprintf_vma (file, prolog_end_addr);
+      bfd_fprintf_vma (abfd, file, eh_data); fputc (' ', file);
+      bfd_fprintf_vma (abfd, file, prolog_end_addr);
       fprintf (file, "   %x", em_data);
 #endif
 
       fprintf (file, "   %x", em_data);
 #endif
 
@@ -1688,8 +1984,189 @@ pe_print_pdata (bfd * abfd, void * vfile)
   free (data);
 
   return TRUE;
   free (data);
 
   return TRUE;
+#undef PDATA_ROW_SIZE
+}
+
+typedef struct sym_cache
+{
+  int        symcount;
+  asymbol ** syms;
+} sym_cache;
+
+static asymbol **
+slurp_symtab (bfd *abfd, sym_cache *psc)
+{
+  asymbol ** sy = NULL;
+  long storage;
+
+  if (!(bfd_get_file_flags (abfd) & HAS_SYMS))
+    {
+      psc->symcount = 0;
+      return NULL;
+    }
+
+  storage = bfd_get_symtab_upper_bound (abfd);
+  if (storage < 0)
+    return NULL;
+  if (storage)
+    {
+      sy = (asymbol **) bfd_malloc (storage);
+      if (sy == NULL)
+       return NULL;
+    }
+
+  psc->symcount = bfd_canonicalize_symtab (abfd, sy);
+  if (psc->symcount < 0)
+    return NULL;
+  return sy;
+}
+
+static const char *
+my_symbol_for_address (bfd *abfd, bfd_vma func, sym_cache *psc)
+{
+  int i;
+
+  if (psc->syms == 0)
+    psc->syms = slurp_symtab (abfd, psc);
+
+  for (i = 0; i < psc->symcount; i++)
+    {
+      if (psc->syms[i]->section->vma + psc->syms[i]->value == func)
+       return psc->syms[i]->name;
+    }
+
+  return NULL;
+}
+
+static void
+cleanup_syms (sym_cache *psc)
+{
+  psc->symcount = 0;
+  free (psc->syms);
+  psc->syms = NULL;
+}
+
+/* This is the version for "compressed" pdata.  */
+
+bfd_boolean
+_bfd_XX_print_ce_compressed_pdata (bfd * abfd, void * vfile)
+{
+# define PDATA_ROW_SIZE        (2 * 4)
+  FILE *file = (FILE *) vfile;
+  bfd_byte *data = NULL;
+  asection *section = bfd_get_section_by_name (abfd, ".pdata");
+  bfd_size_type datasize = 0;
+  bfd_size_type i;
+  bfd_size_type start, stop;
+  int onaline = PDATA_ROW_SIZE;
+  struct sym_cache cache = {0, 0} ;
+
+  if (section == NULL
+      || coff_section_data (abfd, section) == NULL
+      || pei_section_data (abfd, section) == NULL)
+    return TRUE;
+
+  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    Prolog   Function Flags    Exception EH\n\
+     \t\tAddress  Length   Length   32b exc  Handler   Data\n"));
+
+  datasize = section->size;
+  if (datasize == 0)
+    return TRUE;
+
+  if (! bfd_malloc_and_get_section (abfd, section, &data))
+    {
+      if (data != NULL)
+       free (data);
+      return FALSE;
+    }
+
+  start = 0;
+
+  for (i = start; i < stop; i += onaline)
+    {
+      bfd_vma begin_addr;
+      bfd_vma other_data;
+      bfd_vma prolog_length, function_length;
+      int flag32bit, exception_flag;
+      asection *tsection;
+
+      if (i + PDATA_ROW_SIZE > stop)
+       break;
+
+      begin_addr = GET_PDATA_ENTRY (abfd, data + i     );
+      other_data = GET_PDATA_ENTRY (abfd, data + i +  4);
+
+      if (begin_addr == 0 && other_data == 0)
+       /* We are probably into the padding of the section now.  */
+       break;
+
+      prolog_length = (other_data & 0x000000FF);
+      function_length = (other_data & 0x3FFFFF00) >> 8;
+      flag32bit = (int)((other_data & 0x40000000) >> 30);
+      exception_flag = (int)((other_data & 0x80000000) >> 31);
+
+      fputc (' ', file);
+      bfd_fprintf_vma (abfd, file, i + section->vma); fputc ('\t', file);
+      bfd_fprintf_vma (abfd, file, begin_addr); fputc (' ', file);
+      bfd_fprintf_vma (abfd, file, prolog_length); fputc (' ', file);
+      bfd_fprintf_vma (abfd, file, function_length); fputc (' ', file);
+      fprintf (file, "%2d  %2d   ", flag32bit, exception_flag);
+
+      /* Get the exception handler's address and the data passed from the
+         .text section. This is really the data that belongs with the .pdata
+         but got "compressed" out for the ARM and SH4 architectures.  */
+      tsection = bfd_get_section_by_name (abfd, ".text");
+      if (tsection && coff_section_data (abfd, tsection)
+         && pei_section_data (abfd, tsection))
+       {
+         bfd_vma eh_off = (begin_addr - 8) - tsection->vma;
+         bfd_byte *tdata;
+
+         tdata = (bfd_byte *) bfd_malloc (8);
+         if (tdata)
+           {
+             if (bfd_get_section_contents (abfd, tsection, tdata, eh_off, 8))
+               {
+                 bfd_vma eh, eh_data;
+
+                 eh = bfd_get_32 (abfd, tdata);
+                 eh_data = bfd_get_32 (abfd, tdata + 4);
+                 fprintf (file, "%08x  ", (unsigned int) eh);
+                 fprintf (file, "%08x", (unsigned int) eh_data);
+                 if (eh != 0)
+                   {
+                     const char *s = my_symbol_for_address (abfd, eh, &cache);
+
+                     if (s)
+                       fprintf (file, " (%s) ", s);
+                   }
+               }
+             free (tdata);
+           }
+       }
+
+      fprintf (file, "\n");
+    }
+
+  free (data);
+
+  cleanup_syms (& cache);
+
+  return TRUE;
+#undef PDATA_ROW_SIZE
 }
 
 }
 
+\f
 #define IMAGE_REL_BASED_HIGHADJ 4
 static const char * const tbl[] =
 {
 #define IMAGE_REL_BASED_HIGHADJ 4
 static const char * const tbl[] =
 {
@@ -1714,20 +2191,14 @@ pe_print_reloc (bfd * abfd, void * vfile)
   FILE *file = (FILE *) vfile;
   bfd_byte *data = 0;
   asection *section = bfd_get_section_by_name (abfd, ".reloc");
   FILE *file = (FILE *) vfile;
   bfd_byte *data = 0;
   asection *section = bfd_get_section_by_name (abfd, ".reloc");
-  bfd_size_type datasize;
-  bfd_size_type i;
-  bfd_size_type start, stop;
+  bfd_byte *p, *end;
 
 
-  if (section == NULL)
-    return TRUE;
-
-  if (section->size == 0)
+  if (section == NULL || section->size == 0 || !(section->flags & SEC_HAS_CONTENTS))
     return TRUE;
 
   fprintf (file,
           _("\n\nPE File Base Relocations (interpreted .reloc section contents)\n"));
 
     return TRUE;
 
   fprintf (file,
           _("\n\nPE File Base Relocations (interpreted .reloc section contents)\n"));
 
-  datasize = section->size;
   if (! bfd_malloc_and_get_section (abfd, section, &data))
     {
       if (data != NULL)
   if (! bfd_malloc_and_get_section (abfd, section, &data))
     {
       if (data != NULL)
@@ -1735,20 +2206,20 @@ pe_print_reloc (bfd * abfd, void * vfile)
       return FALSE;
     }
 
       return FALSE;
     }
 
-  start = 0;
-
-  stop = section->size;
-
-  for (i = start; i < stop;)
+  p = data;
+  end = data + section->size;
+  while (p + 8 <= end)
     {
       int j;
       bfd_vma virtual_address;
       long number, size;
     {
       int j;
       bfd_vma virtual_address;
       long number, size;
+      bfd_byte *chunk_end;
 
       /* The .reloc section is a sequence of blocks, with a header consisting
         of two 32 bit quantities, followed by a number of 16 bit entries.  */
 
       /* The .reloc section is a sequence of blocks, with a header consisting
         of two 32 bit quantities, followed by a number of 16 bit entries.  */
-      virtual_address = bfd_get_32 (abfd, data+i);
-      size = bfd_get_32 (abfd, data+i+4);
+      virtual_address = bfd_get_32 (abfd, p);
+      size = bfd_get_32 (abfd, p + 4);
+      p += 8;
       number = (size - 8) / 2;
 
       if (size == 0)
       number = (size - 8) / 2;
 
       if (size == 0)
@@ -1756,11 +2227,15 @@ pe_print_reloc (bfd * abfd, void * vfile)
 
       fprintf (file,
               _("\nVirtual Address: %08lx Chunk size %ld (0x%lx) Number of fixups %ld\n"),
 
       fprintf (file,
               _("\nVirtual Address: %08lx Chunk size %ld (0x%lx) Number of fixups %ld\n"),
-              (unsigned long) virtual_address, size, size, number);
+              (unsigned long) virtual_address, size, (unsigned long) size, number);
 
 
-      for (j = 0; j < number; ++j)
+      chunk_end = p + size;
+      if (chunk_end > end)
+       chunk_end = end;
+      j = 0;
+      while (p + 2 <= chunk_end)
        {
        {
-         unsigned short e = bfd_get_16 (abfd, data + i + 8 + j * 2);
+         unsigned short e = bfd_get_16 (abfd, p);
          unsigned int t = (e & 0xF000) >> 12;
          int off = e & 0x0FFF;
 
          unsigned int t = (e & 0xF000) >> 12;
          int off = e & 0x0FFF;
 
@@ -1769,48 +2244,473 @@ pe_print_reloc (bfd * abfd, void * vfile)
 
          fprintf (file,
                   _("\treloc %4d offset %4x [%4lx] %s"),
 
          fprintf (file,
                   _("\treloc %4d offset %4x [%4lx] %s"),
-                  j, off, (long) (off + virtual_address), tbl[t]);
+                  j, off, (unsigned long) (off + virtual_address), tbl[t]);
+
+         p += 2;
+         j++;
 
          /* HIGHADJ takes an argument, - the next record *is* the
             low 16 bits of addend.  */
 
          /* HIGHADJ takes an argument, - the next record *is* the
             low 16 bits of addend.  */
-         if (t == IMAGE_REL_BASED_HIGHADJ)
+         if (t == IMAGE_REL_BASED_HIGHADJ && p + 2 <= chunk_end)
            {
            {
-             fprintf (file, " (%4x)",
-                      ((unsigned int)
-                       bfd_get_16 (abfd, data + i + 8 + j * 2 + 2)));
+             fprintf (file, " (%4x)", (unsigned int) bfd_get_16 (abfd, p));
+             p += 2;
              j++;
            }
 
          fprintf (file, "\n");
        }
              j++;
            }
 
          fprintf (file, "\n");
        }
-
-      i += size;
     }
 
   free (data);
 
   return TRUE;
 }
     }
 
   free (data);
 
   return TRUE;
 }
+\f
+/* A data structure describing the regions of a .rsrc section.
+   Some fields are filled in as the section is parsed.  */
 
 
-/* Print out the program headers.  */
-
-bfd_boolean
-_bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
+typedef struct rsrc_regions
 {
 {
-  FILE *file = (FILE *) vfile;
-  int j;
-  pe_data_type *pe = pe_data (abfd);
-  struct internal_extra_pe_aouthdr *i = &pe->pe_opthdr;
-  const char *subsystem_name = NULL;
+  bfd_byte * section_start;
+  bfd_byte * section_end;
+  bfd_byte * strings_start;
+  bfd_byte * resource_start;
+} rsrc_regions;
+
+static bfd_byte *
+rsrc_print_resource_directory (FILE * , bfd *, unsigned int, bfd_byte *,
+                              rsrc_regions *, bfd_vma);
+
+/* Print the resource entry at DATA, with the text indented by INDENT.
+   Recusively calls rsrc_print_resource_directory to print the contents
+   of directory entries.
+   Returns the address of the end of the data associated with the entry
+   or section_end + 1 upon failure.  */
+
+static bfd_byte *
+rsrc_print_resource_entries (FILE *         file,
+                            bfd *          abfd,
+                            unsigned int   indent,
+                            bfd_boolean    is_name,
+                            bfd_byte *     data,
+                            rsrc_regions * regions,
+                            bfd_vma        rva_bias)
+{
+  unsigned long entry, addr, size;
 
 
-  /* The MS dumpbin program reportedly ands with 0xff0f before
-     printing the characteristics field.  Not sure why.  No reason to
-     emulate it here.  */
-  fprintf (file, _("\nCharacteristics 0x%x\n"), pe->real_flags);
-#undef PF
-#define PF(x, y) if (pe->real_flags & x) { fprintf (file, "\t%s\n", y); }
-  PF (IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped");
-  PF (IMAGE_FILE_EXECUTABLE_IMAGE, "executable");
+  if (data + 8 >= regions->section_end)
+    return regions->section_end + 1;
+
+  fprintf (file, _("%03x %*.s Entry: "), (int)(data - regions->section_start), indent, " ");
+
+  entry = (unsigned long) bfd_get_32 (abfd, data);
+  if (is_name)
+    {
+      bfd_byte * name;
+
+      /* Note - the documentation says that this field is an RVA value
+        but windres appears to produce a section relative offset with
+        the top bit set.  Support both styles for now.  */
+      if (HighBitSet (entry))
+       name = regions->section_start + WithoutHighBit (entry);
+      else
+       name = regions->section_start + entry - rva_bias;
+
+      if (name + 2 < regions->section_end && name > regions->section_start)
+       {
+         unsigned int len;
+
+         if (regions->strings_start == NULL)
+           regions->strings_start = name;
+
+         len = bfd_get_16 (abfd, name);
+
+         fprintf (file, _("name: [val: %08lx len %d]: "), entry, len);
+
+         if (name + 2 + len * 2 < regions->section_end)
+           {
+             /* This strange loop is to cope with multibyte characters.  */
+             while (len --)
+               {
+                 char c;
+
+                 name += 2;
+                 c = * name;
+                 /* Avoid printing control characters.  */
+                 if (c > 0 && c < 32)
+                   fprintf (file, "^%c", c + 64);
+                 else
+                   fprintf (file, "%.1s", name);
+               }
+           }
+         else
+           {
+             fprintf (file, _("<corrupt string length: %#x>\n"), len);
+             /* PR binutils/17512: Do not try to continue decoding a
+                corrupted resource section.  It is likely to end up with
+                reams of extraneous output.  FIXME: We could probably
+                continue if we disable the printing of strings...  */
+             return regions->section_end + 1;
+           }
+       }
+      else
+       {
+         fprintf (file, _("<corrupt string offset: %#lx>\n"), entry);
+         return regions->section_end + 1;
+       }
+    }
+  else
+    fprintf (file, _("ID: %#08lx"), entry);
+
+  entry = (long) bfd_get_32 (abfd, data + 4);
+  fprintf (file, _(", Value: %#08lx\n"), entry);
+
+  if (HighBitSet  (entry))
+    {
+      data = regions->section_start + WithoutHighBit (entry);
+      if (data <= regions->section_start || data > regions->section_end)
+       return regions->section_end + 1;
+
+      /* FIXME: PR binutils/17512: A corrupt file could contain a loop
+        in the resource table.  We need some way to detect this.  */
+      return rsrc_print_resource_directory (file, abfd, indent + 1, data,
+                                           regions, rva_bias);
+    }
+
+  if (regions->section_start + entry + 16 >= regions->section_end)
+    return regions->section_end + 1;
+
+  fprintf (file, _("%03x %*.s  Leaf: Addr: %#08lx, Size: %#08lx, Codepage: %d\n"),
+          (int) (entry),
+          indent, " ",
+          addr = (long) bfd_get_32 (abfd, regions->section_start + entry),
+          size = (long) bfd_get_32 (abfd, regions->section_start + entry + 4),
+          (int) bfd_get_32 (abfd, regions->section_start + entry + 8));
+
+  /* Check that the reserved entry is 0.  */
+  if (bfd_get_32 (abfd, regions->section_start + entry + 12) != 0
+      /* And that the data address/size is valid too.  */
+      || (regions->section_start + (addr - rva_bias) + size > regions->section_end))
+    return regions->section_end + 1;
+
+  if (regions->resource_start == NULL)
+    regions->resource_start = regions->section_start + (addr - rva_bias);
+
+  return regions->section_start + (addr - rva_bias) + size;
+}
+
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+static bfd_byte *
+rsrc_print_resource_directory (FILE *         file,
+                              bfd *          abfd,
+                              unsigned int   indent,
+                              bfd_byte *     data,
+                              rsrc_regions * regions,
+                              bfd_vma        rva_bias)
+{
+  unsigned int num_names, num_ids;
+  bfd_byte * highest_data = data;
+
+  if (data + 16 >= regions->section_end)
+    return regions->section_end + 1;
+
+  fprintf (file, "%03x %*.s ", (int)(data - regions->section_start), indent, " ");
+  switch (indent)
+    {
+    case 0: fprintf (file, "Type"); break;
+    case 2: fprintf (file, "Name"); break;
+    case 4: fprintf (file, "Language"); break;
+    default:
+      fprintf (file, _("<unknown directory type: %d>\n"), indent);
+      /* FIXME: For now we end the printing here.  If in the
+        future more directory types are added to the RSRC spec
+        then we will need to change this.  */
+      return regions->section_end + 1;
+    }
+
+  fprintf (file, _(" Table: Char: %d, Time: %08lx, Ver: %d/%d, Num Names: %d, IDs: %d\n"),
+          (int) bfd_get_32 (abfd, data),
+          (long) bfd_get_32 (abfd, data + 4),
+          (int)  bfd_get_16 (abfd, data + 8),
+          (int)  bfd_get_16 (abfd, data + 10),
+          num_names = (int) bfd_get_16 (abfd, data + 12),
+          num_ids =   (int) bfd_get_16 (abfd, data + 14));
+  data += 16;
+
+  while (num_names --)
+    {
+      bfd_byte * entry_end;
+
+      entry_end = rsrc_print_resource_entries (file, abfd, indent + 1, TRUE,
+                                              data, regions, rva_bias);
+      data += 8;
+      highest_data = max (highest_data, entry_end);
+      if (entry_end >= regions->section_end)
+       return entry_end;
+    }
+
+  while (num_ids --)
+    {
+      bfd_byte * entry_end;
+
+      entry_end = rsrc_print_resource_entries (file, abfd, indent + 1, FALSE,
+                                              data, regions, rva_bias);
+      data += 8;
+      highest_data = max (highest_data, entry_end);
+      if (entry_end >= regions->section_end)
+       return entry_end;
+    }
+
+  return max (highest_data, data);
+}
+
+/* Display the contents of a .rsrc section.  We do not try to
+   reproduce the resources, windres does that.  Instead we dump
+   the tables in a human readable format.  */
+
+static bfd_boolean
+rsrc_print_section (bfd * abfd, void * vfile)
+{
+  bfd_vma rva_bias;
+  pe_data_type * pe;
+  FILE * file = (FILE *) vfile;
+  bfd_size_type datasize;
+  asection * section;
+  bfd_byte * data;
+  rsrc_regions regions;
+
+  pe = pe_data (abfd);
+  if (pe == NULL)
+    return TRUE;
+
+  section = bfd_get_section_by_name (abfd, ".rsrc");
+  if (section == NULL)
+    return TRUE;
+  if (!(section->flags & SEC_HAS_CONTENTS))
+    return TRUE;
+
+  datasize = section->size;
+  if (datasize == 0)
+    return TRUE;
+
+  rva_bias = section->vma - pe->pe_opthdr.ImageBase;
+
+  if (! bfd_malloc_and_get_section (abfd, section, & data))
+    {
+      if (data != NULL)
+       free (data);
+      return FALSE;
+    }
+
+  regions.section_start = data;
+  regions.section_end = data + datasize;
+  regions.strings_start = NULL;
+  regions.resource_start = NULL;
+
+  fflush (file);
+  fprintf (file, "\nThe .rsrc Resource Directory section:\n");
+
+  while (data < regions.section_end)
+    {
+      bfd_byte * p = data;
+
+      data = rsrc_print_resource_directory (file, abfd, 0, data, & regions, rva_bias);
+
+      if (data == regions.section_end + 1)
+       fprintf (file, _("Corrupt .rsrc section detected!\n"));
+      else
+       {
+         /* Align data before continuing.  */
+         int align = (1 << section->alignment_power) - 1;
+
+         data = (bfd_byte *) (((ptrdiff_t) (data + align)) & ~ align);
+         rva_bias += data - p;
+
+         /* For reasons that are unclear .rsrc sections are sometimes created
+            aligned to a 1^3 boundary even when their alignment is set at
+            1^2.  Catch that case here before we issue a spurious warning
+            message.  */
+         if (data == (regions.section_end - 4))
+           data = regions.section_end;
+         else if (data < regions.section_end)
+           {
+             /* If the extra data is all zeros then do not complain.
+                This is just padding so that the section meets the
+                page size requirements.  */
+             while (++ data < regions.section_end)
+               if (*data != 0)
+                 break;
+             if (data < regions.section_end)
+               fprintf (file, _("\nWARNING: Extra data in .rsrc section - it will be ignored by Windows:\n"));
+           }
+       }
+    }
+
+  if (regions.strings_start != NULL)
+    fprintf (file, " String table starts at offset: %#03x\n",
+            (int) (regions.strings_start - regions.section_start));
+  if (regions.resource_start != NULL)
+    fprintf (file, " Resources start at offset: %#03x\n",
+            (int) (regions.resource_start - regions.section_start));
+  
+  free (regions.section_start);
+  return TRUE;
+}
+
+#define IMAGE_NUMBEROF_DEBUG_TYPES 12
+
+static char * debug_type_names[IMAGE_NUMBEROF_DEBUG_TYPES] =
+{
+  "Unknown",
+  "COFF",
+  "CodeView",
+  "FPO",
+  "Misc",
+  "Exception",
+  "Fixup",
+  "OMAP-to-SRC",
+  "OMAP-from-SRC",
+  "Borland",
+  "Reserved",
+  "CLSID",
+};
+
+static bfd_boolean
+pe_print_debugdata (bfd * abfd, void * vfile)
+{
+  FILE *file = (FILE *) vfile;
+  pe_data_type *pe = pe_data (abfd);
+  struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr;
+  asection *section;
+  bfd_byte *data = 0;
+  bfd_size_type dataoff;
+  unsigned int i;
+
+  bfd_vma addr = extra->DataDirectory[PE_DEBUG_DATA].VirtualAddress;
+  bfd_size_type size = extra->DataDirectory[PE_DEBUG_DATA].Size;
+
+  if (size == 0)
+    return TRUE;
+
+  addr += extra->ImageBase;
+  for (section = abfd->sections; section != NULL; section = section->next)
+    {
+      if ((addr >= section->vma) && (addr < (section->vma + section->size)))
+        break;
+    }
+
+  if (section == NULL)
+    {
+      fprintf (file,
+               _("\nThere is a debug directory, but the section containing it could not be found\n"));
+      return TRUE;
+    }
+  else if (!(section->flags & SEC_HAS_CONTENTS))
+    {
+      fprintf (file,
+               _("\nThere is a debug directory in %s, but that section has no contents\n"),
+               section->name);
+      return TRUE;
+    }
+  else if (section->size < size)
+    {
+      fprintf (file,
+               _("\nError: section %s contains the debug data starting address but it is too small\n"),
+               section->name);
+      return FALSE;
+    }
+
+  fprintf (file, _("\nThere is a debug directory in %s at 0x%lx\n\n"),
+          section->name, (unsigned long) addr);
+
+  dataoff = addr - section->vma;
+
+  if (size > (section->size - dataoff))
+    {
+      fprintf (file, _("The debug data size field in the data directory is too big for the section"));
+      return FALSE;
+    }
+
+  fprintf (file,
+          _("Type                Size     Rva      Offset\n"));
+
+  /* Read the whole section.  */
+  if (!bfd_malloc_and_get_section (abfd, section, &data))
+    {
+      if (data != NULL)
+       free (data);
+      return FALSE;
+    }
+
+  for (i = 0; i < size / sizeof (struct external_IMAGE_DEBUG_DIRECTORY); i++)
+    {
+      const char *type_name;
+      struct external_IMAGE_DEBUG_DIRECTORY *ext
+       = &((struct external_IMAGE_DEBUG_DIRECTORY *)(data + dataoff))[i];
+      struct internal_IMAGE_DEBUG_DIRECTORY idd;
+
+      _bfd_XXi_swap_debugdir_in (abfd, ext, &idd);
+
+      if ((idd.Type) >= IMAGE_NUMBEROF_DEBUG_TYPES)
+        type_name = debug_type_names[0];
+      else
+        type_name = debug_type_names[idd.Type];
+
+      fprintf (file, " %2ld  %14s %08lx %08lx %08lx\n",
+              idd.Type, type_name, idd.SizeOfData,
+              idd.AddressOfRawData, idd.PointerToRawData);
+
+      if (idd.Type == PE_IMAGE_DEBUG_TYPE_CODEVIEW)
+        {
+          char signature[CV_INFO_SIGNATURE_LENGTH * 2 + 1];
+          char buffer[256 + 1];
+          CODEVIEW_INFO *cvinfo = (CODEVIEW_INFO *) buffer;
+
+          /* The debug entry doesn't have to have to be in a section,
+            in which case AddressOfRawData is 0, so always use PointerToRawData.  */
+          if (!_bfd_XXi_slurp_codeview_record (abfd, (file_ptr) idd.PointerToRawData,
+                                              idd.SizeOfData, cvinfo))
+            continue;
+
+          for (i = 0; i < cvinfo->SignatureLength; i++)
+            sprintf (&signature[i*2], "%02x", cvinfo->Signature[i] & 0xff);
+
+          fprintf (file, "(format %c%c%c%c signature %s age %ld)\n",
+                  buffer[0], buffer[1], buffer[2], buffer[3],
+                  signature, cvinfo->Age);
+        }
+    }
+
+  if (size % sizeof (struct external_IMAGE_DEBUG_DIRECTORY) != 0)
+    fprintf (file,
+            _("The debug directory size is not a multiple of the debug directory entry size\n"));
+
+  return TRUE;
+}
+
+/* Print out the program headers.  */
+
+bfd_boolean
+_bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
+{
+  FILE *file = (FILE *) vfile;
+  int j;
+  pe_data_type *pe = pe_data (abfd);
+  struct internal_extra_pe_aouthdr *i = &pe->pe_opthdr;
+  const char *subsystem_name = NULL;
+  const char *name;
+
+  /* The MS dumpbin program reportedly ands with 0xff0f before
+     printing the characteristics field.  Not sure why.  No reason to
+     emulate it here.  */
+  fprintf (file, _("\nCharacteristics 0x%x\n"), pe->real_flags);
+#undef PF
+#define PF(x, y) if (pe->real_flags & x) { fprintf (file, "\t%s\n", y); }
+  PF (IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped");
+  PF (IMAGE_FILE_EXECUTABLE_IMAGE, "executable");
   PF (IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped");
   PF (IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped");
   PF (IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware");
   PF (IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped");
   PF (IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped");
   PF (IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware");
@@ -1827,22 +2727,68 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
     time_t t = pe->coff.timestamp;
     fprintf (file, "\nTime/Date\t\t%s", ctime (&t));
   }
     time_t t = pe->coff.timestamp;
     fprintf (file, "\nTime/Date\t\t%s", ctime (&t));
   }
+
+#ifndef IMAGE_NT_OPTIONAL_HDR_MAGIC
+# define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b
+#endif
+#ifndef IMAGE_NT_OPTIONAL_HDR64_MAGIC
+# define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+#endif
+#ifndef IMAGE_NT_OPTIONAL_HDRROM_MAGIC
+# define IMAGE_NT_OPTIONAL_HDRROM_MAGIC 0x107
+#endif
+
+  switch (i->Magic)
+    {
+    case IMAGE_NT_OPTIONAL_HDR_MAGIC:
+      name = "PE32";
+      break;
+    case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+      name = "PE32+";
+      break;
+    case IMAGE_NT_OPTIONAL_HDRROM_MAGIC:
+      name = "ROM";
+      break;
+    default:
+      name = NULL;
+      break;
+    }
+  fprintf (file, "Magic\t\t\t%04x", i->Magic);
+  if (name)
+    fprintf (file, "\t(%s)",name);
+  fprintf (file, "\nMajorLinkerVersion\t%d\n", i->MajorLinkerVersion);
+  fprintf (file, "MinorLinkerVersion\t%d\n", i->MinorLinkerVersion);
+  fprintf (file, "SizeOfCode\t\t%08lx\n", (unsigned long) i->SizeOfCode);
+  fprintf (file, "SizeOfInitializedData\t%08lx\n",
+          (unsigned long) i->SizeOfInitializedData);
+  fprintf (file, "SizeOfUninitializedData\t%08lx\n",
+          (unsigned long) i->SizeOfUninitializedData);
+  fprintf (file, "AddressOfEntryPoint\t");
+  bfd_fprintf_vma (abfd, file, i->AddressOfEntryPoint);
+  fprintf (file, "\nBaseOfCode\t\t");
+  bfd_fprintf_vma (abfd, file, i->BaseOfCode);
+#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64)
+  /* PE32+ does not have BaseOfData member!  */
+  fprintf (file, "\nBaseOfData\t\t");
+  bfd_fprintf_vma (abfd, file, i->BaseOfData);
+#endif
+
   fprintf (file, "\nImageBase\t\t");
   fprintf (file, "\nImageBase\t\t");
-  fprintf_vma (file, i->ImageBase);
+  bfd_fprintf_vma (abfd, file, i->ImageBase);
   fprintf (file, "\nSectionAlignment\t");
   fprintf (file, "\nSectionAlignment\t");
-  fprintf_vma (file, i->SectionAlignment);
+  bfd_fprintf_vma (abfd, file, i->SectionAlignment);
   fprintf (file, "\nFileAlignment\t\t");
   fprintf (file, "\nFileAlignment\t\t");
-  fprintf_vma (file, i->FileAlignment);
+  bfd_fprintf_vma (abfd, file, i->FileAlignment);
   fprintf (file, "\nMajorOSystemVersion\t%d\n", i->MajorOperatingSystemVersion);
   fprintf (file, "MinorOSystemVersion\t%d\n", i->MinorOperatingSystemVersion);
   fprintf (file, "MajorImageVersion\t%d\n", i->MajorImageVersion);
   fprintf (file, "MinorImageVersion\t%d\n", i->MinorImageVersion);
   fprintf (file, "MajorSubsystemVersion\t%d\n", i->MajorSubsystemVersion);
   fprintf (file, "MinorSubsystemVersion\t%d\n", i->MinorSubsystemVersion);
   fprintf (file, "\nMajorOSystemVersion\t%d\n", i->MajorOperatingSystemVersion);
   fprintf (file, "MinorOSystemVersion\t%d\n", i->MinorOperatingSystemVersion);
   fprintf (file, "MajorImageVersion\t%d\n", i->MajorImageVersion);
   fprintf (file, "MinorImageVersion\t%d\n", i->MinorImageVersion);
   fprintf (file, "MajorSubsystemVersion\t%d\n", i->MajorSubsystemVersion);
   fprintf (file, "MinorSubsystemVersion\t%d\n", i->MinorSubsystemVersion);
-  fprintf (file, "Win32Version\t\t%08lx\n", i->Reserved1);
-  fprintf (file, "SizeOfImage\t\t%08lx\n", i->SizeOfImage);
-  fprintf (file, "SizeOfHeaders\t\t%08lx\n", i->SizeOfHeaders);
-  fprintf (file, "CheckSum\t\t%08lx\n", i->CheckSum);
+  fprintf (file, "Win32Version\t\t%08lx\n", (unsigned long) i->Reserved1);
+  fprintf (file, "SizeOfImage\t\t%08lx\n", (unsigned long) i->SizeOfImage);
+  fprintf (file, "SizeOfHeaders\t\t%08lx\n", (unsigned long) i->SizeOfHeaders);
+  fprintf (file, "CheckSum\t\t%08lx\n", (unsigned long) i->CheckSum);
 
   switch (i->Subsystem)
     {
 
   switch (i->Subsystem)
     {
@@ -1864,6 +2810,7 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
     case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
       subsystem_name = "Wince CUI";
       break;
     case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
       subsystem_name = "Wince CUI";
       break;
+    // These are from UEFI Platform Initialization Specification 1.1.
     case IMAGE_SUBSYSTEM_EFI_APPLICATION:
       subsystem_name = "EFI application";
       break;
     case IMAGE_SUBSYSTEM_EFI_APPLICATION:
       subsystem_name = "EFI application";
       break;
@@ -1873,10 +2820,10 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
     case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
       subsystem_name = "EFI runtime driver";
       break;
     case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
       subsystem_name = "EFI runtime driver";
       break;
-    // These are from revision 8.0 of the MS PE/COFF spec
-    case IMAGE_SUBSYSTEM_EFI_ROM:
-      subsystem_name = "EFI ROM";
+    case IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
+      subsystem_name = "SAL runtime driver";
       break;
       break;
+    // This is from revision 8.0 of the MS PE/COFF spec
     case IMAGE_SUBSYSTEM_XBOX:
       subsystem_name = "XBOX";
       break;
     case IMAGE_SUBSYSTEM_XBOX:
       subsystem_name = "XBOX";
       break;
@@ -1890,46 +2837,75 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
     fprintf (file, "\t(%s)", subsystem_name);
   fprintf (file, "\nDllCharacteristics\t%08x\n", i->DllCharacteristics);
   fprintf (file, "SizeOfStackReserve\t");
     fprintf (file, "\t(%s)", subsystem_name);
   fprintf (file, "\nDllCharacteristics\t%08x\n", i->DllCharacteristics);
   fprintf (file, "SizeOfStackReserve\t");
-  fprintf_vma (file, i->SizeOfStackReserve);
+  bfd_fprintf_vma (abfd, file, i->SizeOfStackReserve);
   fprintf (file, "\nSizeOfStackCommit\t");
   fprintf (file, "\nSizeOfStackCommit\t");
-  fprintf_vma (file, i->SizeOfStackCommit);
+  bfd_fprintf_vma (abfd, file, i->SizeOfStackCommit);
   fprintf (file, "\nSizeOfHeapReserve\t");
   fprintf (file, "\nSizeOfHeapReserve\t");
-  fprintf_vma (file, i->SizeOfHeapReserve);
+  bfd_fprintf_vma (abfd, file, i->SizeOfHeapReserve);
   fprintf (file, "\nSizeOfHeapCommit\t");
   fprintf (file, "\nSizeOfHeapCommit\t");
-  fprintf_vma (file, i->SizeOfHeapCommit);
-  fprintf (file, "\nLoaderFlags\t\t%08lx\n", i->LoaderFlags);
-  fprintf (file, "NumberOfRvaAndSizes\t%08lx\n", i->NumberOfRvaAndSizes);
+  bfd_fprintf_vma (abfd, file, i->SizeOfHeapCommit);
+  fprintf (file, "\nLoaderFlags\t\t%08lx\n", (unsigned long) i->LoaderFlags);
+  fprintf (file, "NumberOfRvaAndSizes\t%08lx\n",
+          (unsigned long) i->NumberOfRvaAndSizes);
 
   fprintf (file, "\nThe Data Directory\n");
   for (j = 0; j < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; j++)
     {
       fprintf (file, "Entry %1x ", j);
 
   fprintf (file, "\nThe Data Directory\n");
   for (j = 0; j < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; j++)
     {
       fprintf (file, "Entry %1x ", j);
-      fprintf_vma (file, i->DataDirectory[j].VirtualAddress);
-      fprintf (file, " %08lx ", i->DataDirectory[j].Size);
+      bfd_fprintf_vma (abfd, file, i->DataDirectory[j].VirtualAddress);
+      fprintf (file, " %08lx ", (unsigned long) i->DataDirectory[j].Size);
       fprintf (file, "%s\n", dir_names[j]);
     }
 
   pe_print_idata (abfd, vfile);
   pe_print_edata (abfd, vfile);
       fprintf (file, "%s\n", dir_names[j]);
     }
 
   pe_print_idata (abfd, vfile);
   pe_print_edata (abfd, vfile);
-  pe_print_pdata (abfd, vfile);
+  if (bfd_coff_have_print_pdata (abfd))
+    bfd_coff_print_pdata (abfd, vfile);
+  else
+    pe_print_pdata (abfd, vfile);
   pe_print_reloc (abfd, vfile);
   pe_print_reloc (abfd, vfile);
+  pe_print_debugdata (abfd, file);
+
+  rsrc_print_section (abfd, vfile);
 
   return TRUE;
 }
 
 
   return TRUE;
 }
 
+static bfd_boolean
+is_vma_in_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj)
+{
+  bfd_vma addr = * (bfd_vma *) obj;
+  return (addr >= sect->vma) && (addr < (sect->vma + sect->size));
+}
+
+static asection *
+find_section_by_vma (bfd *abfd, bfd_vma addr)
+{
+  return bfd_sections_find_if (abfd, is_vma_in_section, (void *) & addr);
+}
+
 /* Copy any private info we understand from the input bfd
    to the output bfd.  */
 
 bfd_boolean
 _bfd_XX_bfd_copy_private_bfd_data_common (bfd * ibfd, bfd * obfd)
 {
 /* Copy any private info we understand from the input bfd
    to the output bfd.  */
 
 bfd_boolean
 _bfd_XX_bfd_copy_private_bfd_data_common (bfd * ibfd, bfd * obfd)
 {
+  pe_data_type *ipe, *ope;
+
   /* One day we may try to grok other private data.  */
   if (ibfd->xvec->flavour != bfd_target_coff_flavour
       || obfd->xvec->flavour != bfd_target_coff_flavour)
     return TRUE;
 
   /* One day we may try to grok other private data.  */
   if (ibfd->xvec->flavour != bfd_target_coff_flavour
       || obfd->xvec->flavour != bfd_target_coff_flavour)
     return TRUE;
 
-  pe_data (obfd)->pe_opthdr = pe_data (ibfd)->pe_opthdr;
-  pe_data (obfd)->dll = pe_data (ibfd)->dll;
+  ipe = pe_data (ibfd);
+  ope = pe_data (obfd);
+
+  /* pe_opthdr is copied in copy_object.  */
+  ope->dll = ipe->dll;
+
+  /* Don't copy input subsystem if output is different from input.  */
+  if (obfd->xvec != ibfd->xvec)
+    ope->pe_opthdr.Subsystem = IMAGE_SUBSYSTEM_UNKNOWN;
 
   /* For strip: if we removed .reloc, we'll make a real mess of things
      if we don't remove this entry as well.  */
 
   /* For strip: if we removed .reloc, we'll make a real mess of things
      if we don't remove this entry as well.  */
@@ -1938,6 +2914,73 @@ _bfd_XX_bfd_copy_private_bfd_data_common (bfd * ibfd, bfd * obfd)
       pe_data (obfd)->pe_opthdr.DataDirectory[PE_BASE_RELOCATION_TABLE].VirtualAddress = 0;
       pe_data (obfd)->pe_opthdr.DataDirectory[PE_BASE_RELOCATION_TABLE].Size = 0;
     }
       pe_data (obfd)->pe_opthdr.DataDirectory[PE_BASE_RELOCATION_TABLE].VirtualAddress = 0;
       pe_data (obfd)->pe_opthdr.DataDirectory[PE_BASE_RELOCATION_TABLE].Size = 0;
     }
+
+  /* For PIE, if there is .reloc, we won't add IMAGE_FILE_RELOCS_STRIPPED.
+     But there is no .reloc, we make sure that IMAGE_FILE_RELOCS_STRIPPED
+     won't be added.  */
+  if (! pe_data (ibfd)->has_reloc_section
+      && ! (pe_data (ibfd)->real_flags & IMAGE_FILE_RELOCS_STRIPPED))
+    pe_data (obfd)->dont_strip_reloc = 1;
+
+  /* The file offsets contained in the debug directory need rewriting.  */
+  if (ope->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size != 0)
+    {
+      bfd_vma addr = ope->pe_opthdr.DataDirectory[PE_DEBUG_DATA].VirtualAddress
+       + ope->pe_opthdr.ImageBase;
+      asection *section = find_section_by_vma (obfd, addr);
+      bfd_byte *data;
+
+      if (section && bfd_malloc_and_get_section (obfd, section, &data))
+        {
+          unsigned int i;
+          struct external_IMAGE_DEBUG_DIRECTORY *dd =
+           (struct external_IMAGE_DEBUG_DIRECTORY *)(data + (addr - section->vma));
+
+         /* PR 17512: file: 0f15796a.  */
+         if (ope->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size + (addr - section->vma)
+             > bfd_get_section_size (section))
+           {
+             _bfd_error_handler (_("%A: Data Directory size (%lx) exceeds space left in section (%lx)"),
+                                 obfd, ope->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size,
+                                 bfd_get_section_size (section) - (addr - section->vma));
+             return FALSE;
+           }
+
+          for (i = 0; i < ope->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size
+                / sizeof (struct external_IMAGE_DEBUG_DIRECTORY); i++)
+            {
+              asection *ddsection;
+              struct external_IMAGE_DEBUG_DIRECTORY *edd = &(dd[i]);
+              struct internal_IMAGE_DEBUG_DIRECTORY idd;
+
+              _bfd_XXi_swap_debugdir_in (obfd, edd, &idd);
+
+              if (idd.AddressOfRawData == 0)
+                continue; /* RVA 0 means only offset is valid, not handled yet.  */
+
+              ddsection = find_section_by_vma (obfd, idd.AddressOfRawData + ope->pe_opthdr.ImageBase);
+              if (!ddsection)
+                continue; /* Not in a section! */
+
+              idd.PointerToRawData = ddsection->filepos + (idd.AddressOfRawData
+                                                          + ope->pe_opthdr.ImageBase) - ddsection->vma;
+
+              _bfd_XXi_swap_debugdir_out (obfd, &idd, edd);
+            }
+
+          if (!bfd_set_section_contents (obfd, section, data, 0, section->size))
+           {
+             _bfd_error_handler (_("Failed to update file offsets in debug directory"));
+             return FALSE;
+           }
+        }
+      else if (section)
+       {
+         _bfd_error_handler (_("%A: Failed to read debug data section"), obfd);
+         return FALSE;
+       }
+    }
+
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -1987,41 +3030,1297 @@ _bfd_XX_get_symbol_info (bfd * abfd, asymbol *symbol, symbol_info *ret)
   coff_get_symbol_info (abfd, symbol, ret);
 }
 
   coff_get_symbol_info (abfd, symbol, ret);
 }
 
-/* Handle the .idata section and other things that need symbol table
-   access.  */
-
-bfd_boolean
-_bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
+#if !defined(COFF_WITH_pep) && defined(COFF_WITH_pex64)
+static int
+sort_x64_pdata (const void *l, const void *r)
 {
 {
-  struct coff_link_hash_entry *h1;
-  struct bfd_link_info *info = pfinfo->info;
-  bfd_boolean result = TRUE;
-
-  /* There are a few fields that need to be filled in now while we
-     have symbol table access.
+  const char *lp = (const char *) l;
+  const char *rp = (const char *) r;
+  bfd_vma vl, vr;
+  vl = bfd_getl32 (lp); vr = bfd_getl32 (rp);
+  if (vl != vr)
+    return (vl < vr ? -1 : 1);
+  /* We compare just begin address.  */
+  return 0;
+}
+#endif
+\f
+/* Functions to process a .rsrc section.  */
+
+static unsigned int sizeof_leaves;
+static unsigned int sizeof_strings;
+static unsigned int sizeof_tables_and_entries;
+
+static bfd_byte *
+rsrc_count_directory (bfd *, bfd_byte *, bfd_byte *, bfd_byte *, bfd_vma);
+
+static bfd_byte *
+rsrc_count_entries (bfd *          abfd,
+                   bfd_boolean    is_name,
+                   bfd_byte *     datastart,
+                   bfd_byte *     data,
+                   bfd_byte *     dataend,
+                   bfd_vma        rva_bias)
+{
+  unsigned long entry, addr, size;
 
 
-     The .idata subsections aren't directly available as sections, but
-     they are in the symbol table, so get them from there.  */
+  if (data + 8 >= dataend)
+    return dataend + 1;
 
 
-  /* 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)
+  if (is_name)
     {
     {
-      /* PR ld/2729: We cannot rely upon all the output sections having been 
-        created properly, so check before referencing them.  Issue a warning
-        message for any sections tht could not be found.  */
-      if (h1->root.u.def.section != NULL
-         && h1->root.u.def.section->output_section != NULL)
-       pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_TABLE].VirtualAddress =
-         (h1->root.u.def.value
-          + h1->root.u.def.section->output_section->vma
-          + h1->root.u.def.section->output_offset);
+      bfd_byte * name;
+
+      entry = (long) bfd_get_32 (abfd, data);
+
+      if (HighBitSet (entry))
+       name = datastart + WithoutHighBit (entry);
       else
       else
-       {
+       name = datastart + entry - rva_bias;
+
+      if (name + 2 >= dataend || name < datastart)
+       return dataend + 1;
+
+      unsigned int len = bfd_get_16 (abfd, name);
+      if (len == 0 || len > 256)
+       return dataend + 1;
+    }
+
+  entry = (long) bfd_get_32 (abfd, data + 4);
+
+  if (HighBitSet (entry))
+    {
+      data = datastart + WithoutHighBit (entry);
+
+      if (data <= datastart || data >= dataend)
+       return dataend + 1;
+
+      return rsrc_count_directory (abfd, datastart, data, dataend, rva_bias);
+    }
+
+  if (datastart + entry + 16 >= dataend)
+    return dataend + 1;
+
+  addr = (long) bfd_get_32 (abfd, datastart + entry);
+  size = (long) bfd_get_32 (abfd, datastart + entry + 4);
+
+  return datastart + addr - rva_bias + size;
+}
+
+static bfd_byte *
+rsrc_count_directory (bfd *          abfd,
+                     bfd_byte *     datastart,
+                     bfd_byte *     data,
+                     bfd_byte *     dataend,
+                     bfd_vma        rva_bias)
+{
+  unsigned int  num_entries, num_ids;
+  bfd_byte *    highest_data = data;
+
+  if (data + 16 >= dataend)
+    return dataend + 1;
+
+  num_entries  = (int) bfd_get_16 (abfd, data + 12);
+  num_ids      = (int) bfd_get_16 (abfd, data + 14);
+
+  num_entries += num_ids;
+
+  data += 16;
+
+  while (num_entries --)
+    {
+      bfd_byte * entry_end;
+
+      entry_end = rsrc_count_entries (abfd, num_entries >= num_ids,
+                                     datastart, data, dataend, rva_bias);
+      data += 8;
+      highest_data = max (highest_data, entry_end);
+      if (entry_end >= dataend)
+       break;
+    }
+
+  return max (highest_data, data);
+}
+
+typedef struct rsrc_dir_chain
+{
+  unsigned int         num_entries;
+  struct rsrc_entry *  first_entry;
+  struct rsrc_entry *  last_entry;
+} rsrc_dir_chain;
+
+typedef struct rsrc_directory
+{
+  unsigned int characteristics;
+  unsigned int time;
+  unsigned int major;
+  unsigned int minor;
+
+  rsrc_dir_chain names;
+  rsrc_dir_chain ids;
+
+  struct rsrc_entry * entry;
+} rsrc_directory;
+
+typedef struct rsrc_string
+{
+  unsigned int  len;
+  bfd_byte *    string;
+} rsrc_string;
+
+typedef struct rsrc_leaf
+{
+  unsigned int  size;
+  unsigned int  codepage;
+  bfd_byte *    data;
+} rsrc_leaf;
+
+typedef struct rsrc_entry
+{
+  bfd_boolean is_name;
+  union
+  {
+    unsigned int          id;
+    struct rsrc_string    name;
+  } name_id;
+
+  bfd_boolean is_dir;
+  union
+  {
+    struct rsrc_directory * directory;
+    struct rsrc_leaf *      leaf;
+  } value;
+
+  struct rsrc_entry *     next_entry;
+  struct rsrc_directory * parent;
+} rsrc_entry;
+
+static bfd_byte *
+rsrc_parse_directory (bfd *, rsrc_directory *, bfd_byte *,
+                     bfd_byte *, bfd_byte *, bfd_vma, rsrc_entry *);
+
+static bfd_byte *
+rsrc_parse_entry (bfd *            abfd,
+                 bfd_boolean      is_name,
+                 rsrc_entry *     entry,
+                 bfd_byte *       datastart,
+                 bfd_byte *       data,
+                 bfd_byte *       dataend,
+                 bfd_vma          rva_bias,
+                 rsrc_directory * parent)
+{
+  unsigned long val, addr, size;
+
+  val = bfd_get_32 (abfd, data);
+
+  entry->parent = parent;
+  entry->is_name = is_name;
+
+  if (is_name)
+    {
+      bfd_byte * address;
+
+      if (HighBitSet (val))
+       {
+         val = WithoutHighBit (val);
+
+         address = datastart + val;
+       }
+      else
+       {
+         address = datastart + val - rva_bias;
+       }
+
+      if (address + 3 > dataend)
+       return dataend;
+
+      entry->name_id.name.len    = bfd_get_16 (abfd, address);
+      entry->name_id.name.string = address + 2;
+    }
+  else
+    entry->name_id.id = val;
+
+  val = bfd_get_32 (abfd, data + 4);
+
+  if (HighBitSet (val))
+    {
+      entry->is_dir = TRUE;
+      entry->value.directory = bfd_malloc (sizeof * entry->value.directory);
+      if (entry->value.directory == NULL)
+       return dataend;
+
+      return rsrc_parse_directory (abfd, entry->value.directory,
+                                  datastart,
+                                  datastart + WithoutHighBit (val),
+                                  dataend, rva_bias, entry);
+    }
+
+  entry->is_dir = FALSE;
+  entry->value.leaf = bfd_malloc (sizeof * entry->value.leaf);
+  if (entry->value.leaf == NULL)
+    return dataend;
+
+  addr = bfd_get_32 (abfd, datastart + val);
+  size = entry->value.leaf->size = bfd_get_32 (abfd, datastart + val + 4);
+  entry->value.leaf->codepage = bfd_get_32 (abfd, datastart + val + 8);
+
+  entry->value.leaf->data = bfd_malloc (size);
+  if (entry->value.leaf->data == NULL)
+    return dataend;
+
+  memcpy (entry->value.leaf->data, datastart + addr - rva_bias, size);
+  return datastart + (addr - rva_bias) + size;
+}
+
+static bfd_byte *
+rsrc_parse_entries (bfd *            abfd,
+                   rsrc_dir_chain * chain,
+                   bfd_boolean      is_name,
+                   bfd_byte *       highest_data,
+                   bfd_byte *       datastart,
+                   bfd_byte *       data,
+                   bfd_byte *       dataend,
+                   bfd_vma          rva_bias,
+                   rsrc_directory * parent)
+{
+  unsigned int i;
+  rsrc_entry * entry;
+
+  if (chain->num_entries == 0)
+    {
+      chain->first_entry = chain->last_entry = NULL;
+      return highest_data;
+    }
+
+  entry = bfd_malloc (sizeof * entry);
+  if (entry == NULL)
+    return dataend;
+
+  chain->first_entry = entry;
+
+  for (i = chain->num_entries; i--;)
+    {
+      bfd_byte * entry_end;
+
+      entry_end = rsrc_parse_entry (abfd, is_name, entry, datastart,
+                                   data, dataend, rva_bias, parent);
+      data += 8;
+      highest_data = max (entry_end, highest_data);
+      if (entry_end > dataend)
+       return dataend;
+
+      if (i)
+       {
+         entry->next_entry = bfd_malloc (sizeof * entry);
+         entry = entry->next_entry;
+         if (entry == NULL)
+           return dataend;
+       }
+      else
+       entry->next_entry = NULL;
+    }
+
+  chain->last_entry = entry;
+
+  return highest_data;
+}
+
+static bfd_byte *
+rsrc_parse_directory (bfd *            abfd,
+                     rsrc_directory * table,
+                     bfd_byte *       datastart,
+                     bfd_byte *       data,
+                     bfd_byte *       dataend,
+                     bfd_vma          rva_bias,
+                     rsrc_entry *     entry)
+{
+  bfd_byte * highest_data = data;
+
+  if (table == NULL)
+    return dataend;
+
+  table->characteristics = bfd_get_32 (abfd, data);
+  table->time = bfd_get_32 (abfd, data + 4);
+  table->major = bfd_get_16 (abfd, data + 8);
+  table->minor = bfd_get_16 (abfd, data + 10);
+  table->names.num_entries = bfd_get_16 (abfd, data + 12);
+  table->ids.num_entries = bfd_get_16 (abfd, data + 14);
+  table->entry = entry;
+
+  data += 16;
+
+  highest_data = rsrc_parse_entries (abfd, & table->names, TRUE, data,
+                                    datastart, data, dataend, rva_bias, table);
+  data += table->names.num_entries * 8;
+
+  highest_data = rsrc_parse_entries (abfd, & table->ids, FALSE, highest_data,
+                                    datastart, data, dataend, rva_bias, table);
+  data += table->ids.num_entries * 8;
+
+  return max (highest_data, data);
+}
+
+typedef struct rsrc_write_data
+{
+  bfd *      abfd;
+  bfd_byte * datastart;
+  bfd_byte * next_table;
+  bfd_byte * next_leaf;
+  bfd_byte * next_string;
+  bfd_byte * next_data;
+  bfd_vma    rva_bias;
+} rsrc_write_data;
+
+static void
+rsrc_write_string (rsrc_write_data * data,
+                  rsrc_string *     string)
+{
+  bfd_put_16 (data->abfd, string->len, data->next_string);
+  memcpy (data->next_string + 2, string->string, string->len * 2);
+  data->next_string += (string->len + 1) * 2;
+}
+
+static inline unsigned int
+rsrc_compute_rva (rsrc_write_data * data,
+                 bfd_byte *        addr)
+{
+  return (addr - data->datastart) + data->rva_bias;
+}
+
+static void
+rsrc_write_leaf (rsrc_write_data * data,
+                rsrc_leaf *       leaf)
+{
+  bfd_put_32 (data->abfd, rsrc_compute_rva (data, data->next_data),
+             data->next_leaf);
+  bfd_put_32 (data->abfd, leaf->size,     data->next_leaf + 4);
+  bfd_put_32 (data->abfd, leaf->codepage, data->next_leaf + 8);
+  bfd_put_32 (data->abfd, 0 /*reserved*/, data->next_leaf + 12);
+  data->next_leaf += 16;
+
+  memcpy (data->next_data, leaf->data, leaf->size);
+  /* An undocumented feature of Windows resources is that each unit
+     of raw data is 8-byte aligned...  */
+  data->next_data += ((leaf->size + 7) & ~7);
+}
+
+static void rsrc_write_directory (rsrc_write_data *, rsrc_directory *);
+
+static void
+rsrc_write_entry (rsrc_write_data *  data,
+                 bfd_byte *         where,
+                 rsrc_entry *       entry)
+{
+  if (entry->is_name)
+    {
+      bfd_put_32 (data->abfd,
+                 SetHighBit (data->next_string - data->datastart),
+                 where);
+      rsrc_write_string (data, & entry->name_id.name);
+    }
+  else
+    bfd_put_32 (data->abfd, entry->name_id.id, where);
+
+  if (entry->is_dir)
+    {
+      bfd_put_32 (data->abfd,
+                 SetHighBit (data->next_table - data->datastart),
+                 where + 4);
+      rsrc_write_directory (data, entry->value.directory);
+    }
+  else
+    {
+      bfd_put_32 (data->abfd, data->next_leaf - data->datastart, where + 4);
+      rsrc_write_leaf (data, entry->value.leaf);
+    }
+}
+
+static void
+rsrc_compute_region_sizes (rsrc_directory * dir)
+{
+  struct rsrc_entry * entry;
+
+  if (dir == NULL)
+    return;
+
+  sizeof_tables_and_entries += 16;
+
+  for (entry = dir->names.first_entry; entry != NULL; entry = entry->next_entry)
+    {
+      sizeof_tables_and_entries += 8;
+
+      sizeof_strings += (entry->name_id.name.len + 1) * 2;
+         
+      if (entry->is_dir)
+       rsrc_compute_region_sizes (entry->value.directory);
+      else
+       sizeof_leaves += 16;
+    }
+
+  for (entry = dir->ids.first_entry; entry != NULL; entry = entry->next_entry)
+    {
+      sizeof_tables_and_entries += 8;
+
+      if (entry->is_dir)
+       rsrc_compute_region_sizes (entry->value.directory);
+      else
+       sizeof_leaves += 16;
+    }
+}
+
+static void
+rsrc_write_directory (rsrc_write_data * data,
+                     rsrc_directory *  dir)
+{
+  rsrc_entry * entry;
+  unsigned int i;
+  bfd_byte * next_entry;
+  bfd_byte * nt;
+
+  bfd_put_32 (data->abfd, dir->characteristics, data->next_table);
+  bfd_put_32 (data->abfd, 0 /*dir->time*/, data->next_table + 4);
+  bfd_put_16 (data->abfd, dir->major, data->next_table + 8);
+  bfd_put_16 (data->abfd, dir->minor, data->next_table + 10);
+  bfd_put_16 (data->abfd, dir->names.num_entries, data->next_table + 12);
+  bfd_put_16 (data->abfd, dir->ids.num_entries, data->next_table + 14);
+
+  /* Compute where the entries and the next table will be placed.  */
+  next_entry = data->next_table + 16;
+  data->next_table = next_entry + (dir->names.num_entries * 8)
+    + (dir->ids.num_entries * 8);
+  nt = data->next_table;
+
+  /* Write the entries.  */
+  for (i = dir->names.num_entries, entry = dir->names.first_entry;
+       i > 0 && entry != NULL;
+       i--, entry = entry->next_entry)
+    {
+      BFD_ASSERT (entry->is_name);
+      rsrc_write_entry (data, next_entry, entry);
+      next_entry += 8;
+    }
+  BFD_ASSERT (i == 0);
+  BFD_ASSERT (entry == NULL);
+
+  for (i = dir->ids.num_entries, entry = dir->ids.first_entry;
+       i > 0 && entry != NULL;
+       i--, entry = entry->next_entry)
+    {
+      BFD_ASSERT (! entry->is_name);
+      rsrc_write_entry (data, next_entry, entry);
+      next_entry += 8;
+    }
+  BFD_ASSERT (i == 0);
+  BFD_ASSERT (entry == NULL);
+  BFD_ASSERT (nt == next_entry);
+}
+
+#if defined HAVE_WCHAR_H && ! defined __CYGWIN__ && ! defined __MINGW32__
+/* Return the length (number of units) of the first character in S,
+   putting its 'ucs4_t' representation in *PUC.  */
+
+static unsigned int
+u16_mbtouc (wchar_t * puc, const unsigned short * s, unsigned int n)
+{
+  unsigned short c = * s;
+
+  if (c < 0xd800 || c >= 0xe000)
+    {
+      *puc = c;
+      return 1;
+    }
+
+  if (c < 0xdc00)
+    {
+      if (n >= 2)
+        {
+          if (s[1] >= 0xdc00 && s[1] < 0xe000)
+            {
+              *puc = 0x10000 + ((c - 0xd800) << 10) + (s[1] - 0xdc00);
+              return 2;
+            }
+        }
+      else
+        {
+          /* Incomplete multibyte character.  */
+          *puc = 0xfffd;
+          return n;
+        }
+    }
+
+  /* Invalid multibyte character.  */
+  *puc = 0xfffd;
+  return 1;
+}
+#endif /* HAVE_WCHAR_H and not Cygwin/Mingw */
+
+/* Perform a comparison of two entries.  */
+static signed int
+rsrc_cmp (bfd_boolean is_name, rsrc_entry * a, rsrc_entry * b)
+{
+  signed int    res;
+  bfd_byte *    astring;
+  unsigned int  alen;
+  bfd_byte *    bstring;
+  unsigned int  blen;
+
+  if (! is_name)
+    return a->name_id.id - b->name_id.id;
+
+  /* We have to perform a case insenstive, unicode string comparison...  */
+  astring = a->name_id.name.string;
+  alen    = a->name_id.name.len;
+  bstring = b->name_id.name.string;
+  blen    = b->name_id.name.len;
+
+#if defined  __CYGWIN__ || defined __MINGW32__
+  /* Under Windows hosts (both Cygwin and Mingw types),
+     unicode == UTF-16 == wchar_t.  The case insensitive string comparison
+     function however goes by different names in the two environments...  */
+
+#undef rscpcmp
+#ifdef __CYGWIN__
+#define rscpcmp wcsncasecmp
+#endif
+#ifdef __MINGW32__
+#define rscpcmp wcsnicmp
+#endif
+
+  res = rscpcmp ((const wchar_t *) astring, (const wchar_t *) bstring,
+                min (alen, blen));
+
+#elif defined HAVE_WCHAR_H
+  {
+    unsigned int  i;
+    res = 0;
+    for (i = min (alen, blen); i--; astring += 2, bstring += 2)
+      {
+       wchar_t awc;
+       wchar_t bwc;
+
+       /* Convert UTF-16 unicode characters into wchar_t characters so
+          that we can then perform a case insensitive comparison.  */
+       int Alen = u16_mbtouc (& awc, (const unsigned short *) astring, 2);
+       int Blen = u16_mbtouc (& bwc, (const unsigned short *) bstring, 2);
+
+       if (Alen != Blen)
+         return Alen - Blen;
+       res = wcsncasecmp (& awc, & bwc, 1);
+       if (res)
+         break;
+      }
+  }
+#else
+  /* Do the best we can - a case sensitive, untranslated comparison.  */
+  res = memcmp (astring, bstring, min (alen, blen) * 2);
+#endif
+
+  if (res == 0)
+    res = alen - blen;
+
+  return res;
+}
+
+static void
+rsrc_print_name (char * buffer, rsrc_string string)
+{
+  unsigned int  i;
+  bfd_byte *    name = string.string;
+
+  for (i = string.len; i--; name += 2)
+    sprintf (buffer + strlen (buffer), "%.1s", name);
+}
+
+static const char *
+rsrc_resource_name (rsrc_entry * entry, rsrc_directory * dir)
+{
+  static char buffer [256];
+  bfd_boolean is_string = FALSE;
+
+  buffer[0] = 0;
+
+  if (dir != NULL && dir->entry != NULL && dir->entry->parent != NULL
+      && dir->entry->parent->entry != NULL)
+    {
+      strcpy (buffer, "type: ");
+      if (dir->entry->parent->entry->is_name)
+       rsrc_print_name (buffer + strlen (buffer),
+                        dir->entry->parent->entry->name_id.name);
+      else
+       {
+         unsigned int id = dir->entry->parent->entry->name_id.id;
+
+         sprintf (buffer + strlen (buffer), "%x", id);
+         switch (id)
+           {
+           case 1: strcat (buffer, " (CURSOR)"); break;
+           case 2: strcat (buffer, " (BITMAP)"); break;
+           case 3: strcat (buffer, " (ICON)"); break;
+            case 4: strcat (buffer, " (MENU)"); break;
+           case 5: strcat (buffer, " (DIALOG)"); break;
+           case 6: strcat (buffer, " (STRING)"); is_string = TRUE; break;
+           case 7: strcat (buffer, " (FONTDIR)"); break;
+           case 8: strcat (buffer, " (FONT)"); break;
+           case 9: strcat (buffer, " (ACCELERATOR)"); break;
+           case 10: strcat (buffer, " (RCDATA)"); break;
+           case 11: strcat (buffer, " (MESSAGETABLE)"); break;
+           case 12: strcat (buffer, " (GROUP_CURSOR)"); break;
+           case 14: strcat (buffer, " (GROUP_ICON)"); break;
+           case 16: strcat (buffer, " (VERSION)"); break;
+           case 17: strcat (buffer, " (DLGINCLUDE)"); break;
+           case 19: strcat (buffer, " (PLUGPLAY)"); break;
+           case 20: strcat (buffer, " (VXD)"); break;
+           case 21: strcat (buffer, " (ANICURSOR)"); break;
+           case 22: strcat (buffer, " (ANIICON)"); break;
+           case 23: strcat (buffer, " (HTML)"); break;
+           case 24: strcat (buffer, " (MANIFEST)"); break;
+           case 240: strcat (buffer, " (DLGINIT)"); break;
+           case 241: strcat (buffer, " (TOOLBAR)"); break;
+           }
+       }
+    }
+
+  if (dir != NULL && dir->entry != NULL)
+    {
+      strcat (buffer, " name: ");
+      if (dir->entry->is_name)
+       rsrc_print_name (buffer + strlen (buffer), dir->entry->name_id.name);
+      else
+       {
+         unsigned int id = dir->entry->name_id.id;
+
+         sprintf (buffer + strlen (buffer), "%x", id);
+
+         if (is_string)
+           sprintf (buffer + strlen (buffer), " (resource id range: %d - %d)",
+                    (id - 1) << 4, (id << 4) - 1);
+       }
+    }
+
+  if (entry != NULL)
+    {
+      strcat (buffer, " lang: ");
+
+      if (entry->is_name)
+       rsrc_print_name (buffer + strlen (buffer), entry->name_id.name);
+      else
+       sprintf (buffer + strlen (buffer), "%x", entry->name_id.id);
+    }
+
+  return buffer;
+}
+
+/* *sigh* Windows resource strings are special.  Only the top 28-bits of
+   their ID is stored in the NAME entry.  The bottom four bits are used as
+   an index into unicode string table that makes up the data of the leaf.
+   So identical type-name-lang string resources may not actually be
+   identical at all.
+
+   This function is called when we have detected two string resources with
+   match top-28-bit IDs.  We have to scan the string tables inside the leaves
+   and discover if there are any real collisions.  If there are then we report
+   them and return FALSE.  Otherwise we copy any strings from B into A and
+   then return TRUE.  */
+
+static bfd_boolean
+rsrc_merge_string_entries (rsrc_entry * a ATTRIBUTE_UNUSED,
+                          rsrc_entry * b ATTRIBUTE_UNUSED)
+{
+  unsigned int copy_needed = 0;
+  unsigned int i;
+  bfd_byte * astring;
+  bfd_byte * bstring;
+  bfd_byte * new_data;
+  bfd_byte * nstring;
+
+  /* Step one: Find out what we have to do.  */
+  BFD_ASSERT (! a->is_dir);
+  astring = a->value.leaf->data;
+
+  BFD_ASSERT (! b->is_dir);
+  bstring = b->value.leaf->data;
+
+  for (i = 0; i < 16; i++)
+    {
+      unsigned int alen = astring[0] + (astring[1] << 8);
+      unsigned int blen = bstring[0] + (bstring[1] << 8);
+
+      if (alen == 0)
+       {
+         copy_needed += blen * 2;
+       }
+      else if (blen == 0)
+       ;
+      else if (alen != blen)
+       /* FIXME: Should we continue the loop in order to report other duplicates ?  */
+       break;
+      /* alen == blen != 0.  We might have two identical strings.  If so we
+        can ignore the second one.  There is no need for wchar_t vs UTF-16
+        theatrics here - we are only interested in (case sensitive) equality.  */
+      else if (memcmp (astring + 2, bstring + 2, alen * 2) != 0)
+       break;
+
+      astring += (alen + 1) * 2;
+      bstring += (blen + 1) * 2;
+    }
+
+  if (i != 16)
+    {
+      if (a->parent != NULL
+         && a->parent->entry != NULL
+         && a->parent->entry->is_name == FALSE)
+       _bfd_error_handler (_(".rsrc merge failure: duplicate string resource: %d"),
+                           ((a->parent->entry->name_id.id - 1) << 4) + i);
+      return FALSE;
+    }
+
+  if (copy_needed == 0)
+    return TRUE;
+
+  /* If we reach here then A and B must both have non-colliding strings.
+     (We never get string resources with fully empty string tables).
+     We need to allocate an extra COPY_NEEDED bytes in A and then bring
+     in B's strings.  */
+  new_data = bfd_malloc (a->value.leaf->size + copy_needed);
+  if (new_data == NULL)
+    return FALSE;
+
+  nstring = new_data;
+  astring = a->value.leaf->data;
+  bstring = b->value.leaf->data;
+
+  for (i = 0; i < 16; i++)
+    {
+      unsigned int alen = astring[0] + (astring[1] << 8);
+      unsigned int blen = bstring[0] + (bstring[1] << 8);
+
+      if (alen != 0)
+       {
+         memcpy (nstring, astring, (alen + 1) * 2);
+         nstring += (alen + 1) * 2;
+       }
+      else if (blen != 0)
+       {
+         memcpy (nstring, bstring, (blen + 1) * 2);
+         nstring += (blen + 1) * 2;
+       }
+      else
+       {
+         * nstring++ = 0;
+         * nstring++ = 0;
+       }
+
+      astring += (alen + 1) * 2;
+      bstring += (blen + 1) * 2;
+    }
+
+  BFD_ASSERT (nstring - new_data == (signed) (a->value.leaf->size + copy_needed));
+
+  free (a->value.leaf->data);
+  a->value.leaf->data = new_data;
+  a->value.leaf->size += copy_needed;
+
+  return TRUE;
+}
+
+static void rsrc_merge (rsrc_entry *, rsrc_entry *);
+
+/* Sort the entries in given part of the directory.
+   We use an old fashioned bubble sort because we are dealing
+   with lists and we want to handle matches specially.  */
+
+static void
+rsrc_sort_entries (rsrc_dir_chain *  chain,
+                  bfd_boolean       is_name,
+                  rsrc_directory *  dir)
+{
+  rsrc_entry * entry;
+  rsrc_entry * next;
+  rsrc_entry ** points_to_entry;
+  bfd_boolean swapped;
+
+  if (chain->num_entries < 2)
+    return;
+
+  do
+    {
+      swapped = FALSE;
+      points_to_entry = & chain->first_entry;
+      entry = * points_to_entry;
+      next  = entry->next_entry;
+
+      do
+       {
+         signed int cmp = rsrc_cmp (is_name, entry, next);
+
+         if (cmp > 0)
+           {
+             entry->next_entry = next->next_entry;
+             next->next_entry = entry;
+             * points_to_entry = next;
+             points_to_entry = & next->next_entry;
+             next = entry->next_entry;
+             swapped = TRUE;
+           }
+         else if (cmp == 0)
+           {
+             if (entry->is_dir && next->is_dir)
+               {
+                 /* When we encounter identical directory entries we have to
+                    merge them together.  The exception to this rule is for
+                    resource manifests - there can only be one of these,
+                    even if they differ in language.  Zero-language manifests
+                    are assumed to be default manifests (provided by the
+                    Cygwin/MinGW build system) and these can be silently dropped,
+                    unless that would reduce the number of manifests to zero.
+                    There should only ever be one non-zero lang manifest -
+                    if there are more it is an error.  A non-zero lang
+                    manifest takes precedence over a default manifest.  */
+                 if (entry->is_name == FALSE
+                     && entry->name_id.id == 1
+                     && dir != NULL
+                     && dir->entry != NULL
+                     && dir->entry->is_name == FALSE
+                     && dir->entry->name_id.id == 0x18)
+                   {
+                     if (next->value.directory->names.num_entries == 0
+                         && next->value.directory->ids.num_entries == 1
+                         && next->value.directory->ids.first_entry->is_name == FALSE
+                         && next->value.directory->ids.first_entry->name_id.id == 0)
+                       /* Fall through so that NEXT is dropped.  */
+                       ;
+                     else if (entry->value.directory->names.num_entries == 0
+                              && entry->value.directory->ids.num_entries == 1
+                              && entry->value.directory->ids.first_entry->is_name == FALSE
+                              && entry->value.directory->ids.first_entry->name_id.id == 0)
+                       {
+                         /* Swap ENTRY and NEXT.  Then fall through so that the old ENTRY is dropped.  */
+                         entry->next_entry = next->next_entry;
+                         next->next_entry = entry;
+                         * points_to_entry = next;
+                         points_to_entry = & next->next_entry;
+                         next = entry->next_entry;
+                         swapped = TRUE;
+                       }
+                     else
+                       {
+                         _bfd_error_handler (_(".rsrc merge failure: multiple non-default manifests"));
+                         bfd_set_error (bfd_error_file_truncated);
+                         return;
+                       }
+
+                     /* Unhook NEXT from the chain.  */
+                     /* FIXME: memory loss here.  */
+                     entry->next_entry = next->next_entry;
+                     chain->num_entries --;
+                     if (chain->num_entries < 2)
+                       return;
+                     next = next->next_entry;
+                   }
+                 else
+                   rsrc_merge (entry, next);
+               }
+             else if (entry->is_dir != next->is_dir)
+               {
+                 _bfd_error_handler (_(".rsrc merge failure: a directory matches a leaf"));
+                 bfd_set_error (bfd_error_file_truncated);
+                 return;
+               }
+             else
+               {
+                 /* Otherwise with identical leaves we issue an error
+                    message - because there should never be duplicates.
+                    The exception is Type 18/Name 1/Lang 0 which is the
+                    defaul manifest - this can just be dropped.  */
+                 if (entry->is_name == FALSE
+                     && entry->name_id.id == 0
+                     && dir != NULL
+                     && dir->entry != NULL
+                     && dir->entry->is_name == FALSE
+                     && dir->entry->name_id.id == 1
+                     && dir->entry->parent != NULL
+                     && dir->entry->parent->entry != NULL
+                     && dir->entry->parent->entry->is_name == FALSE
+                     && dir->entry->parent->entry->name_id.id == 0x18 /* RT_MANIFEST */)
+                   ;
+                 else if (dir != NULL
+                          && dir->entry != NULL
+                          && dir->entry->parent != NULL
+                          && dir->entry->parent->entry != NULL
+                          && dir->entry->parent->entry->is_name == FALSE
+                          && dir->entry->parent->entry->name_id.id == 0x6 /* RT_STRING */)
+                   {
+                     /* Strings need special handling.  */
+                     if (! rsrc_merge_string_entries (entry, next))
+                       {
+                         /* _bfd_error_handler should have been called inside merge_strings.  */
+                         bfd_set_error (bfd_error_file_truncated);
+                         return;
+                       }
+                   }
+                 else
+                   {
+                     if (dir == NULL
+                         || dir->entry == NULL
+                         || dir->entry->parent == NULL
+                         || dir->entry->parent->entry == NULL)
+                       _bfd_error_handler (_(".rsrc merge failure: duplicate leaf"));
+                     else
+                       _bfd_error_handler (_(".rsrc merge failure: duplicate leaf: %s"),
+                                           rsrc_resource_name (entry, dir));
+                     bfd_set_error (bfd_error_file_truncated);
+                     return;
+                   }
+               }
+
+             /* Unhook NEXT from the chain.  */
+             entry->next_entry = next->next_entry;
+             chain->num_entries --;
+             if (chain->num_entries < 2)
+               return;
+             next = next->next_entry;
+           }
+         else
+           {
+             points_to_entry = & entry->next_entry;
+             entry = next;
+             next = next->next_entry;
+           }
+       }
+      while (next);
+
+      chain->last_entry = entry;
+    }
+  while (swapped);
+}
+
+/* Attach B's chain onto A.  */
+static void
+rsrc_attach_chain (rsrc_dir_chain * achain, rsrc_dir_chain * bchain)
+{
+  if (bchain->num_entries == 0)
+    return;
+
+  achain->num_entries += bchain->num_entries;
+
+  if (achain->first_entry == NULL)
+    {
+      achain->first_entry = bchain->first_entry;
+      achain->last_entry  = bchain->last_entry;
+    }
+  else
+    {
+      achain->last_entry->next_entry = bchain->first_entry;
+      achain->last_entry = bchain->last_entry;
+    }
+
+  bchain->num_entries = 0;
+  bchain->first_entry = bchain->last_entry = NULL;
+}
+
+static void
+rsrc_merge (struct rsrc_entry * a, struct rsrc_entry * b)
+{
+  rsrc_directory * adir;
+  rsrc_directory * bdir;
+
+  BFD_ASSERT (a->is_dir);
+  BFD_ASSERT (b->is_dir);
+
+  adir = a->value.directory;
+  bdir = b->value.directory;
+
+  if (adir->characteristics != bdir->characteristics)
+    {
+      _bfd_error_handler (_(".rsrc merge failure: dirs with differing characteristics\n"));
+      bfd_set_error (bfd_error_file_truncated);
+      return;
+    }
+
+  if (adir->major != bdir->major || adir->minor != bdir->minor)
+    {
+      _bfd_error_handler (_(".rsrc merge failure: differing directory versions\n"));
+      bfd_set_error (bfd_error_file_truncated);
+      return;
+    }
+
+  /* Attach B's name chain to A.  */
+  rsrc_attach_chain (& adir->names, & bdir->names);
+
+  /* Attach B's ID chain to A.  */
+  rsrc_attach_chain (& adir->ids, & bdir->ids);
+
+  /* Now sort A's entries.  */
+  rsrc_sort_entries (& adir->names, TRUE, adir);
+  rsrc_sort_entries (& adir->ids, FALSE, adir);
+}
+
+/* Check the .rsrc section.  If it contains multiple concatenated
+   resources then we must merge them properly.  Otherwise Windows
+   will ignore all but the first set.  */
+
+static void
+rsrc_process_section (bfd * abfd,
+                     struct coff_final_link_info * pfinfo)
+{
+  rsrc_directory    new_table;
+  bfd_size_type     size;
+  asection *        sec;
+  pe_data_type *    pe;
+  bfd_vma           rva_bias;
+  bfd_byte *        data;
+  bfd_byte *        datastart;
+  bfd_byte *        dataend;
+  bfd_byte *        new_data;
+  unsigned int      num_resource_sets;
+  rsrc_directory *  type_tables;
+  rsrc_write_data   write_data;
+  unsigned int      indx;
+  bfd *             input;
+  unsigned int      num_input_rsrc = 0;
+  unsigned int      max_num_input_rsrc = 4;
+  ptrdiff_t *       rsrc_sizes = NULL;
+
+  new_table.names.num_entries = 0;
+  new_table.ids.num_entries = 0;
+
+  sec = bfd_get_section_by_name (abfd, ".rsrc");
+  if (sec == NULL || (size = sec->rawsize) == 0)
+    return;
+
+  pe = pe_data (abfd);
+  if (pe == NULL)
+    return;
+
+  rva_bias = sec->vma - pe->pe_opthdr.ImageBase;
+
+  data = bfd_malloc (size);
+  if (data == NULL)
+    return;
+
+  datastart = data;
+
+  if (! bfd_get_section_contents (abfd, sec, data, 0, size))
+    goto end;
+
+  /* Step zero: Scan the input bfds looking for .rsrc sections and record
+     their lengths.  Note - we rely upon the fact that the linker script
+     does *not* sort the input .rsrc sections, so that the order in the
+     linkinfo list matches the order in the output .rsrc section.
+
+     We need to know the lengths because each input .rsrc section has padding
+     at the end of a variable amount.  (It does not appear to be based upon
+     the section alignment or the file alignment).  We need to skip any
+     padding bytes when parsing the input .rsrc sections.  */
+  rsrc_sizes = bfd_malloc (max_num_input_rsrc * sizeof * rsrc_sizes);
+  if (rsrc_sizes == NULL)
+    goto end;
+
+  for (input = pfinfo->info->input_bfds;
+       input != NULL;
+       input = input->link.next)
+    {
+      asection * rsrc_sec = bfd_get_section_by_name (input, ".rsrc");
+
+      if (rsrc_sec != NULL)
+       {
+         if (num_input_rsrc == max_num_input_rsrc)
+           {
+             max_num_input_rsrc += 10;
+             rsrc_sizes = bfd_realloc (rsrc_sizes, max_num_input_rsrc
+                                       * sizeof * rsrc_sizes);
+             if (rsrc_sizes == NULL)
+               goto end;
+           }
+
+         BFD_ASSERT (rsrc_sec->size > 0);
+         rsrc_sizes [num_input_rsrc ++] = rsrc_sec->size;
+       }
+    }
+
+  if (num_input_rsrc < 2)
+    goto end;
+
+  /* Step one: Walk the section, computing the size of the tables,
+     leaves and data and decide if we need to do anything.  */
+  dataend = data + size;
+  num_resource_sets = 0;
+
+  while (data < dataend)
+    {
+      bfd_byte * p = data;
+
+      data = rsrc_count_directory (abfd, data, data, dataend, rva_bias);
+
+      if (data > dataend)
+       {
+         /* Corrupted .rsrc section - cannot merge.  */
+         _bfd_error_handler (_("%s: .rsrc merge failure: corrupt .rsrc section"),
+                             bfd_get_filename (abfd));
+         bfd_set_error (bfd_error_file_truncated);
+         goto end;
+       }
+
+      if ((data - p) > rsrc_sizes [num_resource_sets])
+       {
+         _bfd_error_handler (_("%s: .rsrc merge failure: unexpected .rsrc size"),
+                             bfd_get_filename (abfd));
+         bfd_set_error (bfd_error_file_truncated);
+         goto end;
+       }
+      /* FIXME: Should we add a check for "data - p" being much smaller
+        than rsrc_sizes[num_resource_sets] ?  */
+
+      data = p + rsrc_sizes[num_resource_sets];
+      rva_bias += data - p;
+      ++ num_resource_sets;
+    }
+  BFD_ASSERT (num_resource_sets == num_input_rsrc);
+
+  /* Step two: Walk the data again, building trees of the resources.  */
+  data = datastart;
+  rva_bias = sec->vma - pe->pe_opthdr.ImageBase;
+
+  type_tables = bfd_malloc (num_resource_sets * sizeof * type_tables);
+  if (type_tables == NULL)
+    goto end;
+
+  indx = 0;
+  while (data < dataend)
+    {
+      bfd_byte * p = data;
+
+      (void) rsrc_parse_directory (abfd, type_tables + indx, data, data,
+                                  dataend, rva_bias, NULL);
+      data = p + rsrc_sizes[indx];
+      rva_bias += data - p;
+      ++ indx;
+    }
+  BFD_ASSERT (indx == num_resource_sets);
+
+  /* Step three: Merge the top level tables (there can be only one).
+
+     We must ensure that the merged entries are in ascending order.
+
+     We also thread the top level table entries from the old tree onto
+     the new table, so that they can be pulled off later.  */
+
+  /* FIXME: Should we verify that all type tables are the same ?  */
+  new_table.characteristics = type_tables[0].characteristics;
+  new_table.time            = type_tables[0].time;
+  new_table.major           = type_tables[0].major;
+  new_table.minor           = type_tables[0].minor;
+
+  /* Chain the NAME entries onto the table.  */
+  new_table.names.first_entry = NULL;
+  new_table.names.last_entry = NULL;
+
+  for (indx = 0; indx < num_resource_sets; indx++)
+    rsrc_attach_chain (& new_table.names, & type_tables[indx].names);
+
+  rsrc_sort_entries (& new_table.names, TRUE, & new_table);
+
+  /* Chain the ID entries onto the table.  */
+  new_table.ids.first_entry = NULL;
+  new_table.ids.last_entry = NULL;
+
+  for (indx = 0; indx < num_resource_sets; indx++)
+    rsrc_attach_chain (& new_table.ids, & type_tables[indx].ids);
+
+  rsrc_sort_entries (& new_table.ids, FALSE, & new_table);
+
+  /* Step four: Create new contents for the .rsrc section.  */
+  /* Step four point one: Compute the size of each region of the .rsrc section.
+     We do this now, rather than earlier, as the merging above may have dropped
+     some entries.  */
+  sizeof_leaves = sizeof_strings = sizeof_tables_and_entries = 0;
+  rsrc_compute_region_sizes (& new_table);
+  /* We increment sizeof_strings to make sure that resource data
+     starts on an 8-byte boundary.  FIXME: Is this correct ?  */
+  sizeof_strings = (sizeof_strings + 7) & ~ 7;
+
+  new_data = bfd_zalloc (abfd, size);
+  if (new_data == NULL)
+    goto end;
+
+  write_data.abfd        = abfd;
+  write_data.datastart   = new_data;
+  write_data.next_table  = new_data;
+  write_data.next_leaf   = new_data + sizeof_tables_and_entries;
+  write_data.next_string = write_data.next_leaf + sizeof_leaves;
+  write_data.next_data   = write_data.next_string + sizeof_strings;
+  write_data.rva_bias    = sec->vma - pe->pe_opthdr.ImageBase;
+
+  rsrc_write_directory (& write_data, & new_table);
+
+  /* Step five: Replace the old contents with the new.
+     We recompute the size as we may have lost entries due to mergeing.  */
+  size = ((write_data.next_data - new_data) + 3) & ~ 3;
+
+  {
+    int page_size;
+
+    if (coff_data (abfd)->link_info)
+      {
+       page_size = pe_data (abfd)->pe_opthdr.FileAlignment;
+
+       /* If no file alignment has been set, default to one.
+          This repairs 'ld -r' for arm-wince-pe target.  */
+       if (page_size == 0)
+         page_size = 1;
+      }
+    else
+      page_size = PE_DEF_FILE_ALIGNMENT;
+    size = (size + page_size - 1) & - page_size;
+  }
+
+  bfd_set_section_contents (pfinfo->output_bfd, sec, new_data, 0, size);
+  sec->size = sec->rawsize = size;
+
+ end:
+  /* Step six: Free all the memory that we have used.  */
+  /* FIXME: Free the resource tree, if we have one.  */
+  free (datastart);
+  free (rsrc_sizes);
+}
+
+/* Handle the .idata section and other things that need symbol table
+   access.  */
+
+bfd_boolean
+_bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
+{
+  struct coff_link_hash_entry *h1;
+  struct bfd_link_info *info = pfinfo->info;
+  bfd_boolean result = TRUE;
+
+  /* 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)
+    {
+      /* PR ld/2729: We cannot rely upon all the output sections having been
+        created properly, so check before referencing them.  Issue a warning
+        message for any sections tht could not be found.  */
+      if ((h1->root.type == bfd_link_hash_defined
+          || h1->root.type == bfd_link_hash_defweak)
+         && h1->root.u.def.section != NULL
+         && h1->root.u.def.section->output_section != NULL)
+       pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_TABLE].VirtualAddress =
+         (h1->root.u.def.value
+          + h1->root.u.def.section->output_section->vma
+          + h1->root.u.def.section->output_offset);
+      else
+       {
          _bfd_error_handler
          _bfd_error_handler
-           (_("%B: unable to fill in DataDictionary[1] because .idata$2 is missing"), 
+           (_("%B: unable to fill in DataDictionary[1] because .idata$2 is missing"),
             abfd);
          result = FALSE;
        }
             abfd);
          result = FALSE;
        }
@@ -2029,6 +4328,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
       h1 = coff_link_hash_lookup (coff_hash_table (info),
                                  ".idata$4", FALSE, FALSE, TRUE);
       if (h1 != NULL
       h1 = coff_link_hash_lookup (coff_hash_table (info),
                                  ".idata$4", FALSE, FALSE, TRUE);
       if (h1 != NULL
+         && (h1->root.type == bfd_link_hash_defined
+          || h1->root.type == bfd_link_hash_defweak)
          && h1->root.u.def.section != NULL
          && h1->root.u.def.section->output_section != NULL)
        pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_TABLE].Size =
          && h1->root.u.def.section != NULL
          && h1->root.u.def.section->output_section != NULL)
        pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_TABLE].Size =
@@ -2039,7 +4340,7 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
       else
        {
          _bfd_error_handler
       else
        {
          _bfd_error_handler
-           (_("%B: unable to fill in DataDictionary[1] because .idata$4 is missing"), 
+           (_("%B: unable to fill in DataDictionary[1] because .idata$4 is missing"),
             abfd);
          result = FALSE;
        }
             abfd);
          result = FALSE;
        }
@@ -2049,6 +4350,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
       h1 = coff_link_hash_lookup (coff_hash_table (info),
                                  ".idata$5", FALSE, FALSE, TRUE);
       if (h1 != NULL
       h1 = coff_link_hash_lookup (coff_hash_table (info),
                                  ".idata$5", FALSE, FALSE, TRUE);
       if (h1 != NULL
+         && (h1->root.type == bfd_link_hash_defined
+          || h1->root.type == bfd_link_hash_defweak)
          && h1->root.u.def.section != NULL
          && h1->root.u.def.section->output_section != NULL)
        pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].VirtualAddress =
          && h1->root.u.def.section != NULL
          && h1->root.u.def.section->output_section != NULL)
        pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].VirtualAddress =
@@ -2058,7 +4361,7 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
       else
        {
          _bfd_error_handler
       else
        {
          _bfd_error_handler
-           (_("%B: unable to fill in DataDictionary[12] because .idata$5 is missing"), 
+           (_("%B: unable to fill in DataDictionary[12] because .idata$5 is missing"),
             abfd);
          result = FALSE;
        }
             abfd);
          result = FALSE;
        }
@@ -2066,27 +4369,76 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
       h1 = coff_link_hash_lookup (coff_hash_table (info),
                                  ".idata$6", FALSE, FALSE, TRUE);
       if (h1 != NULL
       h1 = coff_link_hash_lookup (coff_hash_table (info),
                                  ".idata$6", FALSE, FALSE, TRUE);
       if (h1 != NULL
+         && (h1->root.type == bfd_link_hash_defined
+          || h1->root.type == bfd_link_hash_defweak)
          && h1->root.u.def.section != NULL
          && h1->root.u.def.section->output_section != NULL)
        pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].Size =
          ((h1->root.u.def.value
            + h1->root.u.def.section->output_section->vma
            + h1->root.u.def.section->output_offset)
          && h1->root.u.def.section != NULL
          && h1->root.u.def.section->output_section != NULL)
        pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].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[PE_IMPORT_ADDRESS_TABLE].VirtualAddress);      
+          - pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].VirtualAddress);
       else
        {
          _bfd_error_handler
       else
        {
          _bfd_error_handler
-           (_("%B: unable to fill in DataDictionary[PE_IMPORT_ADDRESS_TABLE (12)] because .idata$6 is missing"), 
+           (_("%B: unable to fill in DataDictionary[PE_IMPORT_ADDRESS_TABLE (12)] because .idata$6 is missing"),
             abfd);
          result = FALSE;
        }
     }
             abfd);
          result = FALSE;
        }
     }
+  else
+    {
+      h1 = coff_link_hash_lookup (coff_hash_table (info),
+                                 "__IAT_start__", FALSE, FALSE, TRUE);
+      if (h1 != NULL
+         && (h1->root.type == bfd_link_hash_defined
+          || h1->root.type == bfd_link_hash_defweak)
+         && h1->root.u.def.section != NULL
+         && h1->root.u.def.section->output_section != NULL)
+       {
+         bfd_vma iat_va;
+
+         iat_va =
+           (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),
+                                     "__IAT_end__", FALSE, FALSE, TRUE);
+         if (h1 != NULL
+             && (h1->root.type == bfd_link_hash_defined
+              || h1->root.type == bfd_link_hash_defweak)
+             && h1->root.u.def.section != NULL
+             && h1->root.u.def.section->output_section != NULL)
+           {
+             pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].Size =
+               ((h1->root.u.def.value
+                 + h1->root.u.def.section->output_section->vma
+                 + h1->root.u.def.section->output_offset)
+                - iat_va);
+             if (pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].Size != 0)
+               pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].VirtualAddress =
+                 iat_va - pe_data (abfd)->pe_opthdr.ImageBase;
+           }
+         else
+           {
+             _bfd_error_handler
+               (_("%B: unable to fill in DataDictionary[PE_IMPORT_ADDRESS_TABLE(12)]"
+                  " because .idata$6 is missing"), abfd);
+             result = FALSE;
+           }
+        }
+    }
 
   h1 = coff_link_hash_lookup (coff_hash_table (info),
 
   h1 = coff_link_hash_lookup (coff_hash_table (info),
-                             "__tls_used", FALSE, FALSE, TRUE);
+                             (bfd_get_symbol_leading_char (abfd) != 0
+                              ? "__tls_used" : "_tls_used"),
+                             FALSE, FALSE, TRUE);
   if (h1 != NULL)
     {
   if (h1 != NULL)
     {
-      if (h1->root.u.def.section != NULL
+      if ((h1->root.type == bfd_link_hash_defined
+          || h1->root.type == bfd_link_hash_defweak)
+         && h1->root.u.def.section != NULL
          && h1->root.u.def.section->output_section != NULL)
        pe_data (abfd)->pe_opthdr.DataDirectory[PE_TLS_TABLE].VirtualAddress =
          (h1->root.u.def.value
          && h1->root.u.def.section->output_section != NULL)
        pe_data (abfd)->pe_opthdr.DataDirectory[PE_TLS_TABLE].VirtualAddress =
          (h1->root.u.def.value
@@ -2096,14 +4448,55 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
       else
        {
          _bfd_error_handler
       else
        {
          _bfd_error_handler
-           (_("%B: unable to fill in DataDictionary[9] because __tls_used is missing"), 
+           (_("%B: unable to fill in DataDictionary[9] because __tls_used is missing"),
             abfd);
          result = FALSE;
        }
             abfd);
          result = FALSE;
        }
-
+     /* According to PECOFF sepcifications by Microsoft version 8.2
+       the TLS data directory consists of 4 pointers, followed
+       by two 4-byte integer. This implies that the total size
+       is different for 32-bit and 64-bit executables.  */
+#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64)
       pe_data (abfd)->pe_opthdr.DataDirectory[PE_TLS_TABLE].Size = 0x18;
       pe_data (abfd)->pe_opthdr.DataDirectory[PE_TLS_TABLE].Size = 0x18;
+#else
+      pe_data (abfd)->pe_opthdr.DataDirectory[PE_TLS_TABLE].Size = 0x28;
+#endif
     }
 
     }
 
+/* If there is a .pdata section and we have linked pdata finally, we
+     need to sort the entries ascending.  */
+#if !defined(COFF_WITH_pep) && defined(COFF_WITH_pex64)
+  {
+    asection *sec = bfd_get_section_by_name (abfd, ".pdata");
+
+    if (sec)
+      {
+       bfd_size_type x = sec->rawsize;
+       bfd_byte *tmp_data = NULL;
+
+       if (x)
+         tmp_data = bfd_malloc (x);
+
+       if (tmp_data != NULL)
+         {
+           if (bfd_get_section_contents (abfd, sec, tmp_data, 0, x))
+             {
+               qsort (tmp_data,
+                      (size_t) (x / 12),
+                      12, sort_x64_pdata);
+               bfd_set_section_contents (pfinfo->output_bfd, sec,
+                                         tmp_data, 0, x);
+             }
+           free (tmp_data);
+         }
+       else
+         result = FALSE;
+      }
+  }
+#endif
+
+  rsrc_process_section (abfd, pfinfo);
+
   /* 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....  */
   /* 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....  */
This page took 0.059719 seconds and 4 git commands to generate.