[PATCH] strip, unstrip: Handle SHT_GROUP correctly.

Mark Wielaard mark@klomp.org
Sat Oct 13 08:46:00 GMT 2018


The usage of annobin in Fedora showed a couple of bugs when using
eu-strip and eu-unstrip on ET_REL files that contain multiple group
sections.

When stripping we should not remove the SHF_GROUP flag from sections
even if the group section itself might be removed. Either the section
itself gets removed, and so the flag doesn't matter. Or it gets moved
together with the group section into the debug file, and then it still
needs to have the flag set. Also we would "renumber" the section group
flag field (which isn't a section index, and so shouldn't be changed).

Often the group sections have the exact same name (".group"), flags
(none) and sometimes the same sizes. Which makes matching them hard.
Extract the group signature and compare those when comparing two
group sections.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 src/ChangeLog                            |  12 +++++++
 src/strip.c                              |  12 +++++--
 src/unstrip.c                            |  60 ++++++++++++++++++++++++++++---
 tests/ChangeLog                          |   6 ++++
 tests/Makefile.am                        |   1 +
 tests/run-annobingroup.sh                |  33 +++++++++++++++++
 tests/testfile-annobingroup-x86_64.o.bz2 | Bin 0 -> 1437 bytes
 7 files changed, 116 insertions(+), 8 deletions(-)
 create mode 100644 tests/testfile-annobingroup-x86_64.o.bz2

diff --git a/src/ChangeLog b/src/ChangeLog
index 6a702ee..eb5e8ba 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,15 @@
+2018-10-12  Mark Wielaard  <mark@klomp.org>
+
+	* strip.c (handle_elf): Don't remove SHF_GROUP flag from sections.
+	Skip group section flag when renumbering section indexes.
+	* unstrip.c (struct section): Add sig field.
+	(compare_unalloc_sections): Take and use sig1 and sig2 as arguments.
+	(compare_sections): Pass signatures to compare_unalloc_sections.
+	(get_group_sig): New function.
+	(find_alloc_sections_prelink): Set signature.
+	(copy_elided_sections): Likewise and pass them on.
+	(find_unalloc_section): Take and pass signatures.
+
 2018-09-13  Mark Wielaard  <mark@klomp.org>
 
 	* readelf.c (print_shdr): Get number of section with elf_getshdrnum.
diff --git a/src/strip.c b/src/strip.c
index 4a3db1b..da639b9 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -792,9 +792,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
 	  if (shdr_info[shdr_info[cnt].group_idx].idx == 0)
 	    {
-	      /* The section group section will be removed.  */
+	      /* The section group section might be removed.
+		 Don't remove the SHF_GROUP flag.  The section is
+		 either also removed, in which case the flag doesn't matter.
+		 Or it moves with the group into the debug file, then
+		 it will be reconnected with the new group and should
+		 still have the flag set.  */
 	      shdr_info[cnt].group_idx = 0;
-	      shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP;
 	    }
 	}
 
@@ -1368,7 +1372,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 			&& shdr_info[cnt].data->d_buf != NULL);
 
 	    Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
-	    for (size_t inner = 0;
+	    /* First word is the section group flag.
+	       Followed by section indexes, that need to be renumbered.  */
+	    for (size_t inner = 1;
 		 inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
 		 ++inner)
 	      if (grpref[inner] < shnum)
diff --git a/src/unstrip.c b/src/unstrip.c
index e6f0947..03a0346 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -696,6 +696,7 @@ struct section
 {
   Elf_Scn *scn;
   const char *name;
+  const char *sig;
   Elf_Scn *outscn;
   Dwelf_Strent *strent;
   GElf_Shdr shdr;
@@ -720,7 +721,8 @@ compare_alloc_sections (const struct section *s1, const struct section *s2,
 
 static int
 compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
-			  const char *name1, const char *name2)
+			  const char *name1, const char *name2,
+			  const char *sig1, const char *sig2)
 {
   /* Sort by sh_flags as an arbitrary ordering.  */
   if (shdr1->sh_flags < shdr2->sh_flags)
@@ -734,6 +736,10 @@ compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
   if (shdr1->sh_size > shdr2->sh_size)
     return 1;
 
+  /* Are they both SHT_GROUP sections? Then compare signatures.  */
+  if (sig1 != NULL && sig2 != NULL)
+    return strcmp (sig1, sig2);
+
   /* Sort by name as last resort.  */
   return strcmp (name1, name2);
 }
@@ -751,7 +757,8 @@ compare_sections (const void *a, const void *b, bool rel)
   return ((s1->shdr.sh_flags & SHF_ALLOC)
 	  ? compare_alloc_sections (s1, s2, rel)
 	  : compare_unalloc_sections (&s1->shdr, &s2->shdr,
-				      s1->name, s2->name));
+				      s1->name, s2->name,
+				      s1->sig, s2->sig));
 }
 
 static int
