d1bbc4
commit d7193bd7c9dc2a979352eee7fc446dacd3e97779
d1bbc4
Author: Mark Wielaard <mark@klomp.org>
d1bbc4
Date:   Sun May 12 00:37:45 2019 +0200
d1bbc4
d1bbc4
    libelf: Mark shdr_flags dirty if offset or size changes during update.
d1bbc4
    
d1bbc4
    We forgot to mark the shdr_flags dirty when only the sh_size or
d1bbc4
    sh_offset changed during elf_update (). This meant that if there were
d1bbc4
    no other shdr changes we only wrote out the section data, but didn't
d1bbc4
    write out the shdr table to the file.
d1bbc4
    
d1bbc4
    Add a testcase that puts some sections in the reverse order and then
d1bbc4
    writes out the resulting file again without doing any other
d1bbc4
    updates. This would show the issue after write out of the
d1bbc4
    (re-reversed) ELF file (the .shstrtab section offset would be wrong
d1bbc4
    causing all section names to be garbage). Also run a self test.
d1bbc4
    
d1bbc4
    Signed-off-by: Mark Wielaard <mark@klomp.org>
d1bbc4
d1bbc4
diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c
d1bbc4
index 2ce6a59..303055a 100644
d1bbc4
--- a/libelf/elf32_updatenull.c
d1bbc4
+++ b/libelf/elf32_updatenull.c
d1bbc4
@@ -366,12 +366,15 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
d1bbc4
 		    }
d1bbc4
 
d1bbc4
 		  /* See whether the section size is correct.  */
d1bbc4
+		  int size_changed = 0;
d1bbc4
 		  update_if_changed (shdr->sh_size, (GElf_Word) offset,
d1bbc4
-				     changed);
d1bbc4
+				     size_changed);
d1bbc4
+		  changed |= size_changed;
d1bbc4
 
d1bbc4
 		  if (shdr->sh_type != SHT_NOBITS)
d1bbc4
 		    size += offset;
d1bbc4
 
d1bbc4
+		  scn->shdr_flags |= (offset_changed | size_changed);
d1bbc4
 		  scn->flags |= changed;
d1bbc4
 		}
d1bbc4
 
d1bbc4
diff --git a/tests/Makefile.am b/tests/Makefile.am
d1bbc4
index 80900e4..87428aa 100644
d1bbc4
--- a/tests/Makefile.am
d1bbc4
+++ b/tests/Makefile.am
d1bbc4
@@ -60,7 +60,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
d1bbc4
 		  fillfile dwarf_default_lower_bound dwarf-die-addr-die \
d1bbc4
 		  get-units-invalid get-units-split attr-integrate-skel \
d1bbc4
 		  all-dwarf-ranges unit-info next_cfi \
d1bbc4
-		  elfcopy addsections xlate_notes
d1bbc4
+		  elfcopy addsections xlate_notes elfrdwrnop
d1bbc4
 
d1bbc4
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
d1bbc4
 	    asm-tst6 asm-tst7 asm-tst8 asm-tst9
d1bbc4
@@ -157,6 +157,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
d1bbc4
 	run-all-dwarf-ranges.sh run-unit-info.sh \
d1bbc4
 	run-reloc-bpf.sh \
d1bbc4
 	run-next-cfi.sh run-next-cfi-self.sh \
d1bbc4
+	run-reverse-sections.sh run-reverse-sections-self.sh \
d1bbc4
 	run-copyadd-sections.sh run-copymany-sections.sh \
d1bbc4
 	run-typeiter-many.sh run-strip-test-many.sh \
d1bbc4
 	run-strip-version.sh run-xlate-note.sh
d1bbc4
@@ -419,6 +420,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
d1bbc4
 	     run-unit-info.sh run-next-cfi.sh run-next-cfi-self.sh \
d1bbc4
 	     testfile-riscv64.bz2 testfile-riscv64-s.bz2 \
d1bbc4
 	     testfile-riscv64-core.bz2 \
d1bbc4
+	     run-reverse-sections.sh run-reverse-sections-self.sh \
d1bbc4
 	     run-copyadd-sections.sh run-copymany-sections.sh \
d1bbc4
 	     run-typeiter-many.sh run-strip-test-many.sh \
d1bbc4
 	     testfile-debug-rel-ppc64-g.o.bz2 \
d1bbc4
@@ -598,6 +600,7 @@ next_cfi_LDADD = $(libelf) $(libdw)
d1bbc4
 elfcopy_LDADD = $(libelf)
d1bbc4
 addsections_LDADD = $(libelf)
d1bbc4
 xlate_notes_LDADD = $(libelf)
d1bbc4
+elfrdwrnop_LDADD = $(libelf)
d1bbc4
 
d1bbc4
 # We want to test the libelf header against the system elf.h header.
d1bbc4
 # Don't include any -I CPPFLAGS. Except when we install our own elf.h.
d1bbc4
diff --git a/tests/elfcopy.c b/tests/elfcopy.c
d1bbc4
index 9000cc9..d457bad 100644
d1bbc4
--- a/tests/elfcopy.c
d1bbc4
+++ b/tests/elfcopy.c
d1bbc4
@@ -69,9 +69,11 @@ setshstrndx (Elf *elf, size_t ndx)
d1bbc4
 
d1bbc4
 /* Copies all elements of an ELF file either using mmap or read.  */
d1bbc4
 static void
