This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed, PATCH] Properly convert objects between different ELF classes


The output SHF_COMPRESSED section size is different from input if
ELF classes of input and output aren't the same.  We must adjust
the section sizes as well as the compression headers in
SHF_COMPRESSED sections when converting objects between different
ELF classes.

bfd/

	 PR binutils/18656
	 * bfd.c (bfd_convert_section_size): New function.
	 (bfd_convert_section_contents): Likewise.
	 * bfd-in2.h: Regenerated.

binutils/

2015-07-10  H.J. Lu  <hongjiu.lu@intel.com>

	 PR binutils/18656
	 * objcopy.c (setup_section): Call bfd_convert_section_size
	 to get the output section size.
	 (copy_section): Get the section size from the output section
	 and call bfd_get_full_section_contents to convert section
	 contents for output.

binutils/testsuite/

	 PR binutils/18656
	 * binutils-all/compress.exp (convert_test): New proc.
	 Run conversion tests between x86-64 and x32.
---
 bfd/ChangeLog                                |   7 ++
 bfd/bfd-in2.h                                |   6 ++
 bfd/bfd.c                                    | 155 +++++++++++++++++++++++++++
 binutils/ChangeLog                           |   9 ++
 binutils/objcopy.c                           |  11 +-
 binutils/testsuite/ChangeLog                 |   6 ++
 binutils/testsuite/binutils-all/compress.exp |  93 ++++++++++++++++
 7 files changed, 285 insertions(+), 2 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index e8c783e..b552c9f 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,10 @@
+2015-07-10  H.J. Lu  <hongjiu.lu@intel.com>
+
+	 PR binutils/18656
+	 * bfd.c (bfd_convert_section_size): New function.
+	 (bfd_convert_section_contents): Likewise.
+	 * bfd-in2.h: Regenerated.
+
 2015-07-09  Catherine Moore  <clm@codesourcery.com>
 
 	* elflink.c (bfd_elf_size_dynamic_sections): Call to
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 85f2054..e963687 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -6855,6 +6855,12 @@ bfd_boolean bfd_check_compression_header
 
 int bfd_get_compression_header_size (bfd *abfd, asection *sec);
 
+bfd_size_type bfd_convert_section_size
+   (bfd *ibfd, asection *isec, bfd *obfd, bfd_size_type size);
+
+bfd_boolean bfd_convert_section_contents
+   (bfd *ibfd, asection *isec, bfd *obfd, bfd_byte **ptr);
+
 /* Extracted from archive.c.  */
 symindex bfd_get_next_mapent
    (bfd *abfd, symindex previous, carsym **sym);
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 8d85de5..846ab58 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -2111,3 +2111,158 @@ bfd_get_compression_header_size (bfd *abfd, asection *sec)
 
   return 0;
 }
