Several fixes related to ARC PIE support.
[deliverable/binutils-gdb.git] / bfd / peXXigen.c
index 6d95827a047168e0cace3de8305a778b6a3990d1..c92c1eaf5c0746b0ef48e3ce378224abec581c2f 100644 (file)
@@ -1,5 +1,5 @@
 /* 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 (C) 1995-2014 Free Software Foundation, Inc.
+   Copyright (C) 1995-2016 Free Software Foundation, Inc.
    Written by Cygnus Solutions.
 
    This file is part of BFD, the Binary File Descriptor library.
    Written by Cygnus Solutions.
 
    This file is part of BFD, the Binary File Descriptor library.
 #include "libbfd.h"
 #include "coff/internal.h"
 #include "bfdver.h"
 #include "libbfd.h"
 #include "coff/internal.h"
 #include "bfdver.h"
+#include "libiberty.h"
 #ifdef HAVE_WCHAR_H
 #include <wchar.h>
 #endif
 #ifdef HAVE_WCHAR_H
 #include <wchar.h>
 #endif
+#ifdef HAVE_WCTYPE_H
+#include <wctype.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
@@ -116,7 +120,7 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
     memcpy (in->_n._n_name, ext->e.e_name, SYMNMLEN);
 
   in->n_value = H_GET_32 (abfd, ext->e_value);
     memcpy (in->_n._n_name, ext->e.e_name, SYMNMLEN);
 
   in->n_value = H_GET_32 (abfd, ext->e_value);
-  in->n_scnum = H_GET_16 (abfd, ext->e_scnum);
+  in->n_scnum = (short) H_GET_16 (abfd, ext->e_scnum);
 
   if (sizeof (ext->e_type) == 2)
     in->n_type = H_GET_16 (abfd, ext->e_type);
 
   if (sizeof (ext->e_type) == 2)
     in->n_type = H_GET_16 (abfd, ext->e_type);
@@ -149,8 +153,13 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
 
          name = _bfd_coff_internal_syment_name (abfd, in, namebuf);
          if (name == NULL)
 
          name = _bfd_coff_internal_syment_name (abfd, in, namebuf);
          if (name == NULL)
-           /* FIXME: Return error.  */
-           abort ();
+           {
+             _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;
          sec = bfd_get_section_by_name (abfd, name);
          if (sec != NULL)
            in->n_scnum = sec->target_index;
@@ -170,15 +179,22 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
            {
              name = (const char *) bfd_alloc (abfd, strlen (namebuf) + 1);
              if (name == NULL)
            {
              name = (const char *) bfd_alloc (abfd, strlen (namebuf) + 1);
              if (name == NULL)
-               /* FIXME: Return error.  */
-               abort ();
+               {
+                 _bfd_error_handler (_("%B: out of memory creating name for empty section"),
+                                     abfd);
+                 return;
+               }
              strcpy ((char *) name, namebuf);
            }
              strcpy ((char *) name, namebuf);
            }
+
          flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_DATA | SEC_LOAD;
          sec = bfd_make_section_anyway_with_flags (abfd, name, flags);
          if (sec == NULL)
          flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_DATA | SEC_LOAD;
          sec = bfd_make_section_anyway_with_flags (abfd, name, flags);
          if (sec == NULL)
-           /* FIXME: Return error.  */
-           abort ();
+           {
+             _bfd_error_handler (_("%B: unable to create fake empty section"),
+                                 abfd);
+             return;
+           }
 
          sec->vma = 0;
          sec->lma = 0;
 
          sec->vma = 0;
          sec->lma = 0;
@@ -207,6 +223,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)
 {
@@ -221,6 +245,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 == N_ABS)
+    {
+      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);
 
@@ -247,6 +299,9 @@ _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;
 