d1bbc4
-copy_elf (const char *in, const char *out, bool use_mmap)
d1bbc4
+copy_elf (const char *in, const char *out, bool use_mmap, bool reverse_offs)
d1bbc4
 {
d1bbc4
-  printf ("\ncopy_elf: %s -> %s (%s)\n", in, out, use_mmap ? "mmap" : "read");
d1bbc4
+  printf ("\ncopy_elf: %s -> %s (%s,%s)\n", in, out,
d1bbc4
+	  use_mmap ? "mmap" : "read",
d1bbc4
+	  reverse_offs ? "reverse" : "same");
d1bbc4
 
d1bbc4
   /* Existing ELF file.  */
d1bbc4
   int fda = open (in, O_RDONLY);
d1bbc4
@@ -182,8 +184,28 @@ copy_elf (const char *in, const char *out, bool use_mmap)
d1bbc4
 	}
d1bbc4
     }
d1bbc4
 
d1bbc4
+  GElf_Off *offs = NULL;
d1bbc4
+  size_t shnum;
d1bbc4
+  if (reverse_offs)
d1bbc4
+    {
d1bbc4
+      if (elf_getshdrnum (elfa, &shnum) < 0)
d1bbc4
+	{
d1bbc4
+	  printf ("couldn't get shdrnum: %s\n", elf_errmsg (-1));
d1bbc4
+	  exit (1);
d1bbc4
+	}
d1bbc4
+
d1bbc4
+      offs = (GElf_Off *) malloc (shnum * sizeof (GElf_Off));
d1bbc4
+      if (offs == NULL)
d1bbc4
+	{
d1bbc4
+	  printf ("couldn't allocate memory for offs\n");
d1bbc4
+	  exit (1);
d1bbc4
+	}
d1bbc4
+    }
d1bbc4
+
d1bbc4
   /* Copy all sections, headers and data.  */
d1bbc4
   Elf_Scn *scn = NULL;
d1bbc4
+  size_t last_off = 0;
d1bbc4
+  GElf_Shdr last_shdr = { .sh_type = SHT_NULL };
d1bbc4
   while ((scn = elf_nextscn (elfa, scn)) != NULL)
d1bbc4
     {
d1bbc4
       /* Get the header.  */
d1bbc4
@@ -194,6 +216,34 @@ copy_elf (const char *in, const char *out, bool use_mmap)
d1bbc4
 	  exit (1);
d1bbc4
 	}
d1bbc4
 
d1bbc4
+      if (reverse_offs)
d1bbc4
+	{
d1bbc4
+	  offs[last_off] = shdr.sh_offset;
d1bbc4
+
d1bbc4
+	  if (last_shdr.sh_type != SHT_NULL
d1bbc4
+	      && last_shdr.sh_addralign == shdr.sh_addralign
d1bbc4
+	      && shdr.sh_addralign == 1
d1bbc4
+	      && last_shdr.sh_type != SHT_NOBITS
d1bbc4
+	      && shdr.sh_type != SHT_NOBITS
d1bbc4
+	      && (phnum == 0
d1bbc4
+		  || ((shdr.sh_flags & SHF_ALLOC) == 0
d1bbc4
+		      && (last_shdr.sh_flags & SHF_ALLOC) == 0)))
d1bbc4
+	    {
d1bbc4
+	      printf ("Swapping offsets of section %zd and %zd\n",
d1bbc4
+		      last_off, last_off + 1);
d1bbc4
+	      GElf_Word off = offs[last_off - 1];
d1bbc4
+	      offs[last_off - 1] = off + shdr.sh_size;
d1bbc4
+	      offs[last_off] = off;
d1bbc4
+	      last_shdr.sh_type = SHT_NULL;
d1bbc4
+	    }
d1bbc4
+	  else
d1bbc4
+	    {
d1bbc4
+	      last_shdr = shdr;
d1bbc4
+	      offs[last_off] = shdr.sh_offset;
d1bbc4
+	    }
d1bbc4
+	  last_off++;
d1bbc4
+	}
d1bbc4
+
d1bbc4
       /* Create new section.  */
d1bbc4
       Elf_Scn *new_scn = elf_newscn (elfb);
d1bbc4
       if (new_scn == NULL)
d1bbc4
@@ -223,9 +273,34 @@ copy_elf (const char *in, const char *out, bool use_mmap)
d1bbc4
 	}
d1bbc4
     }
d1bbc4
 
d1bbc4
-  /* Write everything to disk.  If there are any phdrs then we want
d1bbc4
-     the exact same layout.  Do we want ELF_F_PERMISSIVE?  */
d1bbc4
-  if (phnum > 0)
d1bbc4
+  if (reverse_offs)
d1bbc4
+    {
d1bbc4
+      last_off = 0;
d1bbc4
+      scn = NULL;
d1bbc4
+      while ((scn = elf_nextscn (elfb, scn)) != NULL)
d1bbc4
+	{
d1bbc4
+	  GElf_Shdr shdr;
d1bbc4
+	  if (gelf_getshdr (scn, &shdr) == NULL)
d1bbc4
+	    {
d1bbc4
+	      printf ("couldn't get shdr for updating: %s\n", elf_errmsg (-1));
d1bbc4
+	      exit (1);
d1bbc4
+	    }
d1bbc4
+
d1bbc4
+	  shdr.sh_offset = offs[last_off++];
d1bbc4
+
d1bbc4
+	  if (gelf_update_shdr (scn, &shdr) == 0)
d1bbc4
+	    {
d1bbc4
+	      printf ("couldn't update shdr sh_off: %s\n", elf_errmsg (-1));
d1bbc4
+	      exit (1);
d1bbc4
+	    }
d1bbc4
+	}
d1bbc4
+      free (offs);
d1bbc4
+    }
d1bbc4
+
d1bbc4
+  /* Write everything to disk.  If there are any phdrs, or we want to
d1bbc4
+     update the offsets, then we want the exact same layout.  Do we
d1bbc4
+     want ELF_F_PERMISSIVE?  */
d1bbc4
+  if (phnum > 0 || reverse_offs)
d1bbc4
     elf_flagelf (elfb, ELF_C_SET, ELF_F_LAYOUT);