+
+/*
+FUNCTION
+	bfd_convert_section_size
+
+SYNOPSIS
+	bfd_size_type bfd_convert_section_size
+	  (bfd *ibfd, asection *isec, bfd *obfd, bfd_size_type size);
+
+DESCRIPTION
+	Convert the size @var{size} of the section @var{isec} in input
+	BFD @var{ibfd} to the section size in output BFD @var{obfd}.
+*/
+
+bfd_size_type
+bfd_convert_section_size (bfd *ibfd, sec_ptr isec, bfd *obfd,
+			  bfd_size_type size)
+{
+  bfd_size_type hdr_size;
+
+  /* Do nothing if input file will be decompressed.  */
+  if ((ibfd->flags & BFD_DECOMPRESS))
+    return size;
+
+  /* Do nothing if either input or output aren't ELF.  */
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return size;
+
+  /* Do nothing if ELF classes of input and output are the same. */
+  if (get_elf_backend_data (ibfd)->s->elfclass
+      == get_elf_backend_data (obfd)->s->elfclass)
+    return size;
+
+  /* Do nothing if the input section isn't a SHF_COMPRESSED section. */
+  hdr_size = bfd_get_compression_header_size (ibfd, isec);
+  if (hdr_size == 0)
+    return size;
+
+  /* Adjust the size of the output SHF_COMPRESSED section.  */
+  if (hdr_size == sizeof (Elf32_External_Chdr))
+    return (size - sizeof (Elf32_External_Chdr)
+	    + sizeof (Elf64_External_Chdr));
+  else
+    return (size - sizeof (Elf64_External_Chdr)
+	    + sizeof (Elf32_External_Chdr));
+}
+
+/*
+FUNCTION
+	bfd_convert_section_contents
+
+SYNOPSIS
+	bfd_boolean bfd_convert_section_contents
+	  (bfd *ibfd, asection *isec, bfd *obfd, bfd_byte **ptr);
+
+DESCRIPTION
+	Convert the contents, stored in @var{*ptr}, of the section
+	@var{isec} in input BFD @var{ibfd} to output BFD @var{obfd}
+	if needed.  The original buffer pointed to by @var{*ptr} may
+	be freed and @var{*ptr} is returned with memory malloc'd by this
+	function.
+*/
+
+bfd_boolean
+bfd_convert_section_contents (bfd *ibfd, sec_ptr isec, bfd *obfd,
+			      bfd_byte **ptr)
+{
+  bfd_byte *contents;
+  bfd_size_type ihdr_size, ohdr_size, size;
+  Elf_Internal_Chdr chdr;
+  bfd_boolean use_memmove;
+
+  /* Do nothing if input file will be decompressed.  */
+  if ((ibfd->flags & BFD_DECOMPRESS))
+    return TRUE;
+
+  /* Do nothing if either input or output aren't ELF.  */
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  /* Do nothing if ELF classes of input and output are the same. */
+  if (get_elf_backend_data (ibfd)->s->elfclass
+      == get_elf_backend_data (obfd)->s->elfclass)
+    return TRUE;
+
+  /* Do nothing if the input section isn't a SHF_COMPRESSED section. */
+  ihdr_size = bfd_get_compression_header_size (ibfd, isec);
+  if (ihdr_size == 0)
+    return TRUE;
+
+  contents = *ptr;
+
+  /* Convert the contents of the input SHF_COMPRESSED section to
+     output.  Get the input compression header and the size of the
+     output compression header.  */
+  if (ihdr_size == sizeof (Elf32_External_Chdr))
+    {
+      Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
+      chdr.ch_type = bfd_get_32 (ibfd, &echdr->ch_type);
+      chdr.ch_size = bfd_get_32 (ibfd, &echdr->ch_size);
+      chdr.ch_addralign = bfd_get_32 (ibfd, &echdr->ch_addralign);
+
+      ohdr_size = sizeof (Elf64_External_Chdr);
+
+      use_memmove = FALSE;
+    }
+  else
+    {
+      Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
+      chdr.ch_type = bfd_get_64 (ibfd, &echdr->ch_type);
+      chdr.ch_size = bfd_get_64 (ibfd, &echdr->ch_size);
+      chdr.ch_addralign = bfd_get_64 (ibfd, &echdr->ch_addralign);
+
+      ohdr_size = sizeof (Elf32_External_Chdr);
+      use_memmove = TRUE;
+    }
+
+  size = bfd_get_section_size (isec) - ihdr_size + ohdr_size;
+  if (!use_memmove)
+    {
+      contents = (bfd_byte *) bfd_malloc (size);
+      if (contents == NULL)
+	return FALSE;
+    }
+
+  /* Write out the output compression header.  */
+  if (ohdr_size == sizeof (Elf32_External_Chdr))
+    {
+      Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
+      bfd_put_32 (obfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+      bfd_put_32 (obfd, chdr.ch_size, &echdr->ch_size);
+      bfd_put_32 (obfd, chdr.ch_addralign, &echdr->ch_addralign);
+    }
+  else
+    {
+      Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
+      bfd_put_64 (obfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+      bfd_put_64 (obfd, chdr.ch_size, &echdr->ch_size);
+      bfd_put_64 (obfd, chdr.ch_addralign, &echdr->ch_addralign);
+    }
+
+  /* Copy the compressed contents.  */
+  if (use_memmove)
+    memmove (contents + ohdr_size, *ptr + ihdr_size, size - ohdr_size);
+  else
+    {
+      memcpy (contents + ohdr_size, *ptr + ihdr_size, size - ohdr_size);
+      free (*ptr);
+      *ptr = contents;
+    }
+
+  return TRUE;
+}
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 09b0e1c..c504b33 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,5 +1,14 @@
 2015-07-10  H.J. Lu  <hongjiu.lu@intel.com>
 
+	 PR binutils/18656
+	 * objcopy.c (setup_section): Call bfd_convert_section_size
+	 to get the output section size.
+	 (copy_section): Get the section size from the output section
+	 and call bfd_get_full_section_contents to convert section
+	 contents for output.
+
+2015-07-10  H.J. Lu  <hongjiu.lu@intel.com>
+
 	* readelf.c (dump_section_as_strings): Warn unsupported compress
 	type and corrupted compressed section.
 	(dump_section_as_bytes): Likewise.
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 7f1bd76..d6516e0 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -2872,6 +2872,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     elf_section_type (osection) = SHT_NOBITS;
 
   size = bfd_section_size (ibfd, isection);
+  size = bfd_convert_section_size (ibfd, isection, obfd, size);
   if (copy_byte >= 0)
     size = (size + interleave - 1) / interleave * copy_width;
   else if (extract_symbol)
@@ -3109,14 +3110,20 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     return;
 
   osection = isection->output_section;
-  size = bfd_get_section_size (isection);
+  /* The output SHF_COMPRESSED section size is different from input if
+     ELF classes of input and output aren't the same.  We must use the
+     output section size here, which has been updated in setup_section
+     via bfd_convert_section_size.  */
+  size = bfd_get_section_size (osection);
 
   if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
       && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
     {
       bfd_byte *memhunk = NULL;
 
-      if (!bfd_get_full_section_contents (ibfd, isection, &memhunk))
+      if (!bfd_get_full_section_contents (ibfd, isection, &memhunk)
+	  || !bfd_convert_section_contents (ibfd, isection, obfd,
+					    &memhunk))
 	{
 	  status = 1;
 	  bfd_nonfatal_message (NULL, ibfd, isection, NULL);
diff --git a/binutils/testsuite/ChangeLog b/binutils/testsuite/ChangeLog
index ebc35c3..435961a 100644
--- a/binutils/testsuite/ChangeLog
+++ b/binutils/testsuite/ChangeLog
@@ -1,5 +1,11 @@
 2015-07-10  H.J. Lu  <hongjiu.lu@intel.com>
 
+	 PR binutils/18656
+	 * binutils-all/compress.exp (convert_test): New proc.
+	 Run conversion tests between x86-64 and x32.
+
+2015-07-10  H.J. Lu  <hongjiu.lu@intel.com>
+
 	* binutils-all/dw2-3.W: Updated to accept .debug_* sections.
 
 2015-05-20  Ed Maste  <emaste@freebsd.org>
diff --git a/binutils/testsuite/binutils-all/compress.exp b/binutils/testsuite/binutils-all/compress.exp
index 43a3ce1..abff197 100644
--- a/binutils/testsuite/binutils-all/compress.exp
+++ b/binutils/testsuite/binutils-all/compress.exp
@@ -570,3 +570,96 @@ if { [regexp_diff objdump.out $srcdir/$subdir/dw2-3gabi.W] } then {
 } else {
     pass "$testname"
 }
+
+proc convert_test { testname  as_flags  objcop_flags } {
+    global srcdir
+    global subdir
+    global testfile3
+    global copyfile
+    global OBJCOPY
+    global OBJDUMP
+
+    if { ![binutils_assemble_flags $srcdir/$subdir/dw2-3.S ${testfile3}.o "$as_flags"] } then {
+       unresolved "$testname"
+       return
+    }
+
+    set got [binutils_run $OBJCOPY "$objcop_flags ${testfile3}.o ${copyfile}.o"]
+    if ![string match "" $got] then {
+	fail "objcopy ($testname)"
+	return
+    }
+
+    set got [remote_exec host "$OBJDUMP -W ${copyfile}.o" "" "/dev/null" "objdump.out"]
+
+    if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	fail "$testname (reason: unexpected output)"
+	send_log $got
+	send_log "\n"
+	return
+    }
+
+    if { [regexp_diff objdump.out $srcdir/$subdir/dw2-3.W] } then {
+	fail "$testname"
+    } else {
+	pass "$testname"
+    }
+}
+
+if { ([istarget "x86_64-*-elf*"]
+       || [istarget "x86_64-*-linux*"]) } {
+    set testname "Convert x86-64 object with zlib-gabi to x32 (1)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gabi --64" "-O elf32-x86-64"
+
+    set testname "Convert x86-64 object with zlib-gabi to x32 (2)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gabi --64" "-O elf32-x86-64 --compress-debug-sections=zlib-gnu"
+
+    set testname "Convert x86-64 object with zlib-gabi to x32 (3)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gabi --64" "-O elf32-x86-64 --decompress-debug-sections"
+
+    set testname "Convert x86-64 object with zlib-gnu to x32 (1)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gnu --64" "-O elf32-x86-64"
+
+    set testname "Convert x86-64 object with zlib-gnu to x32 (2)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gnu --64" "-O elf32-x86-64 --compress-debug-sections=zlib-gabi"
+
+    set testname "Convert x86-64 object with zlib-gnu to x32 (3)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gnu --64" "-O elf32-x86-64 --decompress-debug-sections"
+
+    set testname "Convert x86-64 object to x32 (1)"
+    convert_test "$testname" "--nocompress-debug-sections --64" "-O elf32-x86-64"
+
+    set testname "Convert x86-64 object to x32 (2)"
+    convert_test "$testname" "--nocompress-debug-sections --64" "-O elf32-x86-64 --compress-debug-sections=zlib-gabi"
+
+    set testname "Convert x86-64 object to x32 (3)"
+    convert_test "$testname" "--nocompress-debug-sections --64" "-O elf32-x86-64 --compress-debug-sections=zlib-gnu"
+
+
+    set testname "Convert x32 object with zlib-gabi to x86-64 (1)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gabi --x32" "-O elf64-x86-64"
+
+    set testname "Convert x32 object with zlib-gabi to x86-64 (2)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gabi --x32" "-O elf64-x86-64 --compress-debug-sections=zlib-gnu"
+
+    set testname "Convert x32 object with zlib-gabi to x86-64 (3)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gabi --x32" "-O elf64-x86-64 --decompress-debug-sections"
+
+    set testname "Convert x32 object with zlib-gnu to x86-64 (1)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gnu --x32" "-O elf64-x86-64"
+
+    set testname "Convert x32 object with zlib-gnu to x86-64 (2)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gnu --x32" "-O elf64-x86-64 --compress-debug-sections=zlib-gabi"
+
+    set testname "Convert x32 object with zlib-gnu to x86-64 (3)"
+    convert_test "$testname" "--compress-debug-sections=zlib-gnu --x32" "-O elf64-x86-64 --decompress-debug-sections"
+
+    set testname "Convert x32 object to x86-64 (1)"
+    convert_test "$testname" "--nocompress-debug-sections --x32" "-O elf64-x86-64"
+
+    set testname "Convert x32 object to x86-64 (2)"
+    convert_test "$testname" "--nocompress-debug-sections --x32" "-O elf64-x86-64 --compress-debug-sections=zlib-gabi"
+
+    set testname "Convert x32 object to x86-64 (3)"
+    convert_test "$testname" "--nocompress-debug-sections --x32" "-O elf64-x86-64 --compress-debug-sections=zlib-gnu"
+ }
-- 
2.4.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]