* elf/dl-lookup.c (dl_new_hash): New functions.
authorUlrich Drepper <drepper@redhat.com>
Mon, 10 Jul 2006 21:59:43 +0000 (21:59 +0000)
committerUlrich Drepper <drepper@redhat.com>
Mon, 10 Jul 2006 21:59:43 +0000 (21:59 +0000)
(_dl_lookup_symbol_x): Rename hash to old_hash and don't compute
value here.  Compute new-style hash value.  Pass new hash value
and reference to variable with the old value to do_lookup_x.
(_dl_setup_hash): If DT_GNU_HASH is defined, use it and not
old-style hash table.
(_dl_debug_bindings): Pass new hash value and reference to variable
with the old value to do_lookup_x.
* elf/do-lookup.h (do_lookup_x): Accept additional parameter with
new-style hash value and change old-style hash value parameter to
be a reference.  Reoganize functions to determine whether
new-style hash table is available.  Only fall back on old-style
table.  If old-style hash value is needed, compute it here.
* elf/dynamic-link.h (elf_get_dynamic_info): Relocate DT_GNU_HASH
entry.
* elf/elf.h: Define SHT_GNU_HASH, DT_GNU_HASH, DT_TLSDEC_PLT,
DT_TLSDEC_GOT.  Adjust DT_ADDRNUM.
* include/link.h (struct link_map): Add l_gnu_bitmask_idxbits,
l_gnu_shift, l_gnu_bitmask, l_gnu_buckets and l_gnu_chain_zero.
* Makeconfig: If linker supports --hash-style option add it to all
linker command lines to build DSOs.
* config.make.in: Define have-hash-style.
* configure.in: Test whether linker supports --hash-style option.

* elf/dl-misc.c (_dl_name_match_p): Make MAP parameter const.
* sysdeps/generic/ldsodefs.h: Adjust prototype.

14 files changed:
ChangeLog
Makeconfig
NEWS
config.make.in
configure
configure.in
elf/dl-lookup.c
elf/dl-misc.c
elf/do-lookup.h
elf/dynamic-link.h
elf/elf.h
include/link.h
nptl/pthread_mutex_init.c
sysdeps/generic/ldsodefs.h

index 520062b..7a97b2f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2006-07-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf/dl-lookup.c (dl_new_hash): New functions.
+       (_dl_lookup_symbol_x): Rename hash to old_hash and don't compute
+       value here.  Compute new-style hash value.  Pass new hash value
+       and reference to variable with the old value to do_lookup_x.
+       (_dl_setup_hash): If DT_GNU_HASH is defined, use it and not
+       old-style hash table.
+       (_dl_debug_bindings): Pass new hash value and reference to variable
+       with the old value to do_lookup_x.
+       * elf/do-lookup.h (do_lookup_x): Accept additional parameter with
+       new-style hash value and change old-style hash value parameter to
+       be a reference.  Reoganize functions to determine whether
+       new-style hash table is available.  Only fall back on old-style
+       table.  If old-style hash value is needed, compute it here.
+       * elf/dynamic-link.h (elf_get_dynamic_info): Relocate DT_GNU_HASH
+       entry.
+       * elf/elf.h: Define SHT_GNU_HASH, DT_GNU_HASH, DT_TLSDEC_PLT,
+       DT_TLSDEC_GOT.  Adjust DT_ADDRNUM.
+       * include/link.h (struct link_map): Add l_gnu_bitmask_idxbits,
+       l_gnu_shift, l_gnu_bitmask, l_gnu_buckets and l_gnu_chain_zero.
+       * Makeconfig: If linker supports --hash-style option add it to all
+       linker command lines to build DSOs.
+       * config.make.in: Define have-hash-style.
+       * configure.in: Test whether linker supports --hash-style option.
+
+       * elf/dl-misc.c (_dl_name_match_p): Make MAP parameter const.
+       * sysdeps/generic/ldsodefs.h: Adjust prototype.
+
 2006-06-27  Ulrich Drepper  <drepper@redhat.com>
 
        * elf/dl-load.c (open_path): Fix test to determine whether DSO is