d1bbc4
   if (elf_update (elfb, ELF_C_WRITE) < 0)
d1bbc4
     {
d1bbc4
@@ -264,9 +339,9 @@ main (int argc, const char *argv[])
d1bbc4
   elf_version (EV_CURRENT);
d1bbc4
 
d1bbc4
   /* Takes the given file, and create a new identical one.  */
d1bbc4
-  if (argc < 3 || argc > 4)
d1bbc4
+  if (argc < 3 || argc > 5)
d1bbc4
     {
d1bbc4
-      fprintf (stderr, "elfcopy [--mmap] in.elf out.elf\n");
d1bbc4
+      fprintf (stderr, "elfcopy [--mmap] [--reverse-offs] in.elf out.elf\n");
d1bbc4
       exit (1);
d1bbc4
     }
d1bbc4
 
d1bbc4
@@ -278,9 +353,16 @@ main (int argc, const char *argv[])
d1bbc4
       argn++;
d1bbc4
     }
d1bbc4
 
d1bbc4
+  bool reverse_offs = false;
d1bbc4
+  if (strcmp (argv[argn], "--reverse-offs") == 0)
d1bbc4
+    {
d1bbc4
+      reverse_offs = true;
d1bbc4
+      argn++;
d1bbc4
+    }
d1bbc4
+
d1bbc4
   const char *in = argv[argn++];
d1bbc4
   const char *out = argv[argn];
d1bbc4
-  copy_elf (in, out, use_mmap);
d1bbc4
+  copy_elf (in, out, use_mmap, reverse_offs);
d1bbc4
 
d1bbc4
   return 0;
d1bbc4
 }