@@ -986,6 +993,44 @@ get_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab)
   return shstrtab->d_buf + shdr->sh_name;
 }
 
+/* Returns the signature of a group section, or NULL if the given
+   section isn't a group.  */
+static const char *
+get_group_sig (Elf *elf, GElf_Shdr *shdr)
+{
+  if (shdr->sh_type != SHT_GROUP)
+    return NULL;
+
+  Elf_Scn *symscn = elf_getscn (elf, shdr->sh_link);
+  if (symscn == NULL)
+    error (EXIT_FAILURE, 0, _("bad sh_link for group section: %s"),
+	   elf_errmsg (-1));
+
+  GElf_Shdr symshdr_mem;
+  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
+  if (symshdr == NULL)
+    error (EXIT_FAILURE, 0, _("couldn't get shdr for group section: %s"),
+	   elf_errmsg (-1));
+
+  Elf_Data *symdata = elf_getdata (symscn, NULL);
+  if (symdata == NULL)
+    error (EXIT_FAILURE, 0, _("bad data for group symbol section: %s"),
+	   elf_errmsg (-1));
+
+  GElf_Sym sym_mem;
+  GElf_Sym *sym = gelf_getsym (symdata, shdr->sh_info, &sym_mem);
+  if (sym == NULL)
+    error (EXIT_FAILURE, 0, _("couldn't get symbol for group section: %s"),
+	   elf_errmsg (-1));
+
+  const char *sig = elf_strptr (elf, symshdr->sh_link, sym->st_name);
+  if (sig == NULL)
+    error (EXIT_FAILURE, 0, _("bad symbol name for group section: %s"),
+	   elf_errmsg (-1));
+
+  return sig;
+}
+
 /* Fix things up when prelink has moved some allocated sections around
    and the debuginfo file's section headers no longer match up.
    This fills in SECTIONS[0..NALLOC-1].outscn or exits.
@@ -1111,6 +1156,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	      sec->scn = elf_getscn (main, i + 1); /* Really just for ndx.  */
 	      sec->outscn = NULL;
 	      sec->strent = NULL;
+	      sec->sig = get_group_sig (main, &sec->shdr);
 	      ++undo_nalloc;
 	    }
 	}
@@ -1336,6 +1382,7 @@ more sections in stripped file than debug file -- arguments reversed?"));
       sections[i].scn = scn;
       sections[i].outscn = NULL;
       sections[i].strent = NULL;
+      sections[i].sig = get_group_sig (stripped, shdr);
     }
 
   const struct section *stripped_symtab = NULL;
@@ -1354,7 +1401,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
 
   /* Locate a matching unallocated section in SECTIONS.  */
   inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
-					       const char *name)
+					       const char *name,
+					       const char *sig)
     {
       size_t l = nalloc, u = stripped_shnum - 1;
       while (l < u)
@@ -1362,7 +1410,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
 	  size_t i = (l + u) / 2;
 	  struct section *sec = &sections[i];
 	  int cmp = compare_unalloc_sections (shdr, &sec->shdr,
-					      name, sec->name);
+					      name, sec->name,
+					      sig, sec->sig);
 	  if (cmp < 0)
 	    u = i;
 	  else if (cmp > 0)