index 87f8ba7..5a1aebc 100644 (file)
@@ -413,11 +413,20 @@ LDFLAGS.so += $(relro-LDFLAGS)
 LDFLAGS-rtld += $(relro-LDFLAGS)
 endif
 
+ifeq (yes,$(have-hash-style))
+# For the time being we unconditionally use 'both'.  At some time we
+# should declare statically linked code as 'out of luck' and compile
+# with --hash-style=gnu only.
+hashstyle-LDFLAGS = -Wl,--hash-style=both
+LDFLAGS.so += $(hashstyle-LDFLAGS)
+LDFLAGS-rtld += $(hashstyle-LDFLAGS)
+endif
+
 # Command for linking programs with the C library.
 ifndef +link
 +link = $(CC) -nostdlib -nostartfiles -o $@ \
              $(sysdep-LDFLAGS) $(config-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
-             $(combreloc-LDFLAGS) $(relro-LDFLAGS) \
+             $(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \
              $(addprefix $(csu-objpfx),$(start-installed-name)) \
              $(+preinit) $(+prector) \
              $(filter-out $(addprefix $(csu-objpfx),start.o \
diff --git a/NEWS b/NEWS
index edc576e..0f73029 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2006-05-24
+GNU C Library NEWS -- history of user-visible changes.  2006-07-10
 Copyright (C) 1992-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -13,7 +13,7 @@ Version 2.5
 * Allow system admin to configure getaddrinfo with the /etc/gai.conf file.
   Implemented by Ulrich Drepper.
 
-* New Linux interfaces: splice, tee, sync_file_range, vmsplace.
+* New Linux interfaces: splice, tee, sync_file_range, vmsplice.
 
 * New iconv module for MIK.  Contributed by Alexander Shopov.
 
@@ -31,6 +31,8 @@ Version 2.5
 * The interfaces introduced in RFC 3542 have been implemented by
   Ulrich Drepper.
 
+* Support for the new ELF hash table format was added by Ulrich Drepper.
+
 \f
 Version 2.4
 
index bc8998c..677da3a 100644 (file)
@@ -65,6 +65,7 @@ have-libcap = @have_libcap@
 have-cc-with-libunwind = @libc_cv_cc_with_libunwind@
 fno-unit-at-a-time = @fno_unit_at_a_time@
 bind-now = @bindnow@
+have-hash-style = @libc_cv_hashstyle@
 
 static-libgcc = @libc_cv_gcc_static_libgcc@
 
index b9c8ee8..d14f89a 100755 (executable)
--- a/configure
+++ b/configure
@@ -313,7 +313,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi bindnow force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os subdirs add_ons add_on_subdirs base_machine submachine sysnames sysdeps_add_ons INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP CXX CXXFLAGS ac_ct_CXX AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF SYSINCLUDES CXX_SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_cc_with_libunwind libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_z_relro libc_cv_Bgroup libc_cv_libgcc_s_suffix libc_cv_as_needed ASFLAGS_config libc_cv_z_combreloc libc_cv_z_execstack libc_cv_fpie fno_unit_at_a_time libc_cv_ssp libc_cv_have_initfini no_whole_archive exceptions LIBGD have_libaudit have_libcap have_selinux EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir libc_cv_forced_unwind use_ldconfig ldd_rewrite_script elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi bindnow force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os subdirs add_ons add_on_subdirs base_machine submachine sysnames sysdeps_add_ons INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP CXX CXXFLAGS ac_ct_CXX AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF SYSINCLUDES CXX_SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_cc_with_libunwind libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_z_relro libc_cv_Bgroup libc_cv_libgcc_s_suffix libc_cv_as_needed ASFLAGS_config libc_cv_z_combreloc libc_cv_z_execstack libc_cv_fpie libc_cv_hashstyle fno_unit_at_a_time libc_cv_ssp libc_cv_have_initfini no_whole_archive exceptions LIBGD have_libaudit have_libcap have_selinux EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir libc_cv_forced_unwind use_ldconfig ldd_rewrite_script elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -5876,6 +5876,33 @@ echo "$as_me:$LINENO: result: $libc_cv_fpie" >&5
 echo "${ECHO_T}$libc_cv_fpie" >&6
 
 
+
+  echo "$as_me:$LINENO: checking for --hash-style option" >&5
+echo $ECHO_N "checking for --hash-style option... $ECHO_C" >&6
+if test "${libc_cv_hashstyle+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+    cat > conftest.c <<EOF
+int _start (void) { return 42; }
+EOF
+  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+                             -fPIC -shared -o conftest.so conftest.c
+                             -Wl,--hash-style=both -nostdlib 1>&5'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }
+  then
+    libc_cv_hashstyle=yes
+  else
+    libc_cv_hashstyle=no
+  fi
+  rm -f conftest*
+fi
+echo "$as_me:$LINENO: result: $libc_cv_hashstyle" >&5
+echo "${ECHO_T}$libc_cv_hashstyle" >&6
+
 fi
 
 echo "$as_me:$LINENO: checking for -fno-toplevel-reorder" >&5
@@ -8496,6 +8523,7 @@ s,@ASFLAGS_config@,$ASFLAGS_config,;t t
 s,@libc_cv_z_combreloc@,$libc_cv_z_combreloc,;t t
 s,@libc_cv_z_execstack@,$libc_cv_z_execstack,;t t
 s,@libc_cv_fpie@,$libc_cv_fpie,;t t
+s,@libc_cv_hashstyle@,$libc_cv_hashstyle,;t t
 s,@fno_unit_at_a_time@,$fno_unit_at_a_time,;t t
 s,@libc_cv_ssp@,$libc_cv_ssp,;t t
 s,@libc_cv_have_initfini@,$libc_cv_have_initfini,;t t
index 79fa32e..924b040 100644 (file)
@@ -1589,6 +1589,22 @@ EOF
   rm -f conftest*])
 
   AC_SUBST(libc_cv_fpie)
+
+  AC_CACHE_CHECK(for --hash-style option,
+                libc_cv_hashstyle, [dnl
+  cat > conftest.c <<EOF
+int _start (void) { return 42; }
+EOF
+  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+                             -fPIC -shared -o conftest.so conftest.c
+                             -Wl,--hash-style=both -nostdlib 1>&AS_MESSAGE_LOG_FD])
+  then
+    libc_cv_hashstyle=yes
+  else
+    libc_cv_hashstyle=no
+  fi
+  rm -f conftest*])
+  AC_SUBST(libc_cv_hashstyle)
 fi
 
 AC_CACHE_CHECK(for -fno-toplevel-reorder, libc_cv_fno_toplevel_reorder, [dnl
index 5a7bed1..7cfcc62 100644 (file)
@@ -1,5 +1,5 @@
 /* Look up a symbol in the loaded objects.
-   Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -72,6 +72,16 @@ struct sym_val
 #include "do-lookup.h"
 
 
+static uint_fast32_t
+dl_new_hash (const char *s)
+{
+  uint_fast32_t h = 5381;
+  for (unsigned char c = *s; c != '\0'; c = *++s)
+    h = h * 33 + c;
+  return h & 0xffffffff;
+}
+
+
 /* Add extra dependency on MAP to UNDEF_MAP.  */
 static int
 internal_function
@@ -206,7 +216,8 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
                     const struct r_found_version *version,
                     int type_class, int flags, struct link_map *skip_map)
 {
-  const unsigned long int hash = _dl_elf_hash (undef_name);
+  const uint_fast32_t new_hash = dl_new_hash (undef_name);
+  unsigned long int old_hash = 0xffffffff;
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope = symbol_scope;
 
@@ -229,8 +240,9 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
   /* Search the relevant loaded objects for a definition.  */
   for (size_t start = i; *scope != NULL; start = 0, ++scope)
     {
-      int res = do_lookup_x (undef_name, hash, *ref, &current_value, *scope,
-                            start, version, flags, skip_map, type_class);
+      int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+                            &current_value, *scope, start, version, flags,
+                            skip_map, type_class);
       if (res > 0)
        break;
 
@@ -301,9 +313,9 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
          struct sym_val protected_value = { NULL, NULL };
 
          for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
-           if (do_lookup_x (undef_name, hash, *ref, &protected_value,
-                            *scope, i, version, flags, skip_map,
-                            ELF_RTYPE_CLASS_PLT) != 0)
+           if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+                            &protected_value, *scope, i, version, flags,
+                            skip_map, ELF_RTYPE_CLASS_PLT) != 0)
              break;
 
          if (protected_value.s != NULL && protected_value.m != undef_map)