d1bbc4
diff --git a/tests/elfrdwrnop.c b/tests/elfrdwrnop.c
d1bbc4
new file mode 100644
d1bbc4
index 0000000..997150b
d1bbc4
--- /dev/null
d1bbc4
+++ b/tests/elfrdwrnop.c
d1bbc4
@@ -0,0 +1,100 @@
d1bbc4
+/* Test program for reading and writing out the same file in-place
d1bbc4
+   Copyright (C) 2019 Red Hat, Inc.
d1bbc4
+   This file is part of elfutils.
d1bbc4
+
d1bbc4
+   This file is free software; you can redistribute it and/or modify
d1bbc4
+   it under the terms of the GNU General Public License as published by
d1bbc4
+   the Free Software Foundation; either version 3 of the License, or
d1bbc4
+   (at your option) any later version.
d1bbc4
+
d1bbc4
+   elfutils is distributed in the hope that it will be useful, but
d1bbc4
+   WITHOUT ANY WARRANTY; without even the implied warranty of
d1bbc4
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d1bbc4
+   GNU General Public License for more details.
d1bbc4
+
d1bbc4
+   You should have received a copy of the GNU General Public License
d1bbc4
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
d1bbc4
+
d1bbc4
+
d1bbc4
+#ifdef HAVE_CONFIG_H
d1bbc4
+# include <config.h>
d1bbc4
+#endif
d1bbc4
+
d1bbc4
+#include <errno.h>
d1bbc4
+#include <fcntl.h>
d1bbc4
+#include <inttypes.h>
d1bbc4
+#include <stdbool.h>
d1bbc4
+#include <stdio.h>
d1bbc4
+#include <stdlib.h>
d1bbc4
+#include <string.h>
d1bbc4
+#include <unistd.h>
d1bbc4
+#include <sys/types.h>
d1bbc4
+#include <sys/stat.h>
d1bbc4
+
d1bbc4
+#include ELFUTILS_HEADER(elf)
d1bbc4
+#include <gelf.h>
d1bbc4
+
d1bbc4
+
d1bbc4
+int
d1bbc4
+main (int argc, const char *argv[])
d1bbc4
+{
d1bbc4
+  /* Takes the given file, and create a new identical one.  */
d1bbc4
+  if (argc != 2)
d1bbc4
+    {
d1bbc4
+      fprintf (stderr, "elfrdwrnop elf-file\n");
d1bbc4
+      exit (1);
d1bbc4
+    }
d1bbc4
+
d1bbc4
+  elf_version (EV_CURRENT);
d1bbc4
+
d1bbc4
+  const char *name = argv[1];
d1bbc4
+  printf ("elfrdwrdnop %s\n", name);
d1bbc4
+
d1bbc4
+  int fd = open (name, O_RDWR);
d1bbc4
+  if (fd < 0)
d1bbc4
+    {
d1bbc4
+      fprintf (stderr, "Couldn't open file '%s': %s\n",
d1bbc4
+	       name, strerror (errno));
d1bbc4
+      exit (1);
d1bbc4
+    }
d1bbc4
+
d1bbc4
+  Elf *elf = elf_begin (fd, ELF_C_RDWR, NULL);
d1bbc4
+  if (elf == NULL)
d1bbc4
+    {
d1bbc4
+      fprintf (stderr, "Couldn't open ELF file '%s': %s\n",
d1bbc4
+	       name, elf_errmsg (-1));
d1bbc4
+      exit (1);
d1bbc4
+    }
d1bbc4
+
d1bbc4
+  /* Write everything to disk.  If there are any phdrs, then we want
d1bbc4
+     the exact same layout.  */
d1bbc4
+  size_t phnum;
d1bbc4
+  if (elf_getphdrnum (elf, &phnum) != 0)
d1bbc4
+    {
d1bbc4
+      printf ("cannot get phdrs: %s\n", elf_errmsg (-1));
d1bbc4
+      exit (1);
d1bbc4
+    }
d1bbc4
+
d1bbc4
+  if (phnum > 0)
d1bbc4
+    elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT);
d1bbc4
+
d1bbc4
+  if (elf_update (elf, ELF_C_WRITE) < 0)
d1bbc4
+    {
d1bbc4
+      printf ("failure in elf_update: %s\n", elf_errmsg (-1));
d1bbc4
+      exit (1);
d1bbc4
+    }
d1bbc4
+
d1bbc4
+  if (elf_end (elf) != 0)
d1bbc4
+    {
d1bbc4
+      printf ("couldn't cleanup elf '%s': %s\n", name, elf_errmsg (-1));
d1bbc4
+      exit (1);
d1bbc4
+    }
d1bbc4
+
d1bbc4
+  if (close (fd) != 0)
d1bbc4
+    {
d1bbc4
+      printf ("couldn't close '%s': %s\n", name, strerror (errno));
d1bbc4
+      exit (1);
d1bbc4
+    }
d1bbc4
+
d1bbc4
+  return 0;
d1bbc4
+}
d1bbc4
diff --git a/tests/run-reverse-sections-self.sh b/tests/run-reverse-sections-self.sh
d1bbc4
new file mode 100755
d1bbc4
index 0000000..71afd6a
d1bbc4
--- /dev/null
d1bbc4
+++ b/tests/run-reverse-sections-self.sh
d1bbc4
@@ -0,0 +1,45 @@
d1bbc4
+#! /bin/sh
d1bbc4
+# Copyright (C) 2019 Red Hat, Inc.
d1bbc4
+# This file is part of elfutils.
d1bbc4
+#
d1bbc4
+# This file is free software; you can redistribute it and/or modify
d1bbc4
+# it under the terms of the GNU General Public License as published by
d1bbc4
+# the Free Software Foundation; either version 3 of the License, or
d1bbc4
+# (at your option) any later version.
d1bbc4
+#
d1bbc4
+# elfutils is distributed in the hope that it will be useful, but
d1bbc4
+# WITHOUT ANY WARRANTY; without even the implied warranty of
d1bbc4
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d1bbc4
+# GNU General Public License for more details.
d1bbc4
+#
d1bbc4
+# You should have received a copy of the GNU General Public License
d1bbc4
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
d1bbc4
+
d1bbc4
+. $srcdir/test-subr.sh
d1bbc4
+
d1bbc4
+test_reverse_self ()
d1bbc4
+{
d1bbc4
+  in_file="$1"
d1bbc4
+  base_name="$(basename ${in_file})"
d1bbc4
+  out_file="${base_name}.rev"
d1bbc4
+  out_file_mmap="${out_file}.mmap"
d1bbc4
+
d1bbc4
+  tempfiles ${out_file} ${out_file_mmap}
d1bbc4
+
d1bbc4
+  # Reverse the offsets (the files should still be the same otherwise)
d1bbc4
+  testrun ${abs_builddir}/elfcopy --reverse-offs ${in_file} ${out_file}
d1bbc4
+  testrun ${abs_top_builddir}/src/elfcmp ${in_file} ${out_file}
d1bbc4
+  testrun ${abs_top_builddir}/src/elflint --gnu ${out_file}
d1bbc4
+  # An in-place nop will likely revert them back
d1bbc4
+  testrun ${abs_builddir}/elfrdwrnop ${out_file}
d1bbc4
+  testrun ${abs_top_builddir}/src/elfcmp ${in_file} ${out_file}
d1bbc4
+  testrun ${abs_top_builddir}/src/elflint --gnu ${out_file}
d1bbc4
+}
d1bbc4
+
d1bbc4
+# Only really makes sense for ET_REL files, but try all, just to check
d1bbc4
+# it also works if we keep the order for the allocated sections.
d1bbc4
+for file in $self_test_files; do
d1bbc4
+  test_reverse_self $file
d1bbc4
+done
d1bbc4
+
d1bbc4
+exit 0
d1bbc4
diff --git a/tests/run-reverse-sections.sh b/tests/run-reverse-sections.sh
d1bbc4
new file mode 100755
d1bbc4
index 0000000..102a126
d1bbc4
--- /dev/null
d1bbc4
+++ b/tests/run-reverse-sections.sh
d1bbc4
@@ -0,0 +1,69 @@
d1bbc4
+#! /bin/sh
d1bbc4
+# Copyright (C) 2019 Red Hat, Inc.
d1bbc4
+# This file is part of elfutils.
d1bbc4
+#
d1bbc4
+# This file is free software; you can redistribute it and/or modify
d1bbc4
+# it under the terms of the GNU General Public License as published by
d1bbc4
+# the Free Software Foundation; either version 3 of the License, or
d1bbc4
+# (at your option) any later version.
d1bbc4
+#
d1bbc4
+# elfutils is distributed in the hope that it will be useful, but
d1bbc4
+# WITHOUT ANY WARRANTY; without even the implied warranty of
d1bbc4
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d1bbc4
+# GNU General Public License for more details.
d1bbc4
+#
d1bbc4
+# You should have received a copy of the GNU General Public License
d1bbc4
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
d1bbc4
+
d1bbc4
+. $srcdir/test-subr.sh
d1bbc4
+
d1bbc4
+test_reverse ()
d1bbc4
+{
d1bbc4
+  in_file="$1"
d1bbc4
+  out_file="${in_file}.rev"
d1bbc4
+  out_file_mmap="${out_file}.mmap"
d1bbc4
+
d1bbc4
+  testfiles ${in_file}
d1bbc4
+  tempfiles ${out_file} ${out_file_mmap}
d1bbc4
+
d1bbc4
+  # Reverse the offsets (the files should still be the same otherwise)
d1bbc4
+  testrun ${abs_builddir}/elfcopy --reverse-offs ${in_file} ${out_file}
d1bbc4
+  testrun ${abs_top_builddir}/src/elfcmp ${in_file} ${out_file}
d1bbc4
+  testrun ${abs_top_builddir}/src/elflint --gnu ${out_file}
d1bbc4
+  # An in-place nop will likely revert them back
d1bbc4
+  testrun ${abs_builddir}/elfrdwrnop ${out_file}
d1bbc4
+  testrun ${abs_top_builddir}/src/elfcmp ${in_file} ${out_file}
d1bbc4
+  testrun ${abs_top_builddir}/src/elflint --gnu ${out_file}
d1bbc4
+}
d1bbc4
+
d1bbc4
+# A collection of random testfiles to test 32/64bit, little/big endian
d1bbc4
+# and non-ET_REL (with phdrs)/ET_REL (without phdrs).
d1bbc4
+
d1bbc4
+# 32bit, big endian, rel
d1bbc4
+test_reverse testfile29
d1bbc4
+
d1bbc4
+# 64bit, big endian, rel
d1bbc4
+test_reverse testfile23
d1bbc4
+
d1bbc4
+# 32bit, little endian, rel
d1bbc4
+test_reverse testfile9
d1bbc4
+
d1bbc4
+# 64bit, little endian, rel
d1bbc4
+test_reverse testfile38
d1bbc4
+
d1bbc4
+# 32bit, big endian, non-rel
d1bbc4
+test_reverse testfile26
d1bbc4
+
d1bbc4
+# 64bit, big endian, non-rel
d1bbc4
+test_reverse testfile27
d1bbc4
+
d1bbc4
+# 32bit, little endian, non-rel
d1bbc4
+test_reverse testfile
d1bbc4
+
d1bbc4
+# 64bit, little endian, non-rel
d1bbc4
+# Don't use testfile10. It has section headers in the middle of the file.
d1bbc4
+# Same for testfile12. It is legal, but not the point of this testcase.
d1bbc4
+# test_reverse testfile10
d1bbc4
+test_reverse testfile13
d1bbc4
+
d1bbc4
+exit 0
d1bbc4
diff -ru elfutils-0.176.orig/tests/Makefile.in elfutils-0.176/tests/Makefile.in
d1bbc4
--- elfutils-0.176.orig/tests/Makefile.in	2019-06-03 14:57:17.223607024 +0200
d1bbc4
+++ elfutils-0.176/tests/Makefile.in	2019-06-03 14:58:32.671049626 +0200
d1bbc4
@@ -131,8 +131,8 @@
d1bbc4
 	get-units-invalid$(EXEEXT) get-units-split$(EXEEXT) \
