about summary refs log tree commit diff
path: root/elf/dl-lookup.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-02-19 04:43:53 +0000
committerUlrich Drepper <drepper@redhat.com>1997-02-19 04:43:53 +0000
commit1fb05e3db1891142410bc58c320dfe281749fffe (patch)
tree46299dbecec282055e3493787910444e77099fe7 /elf/dl-lookup.c
parentc84142e8fe3cbcce43ae35ac957a74ac8216d11d (diff)
downloadglibc-1fb05e3db1891142410bc58c320dfe281749fffe.tar.gz
glibc-1fb05e3db1891142410bc58c320dfe281749fffe.tar.xz
glibc-1fb05e3db1891142410bc58c320dfe281749fffe.zip
update from main archive 970218 cvs/libc-970221 cvs/libc-970220 cvs/libc-970219
1997-02-19 03:28  Miles Bader  <miles@gnu.ai.mit.edu>

	* argp/argp-help.c: Add support for user provided filter of help
	messages.
	* argp/argp-parse.c: Likewise.
	* argp/argp.h: Likewise.
	* argp/argp-namefrob.h: Define __argp_input.

	* argp/argp-test.c: Add example for filter.

1997-02-19 02:58  Ulrich Drepper  <drepper@cygnus.com>

	* argp.h: New file.
	* locale/programs/locale.c: Switch to use argp.

	* errno.h: Make it possible to get definition of error_t even
	after having errno.h already.

	* elf/dl-hash.h: New file.  ELF hashing function.  Extracted
	from dl-lookup.c.
	* elf/dl-lookup.c (_dl_elf_hash): Remove definition.

	* elf/dl-load.c: Rename _dl_does_name_match_p to _dl_name_match_p.
	* elf/dl-version.c: Likewise.

	* elf/dl-lookup.c: Implement new versioning lookup scheme.
	* elf/dl-version.c (_dl_check_map_versions): Initialize new field
	in l_versions member.

	* elf/dlvsym.c: Correct call of _dl_lookup_versioned_symbol_skip
	and _dl_lookup_versioned_symbol.

	* elf/link.h: Rename hash_name_pair to struct r_found_version.
	* sysdeps/alpha/dl-machine.h: Likewise.
	* sysdeps/i386/dl-machine.h: Likewise.
	* sysdeps/m68k/dl-machine.h: Likewise.
	* sysdeps/mips/dl-machine.h: Likewise.

	* intl/l10nflist.c: (_nl_make_l10nflist): Fix bug in computation of
	length of abs_filename.

	* locale/Makefile (CPPFLAGS): Define LOCALE_ALIAS_PATH.

	* locale/programs/ld-monetary.c (monetary_add): Allow value 0
	in mon_grouping information.  This means no more grouping.
	* locale/programs/ld-numeric.c (numeric_add): Write value \377
	when seein value 0 in grouping information.
	* locale/programs/linereader.c (lr_close): Don't free fname since
	it might be used in error messages.

	* locale/programs/locale.c: Check whether output of `locale -a'
	really is locale directory.  Also print locale aliases.

	* misc/search.h (__action_fn_t): Parameters VALUE and LEVEL cannot
	be const.

1997-02-19 02:16  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/bsd/sun/sunos4/resourcebits.h: Correct #defin to
	#define.  Reported by Rick Flower <FLOWER@sdvax2.sdd.TRW.COM>.

1997-02-19 01:37  Erik Troan  <ewt@redhat.com>

	* shadow/sgetspent_r.c: Accept empty third, fourth and fifth fields.

1997-02-19 01:02  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/mman/syscalls.list: msync takes 3 arguments.
	Reported by Andreas Jaeger <aj@arthur.pfalz.de>.

	* sysdeps/stub/msync.c (msync): Add missing third parameter.

1997-02-19 00:29  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/bsd/sigsuspend.c: Call __sigpause with needed
	additional argument.

1997-02-18 22:13  Ulrich Drepper  <drepper@cygnus.com>

	* inet/net/ethernet.h: New file.
	* sysdeps/unix/sysv/linux/netinet/if_ether.c: Add BSD compatibility.
	* sysdeps/unix/sysv/linux/net/if_slip.h: New file.
	Contributed by a sun <asun@zoology.washington.edu>.

	* sysdeps/unix/sysv/linux/net/if_arp.h: Include <sys/socket.h>.
	* sunrpc/rpc/rpc_msg.h: Include <rpc/clnt.h>.
	Reported by a sun <asun@zoology.washington.edu>.

1997-02-16 14:25  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* Makerules ((common-objpfx)distinfo-$(subdir)): Depend on sysdep
	makefiles which may change the distinfo variables.

1997-02-16 14:03  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/Makefile (sysdep_headers)
	[$(subdir)=misc]: Add sys/quota.h.
	(sysdep_headers) [$(subdir)=inet]: Add netinet/udp.h.

1997-02-17 13:12  aleph1@dfw.net

	* sunrpc/clnt_simp.c (callrpc): Prevent buffer overflow by using
	strncpy.

1997-02-18 03:28  Ulrich Drepper  <drepper@cygnus.com>

	* stdio-common/bug10.c (main): Correct parameter.

1997-02-17 02:51  Ulrich Drepper  <drepper@cygnus.com>

	* malloc/obstack.h: Add `extern "C"' protection.
	* posix/regex.h: Likewise.
	* io/ftw.h: Likewise.
	* misc/libgen.h: Likewise.
	* login/utmp.h: Likewise.
	* sysdeps/unix/sysv/linux/sys/reboot.h: Likewise.
	* sysdeps/unix/sysv/linux/netinet/in.h: Likewise.
	* sunrpc/rpc/pmap_rmt.h: Likewise.
	* sunrpc/rpc/auth_des.h: Likewise.
	* elf/link.h: Likewise.
	Reported by HJ Lu.