+  /* PR 17521: Make sure that all fields in the aux structure
+     are initialised.  */
+  memset (in, 0, sizeof * in);
   switch (in_class)
     {
     case C_FILE:
   switch (in_class)
     {
     case C_FILE:
@@ -422,6 +477,7 @@ _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 =
 #if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64)
   /* PE32+ does not have data_start member!  */
   aouthdr_int->data_start =
@@ -468,6 +524,19 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
   {
     int idx;
 
   {
     int 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.  */
     for (idx = 0; idx < a->NumberOfRvaAndSizes; idx++)
       {
         /* If data directory is empty, rva also should be 0.  */
@@ -482,6 +551,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)
@@ -725,7 +801,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]);
@@ -802,7 +878,7 @@ _bfd_XXi_only_swap_filehdr_out (bfd * abfd, void * in, void * out)
 
   /* Only use a real timestamp if the option was chosen.  */
   if ((pe_data (abfd)->insert_timestamp))
 
   /* 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);
+    H_PUT_32 (abfd, time (0), filehdr_out->f_timdat);
 
   PUT_FILEHDR_SYMPTR (abfd, filehdr_in->f_symptr,
                      filehdr_out->f_symptr);
 
   PUT_FILEHDR_SYMPTR (abfd, filehdr_in->f_symptr,
                      filehdr_out->f_symptr);
@@ -985,8 +1061,8 @@ _bfd_XXi_swap_scnhdr_out (bfd * abfd, void * in, void * out)
   }
 
   if (coff_data (abfd)->link_info
   }
 
   if (coff_data (abfd)->link_info
-      && ! coff_data (abfd)->link_info->relocatable
-      && ! coff_data (abfd)->link_info->shared
+      && ! bfd_link_relocatable (coff_data (abfd)->link_info)
+      && ! bfd_link_pic (coff_data (abfd)->link_info)
       && strcmp (scnhdr_int->s_name, ".text") == 0)
     {
       /* By inference from looking at MS output, the 32 bit field
       && strcmp (scnhdr_int->s_name, ".text") == 0)
     {
       /* By inference from looking at MS output, the 32 bit field
@@ -1031,6 +1107,124 @@ _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);
+}
+
+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)
+{
+  const bfd_size_type size = sizeof (CV_INFO_PDB70) + 1;
+  bfd_size_type written;
+  CV_INFO_PDB70 *cvinfo70;
+  char * buffer;
+
+  if (bfd_seek (abfd, where, SEEK_SET) != 0)
+    return 0;
+
+  buffer = xmalloc (size);
+  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';
+
+  written = bfd_bwrite (buffer, size, abfd);
+
+  free (buffer);
+
+  return written == size ? size : 0;
+}
+
 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)]"),
@@ -1111,6 +1305,13 @@ 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"),
     }
 
   fprintf (file, _("\nThere is an import table in %s at 0x%lx\n"),
@@ -1222,7 +1423,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)
        {
@@ -1287,24 +1490,31 @@ pe_print_idata (bfd * abfd, void * vfile)
 #ifdef COFF_WITH_pex64
          for (j = 0; idx + j + 8 <= datasize; j += 8)
            {
 #ifdef COFF_WITH_pex64
          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;
 
+             amt = member - adj;
+
              if (HighBitSet (member_high))
                fprintf (file, "\t%lx%08lx\t %4lx%08lx  <none>",
                         member_high, member,
                         WithoutHighBit (member_high), member);
              if (HighBitSet (member_high))
                fprintf (file, "\t%lx%08lx\t %4lx%08lx  <none>",
                         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
                }
 
              /* If the time stamp is not zero, the import address
@@ -1320,24 +1530,30 @@ pe_print_idata (bfd * abfd, void * vfile)
 #else
          for (j = 0; idx + j + 4 <= datasize; j += 4)
            {
 #else
          for (j = 0; idx + j + 4 <= datasize; j += 4)
            {
+             bfd_size_type amt;
              unsigned long member = bfd_get_32 (abfd, data + idx + j);
 
              /* Print single IMAGE_IMPORT_BY_NAME vector.  */
              if (member == 0)
                break;
 
              unsigned long member = bfd_get_32 (abfd, data + idx + j);
 
              /* Print single IMAGE_IMPORT_BY_NAME vector.  */
              if (member == 0)
                break;
 
+             amt = member - adj;
              if (HighBitSet (member))
                fprintf (file, "\t%04lx\t %4lu  <none>",
                         member, WithoutHighBit (member));
              if (HighBitSet (member))
                fprintf (file, "\t%04lx\t %4lu  <none>",
                         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
                }
 
              /* If the time stamp is not zero, the import address
@@ -1373,7 +1589,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.  */
@@ -1423,6 +1639,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;
@@ -1435,6 +1658,15 @@ 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);
 
@@ -1478,8 +1710,13 @@ pe_print_edata (bfd * abfd, void * vfile)
   fprintf (file,
           _("Name \t\t\t\t"));
   bfd_fprintf_vma (abfd, file, edt.name);
   fprintf (file,
           _("Name \t\t\t\t"));
   bfd_fprintf_vma (abfd, file, edt.name);
-  fprintf (file,
-          " %s\n", data + edt.name - adj);
+
+  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);
@@ -1525,7 +1762,16 @@ 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: 092b1829 */
+      || (edt.num_functions * 4) < edt.num_functions
+      /* 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);
@@ -1537,11 +1783,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
@@ -1561,21 +1808,40 @@ 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
+      /* PR 17512: file: bb68816e.  */
+      || edt.num_names * 4 < edt.num_names
+      || (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);
@@ -1637,6 +1903,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)
@@ -1746,7 +2020,11 @@ slurp_symtab (bfd *abfd, sym_cache *psc)
   if (storage < 0)
     return NULL;
   if (storage)
   if (storage < 0)
     return NULL;
   if (storage)
