* 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.
This commit is contained in:
Ulrich Drepper 2006-07-10 21:59:43 +00:00
parent f3be81a91c
commit 871b91589b
14 changed files with 315 additions and 138 deletions

View file

@ -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> 2006-06-27 Ulrich Drepper <drepper@redhat.com>
* elf/dl-load.c (open_path): Fix test to determine whether DSO is * elf/dl-load.c (open_path): Fix test to determine whether DSO is

View file

@ -413,11 +413,20 @@ LDFLAGS.so += $(relro-LDFLAGS)
LDFLAGS-rtld += $(relro-LDFLAGS) LDFLAGS-rtld += $(relro-LDFLAGS)
endif 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. # Command for linking programs with the C library.
ifndef +link ifndef +link
+link = $(CC) -nostdlib -nostartfiles -o $@ \ +link = $(CC) -nostdlib -nostartfiles -o $@ \
$(sysdep-LDFLAGS) $(config-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \ $(sysdep-LDFLAGS) $(config-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
$(combreloc-LDFLAGS) $(relro-LDFLAGS) \ $(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \
$(addprefix $(csu-objpfx),$(start-installed-name)) \ $(addprefix $(csu-objpfx),$(start-installed-name)) \
$(+preinit) $(+prector) \ $(+preinit) $(+prector) \
$(filter-out $(addprefix $(csu-objpfx),start.o \ $(filter-out $(addprefix $(csu-objpfx),start.o \

6
NEWS
View file

@ -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. Copyright (C) 1992-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
See the end for copying conditions. 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. * Allow system admin to configure getaddrinfo with the /etc/gai.conf file.
Implemented by Ulrich Drepper. 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. * 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 * The interfaces introduced in RFC 3542 have been implemented by
Ulrich Drepper. Ulrich Drepper.
* Support for the new ELF hash table format was added by Ulrich Drepper.
Version 2.4 Version 2.4

View file

@ -65,6 +65,7 @@ have-libcap = @have_libcap@
have-cc-with-libunwind = @libc_cv_cc_with_libunwind@ have-cc-with-libunwind = @libc_cv_cc_with_libunwind@
fno-unit-at-a-time = @fno_unit_at_a_time@ fno-unit-at-a-time = @fno_unit_at_a_time@
bind-now = @bindnow@ bind-now = @bindnow@
have-hash-style = @libc_cv_hashstyle@
static-libgcc = @libc_cv_gcc_static_libgcc@ static-libgcc = @libc_cv_gcc_static_libgcc@

30
configure vendored
View file

@ -313,7 +313,7 @@ ac_includes_default="\
# include <unistd.h> # include <unistd.h>
#endif" #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='' ac_subst_files=''
# Initialize some variables set by options. # 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 "${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 fi
echo "$as_me:$LINENO: checking for -fno-toplevel-reorder" >&5 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_combreloc@,$libc_cv_z_combreloc,;t t
s,@libc_cv_z_execstack@,$libc_cv_z_execstack,;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_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,@fno_unit_at_a_time@,$fno_unit_at_a_time,;t t
s,@libc_cv_ssp@,$libc_cv_ssp,;t t s,@libc_cv_ssp@,$libc_cv_ssp,;t t
s,@libc_cv_have_initfini@,$libc_cv_have_initfini,;t t s,@libc_cv_have_initfini@,$libc_cv_have_initfini,;t t

View file

@ -1589,6 +1589,22 @@ EOF
rm -f conftest*]) rm -f conftest*])
AC_SUBST(libc_cv_fpie) 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 fi
AC_CACHE_CHECK(for -fno-toplevel-reorder, libc_cv_fno_toplevel_reorder, [dnl AC_CACHE_CHECK(for -fno-toplevel-reorder, libc_cv_fno_toplevel_reorder, [dnl

View file

@ -1,5 +1,5 @@
/* Look up a symbol in the loaded objects. /* 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -72,6 +72,16 @@ struct sym_val
#include "do-lookup.h" #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. */ /* Add extra dependency on MAP to UNDEF_MAP. */
static int static int
internal_function 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, const struct r_found_version *version,
int type_class, int flags, struct link_map *skip_map) 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 sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope = symbol_scope; 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. */ /* Search the relevant loaded objects for a definition. */
for (size_t start = i; *scope != NULL; start = 0, ++scope) for (size_t start = i; *scope != NULL; start = 0, ++scope)
{ {
int res = do_lookup_x (undef_name, hash, *ref, &current_value, *scope, int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
start, version, flags, skip_map, type_class); &current_value, *scope, start, version, flags,
skip_map, type_class);
if (res > 0) if (res > 0)
break; 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 }; struct sym_val protected_value = { NULL, NULL };
for (scope = symbol_scope; *scope != NULL; i = 0, ++scope) for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
if (do_lookup_x (undef_name, hash, *ref, &protected_value, if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
*scope, i, version, flags, skip_map, &protected_value, *scope, i, version, flags,
ELF_RTYPE_CLASS_PLT) != 0) skip_map, ELF_RTYPE_CLASS_PLT) != 0)
break; break;
if (protected_value.s != NULL && protected_value.m != undef_map) 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 *hash;
Elf_Symndx nchain; 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]) if (!map->l_info[DT_HASH])
return; return;
hash = (void *) D_PTR (map, l_info[DT_HASH]); 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) || GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
&& undef_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, undef_map->l_local_scope[0], 0, version, 0, NULL,
type_class); type_class);

