[PATCH v3 2/2] elf: Add a test for PT_LOAD segments with mixed p_align

H.J. Lu hjl.tools@gmail.com
Tue Dec 21 03:16:16 GMT 2021


Add tst-alignmod3-edit to edit the copy of tst-alignmod3.so to lower
p_align of the first PT_LOAD segment and verify that the shared library
is mapped with the maximum p_align of all PT_LOAD segments.
---
 elf/Makefile             |  18 ++++++
 elf/tst-alignmod3-edit.c | 122 +++++++++++++++++++++++++++++++++++++++
 elf/tst-p_align1.c       |  27 +++++++++
 3 files changed, 167 insertions(+)
 create mode 100644 elf/tst-alignmod3-edit.c
 create mode 100644 elf/tst-p_align1.c

diff --git a/elf/Makefile b/elf/Makefile
index fe42caeb0e..c3402c65b2 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -378,6 +378,13 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		tst-auditmod18 \
 		tst-audit18mod \
 
+ifeq (yesyes,$(build-shared)$(run-built-tests))
+tests += \
+  tst-alignmod3-edit \
+  tst-p_align1 \
+
+endif
+
 # Most modules build with _ISOMAC defined, but those filtered out
 # depend on internal headers.
 modules-names-tests = $(filter-out ifuncmod% tst-tlsmod%,\
@@ -1995,3 +2002,14 @@ $(objpfx)tst-ro-dynamic-mod.so: $(objpfx)tst-ro-dynamic-mod.os \
 		$(objpfx)tst-ro-dynamic-mod.os
 
 $(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig
+
+$(objpfx)tst-p_align1: $(objpfx)tst-p_alignmod1.so
+
+# Make a copy of tst-alignmod3.so and lower p_align of the first PT_LOAD
+# segment.
+$(objpfx)tst-p_alignmod1.so: $(objpfx)tst-alignmod3-edit \
+			     $(objpfx)tst-alignmod3.so
+	rm -f $@
+	cp $(objpfx)tst-alignmod3.so $@
+	$(test-wrapper-env) $(run-program-env) $(rtld-prefix) \
+	  $(objpfx)tst-alignmod3-edit $@
diff --git a/elf/tst-alignmod3-edit.c b/elf/tst-alignmod3-edit.c
new file mode 100644
index 0000000000..7b7eafbeec
--- /dev/null
+++ b/elf/tst-alignmod3-edit.c
@@ -0,0 +1,122 @@
+/* Lower p_align of the first PT_LOAD segment.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <link.h>
+#include <error.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+int
+main (int argc, char ** argv)
+{
+  if (argc != 2)
+    {
+      printf ("Usage: %s: file\n", argv[0]);
+      return 0;
+    }
+
+  const char *file_name = argv[1];
+  ElfW(Ehdr) ehdr;
+  struct stat statbuf;
+  int errno_saved;
+
+  if (stat (file_name, &statbuf) < 0)
+    error (1, errno, "%s: not exist \n", file_name);
+
+  if (statbuf.st_size < sizeof (ehdr))
+    error (1, 0, "%s: too small\n", file_name);
+
+  FILE *file = fopen (file_name, "r+b");
+  if (file == NULL)
+    error (1, 0, "%s: cann't open\n", file_name);
+
+  /* Read in the identity array.  */
+  if (fread (&ehdr, sizeof (ehdr), 1, file) != 1)
+    {
+      errno_saved = errno;
+      fclose (file);
+      error (1, errno_saved,
+	     "%s: can't read in ELF header\n", file_name);
+    }
+
+  if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+      || ehdr.e_ident[EI_MAG1] != ELFMAG1
+      || ehdr.e_ident[EI_MAG2] != ELFMAG2
+      || ehdr.e_ident[EI_MAG3] != ELFMAG3)
+    {
+      fclose (file);
+      error (1, 0, "%s: bad ELF header\n", file_name);
+    }
+
+  if (ehdr.e_type != ET_DYN)
+    {
+      fclose (file);
+      error (1, 0, "%s: not shared library\n", file_name);
+    }
+
+  /* We only support 32 bit and 64 bit ELF files.  */
+  switch (ehdr.e_ident[EI_CLASS])
+    {
+    default:
+      fclose (file);
+      error (1, 0, "%s: unsupported ELF class: %d\n",
+	     file_name, ehdr.e_ident[EI_CLASS]);
+      break;
+
+    case ELFCLASS32:
+    case ELFCLASS64:
+      break;
+    }
+
+  size_t phdr_size = sizeof (ElfW(Phdr)) * ehdr.e_phentsize;
+  if (statbuf.st_size < (ehdr.e_phoff + phdr_size))
+    {
+      fclose (file);
+      error (1, 0, "%s: too small\n", file_name);
+    }
+
+  /* Map in ELF program header table.  */
+  void *base = mmap (NULL, ehdr.e_phoff + phdr_size,
+		     PROT_READ | PROT_WRITE, MAP_SHARED,
+		     fileno (file), 0);
+  if (base == MAP_FAILED)
+    {
+      errno_saved = errno;
+      fclose (file);
+      error (1, errno_saved,
+	     "%s: failed to map in program header table\n",
+	     file_name);
+    }
+
+  ElfW(Phdr) *phdr = (ElfW(Phdr) *) (base + ehdr.e_phoff);
+
+  for (int i = 0; i < ehdr.e_phnum; i++, phdr++)
+    if (phdr->p_type == PT_LOAD)
+      {
+	/* Reduce p_align of the first PT_LOAD segment by half.  */
+	phdr->p_align = phdr->p_align >> 1;
+	break;
+      }
+
+  fclose (file);
+  munmap (base, phdr_size);
+
+  return 0;
+}
diff --git a/elf/tst-p_align1.c b/elf/tst-p_align1.c
new file mode 100644
index 0000000000..cab9793220
--- /dev/null
+++ b/elf/tst-p_align1.c
@@ -0,0 +1,27 @@
+/* Check different alignments of PT_LOAD segments in a shared library.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+extern int do_load_test (void);
+
+static int
+do_test (void)
+{
+  return do_load_test ();
+}
+
+#include <support/test-driver.c>
-- 
2.33.1



More information about the Libc-alpha mailing list