-    sy = (asymbol **) bfd_malloc (storage);
+    {
+      sy = (asymbol **) bfd_malloc (storage);
+      if (sy == NULL)
+       return NULL;
+    }
 
   psc->symcount = bfd_canonicalize_symtab (abfd, sy);
   if (psc->symcount < 0)
 
   psc->symcount = bfd_canonicalize_symtab (abfd, sy);
   if (psc->symcount < 0)
@@ -1924,13 +2202,9 @@ 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 i;
-  bfd_size_type start, stop;
-
-  if (section == NULL)
-    return TRUE;
+  bfd_byte *p, *end;
 
 
-  if (section->size == 0)
+  if (section == NULL || section->size == 0 || !(section->flags & SEC_HAS_CONTENTS))
     return TRUE;
 
   fprintf (file,
     return TRUE;
 
   fprintf (file,
@@ -1943,20 +2217,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;
     {
       int j;
       bfd_vma virtual_address;
-      long number, size;
+      unsigned 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)
@@ -1964,11 +2238,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, (unsigned long) size, number);
+              (unsigned long) virtual_address, size, 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;
 
@@ -1979,20 +2257,20 @@ pe_print_reloc (bfd * abfd, void * vfile)
                   _("\treloc %4d offset %4x [%4lx] %s"),
                   j, off, (unsigned long) (off + virtual_address), tbl[t]);
 
                   _("\treloc %4d offset %4x [%4lx] %s"),
                   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);
     }
 
   free (data);
@@ -2000,61 +2278,99 @@ pe_print_reloc (bfd * abfd, void * vfile)
   return TRUE;
 }
 \f
   return TRUE;
 }
 \f
+/* A data structure describing the regions of a .rsrc section.
+   Some fields are filled in as the section is parsed.  */
+
+typedef struct rsrc_regions
+{
+  bfd_byte * section_start;
+  bfd_byte * section_end;
+  bfd_byte * strings_start;
+  bfd_byte * resource_start;
+} rsrc_regions;
 
 static bfd_byte *
 
 static bfd_byte *
-rsrc_print_resource_directory (FILE * , bfd *, unsigned int,
-                              bfd_byte *, bfd_byte *, bfd_byte *, bfd_vma);
+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 *
 
 static bfd_byte *