View file

@ -1,5 +1,5 @@
/* Miscellaneous support functions for dynamic linker /* 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or 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. */ /* Test whether given NAME matches any of the names of the given object. */
int int
internal_function 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) if (strcmp (name, map->l_name) == 0)
return 1; return 1;

View file

@ -17,32 +17,29 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */ 02111-1307 USA. */
/* Inner part of the lookup functions. We return a value > 0 if we /* 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 found the symbol, the value 0 if nothing is found and < 0 if
something bad happened. */ something bad happened. */
static int static int
__attribute_noinline__ __attribute_noinline__
do_lookup_x (const char *undef_name, unsigned long int hash, do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
const ElfW(Sym) *ref, struct sym_val *result, unsigned long int *old_hash, const ElfW(Sym) *ref,
struct r_scope_elem *scope, size_t i, struct sym_val *result, struct r_scope_elem *scope, size_t i,
const struct r_found_version *const version, int flags, const struct r_found_version *const version, int flags,
struct link_map *skip, int type_class) struct link_map *skip, int type_class)
{ {
struct link_map **list = scope->r_list; struct link_map **list = scope->r_list;
size_t n = scope->r_nlist; size_t n = scope->r_nlist;
struct link_map *map;
do do
{ {
const ElfW(Sym) *symtab; /* These variables are used in the nested function. */
const char *strtab;
const ElfW(Half) *verstab;
Elf_Symndx symidx; Elf_Symndx symidx;
const ElfW(Sym) *sym;
int num_versions = 0; int num_versions = 0;
const ElfW(Sym) *versioned_sym = NULL; 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'. */ /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
if (map == 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_name[0] ? map->l_name : rtld_progname,
map->l_ns); map->l_ns);
symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); /* If the hash table is empty there is nothing to do here. */
strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); if (map->l_nbuckets == 0)
verstab = map->l_versyms; continue;
/* Search the appropriate hash bucket in this object's symbol table /* The tables for this map. */
for a definition for the same symbol name. */ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
for (symidx = map->l_buckets[hash % map->l_nbuckets]; const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
symidx != STN_UNDEF;
symidx = map->l_chain[symidx])
/* 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));
/* 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:
- a binary which does not include versioning information
is loaded
- dlsym() instead of dlvsym() is used to get a symbol which
might exist in more than one form
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))
{ {
sym = &symtab[symidx]; ElfW(Addr) bitmask_word
= bitmask[(new_hash / __ELF_NATIVE_CLASS)
& map->l_gnu_bitmask_idxbits];
assert (ELF_RTYPE_CLASS_PLT == 1); unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
if ((sym->st_value == 0 /* No value. */ unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
#ifdef USE_TLS & (__ELF_NATIVE_CLASS - 1));
&& 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 if (__builtin_expect ((bitmask_word >> hashbit1)
#ifdef USE_TLS & (bitmask_word >> hashbit2) & 1, 0))
&& 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)) Elf32_Word bucket = map->l_gnu_buckets[new_hash
% map->l_nbuckets];
if (bucket != 0)
{ {
/* We need a versioned symbol but haven't found any. If const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
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 do
the list of required versions is incomplete and so the if ((*hasharr & ~1u) == (new_hash & ~1u))
tests in dl-version.c haven't found a problem.*/ {
assert (version->filename == NULL symidx = hasharr - map->l_gnu_chain_zero;
|| ! _dl_name_match_p (version->filename, map)); sym = check_match (&symtab[symidx]);
if (sym != NULL)
/* Otherwise we accept the symbol. */ goto found_it;
} }
else while ((*hasharr++ & 1u) == 0);
{
/* 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 }
else
{
if (*old_hash == 0xffffffff)
*old_hash = _dl_elf_hash (undef_name);
/* 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])
{ {
/* No specific version is selected. There are two ways we sym = check_match (&symtab[symidx]);
can got here: if (sym != NULL)
goto found_it;
- a binary which does not include versioning information
is loaded
- dlsym() instead of dlvsym() is used to get a symbol which
might exist in more than one form
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;
continue;
}
}
} }
/* There cannot be another entry for this symbol so stop here. */
goto found_it;
} }
/* If we have seen exactly one versioned symbol while we are /* 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) if (! result->s)
{ {
result->s = sym; result->s = sym;
result->m = map; result->m = (struct link_map *) map;
} }
break; break;
} }
@ -194,7 +240,7 @@ do_lookup_x (const char *undef_name, unsigned long int hash,
case STB_GLOBAL: case STB_GLOBAL:
/* Global definition. Just what we need. */ /* Global definition. Just what we need. */
result->s = sym; result->s = sym;
result->m = map; result->m = (struct link_map *) map;
return 1; return 1;
default: default:
/* Local symbols are ignored. */ /* 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. */ /* We have not found anything until now. */
return 0; return 0;
} }
#undef FCT
#undef ARG
#undef VERSIONED