@@ -352,6 +364,31 @@ _dl_setup_hash (struct link_map *map)
   Elf_Symndx *hash;
   Elf_Symndx nchain;
 
+  if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+                                   + DT_THISPROCNUM + DT_VERSIONTAGNUM
+                                   + DT_EXTRANUM + DT_VALNUM] != NULL, 1))
+    {
+      Elf32_Word *hash32
+       = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+                                     + DT_THISPROCNUM + DT_VERSIONTAGNUM
+                                     + DT_EXTRANUM + DT_VALNUM]);
+      map->l_nbuckets = *hash32++;
+      Elf32_Word symbias = *hash32++;
+      Elf32_Word bitmask_nwords = *hash32++;
+      /* Must be a power of two.  */
+      assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0);
+      map->l_gnu_bitmask_idxbits = bitmask_nwords - 1;
+      map->l_gnu_shift = *hash32++;
+
+      map->l_gnu_bitmask = (ElfW(Addr) *) hash32;
+      hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords;
+
+      map->l_gnu_buckets = hash32;
+      hash32 += map->l_nbuckets;
+      map->l_gnu_chain_zero = hash32 - symbias;
+      return;
+    }
+
   if (!map->l_info[DT_HASH])
     return;
   hash = (void *) D_PTR (map, l_info[DT_HASH]);