-rsrc_print_resource_entries (FILE *        file,
-                            bfd *         abfd,
-                            unsigned int  indent,
-                            bfd_boolean   is_name,
-                            bfd_byte *    datastart,
-                            bfd_byte *    data,
-                            bfd_byte *    dataend,
-                            bfd_vma       rva_bias)
+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;
 {
   unsigned long entry, addr, size;
+  bfd_byte * leaf;
 
 
-  if (data + 8 >= dataend)
-    return dataend + 1;
+  if (data + 8 >= regions->section_end)
+    return regions->section_end + 1;
 
 
-  fprintf (file, _("%*.s Entry: "), indent, " ");
+  fprintf (file, _("%03x %*.s Entry: "), (int)(data - regions->section_start), indent, " ");
 
 
-  entry = (long) bfd_get_32 (abfd, data);
+  entry = (unsigned long) bfd_get_32 (abfd, data);
   if (is_name)
     {
       bfd_byte * name;
 
   if (is_name)
     {
       bfd_byte * name;
 
-      /* Note - the documenation says that this field is an RVA value
+      /* 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))
         but windres appears to produce a section relative offset with
         the top bit set.  Support both styles for now.  */
       if (HighBitSet (entry))
-       name = datastart + WithoutHighBit (entry);
+       name = regions->section_start + WithoutHighBit (entry);
       else
       else
-       name = datastart + entry - rva_bias;
+       name = regions->section_start + entry - rva_bias;
 
 
-      if (name + 2 < dataend)
+      if (name + 2 < regions->section_end && name > regions->section_start)
        {
          unsigned int len;
        {
          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);
          len = bfd_get_16 (abfd, name);
 
          fprintf (file, _("name: [val: %08lx len %d]: "), entry, len);
-         if (name + 2 + len * 2 < dataend)
+
+         if (name + 2 + len * 2 < regions->section_end)
            {
              /* This strange loop is to cope with multibyte characters.  */
              while (len --)
                {
            {
              /* This strange loop is to cope with multibyte characters.  */
              while (len --)
                {
+                 char c;
+
                  name += 2;
                  name += 2;
-                 fprintf (file, "%.1s", name);
+                 c = * name;
+                 /* Avoid printing control characters.  */
+                 if (c > 0 && c < 32)
+                   fprintf (file, "^%c", c + 64);
+                 else
+                   fprintf (file, "%.1s", name);
                }
            }
          else
                }
            }
          else
-           fprintf (file, _("<corrupt string length: %#x>"), len);
+           {
+             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
        }
       else
-       fprintf (file, _("<corrupt string offset: %#lx>"), entry);
+       {
+         fprintf (file, _("<corrupt string offset: %#lx>\n"), entry);
+         return regions->section_end + 1;
+       }
     }
   else
     fprintf (file, _("ID: %#08lx"), entry);
     }
   else
     fprintf (file, _("ID: %#08lx"), entry);
@@ -2063,54 +2379,71 @@ rsrc_print_resource_entries (FILE *        file,
   fprintf (file, _(", Value: %#08lx\n"), entry);
 
   if (HighBitSet  (entry))
   fprintf (file, _(", Value: %#08lx\n"), entry);
 
   if (HighBitSet  (entry))
-    return rsrc_print_resource_directory (file, abfd, indent + 1,
-                                         datastart,
-                                         datastart + WithoutHighBit (entry),
-                                         dataend, rva_bias);
+    {
+      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 (datastart + entry + 16 >= dataend)
-    return dataend + 1;
+  leaf = regions->section_start + entry;
 
 
-  fprintf (file, _("%*.s  Leaf: Addr: %#08lx, Size: %#08lx, Codepage: %d\n"),
-          indent, " ",
-          addr = (long) bfd_get_32 (abfd, datastart + entry),
-          size = (long) bfd_get_32 (abfd, datastart + entry + 4),
-          (int) bfd_get_32 (abfd, datastart + entry + 8));
+  if (leaf + 16 >= regions->section_end
+      /* PR 17512: file: 055dff7e.  */
+      || leaf < regions->section_start)
+    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, leaf),
+          size = (long) bfd_get_32 (abfd, leaf + 4),
+          (int) bfd_get_32 (abfd, leaf + 8));
 
   /* Check that the reserved entry is 0.  */
 
   /* Check that the reserved entry is 0.  */
-  if (bfd_get_32 (abfd, datastart + entry + 12) != 0
+  if (bfd_get_32 (abfd, leaf + 12) != 0
       /* And that the data address/size is valid too.  */
       /* And that the data address/size is valid too.  */
-      || (datastart + (addr - rva_bias) + size > dataend))
-    return dataend + 1;
+      || (regions->section_start + (addr - rva_bias) + size > regions->section_end))
+    return regions->section_end + 1;
 
 
-  return datastart + (addr - rva_bias) + size;
+  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 *
 }
 
 #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 *    datastart,
-                              bfd_byte *    data,
-                              bfd_byte *    dataend,
-                              bfd_vma       rva_bias)
+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;
 
 {
   unsigned int num_names, num_ids;
   bfd_byte * highest_data = data;
 
-  if (data + 16 >= dataend)
-    return dataend + 1;
+  if (data + 16 >= regions->section_end)
+    return regions->section_end + 1;
 
 
-  fprintf (file, "%*.s ", indent, " ");
+  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;
   switch (indent)
     {
     case 0: fprintf (file, "Type"); break;
     case 2: fprintf (file, "Name"); break;
     case 4: fprintf (file, "Language"); break;
-    default: fprintf (file, "<unknown>"); 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"),
     }
 
   fprintf (file, _(" Table: Char: %d, Time: %08lx, Ver: %d/%d, Num Names: %d, IDs: %d\n"),
@@ -2127,10 +2460,10 @@ rsrc_print_resource_directory (FILE *        file,
       bfd_byte * entry_end;
 
       entry_end = rsrc_print_resource_entries (file, abfd, indent + 1, TRUE,
       bfd_byte * entry_end;
 
       entry_end = rsrc_print_resource_entries (file, abfd, indent + 1, TRUE,
-                                              datastart, data, dataend, rva_bias);
+                                              data, regions, rva_bias);
       data += 8;
       highest_data = max (highest_data, entry_end);
       data += 8;
       highest_data = max (highest_data, entry_end);
-      if (entry_end >= dataend)
+      if (entry_end >= regions->section_end)
        return entry_end;
     }
 
        return entry_end;
     }
 
@@ -2139,11 +2472,10 @@ rsrc_print_resource_directory (FILE *        file,
       bfd_byte * entry_end;
 
       entry_end = rsrc_print_resource_entries (file, abfd, indent + 1, FALSE,
       bfd_byte * entry_end;
 
       entry_end = rsrc_print_resource_entries (file, abfd, indent + 1, FALSE,
-                                              datastart, data, dataend,
-                                              rva_bias);
+                                              data, regions, rva_bias);
       data += 8;
       highest_data = max (highest_data, entry_end);
       data += 8;
       highest_data = max (highest_data, entry_end);
-      if (entry_end >= dataend)
+      if (entry_end >= regions->section_end)
        return entry_end;
     }
 
        return entry_end;
     }
 