View file

@ -1,5 +1,5 @@
/* Inline functions for dynamic linking. /* 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or 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 # endif
ADJUST_DYN_INFO (DT_JMPREL); ADJUST_DYN_INFO (DT_JMPREL);
ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); 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 # undef ADJUST_DYN_INFO
assert (cnt <= DL_RO_DYN_TEMP_CNT); assert (cnt <= DL_RO_DYN_TEMP_CNT);
} }

View file

@ -329,7 +329,8 @@ typedef struct
#define SHT_GROUP 17 /* Section group */ #define SHT_GROUP 17 /* Section group */
#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
#define SHT_NUM 19 /* Number of defined types. */ #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_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ #define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ #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 If any adjustment is made to the ELF object after it has been
built these entries will need to be adjusted. */ built these entries will need to be adjusted. */
#define DT_ADDRRNGLO 0x6ffffe00 #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_CONFLICT 0x6ffffef8 /* Start of conflict section */
#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ #define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
#define DT_CONFIG 0x6ffffefa /* Configuration information. */ #define DT_CONFIG 0x6ffffefa /* Configuration information. */
@ -709,7 +713,7 @@ typedef struct
#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ #define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
#define DT_ADDRRNGHI 0x6ffffeff #define DT_ADDRRNGHI 0x6ffffeff
#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ #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 /* The versioning entry types. The next are defined as part of the
GNU extension. */ GNU extension. */

View file

@ -124,7 +124,7 @@ struct link_map
const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */ const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */
ElfW(Addr) l_entry; /* Entry point location. */ ElfW(Addr) l_entry; /* Entry point location. */
ElfW(Half) l_phnum; /* Number of program header entries. */ 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 /* Array of DT_NEEDED dependencies and their dependencies, in
dependency order for symbol lookup (with and without dependency order for symbol lookup (with and without
@ -141,7 +141,19 @@ struct link_map
/* Symbol hash table. */ /* Symbol hash table. */
Elf_Symndx l_nbuckets; 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. */ unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose. */
enum /* Where this object came from. */ enum /* Where this object came from. */

View file

@ -41,7 +41,8 @@ __pthread_mutex_init (mutex, mutexattr)
imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr; imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
/* Sanity checks. */ /* 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 switch (__builtin_expect (imutexattr->mutexkind
& PTHREAD_MUTEXATTR_PROTOCOL_MASK, & PTHREAD_MUTEXATTR_PROTOCOL_MASK,
PTHREAD_PRIO_NONE PTHREAD_PRIO_NONE
@ -50,13 +51,6 @@ __pthread_mutex_init (mutex, mutexattr)
case PTHREAD_PRIO_NONE << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: case PTHREAD_PRIO_NONE << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
break; 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: default:
return ENOTSUP; return ENOTSUP;
} }
@ -81,11 +75,11 @@ __pthread_mutex_init (mutex, mutexattr)
switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK) switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK)
{ {
case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: 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; break;
case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: 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 if (PTHREAD_MUTEX_PRIO_CEILING_MASK
== PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) == PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
mutex->__data.__kind |= (imutexattr->mutexkind mutex->__data.__kind |= (imutexattr->mutexkind

View file

@ -331,7 +331,7 @@ struct audit_ifaces
/* Test whether given NAME matches any of the names of the given object. */ /* 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; internal_function;
/* Function used as argument for `_dl_receive_error' function. The /* Function used as argument for `_dl_receive_error' function. The