d1bbc4
 	attr-integrate-skel$(EXEEXT) all-dwarf-ranges$(EXEEXT) \
d1bbc4
 	unit-info$(EXEEXT) next_cfi$(EXEEXT) elfcopy$(EXEEXT) \
d1bbc4
-	addsections$(EXEEXT) xlate_notes$(EXEEXT) $(am__EXEEXT_1) \
d1bbc4
-	$(am__EXEEXT_2) $(am__EXEEXT_4)
d1bbc4
+	addsections$(EXEEXT) xlate_notes$(EXEEXT) elfrdwrnop$(EXEEXT) \
d1bbc4
+	$(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_4)
d1bbc4
 @BIARCH_TRUE@am__append_5 = backtrace-child-biarch
d1bbc4
 TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile$(EXEEXT) \
d1bbc4
 	test-nlist$(EXEEXT) update1$(EXEEXT) update2$(EXEEXT) \
d1bbc4
@@ -209,7 +209,8 @@
d1bbc4
 	run-get-units-invalid.sh run-get-units-split.sh \
d1bbc4
 	run-attr-integrate-skel.sh run-all-dwarf-ranges.sh \
d1bbc4
 	run-unit-info.sh run-reloc-bpf.sh run-next-cfi.sh \
d1bbc4
-	run-next-cfi-self.sh run-copyadd-sections.sh \
d1bbc4
+	run-next-cfi-self.sh run-reverse-sections.sh \
d1bbc4
+	run-reverse-sections-self.sh run-copyadd-sections.sh \
d1bbc4
 	run-copymany-sections.sh run-typeiter-many.sh \
