Improve .rsrc section merging again. This time with an algorithm that
authorNick Clifton <nickc@redhat.com>
Wed, 19 Mar 2014 14:46:15 +0000 (14:46 +0000)
committerNick Clifton <nickc@redhat.com>
Wed, 19 Mar 2014 14:46:15 +0000 (14:46 +0000)
should work for all types of input .rsrc section.

* peXXigen.c (rsrc_process_section): Add code to scan input
sections and record their lengths.  Use these lengths to find the
start of each merged .rsrc section.

* scripttempl/pe.sc (R_RSRC): Fix default-manifest exclusion.
(.rsrc): Add SUBALIGN(4).  Remove SORT.
* scripttempl/pep.sc: Likewise.

bfd/ChangeLog
bfd/peXXigen.c
ld/ChangeLog
ld/scripttempl/pe.sc
ld/scripttempl/pep.sc

index 28e1bdc..40f3bed 100644 (file)
@@ -1,8 +1,8 @@
 2014-03-19  Nick Clifton  <nickc@redhat.com>
 
-       * peXXigen.c (rsrc_align): New function.  Attempts to cope with
-       alignment variances when .rsrc sections are merged.
-       (rsrc_process_section): Use rsrc_align.
+       * peXXigen.c (rsrc_process_section): Add code to scan input
+       sections and record their lengths.  Use these lengths to find the
+       start of each merged .rsrc section.
 
 2014-03-17  Tristan Gingold  <gingold@adacore.com>
 
index e53d6c7..6d95827 100644 (file)
@@ -3477,63 +3477,6 @@ rsrc_merge (struct rsrc_entry * a, struct rsrc_entry * b)
   rsrc_sort_entries (& adir->ids, FALSE, adir);
 }
 
-static bfd_byte *
-rsrc_align (bfd * abfd, bfd_byte * data, bfd_byte * dataend)
-{
-  ptrdiff_t d;
-
-  /* Align the data pointer - we no longer have access to the original sections
-     so we do not know the alignment value they used.  We default to 1^2 alignment
-     but check to see if 1^3 is better.  */
-  d = (ptrdiff_t) data;
-  d = (d + 3) & ~3;
-
-  if ((bfd_byte *) d == (dataend - 4))
-    return dataend;
-      
-  if ((d & 0x4) == 0)
-    return (bfd_byte *) d;
-
-  /* Aligning to 1^3 would change the value of the pointer.  See if the
-     next 16 bytes (without aligning to 1^3) would form a valid Resource
-     Directory Table.  If not then increase the alignment.  */
-  data = (bfd_byte *) d;
-
-  if (data + 16 >= dataend)
-    /* Not enough room left for a resource table anyway.  Just stop.  */
-    return dataend;
-
-  if (bfd_get_32 (abfd, data) != 0)
-    /* A non-zero characteristics field.  This should not happen.
-       Possibly the padding between merged .rsrc sections was not zero.
-       Choose to advance the pointer.  */
-    return (bfd_byte *) (d + 4);
-
-  if (bfd_get_32 (abfd, data + 4) != 0)
-    /* A non-zero time field.  It cannot be the characteristics field
-       of a 1^3 aligned .rsrc section because the characteristics are
-       always zero.   Hence we should not increase the alignment.  */
-    return (bfd_byte *) d;
-
-  /* Looking at bytes 8..11 does not help.  These are either the time stamp
-     or the version fields.  They can both have arbitary values, and zero
-     is quite commmon, so we have no way to distinguish them.  */
-
-  /* Bytes 12..15 are either the version values or the number of entries
-     to follow.  If the value is zero then this must be the version fields,
-     since we must always have at least one entry.  A non-zero value on the
-     other hand is ambiguous.  */
-  if (bfd_get_32 (abfd, data + 12) == 0)
-    return (bfd_byte *) (d + 4);
-
-  /* Ho Hum, we have no easy way to resolve this problem, so punt for now.
-     FIXME: try parsing the entire remaining .rsrc section.  If it fails,
-     try re-aligning data and reparsing.  If that works go with the new
-     alignment.  Note - this has the potential to be dangerously recursive.  */
-
-  return (bfd_byte *) d;
-}
-
 /* 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.  */
