[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[committed] Ignore SHT_NOBITS sections in write_dso



Hi,

In a hello world executable, we find a NOBITS section:
...
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  ...
  [24] .data             PROGBITS         0000000000601020  00001020
       0000000000000010  0000000000000000  WA       0     0     8
  [25] .bss              NOBITS           0000000000601030  00001030
       0000000000000008  0000000000000000  WA       0     0     1
  [26] .comment          PROGBITS         0000000000000000  00001030
       0000000000000080  0000000000000001  MS       0     0     1
...

For this type of section, the 'Size' indicates the in-memory size, but the
section occupies no space in the file.  The 'Offset' locates the "conceptual
placement" in the file.

When we do an objcopy --only-keep-debug on the executable:
...
$ objcopy hello -o hello.debug --only-keep-debug
...
some sections are dropped, but are kept in the section header table, set to
the NOBITS type.

Some of the "conceptual placement" of dropped sections is updated,
f.i. for section .gnu.hash:
...
   [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
        0000000000000024  0000000000000000   A       0     0     4
-  [ 4] .hash             HASH             0000000000400298  00000298
+  [ 4] .hash             NOBITS           0000000000400298  00000298
        0000000000000024  0000000000000004   A       6     0     8
-  [ 5] .gnu.hash         GNU_HASH         00000000004002c0  000002c0
+  [ 5] .gnu.hash         NOBITS           00000000004002c0  00000298
        000000000000001c  0000000000000000   A       6     0     8
...

But for others (f.i. .init_array), it's not:
...
-  [18] .eh_frame         PROGBITS         00000000004005e0  000005e0
+  [18] .eh_frame         NOBITS           00000000004005e0  00000298
        00000000000000f0  0000000000000000   A       0     0     8
-  [19] .init_array       INIT_ARRAY       0000000000600e00  00000e00
+  [19] .init_array       NOBITS           0000000000600e00  00000e00
        0000000000000008  0000000000000008  WA       0     0     8
...
which puts .init_array's "conceptual placement" in the middle of
.debug_line:
...
  [30] .debug_line       PROGBITS         0000000000000000  00000c7b
       00000000000002d6  0000000000000000           0     0     1
...
which leads to this error when dwz-ing the executable:
...
dwz: Allocatable section in hello.debug after non-allocatable ones
...

There seems to be no reason why we can't do dwz compression when encountering
stray NOBITS sections.  OTOH, that introduces the question if and how these
sections sh_offset should be updated.  We choose the strategy to not update
the sh_offset of any NOBITS section.

The fix consists of three parts:
- making sure that we don't run into the "Allocatable section in *.debug after
  non-allocatable ones" error
- recording the NOBITS sh_offset at the start of write_dso, and reusing those
  after the sh_offsets updates (rather than special-casing NOBITS sections in
  the update code)
- ensuring that the NOBITS sh_size or sh_addralign does not affect the
  sh_offset of other sections

Committed to trunk.

Thanks,
- Tom

Ignore SHT_NOBITS sections in write_dso

2019-07-10  Tom de Vries  <tdevries@suse.de>

	PR dwz/24251
	* dwz.c (write_dso): Ignore SHT_NOBITS sections.
	* testsuite/dwz.tests/objcopy-eu-unstrip-multifile.sh: New test.
	* testsuite/dwz.tests/objcopy-eu-unstrip.sh: New test.

---
 dwz.c                                               | 13 +++++++++++++
 testsuite/dwz.tests/objcopy-eu-unstrip-multifile.sh | 16 ++++++++++++++++
 testsuite/dwz.tests/objcopy-eu-unstrip.sh           | 12 ++++++++++++
 3 files changed, 41 insertions(+)

diff --git a/dwz.c b/dwz.c
index 7f6db58..4457f8c 100644
--- a/dwz.c
+++ b/dwz.c
@@ -10566,6 +10566,10 @@ write_dso (DSO *dso, const char *file, struct stat *st)
   GElf_Off distance[dso->ehdr.e_shnum + 1];
   /* Array of sections and section header table sorted by file offset.  */
   unsigned int sorted_section_numbers[dso->ehdr.e_shnum + 1];
+  GElf_Off old_sh_offset[dso->ehdr.e_shnum];
+
+  for (i = 1; i < dso->ehdr.e_shnum; ++i)
+    old_sh_offset[i] = dso->shdr[i].sh_offset;
 
   memset (remove_sections, '\0', sizeof (remove_sections));
   ehdr = dso->ehdr;
@@ -10693,6 +10697,8 @@ write_dso (DSO *dso, const char *file, struct stat *st)
 			       && (dso->shdr[j].sh_size == 0
 				   || dso->shdr[j].sh_type == SHT_NOBITS))))
 		continue;
+	      else if (dso->shdr[j].sh_type == SHT_NOBITS)
+		continue;
 	      else if ((dso->shdr[j].sh_flags & SHF_ALLOC) != 0)
 		{
 		  error (0, 0, "Allocatable section in %s after "
@@ -10721,6 +10727,9 @@ write_dso (DSO *dso, const char *file, struct stat *st)
 		  last_shoff = ehdr.e_shoff + ehdr.e_shnum * ehdr.e_shentsize;
 		  continue;
 		}
+	      /* Ignore SHT_NOBITS sections.  */
+	      if (dso->shdr[j].sh_type == SHT_NOBITS)
+		continue;
 	      dso->shdr[j].sh_offset = last_shoff;
 	      if (dso->shdr[j].sh_addralign > 1)
 		dso->shdr[j].sh_offset
@@ -10733,6 +10742,10 @@ write_dso (DSO *dso, const char *file, struct stat *st)
 	}
     }
 
+  for (i = 1; i < dso->ehdr.e_shnum; ++i)
+    if (dso->shdr[i].sh_type == SHT_NOBITS)
+      dso->shdr[i].sh_offset = old_sh_offset[i];
+
   verify_sections (dso, sorted_section_numbers, NULL, addsec, addsize,
 		   ehdr);
 
diff --git a/testsuite/dwz.tests/objcopy-eu-unstrip-multifile.sh b/testsuite/dwz.tests/objcopy-eu-unstrip-multifile.sh
new file mode 100644
index 0000000..87cf313
--- /dev/null
+++ b/testsuite/dwz.tests/objcopy-eu-unstrip-multifile.sh
@@ -0,0 +1,16 @@
+cp ../hello 1
+
+objcopy --only-keep-debug 1 1.debug
+objcopy --strip-debug 1 1.stripped
+
+cp 1.debug 2.debug
+
+dwz -m 3 1.debug 2.debug
+
+rm 2.debug
+
+eu-unstrip 1.stripped 1.debug -o 1.unstripped
+
+smaller-than.sh 1.unstripped 1
+
+rm -f 1 1.debug 1.stripped 1.unstripped 3
diff --git a/testsuite/dwz.tests/objcopy-eu-unstrip.sh b/testsuite/dwz.tests/objcopy-eu-unstrip.sh
new file mode 100644
index 0000000..2645d25
--- /dev/null
+++ b/testsuite/dwz.tests/objcopy-eu-unstrip.sh
@@ -0,0 +1,12 @@
+cp ../hello 1
+
+objcopy --only-keep-debug 1 1.debug
+objcopy --strip-debug 1 1.stripped
+
+dwz 1.debug
+
+eu-unstrip 1.stripped 1.debug -o 1.unstripped
+
+smaller-than.sh 1.unstripped 1
+
+rm -f 1 1.debug 1.stripped 1.unstripped