d1bbc4
 	run-strip-test-many.sh run-strip-version.sh run-xlate-note.sh \
d1bbc4
 	$(am__EXEEXT_2) $(am__append_8) $(am__EXEEXT_5)
d1bbc4
@@ -451,6 +452,9 @@
d1bbc4
 elfputzdata_SOURCES = elfputzdata.c
d1bbc4
 elfputzdata_OBJECTS = elfputzdata.$(OBJEXT)
d1bbc4
 elfputzdata_DEPENDENCIES = $(am__DEPENDENCIES_2)
d1bbc4
+elfrdwrnop_SOURCES = elfrdwrnop.c
d1bbc4
+elfrdwrnop_OBJECTS = elfrdwrnop.$(OBJEXT)
d1bbc4
+elfrdwrnop_DEPENDENCIES = $(am__DEPENDENCIES_2)
d1bbc4
 elfshphehdr_SOURCES = elfshphehdr.c
d1bbc4
 elfshphehdr_OBJECTS = elfshphehdr.$(OBJEXT)
d1bbc4
 elfshphehdr_DEPENDENCIES = $(am__DEPENDENCIES_2)
d1bbc4
@@ -660,13 +664,13 @@
d1bbc4
 	./$(DEPDIR)/early-offscn.Po ./$(DEPDIR)/ecp.Po \
d1bbc4
 	./$(DEPDIR)/elfcopy.Po ./$(DEPDIR)/elfgetchdr.Po \
d1bbc4
 	./$(DEPDIR)/elfgetzdata.Po ./$(DEPDIR)/elfputzdata.Po \
d1bbc4
-	./$(DEPDIR)/elfshphehdr.Po ./$(DEPDIR)/elfstrmerge.Po \
d1bbc4
-	./$(DEPDIR)/elfstrtab.Po ./$(DEPDIR)/emptyfile.Po \
d1bbc4
-	./$(DEPDIR)/fillfile.Po ./$(DEPDIR)/find-prologues.Po \
d1bbc4
-	./$(DEPDIR)/funcretval.Po ./$(DEPDIR)/funcscopes.Po \
d1bbc4
-	./$(DEPDIR)/get-aranges.Po ./$(DEPDIR)/get-files.Po \
d1bbc4
-	./$(DEPDIR)/get-lines.Po ./$(DEPDIR)/get-pubnames.Po \
d1bbc4
-	./$(DEPDIR)/get-units-invalid.Po \
d1bbc4
+	./$(DEPDIR)/elfrdwrnop.Po ./$(DEPDIR)/elfshphehdr.Po \
d1bbc4
+	./$(DEPDIR)/elfstrmerge.Po ./$(DEPDIR)/elfstrtab.Po \
d1bbc4
+	./$(DEPDIR)/emptyfile.Po ./$(DEPDIR)/fillfile.Po \
d1bbc4
+	./$(DEPDIR)/find-prologues.Po ./$(DEPDIR)/funcretval.Po \
d1bbc4
+	./$(DEPDIR)/funcscopes.Po ./$(DEPDIR)/get-aranges.Po \
d1bbc4
+	./$(DEPDIR)/get-files.Po ./$(DEPDIR)/get-lines.Po \
d1bbc4
+	./$(DEPDIR)/get-pubnames.Po ./$(DEPDIR)/get-units-invalid.Po \
d1bbc4
 	./$(DEPDIR)/get-units-split.Po ./$(DEPDIR)/getsrc_die.Po \
d1bbc4
 	./$(DEPDIR)/hash.Po ./$(DEPDIR)/line2addr.Po \
d1bbc4
 	./$(DEPDIR)/low_high_pc.Po ./$(DEPDIR)/msg_tst.Po \
d1bbc4
@@ -718,19 +722,19 @@
d1bbc4
 	dwfl-bug-getmodules.c dwfl-bug-report.c dwfl-proc-attach.c \
d1bbc4
 	dwfl-report-elf-align.c dwfllines.c dwflmodtest.c dwflsyms.c \
d1bbc4
 	early-offscn.c ecp.c elfcopy.c elfgetchdr.c elfgetzdata.c \