@@ -2163,9 +2495,7 @@ rsrc_print_section (bfd * abfd, void * vfile)
   bfd_size_type datasize;
   asection * section;
   bfd_byte * data;
   bfd_size_type datasize;
   asection * section;
   bfd_byte * data;
-  bfd_byte * dataend;
-  bfd_byte * datastart;
-
+  rsrc_regions regions;
 
   pe = pe_data (abfd);
   if (pe == NULL)
 
   pe = pe_data (abfd);
   if (pe == NULL)
@@ -2174,33 +2504,37 @@ rsrc_print_section (bfd * abfd, void * vfile)
   section = bfd_get_section_by_name (abfd, ".rsrc");
   if (section == NULL)
     return TRUE;
   section = bfd_get_section_by_name (abfd, ".rsrc");
   if (section == NULL)
     return TRUE;
-
-  rva_bias = section->vma - pe->pe_opthdr.ImageBase;
+  if (!(section->flags & SEC_HAS_CONTENTS))
+    return TRUE;
 
   datasize = section->size;
   if (datasize == 0)
     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;
     }
   if (! bfd_malloc_and_get_section (abfd, section, & data))
     {
       if (data != NULL)
        free (data);
       return FALSE;
     }
-  datastart = data;
-  dataend = data + datasize;
+
+  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");
 
 
   fflush (file);
   fprintf (file, "\nThe .rsrc Resource Directory section:\n");
 
-  while (data < dataend)
+  while (data < regions.section_end)
     {
       bfd_byte * p = data;
 
     {
       bfd_byte * p = data;
 
-      data = rsrc_print_resource_directory (file, abfd, 0, data, data,
-                                           dataend, rva_bias);
+      data = rsrc_print_resource_directory (file, abfd, 0, data, & regions, rva_bias);
 
 
-      if (data == dataend + 1)
+      if (data == regions.section_end + 1)
        fprintf (file, _("Corrupt .rsrc section detected!\n"));
       else
        {
        fprintf (file, _("Corrupt .rsrc section detected!\n"));
       else
        {
@@ -2214,14 +2548,165 @@ rsrc_print_section (bfd * abfd, void * vfile)
             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.  */
             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 == (dataend - 4))
-           data = dataend;
-         else if (data < dataend)
-           fprintf (file, _("\nWARNING: Extra data in .rsrc section - it will be ignored by Windows:\n"));
+         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"));
+           }
        }
     }
 
        }
     }
 