1997-02-17 01:45  a sun  <asun@zoology.washington.edu>

	Linux specific network headers.
	* sysdeps/unix/sysv/linux/netinet/if_fddi.h: New file.
	* sysdeps/unix/sysv/linux/netinet/if_tr.h: New file.
	* sysdeps/unix/sysv/linux/netinet/ip_icmp.h: New file.
	* sysdeps/unix/sysv/linux/netinet/ip_fw.h: New file.
	* sysdeps/unix/sysv/linux/netinet/igmp.h: New file.
	* sysdeps/unix/sysv/linux/netinet/icmp.h: New file.
	* sysdeps/unix/sysv/linux/netinet/ip.h: New file.
	* sysdeps/unix/sysv/linux/netinet/tcp.h: New file.
	* sysdeps/unix/sysv/linux/netipx/ipx.h: New file.
	* sysdeps/unix/sysv/linux/netatalk/atalk.h: New file.
	* sysdeps/unix/sysv/linux/Dist: Add new network headers.
	* sysdeps/unix/sysv/linux/Makefile [$(subdir)=misc] (sysdep_headers):
	Add sys/quota.h.
	[$(subdir)=inet] (sysdep_headers): Add new network header.

	* sysdeps/unix/sysv/linux/netinet/udp.h: Add Linux specific changes.

	* inet/netinet/ip.h: Move to sysdeps/generic.
	* inet/netinet/tcp.h: Likewise.
	* sysdeps/generic/netinet/ip.h: Moved to here from inet/netinet.
	* sysdeps/generic/netinet/tcp.h: Likewise.

1997-02-17 01:18  Ulrich Drepper  <drepper@cygnus.com>

	* misc/sys/syslog.h (prioritynames): Correct definition to use
	braces where necessary.
	(facilitynames): Likewise.
	Patch by Ronald F. Guilmette <rfg@monkeys.com>.
	Comment and beautify declarations.

