summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2006-07-07 03:43:47 +0000
committerUlrich Drepper <drepper@redhat.com>2006-07-07 03:43:47 +0000
commit28ed895fdc303b2a793506bb1fcdd35d5fd14e70 (patch)
tree1385a2d5f0e844e26990b9da92b784ca73c73000 /src
parent1d3a64d70c8f2aec1fc3ae26d124823c1ef304a9 (diff)
downloadelfutils-28ed895fdc303b2a793506bb1fcdd35d5fd14e70.tar.gz
merge of 2d5572f10b65f0ac7fdf54361b4dae41ebbd51d0
and fda3a25581b7bfac581504e9e887e9b97f234f86
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog42
-rw-r--r--src/Makefile.am13
-rw-r--r--src/elflint.c348
-rw-r--r--src/i386_ld.c40
-rw-r--r--src/ld.c2
-rw-r--r--src/ld.h4
-rw-r--r--src/ldgeneric.c102
-rw-r--r--src/readelf.c287
8 files changed, 655 insertions, 183 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 87ea9744..1c153b00 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,45 @@
+2006-07-06 Ulrich Drepper <drepper@redhat.com>
+
+ * elflint.c: Adjust for latest new hash table format.
+ * readelf.c: Likewise.
+
+ * elflint.c (check_versym): Ignore hidden bit when comparing version
+ numbers.
+
+2006-07-05 Ulrich Drepper <drepper@redhat.com>
+
+ * ldgeneric.c (ld_generic_create_outfile): Correctly recognize
+ discarded COMDAT symbols.
+
+ * i386_ld.c (elf_i386_count_relocations): Lot of corrections.
+ (elf_i386_create_relocations): Likewise.
+ * ld.h (struct symbol): Add local and hidden bits.
+ * ld.c (create_special_section_symbol): These synthsized symbols
+ are local and hidden.
+ * ldgeneric.c (file_process2): Check whether input file matches
+ the emulation.
+ (fillin_special_symbol): Create symbols as local and/or hidden
+ if requested.
+ (ld_generic_create_outfile): Make local copy of symbol.
+ Don't hide global, defined symbols in dynamic symbol table unless
+ requested. Synthetic symbols have no version information.
+
+ * elflint.c: Add support for checking 64-bit SysV-style hash tables.
+ * readelf.c: Add support for printing 64-bit SysV-style hash tables.
+
+2006-07-04 Ulrich Drepper <drepper@redhat.com>
+
+ * elflint.c (is_rel_dyn): Fix and extend DT_RELCOUNT/DT_RELACOUNT
+ testing.
+
+2006-07-03 Ulrich Drepper <drepper@redhat.com>
+
+ * elflint.c: Add testing of DT_GNU_HASH.
+ * readelf.c: Implement showing histogram for DT_GNU_HASH section.
+
+ * Makefile.am: Add hacks to create dependency files for non-generic
+ linker.
+
2006-06-12 Ulrich Drepper <drepper@redhat.com>
* ldgeneric.c (ld_generic_generate_sections): Don't create .interp
diff --git a/src/Makefile.am b/src/Makefile.am
index 49e01740..604483ab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -63,6 +63,12 @@ else
noinst_LIBRARIES = libld_elf.a $(ld_dsos)
noinst_PROGRAMS = $(ld_dsos:_pic.a=.so)
endif
+if NEVER
+# We never build this library but we need to get the dependency files
+# of all the linker backends that might be used in a non-generic linker.
+noinst_LIBRARIES += libdummy.a
+libdummy_a_SOURCES = i386_ld.c
+endif
textrel_check = if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi
@@ -102,6 +108,7 @@ size_LDADD = $(libelf) $(libeu) $(libmudflap)
strip_LDADD = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl
ld_LDADD = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl
if NATIVE_LD
+# -ldl is always needed for libebl.
ld_LDADD += libld_elf.a
endif
ld_LDFLAGS = -rdynamic
@@ -117,9 +124,10 @@ ldlex.o: ldscript.c
ldlex_no_Werror = yes
ldscript.h: ldscript.c
+if NATIVE_LD
# Machine-specific linker code.
-libld_elf_a_SOURCES = $(base_cpu)_ld.c
-
+libld_elf_a_SOURCES := $(base_cpu)_ld.c
+else
libld_elf_i386_pic_a_SOURCES =
am_libld_elf_i386_pic_a_OBJECTS = i386_ld.os
@@ -129,6 +137,7 @@ libld_elf_i386.so: libld_elf_i386_pic.a libld_elf_i386.map
$(libelf) $(libeu) \
-Wl,--version-script,$(srcdir)/libld_elf_i386.map
$(textrel_check)
+endif
%.os: %.c %.o
diff --git a/src/elflint.c b/src/elflint.c
index cd335fe6..a679acc4 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -951,14 +951,14 @@ section [%2d] '%s': _DYNAMIC symbol size %" PRIu64 " does not match dynamic segm
static bool
is_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr,
- bool rela)
+ bool is_rela)
{
/* If this is no executable or DSO it cannot be a .rel.dyn section. */
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
return false;
/* Check the section name. Unfortunately necessary. */
- if (strcmp (section_name (ebl, idx), rela ? ".rela.dyn" : ".rel.dyn"))
+ if (strcmp (section_name (ebl, idx), is_rela ? ".rela.dyn" : ".rel.dyn"))
return false;
/* When a .rel.dyn section is used a DT_RELCOUNT dynamic section
@@ -984,14 +984,106 @@ is_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr,
if (dyn->d_tag == DT_RELCOUNT)
{
- /* Found it. One last check: does the number
- specified number of relative relocations exceed
- the total number of relocations? */
- if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize)
+ /* Found it. Does the type match. */
+ if (is_rela)
ERROR (gettext ("\
+section [%2d] '%s': DT_RELCOUNT used for this RELA section\n"),
+ idx, section_name (ebl, idx));
+ else
+ {
+ /* Does the number specified number of relative
+ relocations exceed the total number of
+ relocations? */
+ if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize)
+ ERROR (gettext ("\
section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"),
- idx, section_name (ebl, idx),
- (int) dyn->d_un.d_val);
+ idx, section_name (ebl, idx),
+ (int) dyn->d_un.d_val);
+
+ /* Make sure the specified number of relocations are
+ relative. */
+ Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf,
+ idx), NULL);
+ if (reldata != NULL)
+ for (size_t inner = 0;
+ inner < shdr->sh_size / shdr->sh_entsize;
+ ++inner)
+ {
+ GElf_Rel rel_mem;
+ GElf_Rel *rel = gelf_getrel (reldata, inner,
+ &rel_mem);
+ if (rel == NULL)
+ /* The problem will be reported elsewhere. */
+ break;
+
+ if (ebl_relative_reloc_p (ebl,
+ GELF_R_TYPE (rel->r_info)))
+ {
+ if (inner >= dyn->d_un.d_val)
+ ERROR (gettext ("\
+section [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"),
+ idx, section_name (ebl, idx),
+ (int) dyn->d_un.d_val);
+ }
+ else if (inner < dyn->d_un.d_val)
+ ERROR (gettext ("\
+section [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"),
+ idx, section_name (ebl, idx),
+ inner, (int) dyn->d_un.d_val);
+ }
+ }
+ }
+
+ if (dyn->d_tag == DT_RELACOUNT)
+ {
+ /* Found it. Does the type match. */
+ if (!is_rela)
+ ERROR (gettext ("\
+section [%2d] '%s': DT_RELACOUNT used for this REL section\n"),
+ idx, section_name (ebl, idx));
+ else
+ {
+ /* Does the number specified number of relative
+ relocations exceed the total number of
+ relocations? */
+ if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize)
+ ERROR (gettext ("\
+section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"),
+ idx, section_name (ebl, idx),
+ (int) dyn->d_un.d_val);
+
+ /* Make sure the specified number of relocations are
+ relative. */
+ Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf,
+ idx), NULL);
+ if (reldata != NULL)
+ for (size_t inner = 0;
+ inner < shdr->sh_size / shdr->sh_entsize;
+ ++inner)
+ {
+ GElf_Rela rela_mem;
+ GElf_Rela *rela = gelf_getrela (reldata, inner,
+ &rela_mem);
+ if (rela == NULL)
+ /* The problem will be reported elsewhere. */
+ break;
+
+ if (ebl_relative_reloc_p (ebl,
+ GELF_R_TYPE (rela->r_info)))
+ {
+ if (inner >= dyn->d_un.d_val)
+ ERROR (gettext ("\
+section [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"),
+ idx, section_name (ebl, idx),
+ (int) dyn->d_un.d_val);
+ }
+ else if (inner < dyn->d_un.d_val)
+ ERROR (gettext ("\
+section [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"),
+ idx, section_name (ebl, idx),
+ inner, (int) dyn->d_un.d_val);
+ }
+ }
}
}
@@ -1718,7 +1810,194 @@ extended section index is %" PRIu32 " but symbol index is not XINDEX\n"),
static void
-check_hash (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
+check_sysv_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
+ GElf_Shdr *symshdr)
+{
+ Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
+ Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
+
+ if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize)
+ ERROR (gettext ("\
+section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"),
+ idx, section_name (ebl, idx), (long int) shdr->sh_size,
+ (long int) ((2 + nbucket + nchain) * shdr->sh_entsize));
+
+ size_t maxidx = nchain;
+
+ if (symshdr != NULL)
+ {
+ size_t symsize = symshdr->sh_size / symshdr->sh_entsize;
+
+ if (nchain > symshdr->sh_size / symshdr->sh_entsize)
+ ERROR (gettext ("section [%2d] '%s': chain array too large\n"),
+ idx, section_name (ebl, idx));
+
+ maxidx = symsize;
+ }
+
+ size_t cnt;
+ for (cnt = 2; cnt < 2 + nbucket; ++cnt)
+ if (((Elf32_Word *) data->d_buf)[cnt] >= maxidx)
+ ERROR (gettext ("\
+section [%2d] '%s': hash bucket reference %zu out of bounds\n"),
+ idx, section_name (ebl, idx), cnt - 2);
+
+ for (; cnt < 2 + nbucket + nchain; ++cnt)
+ if (((Elf32_Word *) data->d_buf)[cnt] >= maxidx)
+ ERROR (gettext ("\
+section [%2d] '%s': hash chain reference %zu out of bounds\n"),
+ idx, section_name (ebl, idx), cnt - 2 - nbucket);
+}
+
+
+static void
+check_sysv_hash64 (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
+ GElf_Shdr *symshdr)
+{
+ Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
+ Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
+
+ if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize)
+ ERROR (gettext ("\
+section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"),
+ idx, section_name (ebl, idx), (long int) shdr->sh_size,
+ (long int) ((2 + nbucket + nchain) * shdr->sh_entsize));
+
+ size_t maxidx = nchain;
+
+ if (symshdr != NULL)
+ {
+ size_t symsize = symshdr->sh_size / symshdr->sh_entsize;
+
+ if (nchain > symshdr->sh_size / symshdr->sh_entsize)
+ ERROR (gettext ("section [%2d] '%s': chain array too large\n"),
+ idx, section_name (ebl, idx));
+
+ maxidx = symsize;
+ }
+
+ size_t cnt;
+ for (cnt = 2; cnt < 2 + nbucket; ++cnt)
+ if (((Elf64_Xword *) data->d_buf)[cnt] >= maxidx)
+ ERROR (gettext ("\
+section [%2d] '%s': hash bucket reference %zu out of bounds\n"),
+ idx, section_name (ebl, idx), cnt - 2);
+
+ for (; cnt < 2 + nbucket + nchain; ++cnt)
+ if (((Elf64_Xword *) data->d_buf)[cnt] >= maxidx)
+ ERROR (gettext ("\
+section [%2d] '%s': hash chain reference %zu out of bounds\n"),
+ idx, section_name (ebl, idx), cnt - 2 - nbucket);
+}
+
+
+static void
+check_gnu_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
+ GElf_Shdr *symshdr)
+{
+ Elf32_Word nbuckets = ((Elf32_Word *) data->d_buf)[0];
+ Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
+
+ if (shdr->sh_size < (2 + 2 * nbuckets) * sizeof (Elf32_Word))
+ {
+ ERROR (gettext ("\
+section [%2d] '%s': hash table section is too small (is %ld, expected at least%ld)\n"),
+ idx, section_name (ebl, idx), (long int) shdr->sh_size,
+ (long int) ((2 + 2 * nbuckets) * sizeof (Elf32_Word)));
+ return;
+ }
+
+ size_t maxidx = shdr->sh_size / sizeof (Elf32_Word) - (2 + 2 * nbuckets);
+
+ if (symshdr != NULL)
+ maxidx = MIN (maxidx, symshdr->sh_size / symshdr->sh_entsize);
+
+ /* We need the symbol section data. */
+ Elf_Data *symdata = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link), NULL);
+
+ size_t cnt;
+ for (cnt = 2; cnt < 2 + 2 * nbuckets; cnt += 2)
+ {
+ Elf32_Word bitset = ((Elf32_Word *) data->d_buf)[cnt];
+ Elf32_Word symidx = ((Elf32_Word *) data->d_buf)[cnt + 1];
+
+ if (symidx == 0)
+ {
+ /* Nothing in here. No bit in the bitset should be set either. */
+ if (bitset != 0)
+ ERROR (gettext ("\
+section [%2d] '%s': hash chain for bucket %zu empty but bitset is not\n"),
+ idx, section_name (ebl, idx), cnt / 2 - 1);
+
+ continue;
+ }
+
+ if (symidx < symbias)
+ {
+ ERROR (gettext ("\
+section [%2d] '%s': hash chain for bucket %zu lower than symbol index bias\n"),
+ idx, section_name (ebl, idx), cnt / 2 - 1);
+ continue;
+ }
+
+ Elf32_Word collected_bitset = 0;
+ while (symidx - symbias < maxidx)
+ {
+ Elf32_Word chainhash = ((Elf32_Word *) data->d_buf)[2 + 2 * nbuckets
+ + symidx
+ - symbias];
+
+ if (symdata != NULL)
+ {
+ /* Check that the referenced symbol is not undefined. */
+ GElf_Sym sym_mem;
+ GElf_Sym *sym = gelf_getsym (symdata, symidx, &sym_mem);
+ if (sym != NULL && sym->st_shndx == SHN_UNDEF)
+ ERROR (gettext ("\
+section [%2d] '%s': symbol %u referenced in chain for bucket %zu is undefined\n"),
+ idx, section_name (ebl, idx), symidx, cnt / 2 - 1);
+
+ const char *symname = elf_strptr (ebl->elf, symshdr->sh_link,
+ sym->st_name);
+ if (symname != NULL)
+ {
+ Elf32_Word hval = elf_gnu_hash (symname);
+ if ((hval & ~1u) != (chainhash & ~1u))
+ ERROR (gettext ("\
+section [%2d] '%s': hash value for symbol %u in chain for bucket %zu wrong\n"),
+ idx, section_name (ebl, idx), symidx, cnt / 2 - 1);
+ }
+ }
+
+ collected_bitset |= 1 << ((chainhash >> 5) & 31);
+
+ if ((chainhash & 1) != 0)
+ break;
+
+ ++symidx;
+ }
+
+ if (symidx - symbias >= maxidx)
+ ERROR (gettext ("\
+section [%2d] '%s': hash chain for bucket %zu out of bounds\n"),
+ idx, section_name (ebl, idx), cnt / 2 - 1);
+ else if (symshdr != NULL
+ && symidx > symshdr->sh_size / symshdr->sh_entsize)
+ ERROR (gettext ("\
+section [%2d] '%s': symbol reference in chain for bucket %zu out of bounds\n"),
+ idx, section_name (ebl, idx), cnt / 2 - 1);
+
+ if (bitset != collected_bitset)
+ ERROR (gettext ("\
+section [%2d] '%s': bitset for bucket %zu does not match chain entries: computed %#x, reported %#x\n"),
+ idx, section_name (ebl, idx), cnt / 2 - 1,
+ collected_bitset, bitset);
+ }
+}
+
+
+static void
+check_hash (int tag, Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
{
if (ehdr->e_type == ET_REL)
{
@@ -1744,9 +2023,11 @@ section [%2d] '%s': relocatable files cannot have hash tables\n"),
section [%2d] '%s': hash table not for dynamic symbol table\n"),
idx, section_name (ebl, idx));
- if (shdr->sh_entsize != sizeof (Elf32_Word))
+ if (shdr->sh_entsize != (tag == SHT_GNU_HASH
+ ? sizeof (Elf32_Word)
+ : (size_t) ebl_sysvhash_entrysize (ebl)))
ERROR (gettext ("\
-section [%2d] '%s': entry size does not match Elf32_Word\n"),
+section [%2d] '%s': hash table entry size incorrect\n"),
idx, section_name (ebl, idx));
if ((shdr->sh_flags & SHF_ALLOC) == 0)
@@ -1756,40 +2037,26 @@ section [%2d] '%s': entry size does not match Elf32_Word\n"),
if (shdr->sh_size < 2 * shdr->sh_entsize)
{
ERROR (gettext ("\
-section [%2d] '%s': hash table has not even room for nbucket and nchain\n"),
+section [%2d] '%s': hash table has not even room for initial two administrative entries\n"),
idx, section_name (ebl, idx));
return;
}
- Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
- Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
-
- if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize)
- ERROR (gettext ("\
-section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"),
- idx, section_name (ebl, idx), (long int) shdr->sh_size,
- (long int) ((2 + nbucket + nchain) * shdr->sh_entsize));
-
- if (symshdr != NULL)
+ switch (tag)
{
- size_t symsize = symshdr->sh_size / symshdr->sh_entsize;
- size_t cnt;
-
- if (nchain < symshdr->sh_size / symshdr->sh_entsize)
- ERROR (gettext ("section [%2d] '%s': chain array not large enough\n"),
- idx, section_name (ebl, idx));
+ case SHT_HASH:
+ if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
+ check_sysv_hash64 (ebl, shdr, data, idx, symshdr);
+ else
+ check_sysv_hash (ebl, shdr, data, idx, symshdr);
+ break;
- for (cnt = 2; cnt < 2 + nbucket; ++cnt)
- if (((Elf32_Word *) data->d_buf)[cnt] >= symsize)
- ERROR (gettext ("\
-section [%2d] '%s': hash bucket reference %zu out of bounds\n"),
- idx, section_name (ebl, idx), cnt - 2);
+ case SHT_GNU_HASH:
+ check_gnu_hash (ebl, shdr, data, idx, symshdr);
+ break;
- for (; cnt < 2 + nbucket + nchain; ++cnt)
- if (((Elf32_Word *) data->d_buf)[cnt] >= symsize)
- ERROR (gettext ("\
-section [%2d] '%s': hash chain reference %zu out of bounds\n"),
- idx, section_name (ebl, idx), cnt - 2 - nbucket);
+ default:
+ assert (! "should not happen");
}
}
@@ -2178,7 +2445,7 @@ section [%2d] '%s': symbol %d: local symbol with version\n"),
index we need for this symbol. */
struct version_namelist *runp = version_namelist;
while (runp != NULL)
- if (runp->ndx == *versym)
+ if (runp->ndx == (*versym & 0x7fff))
break;
else
runp = runp->next;
@@ -2945,7 +3212,8 @@ section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"),
break;
case SHT_HASH:
- check_hash (ebl, ehdr, shdr, cnt);
+ case SHT_GNU_HASH:
+ check_hash (shdr->sh_type, ebl, ehdr, shdr, cnt);
break;
case SHT_NULL:
diff --git a/src/i386_ld.c b/src/i386_ld.c
index a0c77dbe..c79804cd 100644
--- a/src/i386_ld.c
+++ b/src/i386_ld.c
@@ -72,7 +72,7 @@ elf_i386_relocate_section (struct ld_state *statep __attribute__ ((unused)),
Elf_Data *data;
/* Iterate over all the input sections. Appropriate data buffers in the
- output sections were already created. I get them iteratively, too. */
+ output sections were already created. */
runp = firstp;
data = NULL;
do
@@ -149,8 +149,8 @@ elf_i386_relocate_section (struct ld_state *statep __attribute__ ((unused)),
assert (xndx < SHN_LORESERVE || xndx > SHN_HIRESERVE);
/* We fortunately don't have to do much. The relocations
- mostly get only updates of the offset. Only is a
- relocation referred to a section do we have to do
+ mostly get only updates of the offset. Only for a
+ relocation referring to a section do we have to do
something. In this case the reference to the sections
has no direct equivalent since the part the input section
contributes need not start at the same offset as in the
@@ -159,15 +159,13 @@ elf_i386_relocate_section (struct ld_state *statep __attribute__ ((unused)),
itself. */
if (XELF_ST_TYPE (sym->st_info) == STT_SECTION)
{
- Elf32_Word toadd;
-
- /* We expect here on R_386_32 relocations. */
+ /* We expect here only R_386_32 relocations. */
assert (XELF_R_TYPE (rel->r_info) == R_386_32);
/* Avoid writing to the section memory if this is
effectively a no-op since it might save a
copy-on-write operation. */
- toadd = file->scninfo[xndx].offset;
+ Elf32_Word toadd = file->scninfo[xndx].offset;
if (toadd != 0)
add_4ubyte_unaligned (reltgtdata->d_buf + rel->r_offset,
toadd);
@@ -527,13 +525,15 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
/* Symbols in COMDAT group sections which are discarded do
not have to be relocated. */
- if (unlikely (scninfo->fileinfo->symref[r_sym] == NULL))
+ if (r_sym >= scninfo->fileinfo->nlocalsymbols
+ && unlikely (scninfo->fileinfo->symref[r_sym] == NULL))
continue;
switch (XELF_R_TYPE (rel->r_info))
{
case R_386_GOT32:
- if (! scninfo->fileinfo->symref[r_sym]->defined)
+ if (! scninfo->fileinfo->symref[r_sym]->defined
+ || scninfo->fileinfo->symref[r_sym]->in_dso)
relsize += sizeof (Elf32_Rel);
/* This relocation is not emitted in the output file but
@@ -556,6 +556,8 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
if (statep->file_type == dso_file_type)
{
relsize += sizeof (Elf32_Rel);
+ // XXX Do we have to check whether the target
+ // XXX section is read-only first?
statep->dt_flags |= DF_TEXTREL;
}
else
@@ -575,10 +577,9 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
}
}
else if (statep->file_type == dso_file_type
- && r_sym >= SCNINFO_SHDR (scninfo->fileinfo->scninfo[shdr->sh_link].shdr).sh_info
- && scninfo->fileinfo->symref[r_sym]->outdynsymidx != 0
&& XELF_R_TYPE (rel->r_info) == R_386_32)
relsize += sizeof (Elf32_Rel);
+
break;
case R_386_PLT32:
@@ -702,8 +703,7 @@ elf_i386_create_relocations (struct ld_state *statep,
/* Cache the access to the symbol table data. */
Elf_Data *symdata = elf_getdata (scninfo[rshdr->sh_link].scn, NULL);
- int cnt;
- for (cnt = 0; cnt < nrels; ++cnt)
+ for (int cnt = 0; cnt < nrels; ++cnt)
{
XElf_Rel_vardef (rel);
XElf_Rel *rel2;
@@ -812,8 +812,7 @@ elf_i386_create_relocations (struct ld_state *statep,
}
}
else if (statep->file_type == dso_file_type
- && idx >= SCNINFO_SHDR (scninfo[rshdr->sh_link].shdr).sh_info
- && symref[idx]->outdynsymidx != 0)
+ && XELF_R_TYPE (rel->r_info) == R_386_32)
{
#if NATIVE_ELF != 0
xelf_getrel_ptr (reldyndata, nreldyn, rel2);
@@ -821,8 +820,15 @@ elf_i386_create_relocations (struct ld_state *statep,
rel2 = &rel_mem;
#endif
rel2->r_offset = value;
- rel2->r_info
- = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_32);
+
+ /* For symbols we do not export we generate a relative
+ relocation. */
+ if (idx < SCNINFO_SHDR (scninfo[rshdr->sh_link].shdr).sh_info
+ || symref[idx]->outdynsymidx == 0)
+ rel2->r_info = XELF_R_INFO (0, R_386_RELATIVE);
+ else
+ rel2->r_info
+ = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_32);
(void) xelf_update_rel (reldyndata, nreldyn, rel2);
++nreldyn;
diff --git a/src/ld.c b/src/ld.c
index 5c20f475..61627e58 100644
--- a/src/ld.c
+++ b/src/ld.c
@@ -1519,6 +1519,8 @@ create_special_section_symbol (struct symbol **symp, const char *name)
abort ();
(*symp)->defined = 1;
+ (*symp)->local = 1;
+ (*symp)->hidden = 1;
(*symp)->type = STT_OBJECT;
++ld_state.nsymtab;
diff --git a/src/ld.h b/src/ld.h
index bdabee44..59633e65 100644
--- a/src/ld.h
+++ b/src/ld.h
@@ -446,6 +446,8 @@ struct symbol
unsigned int weak:1;
unsigned int added:1;
unsigned int merged:1;
+ unsigned int local:1;
+ unsigned int hidden:1;
/* Nonzero if the symbol is on the from_dso list. */
unsigned int on_dsolist:1;
/* Nonzero if symbol needs copy relocation, reset when the
@@ -961,7 +963,7 @@ struct ld_state
/* Execuatable stack selection. */
enum execstack
{
- execstack_false = 0,
+ execstack_false = 0,
execstack_true,
execstack_false_force
} execstack;
diff --git a/src/ldgeneric.c b/src/ldgeneric.c
index 47015b16..d282a1d8 100644
--- a/src/ldgeneric.c
+++ b/src/ldgeneric.c
@@ -1008,7 +1008,7 @@ add_section (struct usedfiles *fileinfo, struct scninfo *scninfo)
= find_section_group (runp->fileinfo,
elf_ndxscn (runp->scn),
&grpscndata);
-
+
if (strcmp (grpscn->symbols->name,
grpscn2->symbols->name) == 0)
{
@@ -1436,9 +1436,9 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
_GLOBAL_OFFSET_TABLE_, _DYNAMIC. */
// XXX This loop is hot and the following tests hardly ever match.
// XXX Maybe move the tests somewhere they are executed less often.
- if (((unlikely (hval == 165832675)
+ if (((unlikely (hval == 165832675ul)
&& strcmp (search.name, "_DYNAMIC") == 0)
- || (unlikely (hval == 102264335)
+ || (unlikely (hval == 102264335ul)
&& strcmp (search.name, "_GLOBAL_OFFSET_TABLE_") == 0))
&& sym->st_shndx != SHN_UNDEF
/* If somebody defines such a variable in a relocatable we
@@ -1451,7 +1451,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
struct symbol *newp;
if (likely (oldp == NULL))
{
- /* No symbol of this name know. Add it. */
+ /* No symbol of this name known. Add it. */
newp = (struct symbol *) obstack_alloc (&ld_state.smem,
sizeof (*newp));
newp->name = search.name;
@@ -1467,6 +1467,8 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
newp->weak = XELF_ST_BIND (sym->st_info) == STB_WEAK;
newp->added = 0;
newp->merged = 0;
+ newp->local = 0;
+ newp->hidden = 0;
newp->need_copy = 0;
newp->on_dsolist = 0;
newp->in_dso = secttype == SHT_DYNSYM;
@@ -1932,6 +1934,18 @@ file_process2 (struct usedfiles *fileinfo)
return 1;
}
+ /* Make sure the file type matches the backend. */
+ if (FILEINFO_EHDR (fileinfo->ehdr).e_machine
+ != ebl_get_elfmachine (ld_state.ebl))
+ {
+ fprintf (stderr, gettext ("\
+%s: input file incompatible with ELF machine type %s\n"),
+ fileinfo->rfname,
+ ebl_backend_name (ld_state.ebl));
+ fileinfo->status = closed;
+ return 1;
+ }
+
/* Determine the section header string table section index. */
if (unlikely (elf_getshstrndx (fileinfo->elf, &fileinfo->shstrndx)
< 0))
@@ -2535,7 +2549,7 @@ ld_generic_open_outfile (struct ld_state *statep, int machine, int klass,
{
strcpy (mempcpy (tempfname, ld_state.outfname, outfname_len), ".XXXXXX");
- /* The useof mktemp() here is fine. We do not want to use
+ /* The use of mktemp() here is fine. We do not want to use
mkstemp() since then the umask isn't used. And the output
file will have these permissions anyhow. Any intruder could
change the file later if it would be possible now. */
@@ -3242,7 +3256,7 @@ reduce_symbol_p (XElf_Sym *sym, struct Ebl_Strent *strent)
{
search.id = strndupa (str, version - str);
if (*++version == VER_CHR)
- /* Skip the second '@' signalling a default definition. */
+ /* Skip the second '@' signaling a default definition. */
++version;
}
else
@@ -3560,9 +3574,9 @@ fillin_special_symbol (struct symbol *symst, size_t scnidx, size_t nsym,
/* The name offset will be filled in later. */
sym->st_name = 0;
/* Traditionally: globally visible. */
- sym->st_info = XELF_ST_INFO (STB_GLOBAL, symst->type);
- /* No special visibility or so. */
- sym->st_other = 0;
+ sym->st_info = XELF_ST_INFO (symst->local ? STB_LOCAL : STB_GLOBAL,
+ symst->type);
+ sym->st_other = symst->hidden ? STV_HIDDEN : STV_DEFAULT;
/* Reference to the GOT or dynamic section. Since the GOT and
dynamic section are only created for executables and DSOs it
cannot be that the section index is too large. */
@@ -3719,7 +3733,7 @@ create_verneed_data (XElf_Off offset, Elf_Data *verneeddata,
For executables (shared or not) we have to create the program header,
additional sections like the .interp, eventually (in addition) create
a dynamic symbol table and a dynamic section. Also the relocations
-have to be processed differently. */
+ have to be processed differently. */
static int
ld_generic_create_outfile (struct ld_state *statep)
{
@@ -4587,6 +4601,7 @@ ld_generic_create_outfile (struct ld_state *statep)
file = ld_state.relfiles->next;
symdata = elf_getdata (elf_getscn (ld_state.outelf, ld_state.symscnidx),
NULL);
+
do
{
size_t maxcnt;
@@ -4645,11 +4660,11 @@ ld_generic_create_outfile (struct ld_state *statep)
continue;
#if NATIVE_ELF != 0
- /* Copy old data. */
- XElf_Sym *sym2 = sym;
- assert (nsym < nsym_allocated);
- xelf_getsym (symdata, nsym, sym);
- *sym = *sym2;
+ /* Copy old data. We create a temporary copy because the
+ symbol might still be discarded. */
+ XElf_Sym sym_mem;
+ sym_mem = *sym;
+ sym = &sym_mem;
#endif
if (sym->st_shndx != SHN_UNDEF
@@ -4754,6 +4769,7 @@ section index too large in dynamic symbol table"));
/* Once we know the name this field will get the correct
offset. For now set it to zero which means no name
associated. */
+ GElf_Word st_name = sym->st_name;
sym->st_name = 0;
/* If we had to merge sections we have a completely new
@@ -4764,30 +4780,50 @@ section index too large in dynamic symbol table"));
/* Create the record in the output sections. */
assert (nsym < nsym_allocated);
- xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 0);
+ xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 1);
/* Add the reference to the symbol record in case we need it.
Find the symbol if this has not happened yet. We do
not need the information for local symbols. */
if (defp == NULL && cnt >= file->nlocalsymbols)
- defp = file->symref[cnt];
-
- /* Ignore symbols in discarded COMDAT group sections. */
- if (defp != NULL)
{
- /* Store the reference to the symbol record. The
- sorting code will have to keep this array in the
- correct order, too. */
- ndxtosym[nsym] = defp;
+ defp = file->symref[cnt];
- /* One more entry finished. */
- if (cnt >= file->nlocalsymbols)
+ if (defp == NULL)
{
- assert (file->symref[cnt]->outsymidx == 0);
- file->symref[cnt]->outsymidx = nsym;
+ /* This is a symbol in a discarded COMDAT section.
+ Find the definition we actually use. */
+ // XXX The question is: do we have to do this here
+ // XXX or can we do it earlier when we discard the
+ // XXX section.
+ struct symbol search;
+ search.name = elf_strptr (file->elf, file->symstridx,
+ st_name);
+ struct symbol *realp
+ = ld_symbol_tab_find (&ld_state.symbol_tab,
+ elf_hash (search.name), &search);
+ if (realp == NULL)
+ // XXX What to do here?
+ error (EXIT_FAILURE, 0,
+ "couldn't find symbol from COMDAT section");
+
+ file->symref[cnt] = realp;
+
+ continue;
}
- file->symindirect[cnt] = nsym++;
}
+
+ /* Store the reference to the symbol record. The sorting
+ code will have to keep this array in the correct order, too. */
+ ndxtosym[nsym] = defp;
+
+ /* One more entry finished. */
+ if (cnt >= file->nlocalsymbols)
+ {
+ assert (file->symref[cnt]->outsymidx == 0);
+ file->symref[cnt]->outsymidx = nsym;
+ }
+ file->symindirect[cnt] = nsym++;
}
}
while ((file = file->next) != ld_state.relfiles->next);
@@ -4795,7 +4831,6 @@ section index too large in dynamic symbol table"));
nothing. */
assert (xndxdata == NULL || need_xndx);
-
/* Create the version related sections. */
if (ld_state.verneedscnidx != 0)
{
@@ -5228,7 +5263,8 @@ section index too large in dynamic symbol table"));
if (XELF_ST_TYPE (sym->st_info) == STT_FILE
|| XELF_ST_VISIBILITY (sym->st_other) == STV_INTERNAL
|| XELF_ST_VISIBILITY (sym->st_other) == STV_HIDDEN
- || (!ndxtosym[cnt]->in_dso && ndxtosym[cnt]->defined))
+ || (!ld_state.export_all_dynamic
+ && !ndxtosym[cnt]->in_dso && ndxtosym[cnt]->defined))
{
symstrent[cnt] = NULL;
continue;
@@ -5251,7 +5287,9 @@ section index too large in dynamic symbol table"));
{
struct symbol *symp = ndxtosym[cnt];
- if (symp->file->verdefdata != NULL)
+ /* Synthetic symbols (i.e., those with no file attached)
+ have no version information. */
+ if (symp->file != NULL && symp->file->verdefdata != NULL)
{
GElf_Versym versym;
diff --git a/src/readelf.c b/src/readelf.c
index 135abe36..9fbc24d6 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -2320,6 +2320,194 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
}
+static void
+print_hash_info (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx,
+ uint_fast32_t maxlength, Elf32_Word nbucket,
+ uint_fast32_t nsyms, uint32_t *lengths)
+{
+ uint32_t *counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t));
+
+ for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
+ ++counts[lengths[cnt]];
+
+ GElf_Shdr glink;
+ printf (ngettext ("\
+\nHistogram for bucket list length in section [%2u] '%s' (total of %d bucket):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
+ "\
+\nHistogram for bucket list length in section [%2u] '%s' (total of %d buckets):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
+ nbucket),
+ (unsigned int) elf_ndxscn (scn),
+ elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
+ (int) nbucket,
+ gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18,
+ shdr->sh_addr,
+ shdr->sh_offset,
+ (unsigned int) shdr->sh_link,
+ elf_strptr (ebl->elf, shstrndx,
+ gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
+ &glink)->sh_name));
+
+ if (nbucket > 0)
+ {
+ uint64_t success = 0;
+
+ fputs_unlocked (gettext ("\
+ Length Number % of total Coverage\n"), stdout);
+ printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"),
+ counts[0], (counts[0] * 100.0) / nbucket);
+
+ uint64_t nzero_counts = 0;
+ for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
+ {
+ nzero_counts += counts[cnt] * cnt;
+ printf (gettext ("\
+%7d %6" PRIu32 " %5.1f%% %5.1f%%\n"),
+ (int) cnt, counts[cnt], (counts[cnt] * 100.0) / nbucket,
+ (nzero_counts * 100.0) / nsyms);
+ }
+
+ Elf32_Word acc = 0;
+ for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
+ {
+ acc += cnt;
+ success += counts[cnt] * acc;
+ }
+
+ printf (gettext ("\
+ Average number of tests: successful lookup: %f\n\
+ unsuccessful lookup: %f\n"),
+ (double) success / (double) nzero_counts,
+ (double) nzero_counts / (double) nbucket);
+ }
+
+ free (counts);
+}
+
+
+/* This function handles the traditional System V-style hash table format. */
+static void
+handle_sysv_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
+{
+ Elf_Data *data = elf_getdata (scn, NULL);
+ if (data == NULL)
+ {
+ error (0, 0, gettext ("cannot get data for section %d: %s"),
+ (int) elf_ndxscn (scn), elf_errmsg (-1));
+ return;
+ }
+
+ Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
+ Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
+ Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2];
+ Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + nbucket];
+
+ uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
+
+ uint_fast32_t maxlength = 0;
+ uint_fast32_t nsyms = 0;
+ for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
+ {
+ Elf32_Word inner = bucket[cnt];
+ while (inner > 0 && inner < nchain)
+ {
+ ++nsyms;
+ if (maxlength < ++lengths[cnt])
+ ++maxlength;
+
+ inner = chain[inner];
+ }
+ }
+
+ print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
+ lengths);
+
+ free (lengths);
+}
+
+
+/* This function handles the incorrect, System V-style hash table
+ format some 64-bit architectures use. */
+static void
+handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
+{
+ Elf_Data *data = elf_getdata (scn, NULL);
+ if (data == NULL)
+ {
+ error (0, 0, gettext ("cannot get data for section %d: %s"),
+ (int) elf_ndxscn (scn), elf_errmsg (-1));
+ return;
+ }
+
+ Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
+ Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
+ Elf64_Xword *bucket = &((Elf64_Xword *) data->d_buf)[2];
+ Elf64_Xword *chain = &((Elf64_Xword *) data->d_buf)[2 + nbucket];
+
+ uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
+
+ uint_fast32_t maxlength = 0;
+ uint_fast32_t nsyms = 0;
+ for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt)
+ {
+ Elf64_Xword inner = bucket[cnt];
+ while (inner > 0 && inner < nchain)
+ {
+ ++nsyms;
+ if (maxlength < ++lengths[cnt])
+ ++maxlength;
+
+ inner = chain[inner];
+ }
+ }
+
+ print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
+ lengths);
+
+ free (lengths);
+}
+
+
+/* This function handles the GNU-style hash table format. */
+static void
+handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
+{
+ Elf_Data *data = elf_getdata (scn, NULL);
+ if (data == NULL)
+ {
+ error (0, 0, gettext ("cannot get data for section %d: %s"),
+ (int) elf_ndxscn (scn), elf_errmsg (-1));
+ return;
+ }
+
+ Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
+ Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
+ Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2];
+ Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + 2 * nbucket];
+
+ uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
+
+ uint_fast32_t maxlength = 0;
+ uint_fast32_t nsyms = 0;
+ for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
+ if (bucket[2 * cnt + 1] != 0)
+ {
+ Elf32_Word inner = bucket[2 * cnt + 1] - symbias;
+ do
+ {
+ ++nsyms;
+ if (maxlength < ++lengths[cnt])
+ ++maxlength;
+ }
+ while ((chain[inner++] & 1) == 0);
+ }
+
+ print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
+ lengths);
+
+ free (lengths);
+}
+
+
/* Find the symbol table(s). For this we have to search through the
section table. */
static void
@@ -2338,100 +2526,17 @@ handle_hash (Ebl *ebl)
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- if (shdr != NULL && shdr->sh_type == SHT_HASH)
+ if (shdr != NULL)
{
- Elf_Data *data = elf_getdata (scn, NULL);
- if (data == NULL)
- {
- error (0, 0, gettext ("cannot get data for section %d: %s"),
- (int) elf_ndxscn (scn), elf_errmsg (-1));
- continue;
- }
-
- Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
- Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
- Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2];
- Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + nbucket];
-
- GElf_Shdr glink;
- printf (ngettext ("\
-\nHistogram for bucket list length in section [%2u] '%s' (total of %d bucket):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
- "\
-\nHistogram for bucket list length in section [%2u] '%s' (total of %d buckets):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n",
- nbucket),
- (unsigned int) elf_ndxscn (scn),
- elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
- (int) nbucket,
- gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18,
- shdr->sh_addr,
- shdr->sh_offset,
- (unsigned int) shdr->sh_link,
- elf_strptr (ebl->elf, shstrndx,
- gelf_getshdr (elf_getscn (ebl->elf,
- shdr->sh_link),
- &glink)->sh_name));
-
- uint32_t *lengths = (uint32_t *) xcalloc (nbucket,
- sizeof (uint32_t));
-
- Elf32_Word maxlength = 0;
- Elf32_Word nsyms = 0;
- for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
- if (bucket[cnt] != 0)
- {
- Elf32_Word inner = bucket[cnt];
- while (inner > 0 && inner < nchain)
- {
- ++nsyms;
- if (maxlength < ++lengths[cnt])
- ++maxlength;
-
- inner = chain[inner];
- }
- }
-
- uint32_t *counts = (uint32_t *) xcalloc (maxlength + 1,
- sizeof (uint32_t));
-
- for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
- ++counts[lengths[cnt]];
-
- if (nbucket > 0)
+ if (shdr->sh_type == SHT_HASH)
{
- uint64_t success = 0;
-
- fputs_unlocked (gettext ("\
- Length Number % of total Coverage\n"), stdout);
- printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"),
- counts[0], (counts[0] * 100.0) / nbucket);
-
- uint64_t nzero_counts = 0;
- for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
- {
- nzero_counts += counts[cnt] * cnt;
- printf (gettext ("\
-%7d %6" PRIu32 " %5.1f%% %5.1f%%\n"),
- (int) cnt,
- counts[cnt], (counts[cnt] * 100.0) / nbucket,
- (nzero_counts * 100.0) / nsyms);
- }
-
- Elf32_Word acc = 0;
- for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
- {
- acc += cnt;
- success += counts[cnt] * acc;
- }
-
- printf (gettext ("\
- Average number of tests: successful lookup: %f\n\
- unsuccessful lookup: %f\n"),
- (double) success / (double) nzero_counts,
- (double) nzero_counts / (double) nbucket);
+ if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
+ handle_sysv_hash64 (ebl, scn, shdr, shstrndx);
+ else
+ handle_sysv_hash (ebl, scn, shdr, shstrndx);
}
-
- free (counts);
- free (lengths);
+ else if (shdr->sh_type == SHT_GNU_HASH)
+ handle_gnu_hash (ebl, scn, shdr, shstrndx);
}
}
}