@@ -1435,7 +1484,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
       else
 	{
 	  /* Look for the section that matches.  */
-	  sec = find_unalloc_section (shdr, name);
+	  sec = find_unalloc_section (shdr, name,
+				      get_group_sig (unstripped, shdr));
 	  if (sec == NULL)
 	    {
 	      /* An additional unallocated section is fine if not SHT_NOBITS.
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 04eeb4a..c5f0d77 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2018-09-12  Mark Wielaard  <mark@klomp.org>
+
+	* run-annobingroup.sh: Add x86_64 ET_REL testcase.
+	* testfile-annobingroup-x86_64.o.bz2: New test file.
+	* Makefile.am (EXTRA_DIST): Add testfile-annobingroup-x86_64.o.bz2.
+
 2018-09-18  Mark Wielaard  <mark@klomp.org>
 
 	* backtrace-dwarf.c (thread_callback): Only error when
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 74c477e..15b429b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -199,6 +199,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
 	     run-strip-nothing.sh run-strip-remove-keep.sh run-strip-g.sh \
 	     run-annobingroup.sh testfile-annobingroup.o.bz2 \
 	     testfile-annobingroup-i386.o.bz2 \
+	     testfile-annobingroup-x86_64.o.bz2 \
 	     run-strip-strmerge.sh run-strip-nobitsalign.sh \
 	     testfile-nobitsalign.bz2 testfile-nobitsalign.strip.bz2 \
 	     run-strip-reloc.sh hello_i386.ko.bz2 hello_x86_64.ko.bz2 \
diff --git a/tests/run-annobingroup.sh b/tests/run-annobingroup.sh
index 700df32..fd36e4a 100755
--- a/tests/run-annobingroup.sh
+++ b/tests/run-annobingroup.sh
@@ -120,4 +120,37 @@ EOF
 
 testrun ${abs_top_builddir}/src/elfcmp testfile-annobingroup-i386.o remerged.elf
 
+# echo "void * foo (void) { return foo; }" > testfile-annobingroup-x86_64.c
+# gcc -g -O2 -fplugin=annobin -c testfile-annobingroup-x86_64.c
+testfiles testfile-annobingroup-x86_64.o
+
+testrun_compare ${abs_top_builddir}/src/readelf -g testfile-annobingroup-x86_64.o << EOF
+
+Section group [ 1] '.group' with signature '.text.hot.group' contains 3 entries:
+  [11] .text.hot
+  [12] .gnu.build.attributes.hot
+  [13] .rela.gnu.build.attributes.hot
+
+Section group [ 2] '.group' with signature '.text.unlikely.group' contains 3 entries:
+  [14] .text.unlikely
+  [15] .gnu.build.attributes.unlikely
+  [16] .rela.gnu.build.attributes.unlikely
+
+Section group [ 3] '.group' with signature '.text.hot..group' contains 1 entry:
+  [26] .text.hot
+
+Section group [ 4] '.group' with signature '.text.unlikely..group' contains 1 entry:
+  [27] .text.unlikely
+EOF
+
+testrun ${abs_top_builddir}/src/strip -o stripped.elf -f debugfile.elf testfile-annobingroup-x86_64.o
+
+# This would/should work, except for the unknown NOTEs.
+# testrun ${abs_top_builddir}/src/elflint --gnu stripped.elf
+# testrun ${abs_top_builddir}/src/elflint --gnu --debug debugfile.elf
+
+testrun ${abs_top_builddir}/src/unstrip -o remerged.elf stripped.elf debugfile.elf
+
+testrun ${abs_top_builddir}/src/elfcmp testfile-annobingroup-x86_64.o remerged.elf
+
 exit 0
diff --git a/tests/testfile-annobingroup-x86_64.o.bz2 b/tests/testfile-annobingroup-x86_64.o.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..ec389db2d634b539448a2d6eab321bab68f00625
GIT binary patch
literal 1437
zcmV;O1!DR_T4*^jL0KkKS^bu=6aWUifB*mg|NsB@|NH;_-|7GV-*BBEK!jjI0ANUj
zU|c{1B#6)j6%oBlYHpBouofB$Xd<7fiRnXnQ)+&Sc%#(Q)I8NQQIU`t13~H<05k(8
z5YeHa84Uw!JwTE|0GNy<$u&2nJx8cCdYes8P<o9INv41Sr>W`<4Fg7+008wF4FDPj
zYAB{ANwokC4FEkxfY4|F00w}_&;S5500000gC+^4MiV0wO)wJzU<ATxfF>qP00_ij
z1Y~GnjWRUJrUZ#el4^dWF{Ee)jE$lI0j8P&0|5b`00SV?CYopf0Q5sxr5&S{(CPir
z5%cSPANKc3sF`~4<KlQRC5BPg%rq1we6D*0Sxj-k#Hq{MLa>-IPW2xHKXKj4b-})+
zeO6}H9<PRsg8+A?*S5XY(Pu<RIEgkdnaFnwvg2`W+Or0~t=iXx6w@tndJ<QQCa&d?
z-9w7lt`(<&$ol;~FCW==Bx|Lb^Cd6Uk<l~U=^J2!pu?hP4ARy+9-RH;HYB5RnY*eg
znP-`kwr6nNwl&3sk!X>s*MARPK7~jz9i?67OO$7#HTwgN27&47YU^@vd*eu3xgZXq
zkhOL~iiDzwF;D=8L;>y6trQ{z2Z|`C?AgIwkIlSH?MZI}DZs?q*~}o<pX-vO0Knlp
zd1re%#fRugm}CJGnqQ!Jz$Lwg-FIJUDHQRgG~{H8BC-{M&Fwsk6%`38Y}GXq1gskb
z*nr`*AzZW}NW=qaCHi)R+j2J25*uh5-wD8zVs8E#fi9pIOh+|`D|x+<8#m@?R9GNw
z0EW;l6hIW%5WyzK*8!nJ5u{*(8L4R~ZHReMs2gk&27!zO01qxLt{h_cI52y>e%YI(
z7`$}T`5Q~_CFLtfFK&hWUNs^F#ce>VYk8w*=Sl2)mBgDeU$<x3xVX0&4v;!PPdw<6
zlgELgKxHnBRJV^HYW?8>qB1Ua?O%#CP$Tdot{`EH1G0IftsDV7tNQy|*2Q41M_ij|
z&N8DXU@I29U3|>_0cI8fO|A11paTB!VFgAB6IZ}j1zBCh6bnWnS?8dKO|wg4rQKAo
zD<KtX(3N4BaFVDiLr6EHN~$VcLYat)dhC02e6q^L%(t)jKiEc-0=BB&F3o{)m|PqV
z1X|qjyR!UTQ72;K{ZE={NE1r22*hGy1wakJt6bTZnzSbfcVf1-`OJyi(+?gN^dPxo
zbSpVIpNGGK5=1i;KB}OnWNp$Bk7SIy$Md<;^LgCl=Y0Mt(BCfn!mz!;emBH1%~t*-
z^2IZd&XTjqn|&}#+9>Pg-jB%=(kzL-MU?}WF*5{CmwI-WGxykxorH4daHEbn7==kO
zYOQRm74;*VYjpml(bQkGh|a$ALevqCWs6?9KZFiJb<`o2(2ZzKI^kOXS4I{aTt^D#
z9VI`wmQJSJ7fg-G7c?RF@+7uISjRIOCf$@V<YbNp%9#DlilPBd427R@w_qPj%P;4K
zxTaf2s9U?1$Y<6d8^fvy^DLF}kK;*L6kw-Hz{>z@V%2YytF0BPnJn7MrPRvoF@QYs
zR-vra!P!DC*|KF+Qt9C0wBiD59<3hXO=2OeNdPp3LaKT6pD-yID;We;Wx{sdN0FLG
z;bI4%&&cH!WsFd;GNn4yL8o&H7~F#FRI0_RP!D)5JYt(HV!kacPE0I(;7FSzohu-C
zoB==u<WdBMu>e&w%Z&jW5syi0QjTLR%qb<sZV#}00Lv1`)WEb#1Ptt^mRt7-kWqAI
zYR%jns2F&ifu5xjxoADyLZv9sX|<_}6!d4<tS?6ml++5rC#eg#ZtnGSEP{<G=V-5^
rS!HVt?zz&-owRgll-`aR4U&^Y#Do%($RmsX|BJaIoG3_s%UFs4g1?$P

literal 0
HcmV?d00001

-- 
1.8.3.1



More information about the Elfutils-devel mailing list