]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Updated support for new hash table format.
authorUlrich Drepper <drepper@redhat.com>
Thu, 6 Jul 2006 23:58:40 +0000 (23:58 +0000)
committerUlrich Drepper <drepper@redhat.com>
Thu, 6 Jul 2006 23:58:40 +0000 (23:58 +0000)
Fix handling of discarded COMDAT symbols in ld.

17 files changed:
NEWS
libebl/ChangeLog
libebl/ebldynamictagcheck.c
libebl/ebldynamictagname.c
libebl/eblrelativerelocp.c [new file with mode: 0644]
libebl/eblsectiontypename.c
libebl/eblsysvhashentrysize.c [new file with mode: 0644]
libelf/ChangeLog
libelf/Makefile.am
libelf/elf_gnu_hash.c [new file with mode: 0644]
libelf/libelf.h
libelf/libelf.map
src/ChangeLog
src/elflint.c
src/i386_ld.c
src/ldgeneric.c
src/readelf.c

diff --git a/NEWS b/NEWS
index d2071d46e14bd13df85d95c3005c4ebbb44d7c09..2edfbb30bcc9dd2e011db4ca5ed53028bcf9e50b 100644 (file)
--- 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
 
index 23a215359762364ae60b7c3c3b4eb3b1428554e3..c4f5c65ac609b33b7a0dfe8c5cc86f2828bba7ce 100644 (file)
@@ -1,3 +1,9 @@
+2006-07-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * ebldynamictagname.c: Add support for DT_GNU_HASH.
+       * ebldynamictagcheck.c: Likewise.
+       * eblsectiontypename.c: Add support for SHT_GNU_HASH.
+
 2006-07-05  Ulrich Drepper  <drepper@redhat.com>
 
        * Makefile.am (gen_SOURCES): Add eblsysvhashentrysize.c.
index b082e83d9f6739425d4239da76557c4257ac0ad0..1953a9c05161fb8aa351337866c2b93574486543 100644 (file)
@@ -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 <drepper@redhat.com>, 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
index 1267758536aa6e56ac5bada3d9489fffe0a7633b..d9aa7df06fe5153298287359f139cfb3e72a555a 100644 (file)
@@ -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 <drepper@redhat.com>, 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 (file)
index 0000000..8ea97b8
--- /dev/null
@@ -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 <drepper@redhat.com>, 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
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libeblP.h>
+
+
+bool
+ebl_relative_reloc_p (ebl, reloc)
+     Ebl *ebl;
+     int reloc;
+{
+  return ebl->relative_reloc_p (reloc);
+}
index 18cbd7678d557690add83aa4305326a5cadc5524..b62c37b39cf6843bfd95c1025f758284ed96702d 100644 (file)
@@ -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 <drepper@redhat.com>, 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 (file)
index 0000000..341979c
--- /dev/null
@@ -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 <drepper@redhat.com>, 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
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libeblP.h>
+
+
+int
+ebl_sysvhash_entrysize (ebl)
+     Ebl *ebl;
+{
+  return ebl->sysvhash_entrysize;
+}
index d42bf18bf19256353771c767bdca7bf21dd3fcc4..db4108d3bb6a1de57817727dcc616691ceb29d10 100644 (file)
@@ -1,3 +1,10 @@
+2006-07-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * 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  <drepper@redhat.com>
 
        * elf32_updatefile.c (updatemmap): Preserve section content if
index 51965ceeb3a0d1da3fe34fcf502e3357c4f094c4..fb177d041ce1059d7a708f2ef8e069f054c4c807 100644 (file)
@@ -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 (file)
index 0000000..efaee43
--- /dev/null
@@ -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 <drepper@redhat.com>, 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
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libelfP.h>
+
+/* Get the implementation.  */
+#include <dl-hash.h>
+
+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;
+}
index 7d7d39e80bd92997f7f342f48e7ccc73f2b8b7bf..2727184717af8ba1984d556636b00be3bce62de5 100644 (file)
@@ -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);
index b2a65e8402dd6ffa38c8e1c19148693c4e558e30..9549c3176c220cee7840a0af21fb2d3d4485ae03 100644 (file)
@@ -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;
index b75a7662210caf2857c72a56ded3442a1d893314..1c153b003df319e4c8c2d9a088abc6b89eb6d4b3 100644 (file)
@@ -1,3 +1,11 @@
+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
index a3d7d5cb3e86d6bc789797509f2fef5dbff4697f..a679acc4b657054269b81491c00ebf9eab53baf7 100644 (file)
@@ -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;
index 60e45f3f3361de48e54ada8a27407903d5113213..c79804cda4c2decc1951f56d02f008829c2e9af0 100644 (file)
@@ -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
index 6913d67ecd7fa708c8ddc4f2f9bd8c4cbafcf268..d282a1d8f3fae8f7a57d99f82eb2103c4be05962 100644 (file)
@@ -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);
index b4b6a5aaa3e7fe4ac9bf4b57d640e988febb8e24..9fbc24d6f8476a0724902a95f9914c758cb756c1 100644 (file)
@@ -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;