summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorAaron Merey <[email protected]>2024-01-21 19:44:34 -0500
committerAaron Merey <[email protected]>2024-02-06 15:08:32 -0500
commit2f9b180cc1057fb351332689886b2492b3711aad (patch)
treee819d41c5210546c2e0d025b7be1bb1e08486396 /tests
parentde60eba95b2dd36fc11de33b32391ae9533a15ac (diff)
unstrip: Call adjust_relocs no more than once per section.
During symtab merging, adjust_relocs might be called multiple times on some SHT_REL/SHT_RELA sections. In these cases it is possible for a relocation's symbol index to be correctly mapped from X to Y during the first call to adjust_relocs but then wrongly remapped from Y to Z during the second call. Fix this by adjusting relocation symbol indices just once per section. Also add stable sorting for symbols during symtab merging so that the symbol order in the output file's symtab does not depend on undefined behaviour in qsort. Note that adjust_relocs still might be called a second time on a section during add_new_section_symbols. However since add_new_section_symbols generates its own distinct symbol index map, this should not trigger the bug described above. https://sourceware.org/bugzilla/show_bug.cgi?id=31097 Signed-off-by: Aaron Merey <[email protected]>
Diffstat (limited to 'tests')
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/elf-print-reloc-syms.c142
-rwxr-xr-xtests/run-unstrip-test.sh8
4 files changed, 153 insertions, 1 deletions
diff --git a/tests/.gitignore b/tests/.gitignore
index 5bebb2c4..d00a883e 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -63,6 +63,7 @@
/elfshphehdr
/elfstrmerge
/elfstrtab
+/elf-print-reloc-syms
/emptyfile
/fillfile
/find-prologues
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2373c980..13bd9d56 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -62,7 +62,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
dwelf_elf_e_machine_string \
getphdrnum leb128 read_unaligned \
msg_tst system-elf-libelf-test system-elf-gelf-test \
- nvidia_extended_linemap_libdw \
+ nvidia_extended_linemap_libdw elf-print-reloc-syms \
$(asm_TESTS)
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
@@ -810,6 +810,7 @@ getphdrnum_LDADD = $(libelf) $(libdw)
leb128_LDADD = $(libelf) $(libdw)
read_unaligned_LDADD = $(libelf) $(libdw)
nvidia_extended_linemap_libdw_LDADD = $(libelf) $(libdw)
+elf_print_reloc_syms_LDADD = $(libelf)
# We want to test the libelf headers against the system elf.h header.
# Don't include any -I CPPFLAGS. Except when we install our own elf.h.
diff --git a/tests/elf-print-reloc-syms.c b/tests/elf-print-reloc-syms.c
new file mode 100644
index 00000000..b9453f6b
--- /dev/null
+++ b/tests/elf-print-reloc-syms.c
@@ -0,0 +1,142 @@
+/* Copyright (C) 2024 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ elfutils 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <gelf.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+
+static void
+print_reloc_symnames (Elf *elf, Elf_Scn *scn, GElf_Shdr *shdr, size_t sh_entsize)
+{
+ int nentries = shdr->sh_size / sh_entsize;
+
+ /* Get the data of the section. */
+ Elf_Data *data = elf_getdata (scn, NULL);
+ assert (data != NULL);
+
+ /* Get the symbol table information. */
+ Elf_Scn *symscn = elf_getscn (elf, shdr->sh_link);
+ GElf_Shdr symshdr_mem;
+ GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
+ Elf_Data *symdata = elf_getdata (symscn, NULL);
+ assert (symshdr != NULL);
+ assert (symdata != NULL);
+
+ /* Search for the optional extended section index table. */
+ Elf_Data *xndxdata = NULL;
+ int xndxscnidx = elf_scnshndx (scn);
+ if (xndxscnidx)
+ xndxdata = elf_getdata (elf_getscn (elf, xndxscnidx), NULL);
+
+ /* Get the section header string table index. */
+ size_t shstrndx;
+ assert (elf_getshdrstrndx (elf, &shstrndx) >= 0);
+
+ printf("Section: %s\n", elf_strptr (elf, shstrndx, shdr->sh_name));
+ for (int cnt = 0; cnt < nentries; ++cnt)
+ {
+ GElf_Rel relmem;
+ GElf_Rel *rel = gelf_getrel (data, cnt, &relmem);
+
+
+ if (likely (rel != NULL))
+ {
+ GElf_Sym symmem;
+ Elf32_Word xndx;
+ GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
+ GELF_R_SYM (rel->r_info),
+ &symmem, &xndx);
+
+ if (sym == NULL)
+ {
+ printf ("<SYM NOT FOUND>\n");
+ continue;
+ }
+
+ if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
+ printf ("%s\n", elf_strptr (elf, symshdr->sh_link, sym->st_name));
+ else
+ {
+ /* This is a relocation against a STT_SECTION symbol. */
+ GElf_Shdr secshdr_mem;
+ GElf_Shdr *secshdr;
+ secshdr = gelf_getshdr (elf_getscn (elf,
+ sym->st_shndx == SHN_XINDEX
+ ? xndx : sym->st_shndx),
+ &secshdr_mem);
+
+ if (secshdr == NULL)
+ printf("<SECTION NOT FOUND>\n");
+ else
+ printf ("%s\n",
+ elf_strptr (elf, shstrndx, secshdr->sh_name));
+ }
+ }
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ if (argc != 2)
+ {
+ printf ("Usage: elf_print_reloc_syms FILE\n");
+ return -1;
+ }
+
+ elf_version (EV_CURRENT);
+
+ int fd = open(argv[1], O_RDONLY);
+ assert (fd != -1);
+
+ Elf *elf = elf_begin (fd, ELF_C_READ, NULL);
+ assert (elf != NULL);
+
+ size_t shnums;
+ assert (elf_getshdrnum (elf, &shnums) >= 0);
+
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+
+ if (shdr != NULL)
+ {
+ /* Print the names of symbols referred to by relocations. */
+ if (shdr->sh_type == SHT_REL)
+ {
+ size_t sh_entsize = gelf_fsize (elf, ELF_T_REL, 1, EV_CURRENT);
+ print_reloc_symnames (elf, scn, shdr, sh_entsize);
+ }
+ else if (shdr->sh_type == SHT_RELA)
+ {
+ size_t sh_entsize = gelf_fsize (elf, ELF_T_RELA, 1, EV_CURRENT);
+ print_reloc_symnames (elf, scn, shdr, sh_entsize);
+ }
+ }
+ }
+
+ elf_end (elf);
+ close (fd);
+ return 0;
+}
diff --git a/tests/run-unstrip-test.sh b/tests/run-unstrip-test.sh
index dc7d3a42..8b7143a2 100755
--- a/tests/run-unstrip-test.sh
+++ b/tests/run-unstrip-test.sh
@@ -33,6 +33,14 @@ testrun ${abs_top_builddir}/src/unstrip -o testfile.unstrip $stripped $debugfile
testrun ${abs_top_builddir}/src/elfcmp --hash-inexact $original testfile.unstrip
+tempfiles syms-orig syms-testfile
+
+# Check whether relocated symbols changed.
+testrun ${abs_top_builddir}/tests/elf-print-reloc-syms $original > syms-orig
+testrun ${abs_top_builddir}/tests/elf-print-reloc-syms testfile.unstrip > syms-testfile
+
+testrun diff syms-orig syms-testfile
+
# Also test modifying the file in place.
rm -f testfile.inplace