@@ -399,9 +436,10 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
           || GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
          && undef_map != GL(dl_ns)[LM_ID_BASE]._ns_loaded)
        {
-         const unsigned long int hash = _dl_elf_hash (undef_name);
+         const uint_fast32_t new_hash = dl_new_hash (undef_name);
+         unsigned long int old_hash = 0xffffffff;
 
-         do_lookup_x (undef_name, hash, *ref, &val,
+         do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
                       undef_map->l_local_scope[0], 0, version, 0, NULL,
                       type_class);
 
index 08d6495..6da1e2e 100644 (file)
@@ -1,5 +1,5 @@
 /* Miscellaneous support functions for dynamic linker
-   Copyright (C) 1997-2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1997-2002, 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -308,7 +308,7 @@ _dl_dprintf (int fd, const char *fmt, ...)
 /* Test whether given NAME matches any of the names of the given object.  */
 int
 internal_function
-_dl_name_match_p (const char *name, struct link_map *map)
+_dl_name_match_p (const char *name, const struct link_map *map)
 {
   if (strcmp (name, map->l_name) == 0)
     return 1;
index 7b62b0f..f40ab9d 100644 (file)
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+
 /* Inner part of the lookup functions.  We return a value > 0 if we
    found the symbol, the value 0 if nothing is found and < 0 if
    something bad happened.  */
 static int
 __attribute_noinline__
-do_lookup_x (const char *undef_name, unsigned long int hash,
-            const ElfW(Sym) *ref, struct sym_val *result,
-            struct r_scope_elem *scope, size_t i,
+do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
+            unsigned long int *old_hash, const ElfW(Sym) *ref,
+            struct sym_val *result, struct r_scope_elem *scope, size_t i,
             const struct r_found_version *const version, int flags,
             struct link_map *skip, int type_class)
 {
   struct link_map **list = scope->r_list;
   size_t n = scope->r_nlist;
-  struct link_map *map;
 
   do
     {
-      const ElfW(Sym) *symtab;
-      const char *strtab;
-      const ElfW(Half) *verstab;
+      /* These variables are used in the nested function.  */
       Elf_Symndx symidx;
-      const ElfW(Sym) *sym;
       int num_versions = 0;
       const ElfW(Sym) *versioned_sym = NULL;
 
-      map = list[i]->l_real;
+      const struct link_map *map = list[i]->l_real;
 
       /* Here come the extra test needed for `_dl_lookup_symbol_skip'.  */
       if (map == skip)
@@ -63,109 +60,158 @@ do_lookup_x (const char *undef_name, unsigned long int hash,
                          map->l_name[0] ? map->l_name : rtld_progname,
                          map->l_ns);
 
-      symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
-      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
-      verstab = map->l_versyms;
+      /* If the hash table is empty there is nothing to do here.  */
+      if (map->l_nbuckets == 0)
+       continue;
 
-      /* Search the appropriate hash bucket in this object's symbol table
-        for a definition for the same symbol name.  */
-      for (symidx = map->l_buckets[hash % map->l_nbuckets];
-          symidx != STN_UNDEF;
-          symidx = map->l_chain[symidx])
-       {
-         sym = &symtab[symidx];
-
-         assert (ELF_RTYPE_CLASS_PLT == 1);
-         if ((sym->st_value == 0 /* No value.  */
-#ifdef USE_TLS
-              && ELFW(ST_TYPE) (sym->st_info) != STT_TLS
-#endif
-              )
-             || (type_class & (sym->st_shndx == SHN_UNDEF)))
-           continue;
-
-         if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC
-#ifdef USE_TLS
-             && ELFW(ST_TYPE) (sym->st_info) != STT_TLS
-#endif
-             )
-           /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC
-              entries (and STT_TLS if TLS is supported) since these
-              are no code/data definitions.  */
-           continue;
-
-         if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
-           /* Not the symbol we are looking for.  */
-           continue;
-
-         if (version != NULL)
-           {
-             if (__builtin_expect (verstab == NULL, 0))
-               {
-                 /* We need a versioned symbol but haven't found any.  If
-                    this is the object which is referenced in the verneed
-                    entry it is a bug in the library since a symbol must
-                    not simply disappear.
-
-                    It would also be a bug in the object since it means that
-                    the list of required versions is incomplete and so the
-                    tests in dl-version.c haven't found a problem.*/
-                 assert (version->filename == NULL
-                         || ! _dl_name_match_p (version->filename, map));
-
-                 /* Otherwise we accept the symbol.  */
-               }
-             else
-               {
-                 /* We can match the version information or use the
-                    default one if it is not hidden.  */
-                 ElfW(Half) ndx = verstab[symidx] & 0x7fff;
-                 if ((map->l_versions[ndx].hash != version->hash
-                      || strcmp (map->l_versions[ndx].name, version->name))
-                     && (version->hidden || map->l_versions[ndx].hash
-                         || (verstab[symidx] & 0x8000)))
-                   /* It's not the version we want.  */
-                   continue;
-               }
-           }
-         else
-           {
-             /* No specific version is selected.  There are two ways we
-                can got here:
+      /* The tables for this map.  */
+      const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+      const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+
+      /* Nested routine to check whether the symbol matches.  */
+      const ElfW(Sym) *
+      __attribute_noinline__
+      check_match (const ElfW(Sym) *sym)
+      {
+       assert (ELF_RTYPE_CLASS_PLT == 1);
+       if (__builtin_expect ((sym->st_value == 0 /* No value.  */
+                              && ELFW(ST_TYPE) (sym->st_info) != STT_TLS)
+                             || (type_class & (sym->st_shndx == SHN_UNDEF)),
+                             0))
+         return NULL;
+
+       if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC
+                             && ELFW(ST_TYPE) (sym->st_info) != STT_TLS, 0))
+         /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC
+            entries (and STT_TLS if TLS is supported) since these
+            are no code/data definitions.  */
+         return NULL;
+
+       if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
+         /* Not the symbol we are looking for.  */
+         return NULL;
+
+       const ElfW(Half) *verstab = map->l_versyms;
+       if (version != NULL)
+         {
+           if (__builtin_expect (verstab == NULL, 0))
+             {
+               /* We need a versioned symbol but haven't found any.  If
+                  this is the object which is referenced in the verneed
+                  entry it is a bug in the library since a symbol must
+                  not simply disappear.
+
+                  It would also be a bug in the object since it means that
+                  the list of required versions is incomplete and so the
+                  tests in dl-version.c haven't found a problem.*/
+               assert (version->filename == NULL
+                       || ! _dl_name_match_p (version->filename, map));
 
-                - a binary which does not include versioning information
-                  is loaded
+               /* Otherwise we accept the symbol.  */
+             }
+           else
+             {
+               /* We can match the version information or use the
+                  default one if it is not hidden.  */
+               ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+               if ((map->l_versions[ndx].hash != version->hash
+                    || strcmp (map->l_versions[ndx].name, version->name))
+                   && (version->hidden || map->l_versions[ndx].hash
+                       || (verstab[symidx] & 0x8000)))
+                 /* It's not the version we want.  */
+                 return NULL;
+             }
+         }
+       else
+         {
+           /* No specific version is selected.  There are two ways we
+              can got here:
 
-                - dlsym() instead of dlvsym() is used to get a symbol which
-                  might exist in more than one form
+              - a binary which does not include versioning information
+              is loaded
 
-                If the library does not provide symbol version
-                information there is no problem at at: we simply use the
-                symbol if it is defined.
+              - dlsym() instead of dlvsym() is used to get a symbol which
+              might exist in more than one form
 
-                These two lookups need to be handled differently if the
-                library defines versions.  In the case of the old
-                unversioned application the oldest (default) version
-                should be used.  In case of a dlsym() call the latest and
-                public interface should be returned.  */
-             if (verstab != NULL)
+              If the library does not provide symbol version information
+              there is no problem at at: we simply use the symbol if it
+              is defined.
+
+              These two lookups need to be handled differently if the
+              library defines versions.  In the case of the old
+              unversioned application the oldest (default) version
+              should be used.  In case of a dlsym() call the latest and
+              public interface should be returned.  */
+           if (verstab != NULL)
+             {
+               if ((verstab[symidx] & 0x7fff)
+                   >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
+                 {
+                   /* Don't accept hidden symbols.  */
+                   if ((verstab[symidx] & 0x8000) == 0
+                       && num_versions++ == 0)
+                     /* No version so far.  */
+                     versioned_sym = sym;
+
+                   return NULL;
+                 }
+             }
+         }
+
+       /* There cannot be another entry for this symbol so stop here.  */
+       return sym;
+      }
+
+      const ElfW(Sym) *sym;
+      const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
+      if (__builtin_expect (bitmask != NULL, 1))
+       {
+         ElfW(Addr) bitmask_word
+           = bitmask[(new_hash / __ELF_NATIVE_CLASS)
+                     & map->l_gnu_bitmask_idxbits];
+
+         unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
+         unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
+                                  & (__ELF_NATIVE_CLASS - 1));
+
+         if (__builtin_expect ((bitmask_word >> hashbit1)
+                               & (bitmask_word >> hashbit2) & 1, 0))
+           {
+             Elf32_Word bucket = map->l_gnu_buckets[new_hash
+                                                    % map->l_nbuckets];
+             if (bucket != 0)
                {
-                 if ((verstab[symidx] & 0x7fff)
-                     >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
-                   {
-                     /* Don't accept hidden symbols.  */
-                     if ((verstab[symidx] & 0x8000) == 0
-                         && num_versions++ == 0)
-                       /* No version so far.  */
-                       versioned_sym = sym;
+                 const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
 
-                     continue;
-                   }
+                 do
+                   if ((*hasharr & ~1u) == (new_hash & ~1u))
+                     {
+                       symidx = hasharr - map->l_gnu_chain_zero;
+                       sym = check_match (&symtab[symidx]);
+                       if (sym != NULL)
+                         goto found_it;
+                     }
+                 while ((*hasharr++ & 1u) == 0);
                }
            }
+       }
+      else
+       {
+         if (*old_hash == 0xffffffff)
+           *old_hash = _dl_elf_hash (undef_name);
 
-         /* There cannot be another entry for this symbol so stop here.  */
-         goto found_it;
+         /* Use the old SysV-style hash table.  Search the appropriate
+            hash bucket in this object's symbol table for a definition
+            for the same symbol name.  */
+         for (symidx = map->l_buckets[*old_hash % map->l_nbuckets];
+              symidx != STN_UNDEF;
+              symidx = map->l_chain[symidx])
+           {
+             sym = check_match (&symtab[symidx]);
+             if (sym != NULL)
+               goto found_it;
+           }
        }
 
       /* If we have seen exactly one versioned symbol while we are
@@ -186,7 +232,7 @@ do_lookup_x (const char *undef_name, unsigned long int hash,
                  if (! result->s)
                    {
                      result->s = sym;
-                     result->m = map;
+                     result->m = (struct link_map *) map;
                    }
                  break;
                }
@@ -194,7 +240,7 @@ do_lookup_x (const char *undef_name, unsigned long int hash,
            case STB_GLOBAL:
              /* Global definition.  Just what we need.  */
              result->s = sym;
-             result->m = map;
+             result->m = (struct link_map *) map;
              return 1;
            default:
              /* Local symbols are ignored.  */
@@ -213,7 +259,3 @@ do_lookup_x (const char *undef_name, unsigned long int hash,
   /* We have not found anything until now.  */
   return 0;
 }
-
-#undef FCT
-#undef ARG
-#undef VERSIONED
index cf0d223..7eb9a36 100644 (file)
@@ -1,5 +1,5 @@
 /* Inline functions for dynamic linking.
-   Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -143,6 +143,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
 # endif
       ADJUST_DYN_INFO (DT_JMPREL);
       ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
+      ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
+                      + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
 # undef ADJUST_DYN_INFO
       assert (cnt <= DL_RO_DYN_TEMP_CNT);
     }
index 344f252..dae3597 100644 (file)
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -329,7 +329,8 @@ typedef struct
 #define SHT_GROUP        17            /* Section group */
 #define SHT_SYMTAB_SHNDX  18           /* Extended section indeces */
 #define        SHT_NUM           19            /* Number of defined types.  */
-#define SHT_LOOS         0x60000000    /* Start OS-specific */
+#define SHT_LOOS         0x60000000    /* Start OS-specific.  */
+#define SHT_GNU_HASH     0x6ffffff6    /* GNU-style hash table.  */
 #define SHT_GNU_LIBLIST          0x6ffffff7    /* Prelink library list */
 #define SHT_CHECKSUM     0x6ffffff8    /* Checksum for DSO content.  */
 #define SHT_LOSUNW       0x6ffffffa    /* Sun-specific low bound.  */
@@ -699,6 +700,9 @@ typedef struct
    If any adjustment is made to the ELF object after it has been
    built these entries will need to be adjusted.  */
 #define DT_ADDRRNGLO   0x6ffffe00
+#define DT_GNU_HASH    0x6ffffef5      /* GNU-style hash table.  */
+#define DT_TLSDESC_PLT 0x6ffffef6
+#define DT_TLSDESC_GOT 0x6ffffef7
 #define DT_GNU_CONFLICT        0x6ffffef8      /* Start of conflict section */
 #define DT_GNU_LIBLIST 0x6ffffef9      /* Library list */
 #define DT_CONFIG      0x6ffffefa      /* Configuration information.  */
@@ -709,7 +713,7 @@ typedef struct
 #define DT_SYMINFO     0x6ffffeff      /* Syminfo table.  */
 #define DT_ADDRRNGHI   0x6ffffeff
 #define DT_ADDRTAGIDX(tag)     (DT_ADDRRNGHI - (tag))  /* Reverse order! */
-#define DT_ADDRNUM 10
+#define DT_ADDRNUM 11
 
 /* The versioning entry types.  The next are defined as part of the
    GNU extension.  */
index 3079ae8..9947ee7 100644 (file)
@@ -124,7 +124,7 @@ struct link_map
     const ElfW(Phdr) *l_phdr;  /* Pointer to program header table in core.  */
     ElfW(Addr) l_entry;                /* Entry point location.  */
     ElfW(Half) l_phnum;                /* Number of program header entries.  */
-    ElfW(Half) l_ldnum;        /* Number of dynamic segment entries.  */
+    ElfW(Half) l_ldnum;                /* Number of dynamic segment entries.  */
 
     /* Array of DT_NEEDED dependencies and their dependencies, in
        dependency order for symbol lookup (with and without
@@ -141,7 +141,19 @@ struct link_map
 
     /* Symbol hash table.  */
     Elf_Symndx l_nbuckets;
-    const Elf_Symndx *l_buckets, *l_chain;
+    Elf32_Word l_gnu_bitmask_idxbits;
+    Elf32_Word l_gnu_shift;
+    const ElfW(Addr) *l_gnu_bitmask;
+    union
+    {
+      const Elf32_Word *l_gnu_buckets;
+      const Elf_Symndx *l_chain;
+    };
+    union
+    {
+      const Elf32_Word *l_gnu_chain_zero;
+      const Elf_Symndx *l_buckets;
+    };
 
     unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose.  */
     enum                       /* Where this object came from.  */
index 6ffa30d..c3f9c2d 100644 (file)
@@ -41,7 +41,8 @@ __pthread_mutex_init (mutex, mutexattr)
   imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
 
   /* Sanity checks.  */
-  // XXX For now we don't support priority protected mutexes.
+  // XXX For now we don't support priority inherited or priority protected
+  // XXX mutexes.
   switch (__builtin_expect (imutexattr->mutexkind
                            & PTHREAD_MUTEXATTR_PROTOCOL_MASK,
                            PTHREAD_PRIO_NONE
@@ -50,13 +51,6 @@ __pthread_mutex_init (mutex, mutexattr)
     case PTHREAD_PRIO_NONE << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
       break;
 
-    case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
-#ifndef __ASSUME_SET_ROBUST_LIST
-      if (__set_robust_list_avail < 0)
-       return ENOTSUP;
-#endif
-      break;
-
     default:
       return ENOTSUP;
     }
@@ -81,11 +75,11 @@ __pthread_mutex_init (mutex, mutexattr)
   switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK)
     {
     case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
-      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP;
+      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_PRIVATE_NP;
       break;
 
     case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
-      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
+      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_PRIVATE_NP;
       if (PTHREAD_MUTEX_PRIO_CEILING_MASK
          == PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
        mutex->__data.__kind |= (imutexattr->mutexkind
index 6d81765..ef2b685 100644 (file)
@@ -331,7 +331,7 @@ struct audit_ifaces
 
 
 /* Test whether given NAME matches any of the names of the given object.  */
-extern int _dl_name_match_p (const char *__name, struct link_map *__map)
+extern int _dl_name_match_p (const char *__name, const struct link_map *__map)
      internal_function;
 
 /* Function used as argument for `_dl_receive_error' function.  The