@@ -3555,6 +3498,10 @@ rsrc_process_section (bfd * abfd,
   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;
@@ -3577,6 +3524,44 @@ rsrc_process_section (bfd * abfd,
   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;
@@ -3598,14 +3583,21 @@ rsrc_process_section (bfd * abfd,
          goto end;
        }
 
-      data = rsrc_align (abfd, data, dataend);
+      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;
     }
-
-  if (num_resource_sets < 2)
-    /* No merging necessary.  */
-    goto end;
+  BFD_ASSERT (num_resource_sets == num_input_rsrc);
 
   /* Step two: Walk the data again, building trees of the resources.  */
   data = datastart;
@@ -3620,11 +3612,11 @@ rsrc_process_section (bfd * abfd,
     {
       bfd_byte * p = data;
 
-      data = rsrc_parse_directory (abfd, type_tables + indx, data, data,
+      (void) rsrc_parse_directory (abfd, type_tables + indx, data, data,
                                   dataend, rva_bias, NULL);
-      data = rsrc_align (abfd, data, dataend);
+      data = p + rsrc_sizes[indx];
       rva_bias += data - p;
-      indx ++;
+      ++ indx;
     }
   BFD_ASSERT (indx == num_resource_sets);
 
@@ -3681,8 +3673,10 @@ rsrc_process_section (bfd * abfd,
   sec->size = sec->rawsize = size;
 
  end:
+  /* Step size: 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
index f1855e4..5544956 100644 (file)
@@ -4,7 +4,7 @@
        * Makefile.in: Regenerate.
        * emultempl/default-manifest.rc: Fix typo.
        * scripttempl/pe.sc (R_RSRC): Fix default-manifest exclusion.
-       (.rsrc): Add SUBALIGN(4).
+       (.rsrc): Add SUBALIGN(4).  Remove SORT.
        * scripttempl/pep.sc: Likewise.
 
 2014-03-17  Christopher Faylor  <me.cygwin2014@cgf.cx>
index 4a1951c..e9e5f64 100644 (file)
@@ -47,15 +47,18 @@ if test "${RELOCATING}"; then
   if test -z "$DEFAULT_MANIFEST"; then
     R_RSRC='
       *(.rsrc)
-      *(SORT(.rsrc$*))'
+      *(.rsrc$*)'
   else
     R_RSRC="
       /* The default manifest contains information necessary for
          binaries to run under Windows 8 (or later).  It is included as
          the last resource file so that if the application has provided
-         its own manifest then that one will take precedence.  */
+         its own manifest then that one will take precedence.
+
+        Note - the .rsrc section merging code relies upon the fact
+        that the input .rsrc sections are *not* sorted.  */
       *(EXCLUDE_FILE (*$DEFAULT_MANIFEST) .rsrc)
-      *(SORT(.rsrc*))
+      *(.rsrc*)
       KEEP ($DEFAULT_MANIFEST(.rsrc))"
   fi
 else
index 592489a..5f97d31 100644 (file)
@@ -47,15 +47,18 @@ if test "${RELOCATING}"; then
   if test -z "$DEFAULT_MANIFEST"; then
     R_RSRC='
       *(.rsrc)
-      *(SORT(.rsrc$*))'
+      *(.rsrc$*)'
   else
     R_RSRC="
       /* The default manifest contains information necessary for
          binaries to run under Windows 8 (or later).  It is included as
          the last resource file so that if the application has provided
-         its own manifest then that one will take precedence.  */
+         its own manifest then that one will take precedence.
+
+        Note - the .rsrc section merging code relies upon the fact
+        that the input .rsrc sections are *not* sorted.  */
       *(EXCLUDE_FILE (*$DEFAULT_MANIFEST) .rsrc)
-      *(SORT(.rsrc*))
+      *(.rsrc*)
       KEEP ($DEFAULT_MANIFEST(.rsrc))"
   fi
 else