CONVERT_TO (shdr[cnt].sh_addralign,
notcvt[cnt].sh_addralign);
CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
-
- /* If this is a section with an extended index add a
- reference in the section which uses the extended
- index. */
- if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
- && shdr[cnt].sh_link < shnum)
- elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
- = cnt;
-
- /* Set the own shndx_index field in case it has not yet
- been set. */
- if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
- elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
- = -1;
}
if (copy)
((char *) map_address + offset
+ elf->state.elf32.shdr[cnt].sh_offset);
elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;
-
- /* If this is a section with an extended index add a
- reference in the section which uses the extended
- index. */
- if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
- && elf->state.elf32.shdr[cnt].sh_link < scncnt)
- elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index
- = cnt;
-
- /* Set the own shndx_index field in case it has not yet
- been set. */
- if (elf->state.elf32.scns.data[cnt].shndx_index == 0)
- elf->state.elf32.scns.data[cnt].shndx_index = -1;
}
}
else
((char *) map_address + offset
+ elf->state.elf64.shdr[cnt].sh_offset);
elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;
-
- /* If this is a section with an extended index add a
- reference in the section which uses the extended
- index. */
- if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
- && elf->state.elf64.shdr[cnt].sh_link < scncnt)
- elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index
- = cnt;
-
- /* Set the own shndx_index field in case it has not yet
- been set. */
- if (elf->state.elf64.scns.data[cnt].shndx_index == 0)
- elf->state.elf64.scns.data[cnt].shndx_index = -1;
}
}
else
/* Get the section index of the extended section index table.
Copyright (C) 2007 Red Hat, Inc.
+ Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
int
elf_scnshndx (Elf_Scn *scn)
{
- if (unlikely (scn->shndx_index == 0))
+ size_t scnndx;
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr;
+ Elf *elf;
+ Elf_Scn *nscn;
+
+ if (scn == NULL)
+ return -1;
+
+ scnndx = scn->index;
+ elf = scn->elf;
+
+ shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ return -1;
+
+ /* Only SYMTAB sections can have a SHNDX section. */
+ if (shdr->sh_type != SHT_SYMTAB)
+ return 0;
+
+ /* By convention the SHT_SYMTAB_SHNDX section is right after the the
+ SHT_SYMTAB section, so start there. */
+ nscn = scn;
+ while ((nscn = elf_nextscn (elf, nscn)) != NULL)
{
- /* We do not have the value yet. We get it as a side effect of
- getting a section header. */
- GElf_Shdr shdr_mem;
- (void) INTUSE(gelf_getshdr) (scn, &shdr_mem);
+ shdr = gelf_getshdr (nscn, &shdr_mem);
+ if (shdr == NULL)
+ return -1;
+
+ if (shdr->sh_type == SHT_SYMTAB_SHNDX && shdr->sh_link == scnndx)
+ return nscn->index;
+ }
+
+ /* OK, not found, start from the top. */
+ nscn = NULL;
+ while ((nscn = elf_nextscn (elf, nscn)) != NULL
+ && nscn->index != scnndx)
+ {
+ shdr = gelf_getshdr (nscn, &shdr_mem);
+ if (shdr == NULL)
+ return -1;
+
+ if (shdr->sh_type == SHT_SYMTAB_SHNDX && shdr->sh_link == scnndx)
+ return nscn->index;
}
- return scn->shndx_index;
+ /* No shndx found, but no errors. */
+ return 0;
}
INTDEF(elf_scnshndx)
extern Elf_Scn *elf_newscn (Elf *__elf);
/* Get the section index of the extended section index table for the
- given symbol table. */
+ given symbol table. Returns -1 when the given Elf_Scn is NULL or
+ if an error occurred during lookup, elf_errno will be set. Returns
+ 0 if the given Elf_Scn isn't a symbol table (sh_type is not
+ SHT_SYMTAB) or no extended section index table could be
+ found. Otherwise the section index of the extended section index
+ table for the given Elf_Scn is returned. An extended index table
+ has a sh_type of SHT_SYMTAB_SHNDX and a sh_link equal to the given
+ symbol table section index. */
extern int elf_scnshndx (Elf_Scn *__scn);
/* Get the number of sections in the ELF file. If the file uses more
int data_read; /* Nonzero if the section was created by the
user or if the data from the file/memory
is read. */
- int shndx_index; /* Index of the extended section index
- table for this symbol table (if this
- section is a symbol table). */
size_t index; /* Index of this section. */
struct Elf *elf; /* The underlying ELF file. */
attribute_hidden;
extern Elf_Scn *__elf_nextscn_internal (Elf *__elf, Elf_Scn *__scn)
attribute_hidden;
-extern int __elf_scnshndx_internal (Elf_Scn *__scn) attribute_hidden;
extern Elf_Data *__elf_getdata_internal (Elf_Scn *__scn, Elf_Data *__data)
attribute_hidden;
extern Elf_Data *__elf_getdata_rdlock (Elf_Scn *__scn, Elf_Data *__data)
/* Print information from ELF file in human-readable form.
Copyright (C) 1999-2018 Red Hat, Inc.
- Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org>
+ Copyright (C) 2023, 2025 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
return;
}
- /* Search for the optional extended section index table. */
+ /* Search for the optional extended section index table if there are
+ more than 64k sections. */
Elf_Data *xndxdata = NULL;
- int xndxscnidx = elf_scnshndx (scn);
+ int xndxscnidx = shnum >= SHN_LORESERVE ? elf_scnshndx (symscn) : 0;
if (unlikely (xndxscnidx > 0))
xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
_("INVALID SYMBOL"),
(long int) GELF_R_SYM (rel->r_info));
}
- else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
+ else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION
+ && !(GELF_ST_TYPE (sym->st_info) == STT_NOTYPE
+ && GELF_ST_BIND (sym->st_info) == STB_LOCAL
+ && sym->st_shndx != SHN_UNDEF
+ && sym->st_value == 0)) // local start section label
printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
likely (ebl_reloc_type_check (ebl,
elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
else
{
- /* This is a relocation against a STT_SECTION symbol. */
+ /* This is a relocation against a STT_SECTION symbol
+ or a local start section label for which we print
+ section name. */
GElf_Shdr secshdr_mem;
GElf_Shdr *secshdr;
secshdr = gelf_getshdr (elf_getscn (ebl->elf,
return;
}
- /* Search for the optional extended section index table. */
+ /* Search for the optional extended section index table if there are
+ more than 64k sections. */
Elf_Data *xndxdata = NULL;
- int xndxscnidx = elf_scnshndx (scn);
+ int xndxscnidx = shnum >= SHN_LORESERVE ? elf_scnshndx (symscn) : 0;
if (unlikely (xndxscnidx > 0))
xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
_("INVALID SYMBOL"),
(long int) GELF_R_SYM (rel->r_info));
}
- else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
+ else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION
+ && !(GELF_ST_TYPE (sym->st_info) == STT_NOTYPE
+ && GELF_ST_BIND (sym->st_info) == STB_LOCAL
+ && sym->st_shndx != SHN_UNDEF
+ && sym->st_value == 0)) // local start section label
printf ("\
%#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
else
{
- /* This is a relocation against a STT_SECTION symbol. */
+ /* This is a relocation against a STT_SECTION symbol
+ or a local start section label for which we print
+ section name. */
GElf_Shdr secshdr_mem;
GElf_Shdr *secshdr;
secshdr = gelf_getshdr (elf_getscn (ebl->elf,
getphdrnum leb128 read_unaligned \
msg_tst system-elf-libelf-test system-elf-gelf-test \
nvidia_extended_linemap_libdw elf-print-reloc-syms \
- cu-dwp-section-info declfiles \
+ cu-dwp-section-info declfiles test-manyfuncs \
$(asm_TESTS)
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
$(AM_LDFLAGS) $(LDFLAGS) $(backtrace_child_LDFLAGS) \
-o $@ $<
+# A test object with 64K sections and function symbols
+# Don't try to optimize or add debuginfo
+# Do explicitly add unwind tables, so there are definitely relocations
+# to all function symbols/sections.
+manyfuncs.o: manyfuncs.c
+ $(AM_V_CC)$(CC) -fasynchronous-unwind-tables -g0 -O0 -o $@ -c $<
+
+# We also want the manyfuncs.o (test) file generated
+check-local: manyfuncs.o
+
if GCOV
GCOV_FLAGS=-fprofile-arcs -ftest-coverage
else
run-readelf-aranges.sh run-readelf-line.sh run-readelf-z.sh \
run-readelf-frames.sh \
run-readelf-n.sh \
+ run-readelf-r-manyfuncs.sh \
run-retain.sh \
run-native-test.sh run-bug1-test.sh \
run-debuglink.sh run-debugaltlink.sh run-buildid.sh \
run-readelf-dw-form-indirect.sh run-strip-largealign.sh \
run-readelf-Dd.sh run-dwfl-core-noncontig.sh run-cu-dwp-section-info.sh \
run-declfiles.sh \
- run-sysroot.sh
+ run-sysroot.sh \
+ run-test-manyfuncs.sh
if !BIARCH
export ELFUTILS_DISABLE_BIARCH = 1
testfile_gnu_props.32be.o.bz2 \
testfile_gnu_props.64be.o.bz2 \
testfile-gnu-property-note-aarch64.bz2 \
+ run-readelf-r-manyfuncs.sh \
run-retain.sh testfile-retain.o.bz2 \
run-allfcts-multi.sh \
test-offset-loop.bz2 test-offset-loop.alt.bz2 \
testfile-dwp-4-cu-index-overflow.dwp.bz2 \
testfile-dwp-cu-index-overflow.source \
testfile-define-file.bz2 \
- testfile-sysroot.tar.bz2 run-sysroot.sh run-debuginfod-seekable.sh
+ testfile-sysroot.tar.bz2 run-sysroot.sh \
+ run-test-manyfuncs.sh manyfuncs.c \
+ run-debuginfod-seekable.sh
if USE_VALGRIND
elf_print_reloc_syms_LDADD = $(libelf)
cu_dwp_section_info_LDADD = $(libdw)
declfiles_LDADD = $(libdw)
+test_manyfuncs_LDADD = $(libelf)
+# Make sure the manyfunc.o test object is generated before test-manyfuncs
+EXTRA_test_manyfuncs_DEPENDENCIES = manyfuncs.o
# 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.
# A lock file used to make sure only one test dumps core at a time
MOSTLYCLEANFILES = core-dump-backtrace.lock
-CLEANFILES = $(BUILT_SOURCES)
+CLEANFILES = $(BUILT_SOURCES) manyfuncs.o
if GCOV
check: check-am coverage
/* Search for the optional extended section index table. */
Elf_Data *xndxdata = NULL;
- int xndxscnidx = elf_scnshndx (scn);
- if (xndxscnidx)
+ int xndxscnidx = elf_scnshndx (symscn);
+ if (xndxscnidx > 0)
xndxdata = elf_getdata (elf_getscn (elf, xndxscnidx), NULL);
/* Get the section header string table index. */
--- /dev/null
+/* Test file for a binary with 64K+ sections and symbols.
+ Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
+ 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/>. */
+
+
+/* We need a quoted string starting with a dot (the section name). */
+#define DQ(x) #x
+#define DOTQUOTE(x) DQ(.x)
+
+/* We want 2 * (8 ^ 5) = 2 * ((2 ^ 3) ^ 5) = 2 ^ 16 = 64K functions. */
+#define f(x) __attribute__ ((section (DOTQUOTE(x)))) void x(void) {};
+#define A(x) f(x##0) f(x##1) f(x##2) f(x##3) f(x##4) f(x##5) f(x##6) f(x##7)
+#define B(x) A(x##0) A(x##1) A(x##2) A(x##3) A(x##4) A(x##5) A(x##6) A(x##7)
+#define C(x) B(x##0) B(x##1) B(x##2) B(x##3) B(x##4) B(x##5) B(x##6) B(x##7)
+#define D(x) C(x##0) C(x##1) C(x##2) C(x##3) C(x##4) C(x##5) C(x##6) C(x##7)
+#define E(x) D(x##0) D(x##1) D(x##2) D(x##3) D(x##4) D(x##5) D(x##6) D(x##7)
+E(y)
+E(z)
+
+#undef f
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+
+/* Call all functions from main. */
+#define f(x) x();
+#define A(x) f(x##0) f(x##1) f(x##2) f(x##3) f(x##4) f(x##5) f(x##6) f(x##7)
+#define B(x) A(x##0) A(x##1) A(x##2) A(x##3) A(x##4) A(x##5) A(x##6) A(x##7)
+#define C(x) B(x##0) B(x##1) B(x##2) B(x##3) B(x##4) B(x##5) B(x##6) B(x##7)
+#define D(x) C(x##0) C(x##1) C(x##2) C(x##3) C(x##4) C(x##5) C(x##6) C(x##7)
+#define E(x) D(x##0) D(x##1) D(x##2) D(x##3) D(x##4) D(x##5) D(x##6) D(x##7)
+
+int
+main ()
+{
+E(y)
+E(z)
+}
--- /dev/null
+#! /bin/sh
+# Test readelf -r on file containing 64K+ functions and sections
+# Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
+# 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/>.
+
+. $srcdir/test-subr.sh
+
+# Tests readelf -r on file containing 64K+ functions and sections
+# This forces the use of elf_scnshndx to lookup section indexes
+# The test makes sure that for relocations against sectio symbols
+# the section names are resolved even for section indexes > 64K.
+#
+# Note the sections are named after the symbols (with a '.' in front).
+
+testrun ${abs_top_builddir}/src/readelf -r \
+ ${abs_top_builddir}/tests/manyfuncs.o | grep -F ".y00000" || exit 1
+
+testrun ${abs_top_builddir}/src/readelf -r \
+ ${abs_top_builddir}/tests/manyfuncs.o | grep -F ".z00000" || exit 1
+
+testrun ${abs_top_builddir}/src/readelf -r \
+ ${abs_top_builddir}/tests/manyfuncs.o | grep -F ".y77777" || exit 1
+
+testrun ${abs_top_builddir}/src/readelf -r \
+ ${abs_top_builddir}/tests/manyfuncs.o | grep -F ".z77777" || exit 1
+
+exit 0
--- /dev/null
+#! /bin/sh
+# Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
+# 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/>.
+
+. $srcdir/test-subr.sh
+
+testrun ${abs_top_builddir}/tests/test-manyfuncs \
+ ${abs_top_builddir}/tests/manyfuncs.o
+
+exit 0
--- /dev/null
+/* Test program for reading file with 64k+ sections and symbols.
+ Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
+ 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 <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "system.h"
+
+#include ELFUTILS_HEADER(elf)
+#include <gelf.h>
+
+/* Various fields (Elf_Half) can only contain up to 64k values. So
+ they need to be accessed through libelf functions which know where
+ the "true" value can be found. Also to get the section associated
+ with a symbol will need an extended symbol table entry. Use
+ elf_scnshndx to get at it and check we can get both symbol and
+ associated section names. */
+
+static void
+check_elf (const char *fname, bool use_mmap)
+{
+ printf ("\nfname (use_mmap: %d): %s\n", use_mmap, fname);
+
+ int fd = open (fname, O_RDONLY);
+ if (fd == -1)
+ {
+ printf ("cannot open `%s': %s\n", fname, strerror (errno));
+ exit (1);
+ }
+
+ Elf *elf = elf_begin (fd, use_mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL);
+ if (elf == NULL)
+ {
+ printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ /* How many sections are there? */
+ size_t shnum;
+ if (elf_getshdrnum (elf, &shnum) < 0)
+ {
+ printf ("elf_getshdrstrndx: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ if (shnum < SHN_LORESERVE)
+ {
+ printf ("Not enough section for test, %zd < %d\n",
+ shnum, SHN_LORESERVE);
+ exit (1);
+ }
+
+ printf ("shnum: %zd\n", shnum);
+
+ /* Get the section that contains the section header names. Check it
+ can be found and it contains the substring 'str' in its own
+ name. */
+ size_t shstrndx;
+ if (elf_getshdrstrndx (elf, &shstrndx) < 0)
+ {
+ printf ("elf_getshdrstrndx: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ Elf_Scn *scn = elf_getscn (elf, shstrndx);
+ if (scn == NULL)
+ {
+ printf ("cannot get section at index %zd: %s\n", shstrndx,
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ {
+ printf ("cannot get header for shstrndx section: %s\n",
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ /* Assume the section name contains at least the substring "str". */
+ const char *sname = elf_strptr (elf, shstrndx, shdr->sh_name);
+ if (sname == NULL || strstr (sname, "str") == NULL)
+ {
+ printf ("Bad section name: %s\n", sname);
+ exit (1);
+ }
+
+ printf ("shstrndx section name: %s\n", sname);
+
+ /* The shstrndx section isn't a SYMTAB section, so elf_scnshndx will
+ return zero. */
+ int shndx = elf_scnshndx (scn);
+ if (shndx < 0)
+ {
+ printf ("elf_scnshndx error for shstrndx section: %s\n",
+ elf_errmsg (-1));
+ exit (1);
+ }
+ if (shndx > 0)
+ {
+ printf ("elf_scnshndx not zero for shstrndx section: %d\n", shndx);
+ exit (1);
+ }
+
+ /* Find the symtab and symtab_shndx by hand. */
+ size_t symtabndx = 0;
+ size_t symtabstrndx = 0;
+ size_t symtabsndx = 0;
+ size_t scns = 1; /* scn zero is skipped. */
+ Elf_Scn *symtabscn = NULL;
+ Elf_Scn *xndxscn = NULL;
+ scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ if (scns != elf_ndxscn (scn))
+ {
+ printf ("Unexpected elf_ndxscn %zd != %zd\n",
+ scns, elf_ndxscn (scn));
+ exit (1);
+ }
+
+ shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ {
+ printf ("couldn't get shdr\n");
+ exit (1);
+ }
+
+ if (shdr->sh_type == SHT_SYMTAB)
+ {
+ symtabndx = elf_ndxscn (scn);
+ symtabstrndx = shdr->sh_link;
+ symtabscn = scn;
+ }
+
+ if (shdr->sh_type == SHT_SYMTAB_SHNDX)
+ {
+ symtabsndx = elf_ndxscn (scn);
+ xndxscn = scn;
+ }
+
+ /* We could break if we have both symtabndx and symtabsndx, but
+ we want to run through all sections to see if we get them
+ all and sanity check shnum. */
+ scns++;
+ }
+
+ printf ("scns: %zd\n", scns);
+ if (scns != shnum)
+ {
+ printf ("scns (%zd) != shnum (%zd)\n", scns, shnum);
+ exit (1);
+ }
+
+ printf ("symtabndx: %zd\n", symtabndx);
+ if (symtabndx == 0 || symtabscn == NULL)
+ {
+ printf ("No SYMTAB\n");
+ exit (1);
+ }
+
+ printf ("symtabsndx: %zd\n", symtabsndx);
+ if (symtabsndx == 0)
+ {
+ printf ("No SYMTAB_SNDX\n");
+ exit (1);
+ }
+
+ int scnshndx = elf_scnshndx (symtabscn);
+ printf ("scnshndx: %d\n", scnshndx);
+ if (scnshndx < 0)
+ {
+ printf ("elf_scnshndx failed: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ if (scnshndx == 0)
+ {
+ printf ("elf_scnshndx couldn't find scnshndx, returned zero\n");
+ exit (1);
+ }
+
+ if ((size_t) scnshndx != symtabsndx)
+ {
+ printf ("elf_scnshndx found wrong scnshndx (%d),"
+ " should have been (%zd)\n", scnshndx, symtabsndx);
+ exit (1);
+ }
+
+ Elf_Data *symdata = elf_getdata (symtabscn, NULL);
+ if (symdata == NULL)
+ {
+ printf ("Couldn't elf_getdata for symtabscn: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ size_t nsyms = symdata->d_size / (gelf_getclass (elf) == ELFCLASS32
+ ? sizeof (Elf32_Sym)
+ : sizeof (Elf64_Sym));
+
+ Elf_Data *xndxdata = elf_getdata (xndxscn, NULL);
+ if (xndxdata == NULL)
+ {
+ printf ("Couldn't elf_getdata for xndxscn: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ /* Now for every [yz]ddddd symbol , check that it matches the
+ section name (minus the starting dot). */
+ size_t yzsymcnt = 0;
+ for (size_t cnt = 0; cnt < nsyms; ++cnt)
+ {
+ const char *sym_name;
+ const char *section_name;
+ GElf_Word xndx;
+ GElf_Sym sym_mem;
+ GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata, cnt,
+ &sym_mem, &xndx);
+
+ if (sym == NULL)
+ {
+ printf ("gelf_getsymshndx failed: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ if (sym->st_shndx != SHN_XINDEX)
+ xndx = sym->st_shndx;
+
+ sym_name = elf_strptr (elf, symtabstrndx, sym->st_name);
+ if (sym_name == NULL)
+ {
+ printf ("elf_strptr returned NULL for sym %zd: %s\n",
+ cnt, elf_errmsg (-1));
+ exit (1);
+ }
+
+ scn = elf_getscn (elf, xndx);
+ if (scn == NULL)
+ {
+ printf ("cannot get section at index %d: %s\n", xndx,
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ {
+ printf ("cannot get header for sym xndx section: %s\n",
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
+ if (section_name == NULL)
+ {
+ printf ("elf_strptr returned NULL for section: %s\n",
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ if (GELF_ST_TYPE (sym->st_info) == STT_FUNC
+ && (sym_name[0] == 'y' || sym_name[0] == 'z')
+ && strlen (sym_name) == 6)
+ {
+ yzsymcnt++;
+ /* Every [yz]ddddd symbol comes from a section named after
+ the symbol prefixed with '.'. Except for powerpc ELFv1,
+ where all symbols point into the .opd. */
+ if ((section_name[0] != '.'
+ || strcmp (sym_name, §ion_name[1]) != 0)
+ && strcmp (section_name, ".opd") != 0)
+ {
+ printf ("BAD SYM/SECTION %zd sym: %s, section: %s\n",
+ cnt, sym_name, section_name);
+ exit (1);
+ }
+ }
+ }
+
+#define YZSYMCNT (size_t) (2 * 8 * 8 * 8 * 8 * 8)
+ printf ("yzsymcnt: %zd\n", yzsymcnt);
+ if (yzsymcnt != YZSYMCNT)
+ {
+ printf ("Wrong number of yzsymcnts: %zd, should be %zd\n",
+ yzsymcnt, YZSYMCNT);
+ exit (1);
+ }
+
+ if (elf_end (elf) != 0)
+ {
+ printf ("failure in elf_end: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ close (fd);
+}
+
+int
+main (int argc, char *argv[] __attribute__ ((unused)))
+{
+ elf_version (EV_CURRENT);
+
+ if (argc < 2)
+ {
+ printf ("Need at least one (file name) argument\n");
+ exit (1);
+ }
+
+ /* Test all file using ELF_C_READ and ELF_C_READ_MMAP. */
+ for (int i = 1; i < argc; i++)
+ {
+ check_elf (argv[i], false);
+ check_elf (argv[i], true);
+ }
+
+ return 0;
+}