-  free (datastart);
+  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];
+         /* PR 17512: file: 065-29434-0.001:0.1
+            We need to use a 32-bit aligned buffer
+            to safely read in a codeview record.  */
+          char buffer[256 + 1] ATTRIBUTE_ALIGNED_ALIGNOF (CODEVIEW_INFO);
+
+          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;
 }
 
   return TRUE;
 }
 
@@ -2398,12 +2883,26 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
   else
     pe_print_pdata (abfd, vfile);
   pe_print_reloc (abfd, vfile);
   else
     pe_print_pdata (abfd, vfile);
   pe_print_reloc (abfd, vfile);
+  pe_print_debugdata (abfd, file);
 
   rsrc_print_section (abfd, vfile);
 
   return TRUE;
 }
 
 
   rsrc_print_section (abfd, vfile);
 
   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.  */
 
 /* Copy any private info we understand from the input bfd
    to the output bfd.  */
 
@@ -2442,6 +2941,65 @@ _bfd_XX_bfd_copy_private_bfd_data_common (bfd * ibfd, bfd * obfd)
       && ! (pe_data (ibfd)->real_flags & IMAGE_FILE_RELOCS_STRIPPED))
     pe_data (obfd)->dont_strip_reloc = 1;
 
       && ! (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 (_("%B: 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 (_("%B: Failed to read debug data section"), obfd);
+         return FALSE;
+       }
+    }
+
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -2539,23 +3097,25 @@ rsrc_count_entries (bfd *          abfd,
       else
        name = datastart + entry - rva_bias;
 
       else
        name = datastart + entry - rva_bias;
 
-      if (name + 2 >= dataend)
+      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;
        return dataend + 1;
 
       unsigned int len = bfd_get_16 (abfd, name);
       if (len == 0 || len > 256)
        return dataend + 1;
-
-      sizeof_strings += (len + 1) * 2;
     }
 
   entry = (long) bfd_get_32 (abfd, data + 4);
 
   if (HighBitSet (entry))
     }
 
   entry = (long) bfd_get_32 (abfd, data + 4);
 
   if (HighBitSet (entry))
-    return rsrc_count_directory (abfd,
-                                datastart,
-                                datastart + WithoutHighBit (entry),
-                                dataend, rva_bias);
+    {
+      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;
 
   if (datastart + entry + 16 >= dataend)
     return dataend + 1;
@@ -2563,8 +3123,6 @@ rsrc_count_entries (bfd *          abfd,
   addr = (long) bfd_get_32 (abfd, datastart + entry);
   size = (long) bfd_get_32 (abfd, datastart + entry + 4);
 
   addr = (long) bfd_get_32 (abfd, datastart + entry);
   size = (long) bfd_get_32 (abfd, datastart + entry + 4);
 
-  sizeof_leaves += 16;
-
   return datastart + addr - rva_bias + size;
 }
 
   return datastart + addr - rva_bias + size;
 }
 