1997-02-16 19:54 1997  Philip Blundell  <Philip.Blundell@pobox.com>

	* inet/Makefile (routines): Add in6_addr, getnameinfo.
	* inet/getnameinfo.c: New file.  Implementation of getnameinfo()
	by Craig Metz.
	* inet/in6_addr.c: New file.  IPv6 addressing constants.
	* posix/Makefile (routines): Add gai_strerror.
	* resolv/netdb.h: Add more constants for IPv6 basic API.
	* sysdeps/posix/gai_strerror.c: New file.
	* sysdeps/stub/gai_strerror.c New file.
	* sysdeps/unix/sysv/linux/netinet/in.h: Add definitions for IPv6
	basic API.

	* sysdeps/posix/getaddrinfo.c: Update from latest version by
	Craig Metz and use reentrant getXXbyYY functions.

1997-02-15 14:32 Andreas Jaeger  <aj@arthur.pfalz.de>

	* argp/argp.h: Declare argp_program_version as const char.
	* argp/argp-test.c: Likewise

	* stdlib/testrand.c (main): Declare main prototype.
	* stdlib/testdiv.c (main): Likewise.
	* string/testcopy.c (main): Likewise.
	* string/test-ffs.c (main): Likewise.
	* time/test_time.c (main): Likewise.

	* locale/duplocale.c (__duplocale): Return result.

1997-02-16 03:54  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/sysv/linux/netinet/in.h: Declare bindresvport.
	Reported by fabsoft@fabserver1.zarm.uni-bremen.de.

	* nss/nss.h: Remove declaration of __nss_shlib_revision.
	* nss/nsswitch.c: Don't use NSS_SHLIB_VERSION macro.

1997-02-16 03:48  Thorsten Kukuk  <kukuk@weber.uni-paderborn.de>

	* nis/nss_nis/nis-ethers.c (_nss_nis_getethernam_r): Rename to
	_nss_nis_gethostton_r.
	(_nss_nis_getetherbyaddr_r): Rename to _nss_nis_getntohost_r.

1997-02-15 22:37  Andy Berkheimer  <andy@tho.org>

	* resolv/gethnamaddr.c (gethostbyname2): Test for ':' in name before
	trying to resolv name as numeric IPv6 address.
	* nss/digits_dots.c: Likewise.

Sat Feb 15 04:51:08 1997  Ulrich Drepper  <drepper@cygnus.com>

	* locale/setlocale.c (setlocale): Don't try to be clever about
	unused locales.  When the existence of the locale files isn't
	tested the result of setlocale might be different.

1997-02-15 03:34  Ulrich Drepper  <drepper@cygnus.com>

	* locale/setlocale.c (setlocale): Don't increment usage_count of
	new locale if it already has the value MAX_USAGE_COUNT (it might
	be the C locale data which is read-only).
Diffstat (limited to 'elf/dl-lookup.c')
-rw-r--r--elf/dl-lookup.c187
1 files changed, 93 insertions, 94 deletions
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 06d1d09b90..8702a85bbb 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -22,6 +22,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include <dl-hash.h>
 #include "../stdio-common/_itoa.h"
 
 #define VERSTAG(tag)	(DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
@@ -33,58 +34,32 @@ struct sym_val
   };
 
 
