Blame SOURCES/elfutils-0.176-elf-update.patch

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