From: Ulrich Drepper Date: Thu, 6 Jul 2006 23:58:40 +0000 (+0000) Subject: Updated support for new hash table format. X-Git-Tag: elfutils-0.121~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1b0714c81de473ad3a5ca88bd1c593d93a6ebcdd;p=thirdparty%2Felfutils.git Updated support for new hash table format. Fix handling of discarded COMDAT symbols in ld. --- diff --git a/NEWS b/NEWS index d2071d46e..2edfbb30b 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ libebl:add function to test for relative relocation elflint: fix and extend DT_RELCOUNT/DT_RELACOUNT checks elflint, readelf: add support for DT_GNU_HASH +libelf: add elf_gnu_hash elflint, readelf: add support for 64-bit SysV-style hash tables diff --git a/libebl/ChangeLog b/libebl/ChangeLog index 23a215359..c4f5c65ac 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,9 @@ +2006-07-06 Ulrich Drepper + + * ebldynamictagname.c: Add support for DT_GNU_HASH. + * ebldynamictagcheck.c: Likewise. + * eblsectiontypename.c: Add support for SHT_GNU_HASH. + 2006-07-05 Ulrich Drepper * Makefile.am (gen_SOURCES): Add eblsysvhashentrysize.c. diff --git a/libebl/ebldynamictagcheck.c b/libebl/ebldynamictagcheck.c index b082e83d9..1953a9c05 100644 --- a/libebl/ebldynamictagcheck.c +++ b/libebl/ebldynamictagcheck.c @@ -1,5 +1,5 @@ /* Check dynamic tag. - Copyright (C) 2001, 2002 Red Hat, Inc. + Copyright (C) 2001, 2002, 2006 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2001. @@ -66,7 +66,7 @@ ebl_dynamic_tag_check (ebl, tag) if (!res && ((tag >= 0 && tag < DT_NUM) || (tag >= DT_GNU_PRELINKED && tag <= DT_SYMINENT) - || (tag >= DT_GNU_CONFLICT && tag <= DT_SYMINFO) + || (tag >= DT_GNU_HASH && tag <= DT_SYMINFO) || tag == DT_VERSYM || (tag >= DT_RELACOUNT && tag <= DT_VERNEEDNUM) || tag == DT_AUXILIARY diff --git a/libebl/ebldynamictagname.c b/libebl/ebldynamictagname.c index 126775853..d9aa7df06 100644 --- a/libebl/ebldynamictagname.c +++ b/libebl/ebldynamictagname.c @@ -1,5 +1,5 @@ /* Return dynamic tag name. - Copyright (C) 2001, 2002 Red Hat, Inc. + Copyright (C) 2001, 2002, 2006 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2001. @@ -96,15 +96,16 @@ ebl_dynamic_tag_name (ebl, tag, buf, len) res = valrntags[tag - DT_GNU_PRELINKED]; } - else if (tag >= DT_GNU_CONFLICT && tag <= DT_SYMINFO) + else if (tag >= DT_GNU_HASH && tag <= DT_SYMINFO) { static const char *addrrntags[] = { + "GNU_HASH", "TLSDESC_PLT", "TLSDESC_DOT", "GNU_CONFLICT", "GNU_LIBLIST", "CONFIG", "DEPAUDIT", "AUDIT", "PLTPAD", "MOVETAB", "SYMINFO" }; - res = addrrntags[tag - DT_GNU_CONFLICT]; + res = addrrntags[tag - DT_GNU_HASH]; } else if (tag >= DT_RELACOUNT && tag <= DT_VERNEEDNUM) { diff --git a/libebl/eblrelativerelocp.c b/libebl/eblrelativerelocp.c new file mode 100644 index 000000000..8ea97b880 --- /dev/null +++ b/libebl/eblrelativerelocp.c @@ -0,0 +1,64 @@ +/* Check whether given relocation is a relocation relocation. + Copyright (C) 2006 Red Hat, Inc. + This file is part of Red Hat elfutils. + Written by Ulrich Drepper , 2006. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +bool +ebl_relative_reloc_p (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl->relative_reloc_p (reloc); +} diff --git a/libebl/eblsectiontypename.c b/libebl/eblsectiontypename.c index 18cbd7678..b62c37b39 100644 --- a/libebl/eblsectiontypename.c +++ b/libebl/eblsectiontypename.c @@ -1,5 +1,5 @@ /* Return section type name. - Copyright (C) 2001, 2002 Red Hat, Inc. + Copyright (C) 2001, 2002, 2006 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2001. @@ -116,6 +116,8 @@ ebl_section_type_name (ebl, section, buf, len) res = "CHECKSUM"; else if (section == SHT_GNU_LIBLIST) res = "GNU_LIBLIST"; + else if (section == SHT_GNU_HASH) + res = "GNU_HASH"; /* Handle OS-specific section names. */ else { diff --git a/libebl/eblsysvhashentrysize.c b/libebl/eblsysvhashentrysize.c new file mode 100644 index 000000000..341979c18 --- /dev/null +++ b/libebl/eblsysvhashentrysize.c @@ -0,0 +1,63 @@ +/* Return OS ABI name + Copyright (C) 2006 Red Hat, Inc. + This file is part of Red Hat elfutils. + Written by Ulrich Drepper , 2006. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +int +ebl_sysvhash_entrysize (ebl) + Ebl *ebl; +{ + return ebl->sysvhash_entrysize; +} diff --git a/libelf/ChangeLog b/libelf/ChangeLog index d42bf18bf..db4108d3b 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,10 @@ +2006-07-06 Ulrich Drepper + + * elf_gnu_hash.c: New file. + * libelf.h: Declare elf_gnu_hash. + * Makefile.am (libelf_a_SOURCES): Add elf_gnu_hash. + * libelf.map: Add elf_gnu_map for version ELFUTILS_1.2. + 2006-05-28 Ulrich Drepper * elf32_updatefile.c (updatemmap): Preserve section content if diff --git a/libelf/Makefile.am b/libelf/Makefile.am index 51965ceeb..fb177d041 100644 --- a/libelf/Makefile.am +++ b/libelf/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to create Makefile.in ## -## Copyright (C) 1996-2001, 2002, 2003, 2004, 2005 Red Hat, Inc. +## Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. ## This file is part of Red Hat elfutils. ## ## Red Hat elfutils is free software; you can redistribute it and/or modify @@ -96,7 +96,8 @@ libelf_a_SOURCES = elf_version.c elf_hash.c elf_error.c elf_fill.c \ elf_clone.c \ gelf_getlib.c gelf_update_lib.c \ elf32_offscn.c elf64_offscn.c gelf_offscn.c \ - elf_getaroff.c + elf_getaroff.c \ + elf_gnu_hash.c if !MUDFLAP libelf_pic_a_SOURCES = diff --git a/libelf/elf_gnu_hash.c b/libelf/elf_gnu_hash.c new file mode 100644 index 000000000..efaee435d --- /dev/null +++ b/libelf/elf_gnu_hash.c @@ -0,0 +1,68 @@ +/* GNU-style Hash function used in ELF implementations. + Copyright (C) 2006 Red Hat, Inc. + This file is part of Red Hat elfutils. + Contributed by Ulrich Drepper , 2006. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* Get the implementation. */ +#include + +unsigned long int +elf_gnu_hash (string) + const char *string; +{ + uint_fast32_t h = 5381; + for (unsigned char c = *string; c != '\0'; c = *++string) + h = h * 33 + c; + return h & 0xffffffff; +} diff --git a/libelf/libelf.h b/libelf/libelf.h index 7d7d39e80..272718471 100644 --- a/libelf/libelf.h +++ b/libelf/libelf.h @@ -1,5 +1,5 @@ /* Interface for libelf. - Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005 Red Hat, Inc. + Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005, 2006 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -371,6 +371,10 @@ extern void elf_fill (int __fill); extern unsigned long int elf_hash (const char *__string) __attribute__ ((__pure__)); +/* Compute hash value using the GNU-specific hash function. */ +extern unsigned long int elf_gnu_hash (const char *__string) + __attribute__ ((__pure__)); + /* Compute simple checksum from permanent parts of the ELF file. */ extern long int elf32_checksum (Elf *__elf); diff --git a/libelf/libelf.map b/libelf/libelf.map index b2a65e840..9549c3176 100644 --- a/libelf/libelf.map +++ b/libelf/libelf.map @@ -112,3 +112,8 @@ ELFUTILS_1.1.1 { gelf_offscn; elf_getaroff; } ELFUTILS_1.1; + +ELFUTILS_1.2 { + global: + elf_gnu_hash; +} ELFUTILS_1.1.1; diff --git a/src/ChangeLog b/src/ChangeLog index b75a76622..1c153b003 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2006-07-06 Ulrich Drepper + + * 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 * ldgeneric.c (ld_generic_create_outfile): Correctly recognize diff --git a/src/elflint.c b/src/elflint.c index a3d7d5cb3..a679acc4b 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -1895,19 +1895,19 @@ static void check_gnu_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 nbuckets = ((Elf32_Word *) data->d_buf)[0]; Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1]; - if (shdr->sh_size < (2 + nbucket) * shdr->sh_entsize) + 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 + nbucket) * shdr->sh_entsize)); + (long int) ((2 + 2 * nbuckets) * sizeof (Elf32_Word))); return; } - size_t maxidx = shdr->sh_size / sizeof (Elf32_Word) - (2 + nbucket); + size_t maxidx = shdr->sh_size / sizeof (Elf32_Word) - (2 + 2 * nbuckets); if (symshdr != NULL) maxidx = MIN (maxidx, symshdr->sh_size / symshdr->sh_entsize); @@ -1916,38 +1916,82 @@ section [%2d] '%s': hash table section is too small (is %ld, expected at least%l Elf_Data *symdata = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link), NULL); size_t cnt; - for (cnt = 2; cnt < 2 + nbucket; ++cnt) + for (cnt = 2; cnt < 2 + 2 * nbuckets; cnt += 2) { - Elf32_Word chainidx = ((Elf32_Word *) data->d_buf)[cnt]; + Elf32_Word bitset = ((Elf32_Word *) data->d_buf)[cnt]; + Elf32_Word symidx = ((Elf32_Word *) data->d_buf)[cnt + 1]; - if (chainidx == ~0u) - /* Nothing in here. */ - continue; + 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); - while (chainidx < maxidx - && ((((Elf32_Word *) data->d_buf)[2 + nbucket + chainidx] & 1) - == 0)) - ++chainidx; + if ((chainhash & 1) != 0) + break; + + ++symidx; + } - if (chainidx >= maxidx) + 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); + idx, section_name (ebl, idx), cnt / 2 - 1); else if (symshdr != NULL - && symbias + chainidx > symshdr->sh_size / symshdr->sh_entsize) + && 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); - else if (symdata != NULL) - { - /* Check that the referenced symbol is not undefined. */ - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (symdata, symbias + cnt - 2, &sym_mem); - if (sym != NULL && sym->st_shndx == SHN_UNDEF) + idx, section_name (ebl, idx), cnt / 2 - 1); + + if (bitset != collected_bitset) ERROR (gettext ("\ -section [%2d] '%s': symbol reference in chain for bucket %zu is undefined\n"), - idx, section_name (ebl, idx), cnt - 2); - } +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); } } @@ -1979,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) @@ -1991,7 +2037,7 @@ 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; } @@ -2399,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; diff --git a/src/i386_ld.c b/src/i386_ld.c index 60e45f3f3..c79804cda 100644 --- a/src/i386_ld.c +++ b/src/i386_ld.c @@ -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 diff --git a/src/ldgeneric.c b/src/ldgeneric.c index 6913d67ec..d282a1d8f 100644 --- a/src/ldgeneric.c +++ b/src/ldgeneric.c @@ -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; @@ -4767,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 @@ -4783,24 +4786,44 @@ section index too large in dynamic symbol table")); 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 || cnt < file->nlocalsymbols) { - /* 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); diff --git a/src/readelf.c b/src/readelf.c index b4b6a5aaa..9fbc24d6f 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -2480,17 +2480,18 @@ handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx) } 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 + nbucket]; + 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[cnt] != ~0u) + if (bucket[2 * cnt + 1] != 0) { - Elf32_Word inner = bucket[cnt]; + Elf32_Word inner = bucket[2 * cnt + 1] - symbias; do { ++nsyms;