-/* This is the hashing function specified by the ELF ABI.  In the
-   first five operations now overflow is possible so we optimized it a
-   bit.  */
-static inline unsigned
-_dl_elf_hash (const char *name)
-{
-  unsigned long int hash = 0;
-  if (*name != '\0')
-    {
-      hash = (hash << 4) + *name++;
-      if (*name != '\0')
-	{
-	  hash = (hash << 4) + *name++;
-	  if (*name != '\0')
-	    {
-	      hash = (hash << 4) + *name++;
-	      if (*name != '\0')
-		{
-		  hash = (hash << 4) + *name++;
-		  if (*name != '\0')
-		    {
-		      hash = (hash << 4) + *name++;
-		      while (*name != '\0')
-			{
-			  unsigned long int hi;
-			  hash = (hash << 4) + *name++;
-			  hi = hash & 0xf0000000;
-			  if (hi != 0)
-			    {
-			      hash ^= hi >> 24;
-			      /* The ELF ABI says `hash &= ~hi', but
-				 this is equivalent in this case and
-				 on some machines one insn instead of
-				 two.  */
-			      hash ^= hi;
-			    }
-			}
-		    }
-		}
-	    }
-	}
-    }
-  return hash;
-}
-
-
-/* Inner part of the lookup functions.  */
-static inline ElfW(Addr)
+#define make_string(string, rest...) \
+  ({									      \
+    const char *all[] = { string, ## rest };				      \
+    size_t len, cnt;							      \
+    char *result, *cp;							      \
+									      \
+    len = 1;								      \
+    for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)		      \
+      len += strlen (all[cnt]);						      \
+									      \
+    cp = result = alloca (len);						      \
+    for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)		      \
+      cp = stpcpy (cp, all[cnt]);					      \
+									      \
+    result;								      \
+  })
+
+
+/* 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 inline int
 do_lookup (const char *undef_name, unsigned long int hash,
 	   const ElfW(Sym) **ref, struct sym_val *result,
 	   struct link_map *list[], size_t i, size_t n,
-	   const char *reference_name, const hash_name_pair *version,
+	   const char *reference_name, const struct r_found_version *version,
 	   struct link_map *skip, int flags)
 {
   struct link_map *map;
@@ -108,8 +83,7 @@ do_lookup (const char *undef_name, unsigned long int hash,
 
       symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
       strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
-      if (version != NULL
-	  && map->l_nversions > 0 && map->l_info[VERSTAG (DT_VERSYM)] != NULL)
+      if (map->l_nversions > 0 && map->l_info[VERSTAG (DT_VERSYM)] != NULL)
 	verstab = ((void *) map->l_addr
 		   + map->l_info[VERSTAG (DT_VERSYM)]->d_un.d_ptr);
       else
@@ -143,13 +117,41 @@ do_lookup (const char *undef_name, unsigned long int hash,
 	    /* Not the symbol we are looking for.  */
 	    continue;
 
-	  if (verstab != NULL)
+	  if (version == NULL)
 	    {
-	      /* We can match the version information.  */
-	      ElfW(Half) ndx = verstab[symidx] & 0x7fff;
-	      if (map->l_versions[ndx].hash != version->hash
-		  || strcmp (map->l_versions[ndx].name, version->name))
-	      continue;
+	      /* No specific version is selected.  When the object
+		 file also does not define a version we have a match.
+		 Otherwise we only accept the default version, i.e.,
+		 the version which name is "".  */
+	      if (verstab != NULL)
+		{
+		  ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+		  if (map->l_versions[ndx].hash != 0)
+		    continue;
+		}
+	    }
+	  else
+	    {
+	      if (verstab == NULL)
+		{
+		  /* We need a versioned system 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.  */
+		  if (version->filename != NULL
+		      && _dl_name_match_p (version->filename, map))
+		    return -1;
+		  /* Otherwise we accept the symbol.  */
+		}
+	      else
+		{
+		  /* We can match the version information.  */
+		  ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+		  if (map->l_versions[ndx].hash != version->hash
+		      || strcmp (map->l_versions[ndx].name, version->name))
+		    /* It's not the version we want.  */
+		    continue;
+		}
 	    }
 
 	  switch (ELFW(ST_BIND) (sym->st_info))
@@ -173,6 +175,12 @@ do_lookup (const char *undef_name, unsigned long int hash,
 	      break;
 	    }
 	}
+
+      /* If this current is the one mentioned in the verneed entry it
+	 is a bug.  */
+      if (version != NULL && version->filename != NULL
+	  && _dl_name_match_p (version->filename, map))
+	return -1;
     }
 
   /* We have not found anything until now.  */
@@ -204,15 +212,9 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
 
   if (current_value.s == NULL &&
       (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK))
-    {
-      /* We could find no value for a strong reference.  */
-      static const char msg[] = "undefined symbol: ";
-      const size_t len = strlen (undef_name);
-      char buf[sizeof msg + len];
-      memcpy (buf, msg, sizeof msg - 1);
-      memcpy (&buf[sizeof msg - 1], undef_name, len + 1);
-      _dl_signal_error (0, reference_name, buf);
-    }
+    /* We could find no value for a strong reference.  */
+    _dl_signal_error (0, reference_name,
+		      make_string ("undefined symbol: ", undef_name));
 
   *ref = current_value.s;
   return current_value.a;