d1bbc4
-	elfputzdata.c elfshphehdr.c elfstrmerge.c elfstrtab.c \
d1bbc4
-	emptyfile.c fillfile.c find-prologues.c funcretval.c \
d1bbc4
-	funcscopes.c get-aranges.c get-files.c get-lines.c \
d1bbc4
-	get-pubnames.c get-units-invalid.c get-units-split.c \
d1bbc4
-	getsrc_die.c hash.c line2addr.c low_high_pc.c msg_tst.c \
d1bbc4
-	newdata.c newfile.c newscn.c next-files.c next-lines.c \
d1bbc4
-	next_cfi.c peel_type.c rdwrmmap.c rerequest_tag.c saridx.c \
d1bbc4
-	scnnames.c sectiondump.c show-abbrev.c show-die-info.c \
d1bbc4
-	showptable.c strptr.c system-elf-libelf-test.c \
d1bbc4
-	test-elf_cntl_gelf_getshdr.c test-flag-nobits.c test-nlist.c \
d1bbc4
-	typeiter.c typeiter2.c unit-info.c update1.c update2.c \
d1bbc4
-	update3.c update4.c varlocs.c vdsosyms.c vendorelf.c \
d1bbc4
-	xlate_notes.c zstrptr.c
d1bbc4
+	elfputzdata.c elfrdwrnop.c elfshphehdr.c elfstrmerge.c \
d1bbc4
+	elfstrtab.c emptyfile.c fillfile.c find-prologues.c \
d1bbc4
+	funcretval.c funcscopes.c get-aranges.c get-files.c \
d1bbc4
+	get-lines.c get-pubnames.c get-units-invalid.c \
d1bbc4
+	get-units-split.c getsrc_die.c hash.c line2addr.c \
d1bbc4
+	low_high_pc.c msg_tst.c newdata.c newfile.c newscn.c \
d1bbc4
+	next-files.c next-lines.c next_cfi.c peel_type.c rdwrmmap.c \
d1bbc4
+	rerequest_tag.c saridx.c scnnames.c sectiondump.c \
d1bbc4
+	show-abbrev.c show-die-info.c showptable.c strptr.c \
d1bbc4
+	system-elf-libelf-test.c test-elf_cntl_gelf_getshdr.c \
d1bbc4
+	test-flag-nobits.c test-nlist.c typeiter.c typeiter2.c \
d1bbc4
+	unit-info.c update1.c update2.c update3.c update4.c varlocs.c \
d1bbc4
+	vdsosyms.c vendorelf.c xlate_notes.c zstrptr.c
d1bbc4
 DIST_SOURCES = addrcfi.c addrscopes.c addsections.c aggregate_size.c \
d1bbc4
 	all-dwarf-ranges.c alldts.c allfcts.c allregs.c arextract.c \
d1bbc4
 	arls.c arsymtest.c asm-tst1.c asm-tst2.c asm-tst3.c asm-tst4.c \
d1bbc4
@@ -745,19 +749,19 @@
d1bbc4
 	dwfl-bug-getmodules.c dwfl-bug-report.c dwfl-proc-attach.c \
d1bbc4
 	dwfl-report-elf-align.c dwfllines.c dwflmodtest.c dwflsyms.c \
d1bbc4
 	early-offscn.c ecp.c elfcopy.c elfgetchdr.c elfgetzdata.c \
d1bbc4
-	elfputzdata.c elfshphehdr.c elfstrmerge.c elfstrtab.c \
d1bbc4
-	emptyfile.c fillfile.c find-prologues.c funcretval.c \
d1bbc4
-	funcscopes.c get-aranges.c get-files.c get-lines.c \
d1bbc4
-	get-pubnames.c get-units-invalid.c get-units-split.c \
d1bbc4
-	getsrc_die.c hash.c line2addr.c low_high_pc.c msg_tst.c \
d1bbc4
-	newdata.c newfile.c newscn.c next-files.c next-lines.c \
d1bbc4
-	next_cfi.c peel_type.c rdwrmmap.c rerequest_tag.c saridx.c \
d1bbc4
-	scnnames.c sectiondump.c show-abbrev.c show-die-info.c \
d1bbc4
-	showptable.c strptr.c system-elf-libelf-test.c \
d1bbc4
-	test-elf_cntl_gelf_getshdr.c test-flag-nobits.c test-nlist.c \
d1bbc4
-	typeiter.c typeiter2.c unit-info.c update1.c update2.c \
d1bbc4
-	update3.c update4.c varlocs.c vdsosyms.c vendorelf.c \
d1bbc4
-	xlate_notes.c zstrptr.c
d1bbc4
+	elfputzdata.c elfrdwrnop.c elfshphehdr.c elfstrmerge.c \
d1bbc4
+	elfstrtab.c emptyfile.c fillfile.c find-prologues.c \
d1bbc4
+	funcretval.c funcscopes.c get-aranges.c get-files.c \
d1bbc4
+	get-lines.c get-pubnames.c get-units-invalid.c \
d1bbc4
+	get-units-split.c getsrc_die.c hash.c line2addr.c \
d1bbc4
+	low_high_pc.c msg_tst.c newdata.c newfile.c newscn.c \
d1bbc4
+	next-files.c next-lines.c next_cfi.c peel_type.c rdwrmmap.c \
d1bbc4
+	rerequest_tag.c saridx.c scnnames.c sectiondump.c \
d1bbc4
+	show-abbrev.c show-die-info.c showptable.c strptr.c \
d1bbc4
+	system-elf-libelf-test.c test-elf_cntl_gelf_getshdr.c \
d1bbc4
+	test-flag-nobits.c test-nlist.c typeiter.c typeiter2.c \
d1bbc4
+	unit-info.c update1.c update2.c update3.c update4.c varlocs.c \
d1bbc4
+	vdsosyms.c vendorelf.c xlate_notes.c zstrptr.c
d1bbc4
 am__can_run_installinfo = \
d1bbc4
   case $$AM_UPDATE_INFO_DIR in \
d1bbc4
     n|no|NO) false;; \
d1bbc4
@@ -1405,6 +1409,7 @@
d1bbc4
 	     run-unit-info.sh run-next-cfi.sh run-next-cfi-self.sh \
d1bbc4
 	     testfile-riscv64.bz2 testfile-riscv64-s.bz2 \
d1bbc4
 	     testfile-riscv64-core.bz2 \
d1bbc4
+	     run-reverse-sections.sh run-reverse-sections-self.sh \
d1bbc4
 	     run-copyadd-sections.sh run-copymany-sections.sh \
d1bbc4
 	     run-typeiter-many.sh run-strip-test-many.sh \