@@ -2587,7 +3145,6 @@ rsrc_count_directory (bfd *          abfd,
   num_entries += num_ids;
 
   data += 16;
   num_entries += num_ids;
 
   data += 16;
-  sizeof_tables_and_entries += 16;
 
   while (num_entries --)
     {
 
   while (num_entries --)
     {
@@ -2596,7 +3153,6 @@ rsrc_count_directory (bfd *          abfd,
       entry_end = rsrc_count_entries (abfd, num_entries >= num_ids,
                                      datastart, data, dataend, rva_bias);
       data += 8;
       entry_end = rsrc_count_entries (abfd, num_entries >= num_ids,
                                      datastart, data, dataend, rva_bias);
       data += 8;
-      sizeof_tables_and_entries += 8;
       highest_data = max (highest_data, entry_end);
       if (entry_end >= dataend)
        break;
       highest_data = max (highest_data, entry_end);
       if (entry_end >= dataend)
        break;
@@ -2681,20 +3237,24 @@ rsrc_parse_entry (bfd *            abfd,
 
   if (is_name)
     {
 
   if (is_name)
     {
-      /* FIXME: Add range checking ?  */
+      bfd_byte * address;
+
       if (HighBitSet (val))
        {
          val = WithoutHighBit (val);
 
       if (HighBitSet (val))
        {
          val = WithoutHighBit (val);
 
-         entry->name_id.name.len    = bfd_get_16 (abfd, datastart + val);
-         entry->name_id.name.string = datastart + val + 2;
+         address = datastart + val;
        }
       else
        {
        }
       else
        {
-         entry->name_id.name.len    = bfd_get_16 (abfd, datastart + val
-                                                  - rva_bias);
-         entry->name_id.name.string = datastart + val - rva_bias + 2;
+         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;
     }
   else
     entry->name_id.id = val;
@@ -2719,9 +3279,14 @@ rsrc_parse_entry (bfd *            abfd,
   if (entry->value.leaf == NULL)
     return dataend;
 
   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);
+  data = datastart + val;
+  if (data < datastart || data >= dataend)
+    return dataend;
+
+  addr = bfd_get_32 (abfd, data);
+  size = entry->value.leaf->size = bfd_get_32 (abfd, data + 4);
+  entry->value.leaf->codepage = bfd_get_32 (abfd, data + 8);
+  /* FIXME: We assume that the reserved field (data + 12) is OK.  */
 
   entry->value.leaf->data = bfd_malloc (size);
   if (entry->value.leaf->data == NULL)
 
   entry->value.leaf->data = bfd_malloc (size);
   if (entry->value.leaf->data == NULL)
@@ -2858,7 +3423,9 @@ rsrc_write_leaf (rsrc_write_data * data,
   data->next_leaf += 16;
 
   memcpy (data->next_data, leaf->data, leaf->size);
   data->next_leaf += 16;
 
   memcpy (data->next_data, leaf->data, leaf->size);
-  data->next_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_directory (rsrc_write_data *, rsrc_directory *);
@@ -2892,6 +3459,39 @@ rsrc_write_entry (rsrc_write_data *  data,
     }
 }
 
     }
 }
 
+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)
 static void
 rsrc_write_directory (rsrc_write_data * data,
                      rsrc_directory *  dir)
@@ -2919,6 +3519,7 @@ rsrc_write_directory (rsrc_write_data * data,
        i > 0 && entry != NULL;
        i--, entry = entry->next_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;
     }
       rsrc_write_entry (data, next_entry, entry);
       next_entry += 8;
     }
@@ -2929,6 +3530,7 @@ rsrc_write_directory (rsrc_write_data * data,
        i > 0 && entry != NULL;
        i--, entry = entry->next_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;
     }
       rsrc_write_entry (data, next_entry, entry);
       next_entry += 8;
     }
@@ -2942,7 +3544,11 @@ rsrc_write_directory (rsrc_write_data * data,
    putting its 'ucs4_t' representation in *PUC.  */
 
 static unsigned int
    putting its 'ucs4_t' representation in *PUC.  */
 
 static unsigned int
+#if defined HAVE_WCTYPE_H
+u16_mbtouc (wint_t * puc, const unsigned short * s, unsigned int n)
+#else
 u16_mbtouc (wchar_t * puc, const unsigned short * s, unsigned int n)
 u16_mbtouc (wchar_t * puc, const unsigned short * s, unsigned int n)
+#endif
 {
   unsigned short c = * s;
 
 {
   unsigned short c = * s;
 
@@ -3014,20 +3620,34 @@ rsrc_cmp (bfd_boolean is_name, rsrc_entry * a, rsrc_entry * b)
 #elif defined HAVE_WCHAR_H
   {
     unsigned int  i;
 #elif defined HAVE_WCHAR_H
   {
     unsigned int  i;
+
     res = 0;
     for (i = min (alen, blen); i--; astring += 2, bstring += 2)
       {
     res = 0;
     for (i = min (alen, blen); i--; astring += 2, bstring += 2)
       {
+#if defined HAVE_WCTYPE_H
+       wint_t awc;
+       wint_t bwc;
+#else
        wchar_t awc;
        wchar_t bwc;
        wchar_t awc;
        wchar_t bwc;
+#endif
 
 
-       /* 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);
+       /* Convert UTF-16 unicode characters into wchar_t characters
+          so that we can then perform a case insensitive comparison.  */
+       unsigned int Alen = u16_mbtouc (& awc, (const unsigned short *) astring, 2);
+       unsigned int Blen = u16_mbtouc (& bwc, (const unsigned short *) bstring, 2);
 
        if (Alen != Blen)
          return Alen - Blen;
 
        if (Alen != Blen)
          return Alen - Blen;
+
+#ifdef HAVE_WCTYPE_H
+       awc = towlower (awc);
+       bwc = towlower (bwc);
+
+       res = awc - bwc;
+#else
        res = wcsncasecmp (& awc, & bwc, 1);
        res = wcsncasecmp (& awc, & bwc, 1);
+#endif
        if (res)
          break;
       }
        if (res)
          break;
       }
@@ -3293,7 +3913,7 @@ rsrc_sort_entries (rsrc_dir_chain *  chain,
                     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
                     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 build system) and these can be silently dropped,
+                    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
                     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
@@ -3519,6 +4139,7 @@ rsrc_process_section (bfd * abfd,
   data = bfd_malloc (size);
   if (data == NULL)
     return;
   data = bfd_malloc (size);
   if (data == NULL)
     return;
+
   datastart = data;
 
   if (! bfd_get_section_contents (abfd, sec, data, 0, size))
   datastart = data;
 
   if (! bfd_get_section_contents (abfd, sec, data, 0, size))
@@ -3539,11 +4160,12 @@ rsrc_process_section (bfd * abfd,
 
   for (input = pfinfo->info->input_bfds;
        input != NULL;
 
   for (input = pfinfo->info->input_bfds;
        input != NULL;
-       input = input->link_next)
+       input = input->link.next)
     {
       asection * rsrc_sec = bfd_get_section_by_name (input, ".rsrc");
 
     {
       asection * rsrc_sec = bfd_get_section_by_name (input, ".rsrc");
 
-      if (rsrc_sec != NULL)
+      /* PR 18372 - skip discarded .rsrc sections.  */
+      if (rsrc_sec != NULL && !discarded_section (rsrc_sec))
        {
          if (num_input_rsrc == max_num_input_rsrc)
            {
        {
          if (num_input_rsrc == max_num_input_rsrc)
            {
@@ -3561,12 +4183,11 @@ rsrc_process_section (bfd * abfd,
 
   if (num_input_rsrc < 2)
     goto end;
 
   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;
   /* 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;
-  sizeof_leaves = sizeof_strings = sizeof_tables_and_entries = 0;
 
   while (data < dataend)
     {
 
   while (data < dataend)
     {
@@ -3652,7 +4273,16 @@ rsrc_process_section (bfd * abfd,
   rsrc_sort_entries (& new_table.ids, FALSE, & new_table);
 
   /* Step four: Create new contents for the .rsrc section.  */
   rsrc_sort_entries (& new_table.ids, FALSE, & new_table);
 
   /* Step four: Create new contents for the .rsrc section.  */
-  new_data = bfd_malloc (size);
+  /* 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;
 
   if (new_data == NULL)
     goto end;
 
@@ -3669,11 +4299,29 @@ rsrc_process_section (bfd * abfd,
   /* 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;
   /* 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:
   bfd_set_section_contents (pfinfo->output_bfd, sec, new_data, 0, size);
   sec->size = sec->rawsize = size;
 
  end:
-  /* Step size: Free all the memory that we have used.  */
+  /* Step six: Free all the memory that we have used.  */
   /* FIXME: Free the resource tree, if we have one.  */
   free (datastart);
   free (rsrc_sizes);
   /* FIXME: Free the resource tree, if we have one.  */
   free (datastart);
   free (rsrc_sizes);
@@ -3826,7 +4474,7 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
     }
 
   h1 = coff_link_hash_lookup (coff_hash_table (info),
     }
 
   h1 = coff_link_hash_lookup (coff_hash_table (info),
-                             (bfd_get_symbol_leading_char(abfd) != 0
+                             (bfd_get_symbol_leading_char (abfd) != 0
                               ? "__tls_used" : "_tls_used"),
                              FALSE, FALSE, TRUE);
   if (h1 != NULL)
                               ? "__tls_used" : "_tls_used"),
                              FALSE, FALSE, TRUE);
   if (h1 != NULL)
@@ -3884,6 +4532,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
              }
            free (tmp_data);
          }
              }
            free (tmp_data);
          }
+       else
+         result = FALSE;
       }
   }
 #endif
       }
   }
 #endif
This page took 0.04584 seconds and 4 git commands to generate.