@@ -264,7 +266,7 @@ ElfW(Addr)
 _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
 			     struct link_map *symbol_scope[],
 			     const char *reference_name,
-			     const hash_name_pair *version, int flags)
+			     const struct r_found_version *version, int flags)
 {
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { 0, NULL };
@@ -272,28 +274,30 @@ _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
 
   /* Search the relevant loaded objects for a definition.  */
   for (scope = symbol_scope; *scope; ++scope)
-    if (do_lookup (undef_name, hash, ref, &current_value,
-		   (*scope)->l_searchlist, 0, (*scope)->l_nsearchlist,
-		   reference_name, version, NULL, flags))
-      break;
+    {
+      int res = do_lookup (undef_name, hash, ref, &current_value,
+			   (*scope)->l_searchlist, 0, (*scope)->l_nsearchlist,
+			   reference_name, version, NULL, flags);
+      if (res > 0)
+	break;
+
+      if (res < 0)
+	/* Oh, oh.  The file named in the relocation entry does not
+	   contain the needed symbol.  */
+	_dl_signal_error (0, *reference_name ? reference_name : NULL,
+			  make_string ("symbol ", undef_name, ", version ",
+				       version->name,
+				       " not defined in file ",
+				       version->filename,
+				       " with link time reference"));
+    }
 
   if (current_value.s == NULL &&
       (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK))
-    {
-      /* We could find no value for a strong reference.  */
-      static const char msg1[] = "undefined symbol: ";
-      const size_t len = strlen (undef_name);
-      static const char msg2[] = ", version ";
-      const size_t verslen = strlen (version->name ?: "") + 1;
-      char buf[sizeof msg1 - 1 + len + sizeof msg2 - 1 + verslen];
-
-      memcpy (buf, msg1, sizeof msg1 - 1);
-      memcpy (&buf[sizeof msg1 - 1], undef_name, len + 1);
-      memcpy (&buf[sizeof msg1 - 1 + len], msg2, sizeof msg2 - 1);
-      memcpy (&buf[sizeof msg1 - 1 + len + sizeof msg2 - 1], version->name,
-	      verslen);
-      _dl_signal_error (0, reference_name, buf);
-    }
+    /* We could find no value for a strong reference.  */
+    _dl_signal_error (0, reference_name,
+		      make_string ("undefined symbol: ", undef_name,
+				   ", version ", version->name ?: NULL));
 
   *ref = current_value.s;
   return current_value.a;
@@ -307,20 +311,15 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
 				  const ElfW(Sym) **ref,
 				  struct link_map *symbol_scope[],
 				  const char *reference_name,
-				  const char *version_name,
+				  const struct r_found_version *version,
 				  struct link_map *skip_map,
 				  int flags)
 {
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { 0, NULL };
   struct link_map **scope;
-  hash_name_pair version;
   size_t i;
 
-  /* First convert the VERSION_NAME into a `hash_name_pair' value.  */
-  version.hash = _dl_elf_hash (version_name);
-  version.name = version_name;
-
   /* Search the relevant loaded objects for a definition.  */
   scope = symbol_scope;
   for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i)
@@ -328,11 +327,11 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
 
   if (! do_lookup (undef_name, hash, ref, &current_value,
 		   (*scope)->l_dupsearchlist, i, (*scope)->l_ndupsearchlist,
-		   reference_name, &version, skip_map, flags))
+		   reference_name, version, skip_map, flags))
     while (*++scope)
       if (do_lookup (undef_name, hash, ref, &current_value,
 		     (*scope)->l_dupsearchlist, 0, (*scope)->l_ndupsearchlist,
-		     reference_name, &version, skip_map, flags))
+		     reference_name, version, skip_map, flags))
 	break;
 
   *ref = current_value.s;