d1bbc4
 	     testfile-debug-rel-ppc64-g.o.bz2 \
d1bbc4
@@ -1566,6 +1571,7 @@
d1bbc4
 elfcopy_LDADD = $(libelf)
d1bbc4
 addsections_LDADD = $(libelf)
d1bbc4
 xlate_notes_LDADD = $(libelf)
d1bbc4
+elfrdwrnop_LDADD = $(libelf)
d1bbc4
 
d1bbc4
 # We want to test the libelf header against the system elf.h header.
d1bbc4
 # Don't include any -I CPPFLAGS. Except when we install our own elf.h.
d1bbc4
@@ -1822,6 +1828,10 @@
d1bbc4
 	@rm -f elfputzdata$(EXEEXT)
d1bbc4
 	$(AM_V_CCLD)$(LINK) $(elfputzdata_OBJECTS) $(elfputzdata_LDADD) $(LIBS)
d1bbc4
 
d1bbc4
+elfrdwrnop$(EXEEXT): $(elfrdwrnop_OBJECTS) $(elfrdwrnop_DEPENDENCIES) $(EXTRA_elfrdwrnop_DEPENDENCIES) 
d1bbc4
+	@rm -f elfrdwrnop$(EXEEXT)
d1bbc4
+	$(AM_V_CCLD)$(LINK) $(elfrdwrnop_OBJECTS) $(elfrdwrnop_LDADD) $(LIBS)
d1bbc4
+
d1bbc4
 elfshphehdr$(EXEEXT): $(elfshphehdr_OBJECTS) $(elfshphehdr_DEPENDENCIES) $(EXTRA_elfshphehdr_DEPENDENCIES) 
d1bbc4
 	@rm -f elfshphehdr$(EXEEXT)
d1bbc4
 	$(AM_V_CCLD)$(LINK) $(elfshphehdr_OBJECTS) $(elfshphehdr_LDADD) $(LIBS)
d1bbc4
@@ -2086,6 +2096,7 @@
d1bbc4
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfgetchdr.Po@am__quote@ # am--include-marker
d1bbc4
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfgetzdata.Po@am__quote@ # am--include-marker
d1bbc4
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfputzdata.Po@am__quote@ # am--include-marker
d1bbc4
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfrdwrnop.Po@am__quote@ # am--include-marker
d1bbc4
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfshphehdr.Po@am__quote@ # am--include-marker
d1bbc4
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfstrmerge.Po@am__quote@ # am--include-marker
d1bbc4
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfstrtab.Po@am__quote@ # am--include-marker
d1bbc4
@@ -3709,6 +3720,20 @@
d1bbc4
 	--log-file $$b.log --trs-file $$b.trs \
d1bbc4
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
d1bbc4
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
d1bbc4
+run-reverse-sections.sh.log: run-reverse-sections.sh
d1bbc4
+	@p='run-reverse-sections.sh'; \
d1bbc4
+	b='run-reverse-sections.sh'; \
d1bbc4
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
d1bbc4
+	--log-file $$b.log --trs-file $$b.trs \
d1bbc4
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
d1bbc4
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
d1bbc4
+run-reverse-sections-self.sh.log: run-reverse-sections-self.sh
d1bbc4
+	@p='run-reverse-sections-self.sh'; \
d1bbc4
+	b='run-reverse-sections-self.sh'; \
d1bbc4
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
d1bbc4
+	--log-file $$b.log --trs-file $$b.trs \
d1bbc4
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
d1bbc4
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
d1bbc4
 run-copyadd-sections.sh.log: run-copyadd-sections.sh
d1bbc4
 	@p='run-copyadd-sections.sh'; \
d1bbc4
 	b='run-copyadd-sections.sh'; \
d1bbc4
@@ -3997,6 +4022,7 @@
d1bbc4
 	-rm -f ./$(DEPDIR)/elfgetchdr.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfgetzdata.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfputzdata.Po
d1bbc4
+	-rm -f ./$(DEPDIR)/elfrdwrnop.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfshphehdr.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfstrmerge.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfstrtab.Po
d1bbc4
@@ -4147,6 +4173,7 @@
d1bbc4
 	-rm -f ./$(DEPDIR)/elfgetchdr.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfgetzdata.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfputzdata.Po
d1bbc4
+	-rm -f ./$(DEPDIR)/elfrdwrnop.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfshphehdr.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfstrmerge.Po
d1bbc4
 	-rm -f ./$(DEPDIR)/elfstrtab.Po
d1bbc4
diff --git a/tests/elfcopy.c b/tests/elfcopy.c
d1bbc4
index d457bad..4542222 100644
d1bbc4
--- a/tests/elfcopy.c
d1bbc4
+++ b/tests/elfcopy.c
d1bbc4
@@ -225,6 +225,7 @@ copy_elf (const char *in, const char *out, bool use_mmap, bool reverse_offs)
d1bbc4
 	      && shdr.sh_addralign == 1
d1bbc4
 	      && last_shdr.sh_type != SHT_NOBITS
d1bbc4
 	      && shdr.sh_type != SHT_NOBITS
d1bbc4
+	      && last_shdr.sh_offset + last_shdr.sh_size == shdr.sh_offset
d1bbc4
 	      && (phnum == 0
d1bbc4
 		  || ((shdr.sh_flags & SHF_ALLOC) == 0
d1bbc4
 		      && (last_shdr.sh_flags & SHF_ALLOC) == 0)))