glibc/elf/dl-lookup.c
Ulrich Drepper 1f205a479b Update.
1997-05-21 02:49  Ulrich Drepper  <drepper@cygnus.com>

	* gnu-versions.h (_GNU_OBSTACK_INTERFACE_VERSION): Set to 2 since
	interface was changed with addition of _obstack_memory_used.
	Suggested by Ian Taylor <ian@cygnus.com>.

	* malloc/obstack.c: Include <config.h>.  Include <stdlib.h> only
	if __GNU_LIBRARY__ or HAVE_STDLIB_H is defined.
	Reported by Ian Taylor <ian@cygnus.com>.

	* dirent/Makefile (routines): Add versionsort.
	* dirent/dirent.h: Add prototype for versionsort.
	* dirent/versionsort.c: New file.
	* manual/filesys.texi: Add documentation for versionsort.
	* manual/string.texi: Add documentation for strverscmp.
	* string/Makefile (routines): Add strverscmp.
	(tests): Add tst-svc.
	* string/string.h: Add prototype for strverscmp.
	* string/strverscmp.c: New file.
	* string/tst-svc.c: New file.  Test for strverscmp.
	* string/tst-svc.input: New file.  Input data for tst-svc.
	* string/tst-svc.expect: New file.  Expected out from tst-svc.

	* math/Makefile (calls): Add s_signbit.

	* po/sv.po: Update.

	* resolv/nss_dns/dns-host.c: Add casts to prevent warnings.
	* sunrpc/pmap_rmt.c: Likewise.

	* string/basename.c: Don't use ISO C definition style.
	Include <config.h> is HAVE_CONFIG_H is defined.

	* sunrpc/proto.h: Add `const' wherever possible.
	* sunrpc/rpc_cout.c: Likewise.
	* sunrpc/rpc_svcout.c: Likewise.
	* sunrpc/xdr_mem.c: Likewise.
	* sunrpc/xdr_rec.c: Likewise.
	* sunrpc/xdr_stdio.c: Likewise.
	* sunrpc/rpc_parse.c: Delete comma from end of enum definition.
	* sunrpc/xdr.c: Little code cleanups.
	* sunrpc/xdr_flaot.c: Likewise.
	Patches by Matthew Wilcox <matthew.wilcox@chbs.mhs.ciba.com>.

	* sysdeps/i386/fpu/__math.h (__finite): Fix typo.

	* sysdeps/unix/sysv/linux/shmdt.c: Add cast to prevent warning.

	* time/europe: Update from tzdata1997f.
	* time/zic.c: Update from tzcode1997e.

1997-05-20 19:20  Miguel de Icaza <miguel@athena.nuclecu.unam.mx>

	* sysdeps/sparc/setjmp.S: Flush windows.
	Bug found by Richard Henderson.

1997-05-19 12:54  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* misc/efgcvt_r.c (fcvt_r, ecvt_r): Rewritten as to fit the specs.

1997-05-19 18:41  Thorsten Kukuk  <kukuk@uni-paderborn.de>

	* nis/nss_nisplus/nisplus-spwd.c (_nss_nisplus_parse_spent): Use
	atol instead of atoi.

1997-05-18 00:22  Philip Blundell <pjb27@cam.ac.uk>

	* inet/Makefile (routines): Add if_index.
	* sysdeps/unix/sysv/linux/if_index.c: New file.
	* sysdeps/stub/if_index.c: New file.
	* sysdeps/unix/sysv/linux/net/if.h: Add prototypes for routines in
	if_index.c (required by IPv6 basic API).
	* sysdeps/unix/sysv/linux/netinet/in.h: Add struct ipv6_pktinfo.

1997-05-17 23:29  Philip Blundell  <pjb27@cam.ac.uk>

	* sysdeps/unix/sysv/linux/netinet/in.h: Update IPv6 definitions
	for new advanced API draft.

1997-05-13 21:33  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* stdio-common/printf_fp.c: Only use the field width for deciding
	on padding when printing special values.
	* stdio-common/printf_fphex.c: Likewise.

1997-05-15 13:14  Miles Bader  <miles@gnu.ai.mit.edu>

	Changes by Thomas Bushnell <thomas@gnu.ai.mit.edu>:
	* hurd/hurdauth.c (_S_msg_add_auth): Implement correctly.

1997-05-12 14:50  Thomas Bushnell, n/BSG  <thomas@gnu.ai.mit.edu>

	* hurd/hurdsig.c (_hurdsig_init): Double size of sigthread stack;
	msg_add_auth was overflowing it.

1997-05-12 21:20  Richard Henderson  <rth@tamu.edu>

	* elf/dl-lookup.c (_dl_lookup_symbol_skip): Call _dl_signal_error
	when we can't find the symbol.

1997-05-12 16:54  Ulrich Drepper  <drepper@cygnus.com>

	* posix/regex.c: Fix handling of 32-bit Windog environments.
	Patch by Arnold Robbins <arnold@skeeve.atl.ga.us>.

1997-05-10 23:26  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/m68k/syscalls.list: Add cacheflush.

1997-05-10 11:40  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* elf/ldd.bash.in: Remove spurious quote character from version
	message.

1997-05-10 08:49  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* locale/programs/locale.c (write_charmaps): Don't get stuck in a
	loop if the file ends in a long line without newline.
	* locale/programs/charmap.c (charmap_read): Likewise.

1997-05-12 03:47  Ulrich Drepper  <drepper@cygnus.com>

	* sunrpc/rpc/xdr.h: Include more headers to be self-contained.
	* sunrpc/rpc/svc_auth.h: Likewise.
	* sunrpc/rpc/svc.h: Likewise.
	* sunrpc/rpc/rpc_msg.h: Likewise.
	* sunrpc/rpc/pmap_rmt.h: Likewise.
	* sunrpc/rpc/pmap_clnt.h: Likewise.
	* sunrpc/rpc/clnt.h: Likewise.
	* sunrpc/rpc/auth_unix.h: Likewise.
	* sysdeps/generic/rpc/auth.h: Likewise.
	Patches by Michael Deutschmann <ldeutsch@mail.netshop.net>.

1997-05-11 15:29  Philip Blundell  <pjb27@cam.ac.uk>

	* sysdeps/stub/sigaction.c (__sigaction): Correct typo.
	* sysdeps/standalone/arm/errnos.h: New file.
	* sysdeps/stub/sys/param.h: Add dummy definition of MAXSYMLINKS.
	* sysdeps/unix/arm/fork.S: New file.
	* sysdeps/unix/sysv/linux/arm/sysdep.h: New file.
	* sysdeps/stub/tempname.c (__stdio_gen_tempname): Add missing
	`streamptr' argument.
	* sysdeps/stub/vdprintf.c: Remove second copy of file (!), include
	<stdarg.h> to get va_list defined, return 0 not NULL.
	* sysdeps/unix/sysv/linux/statfsbuf.h: Include <gnu/types.h>.
	* sysdeps/unix/sysv/linux/arm/syscall.S: New file.
	* sysdeps/stub/direntry.h (struct dirent): Add missing ';'.
	* sysdeps/stub/seekdir.c (seekdir): Likewise.
	* sysdeps/stub/dirfd.c (dirfd): Argument dirp is DIR*, not FILE*.
	* sysdeps/standalone/dirstream.h: Define struct __dirstream
	not DIR; <dirent.h> provides typedef.
	* sysdeps/unix/sysv/linux/arm/clone.S: New file.
	* sysdeps/unix/sysv/linux/arm/socket.S: New file.
	* sysdeps/stub/sysconf.c (__sysconf): Fix typos.

1997-05-01 06:35  Geoff Keating  <geoffk@ozemail.com.au>

	* sysdeps/powerpc/Dist: New file.
	* sysdeps/powerpc/Makefile: New file.
	* sysdeps/powerpc/fclrexcpt.c: New file.
	* sysdeps/powerpc/fegetenv.c: New file.
	* sysdeps/powerpc/fegetround.c: New file.
	* sysdeps/powerpc/feholdexcpt.c: New file.
	* sysdeps/powerpc/fenvbits.h: New file.
	* sysdeps/powerpc/fenv_const.c: New file.
	* sysdeps/powerpc/fenv_libc.h: New file.
	* sysdeps/powerpc/fesetenv.c: New file.
	* sysdeps/powerpc/fesetround.c: New file.
	* sysdeps/powerpc/feupdateenv.c: New file.
	* sysdeps/powerpc/fgetexcptflg.c: New file.
	* sysdeps/powerpc/fraiseexcpt.c: New file.
	* sysdeps/powerpc/fsetexcptflg.c: New file.
	* sysdeps/powerpc/ftestexcept.c: New file.
	* sysdeps/powerpc/mathbits.h: New file.

	* sysdeps/powerpc/dl-machine.h: Wrap in #ifndef dl_machine_h;
	define elf_machine_lookup_noexec_p, elf_machine_lookup_noplt_p,
	ELF_MACHINE_RELOC_NOPLT; consequent changes to elf_machine_rela.

	* sysdeps/powerpc/__math.h: Remove definition for hypot and __sgn.

	* sysdep/powerpc/fpu_control.h: Correct IEEE default mode.

	* sysdeps/unix/sysv/linux/powerpc/sysdep.h: Don't use .text, but
	instead .section ".text".

1997-04-25 05:06  Geoff Keating  <geoffk@ozemail.com.au>

	* sysdeps/powerpc/__longjmp.S: Use symbolic register numbering.
	* sysdeps/powerpc/bsd-_setjmp.S: Likewise.
	* sysdeps/powerpc/bsd-setjmp.S: Likewise.
	* sysdeps/powerpc/setjmp.S: Likewise.

	* sysdeps/unix/sysv/linux/clone.S: Likewise.
	* sysdeps/unix/sysv/linux/socket.S: Likewise.
	* sysdeps/unix/sysv/linux/syscall.S: Likewise.

1997-04-20 04:37  Geoff Keating  <geoffk@ozemail.com.au>

	* sysdeps/powerpc/strchr.s: New file.
	* sysdeps/powerpc/strcmp.s: New (ugly) file.
	* sysdeps/powerpc/memset.s: New file.
	* string/tester.c: Include prototype and _GNU_SOURCE to make
	standalone compilation possible. Give strcmp a better
	test. Give memset a better test.

1997-04-05 06:34  Geoff Keating  <geoffk@ozemail.com.au>

	* sysdeps/powerpc/strlen.s: Fixed bugs (how did it ever pass its
	tests before?). Changed to symbolic register numbering as an
	experiment.
	* sysdeps/powerpc/ffs.c: Don't include bstring.h, it doesn't
	exist.
	* sysdeps/rs6000/ffs.c: Likewise.

1997-05-12 02:28  Ulrich Drepper  <drepper@cygnus.com>

	* time/sys/time.h: Make second argument of setitimer const.
	Patch by Michael Deutschmann <ldeutsch@mail.netshop.net>.
	* sysdeps/stub/setitimer.c: Likewise.
	* sysdeps/mach/hurd/setitimer.c: Likewise.
1997-05-21 01:48:59 +00:00

365 lines
11 KiB
C

/* Look up a symbol in the loaded objects.
Copyright (C) 1995, 1996, 1997 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
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <stddef.h>
#include <link.h>
#include <assert.h>
#include <string.h>
#include "dl-hash.h"
#include <dl-machine.h>
#include "../stdio-common/_itoa.h"
#define VERSTAG(tag) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
struct sym_val
{
ElfW(Addr) a;
const ElfW(Sym) *s;
};
#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 struct r_found_version *version,
struct link_map *skip, int reloc_type)
{
struct link_map *map;
for (; i < n; ++i)
{
const ElfW(Sym) *symtab;
const char *strtab;
const ElfW(Half) *verstab;
ElfW(Symndx) symidx;
map = list[i];
/* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
if (skip != NULL && map == skip)
continue;
/* Don't search the executable when resolving a copy reloc. */
if (elf_machine_lookup_noexec_p (reloc_type) &&
map->l_type == lt_executable)
continue;
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 (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
verstab = NULL;
/* 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])
{
const ElfW(Sym) *sym = &symtab[symidx];
if (sym->st_value == 0 || /* No value. */
(elf_machine_lookup_noplt_p (reloc_type) /* Reject PLT entry. */
&& sym->st_shndx == SHN_UNDEF))
continue;
switch (ELFW(ST_TYPE) (sym->st_info))
{
case STT_NOTYPE:
case STT_FUNC:
case STT_OBJECT:
break;
default:
/* Not a code/data definition. */
continue;
}
if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
/* Not the symbol we are looking for. */
continue;
if (version == NULL)
{
/* 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))
{
case STB_GLOBAL:
/* Global definition. Just what we need. */
result->s = sym;
result->a = map->l_addr;
return 1;
case STB_WEAK:
/* Weak definition. Use this value if we don't find
another. */
if (! result->s)
{
result->s = sym;
result->a = map->l_addr;
}
break;
default:
/* Local symbols are ignored. */
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. */
return 0;
}
/* Search loaded objects' symbol tables for a definition of the symbol
UNDEF_NAME. */
ElfW(Addr)
_dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
struct link_map *symbol_scope[],
const char *reference_name,
int reloc_type)
{
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { 0, NULL };
struct link_map **scope;
/* 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, NULL, NULL, reloc_type))
break;
if (current_value.s == NULL &&
(*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK))
/* 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;
}
/* This function is nearly the same as `_dl_lookup_symbol' but it
skips in the first list all objects until SKIP_MAP is found. I.e.,
it only considers objects which were loaded after the described
object. If there are more search lists the object described by
SKIP_MAP is only skipped. */
ElfW(Addr)
_dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
struct link_map *symbol_scope[],
const char *reference_name,
struct link_map *skip_map)
{
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { 0, NULL };
struct link_map **scope;
size_t i;
/* Search the relevant loaded objects for a definition. */
scope = symbol_scope;
for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i)
assert (i < (*scope)->l_ndupsearchlist);
if (! do_lookup (undef_name, hash, *ref, &current_value,
(*scope)->l_dupsearchlist, i, (*scope)->l_ndupsearchlist,
reference_name, NULL, skip_map, 0))
while (*++scope)
if (do_lookup (undef_name, hash, *ref, &current_value,
(*scope)->l_dupsearchlist, 0, (*scope)->l_ndupsearchlist,
reference_name, NULL, skip_map, 0))
break;
*ref = current_value.s;
return current_value.a;
}
/* This function works like _dl_lookup_symbol but it takes an
additional arguement with the version number of the requested
symbol.
XXX We'll see whether we need this separate function. */
ElfW(Addr)
_dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
struct link_map *symbol_scope[],
const char *reference_name,
const struct r_found_version *version,
int reloc_type)
{
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { 0, NULL };
struct link_map **scope;
/* Search the relevant loaded objects for a definition. */
for (scope = symbol_scope; *scope; ++scope)
{
int res = do_lookup (undef_name, hash, *ref, &current_value,
(*scope)->l_searchlist, 0, (*scope)->l_nsearchlist,
reference_name, version, NULL, reloc_type);
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. */
_dl_signal_error (0, reference_name,
make_string ("undefined symbol: ", undef_name,
", version ", version->name ?: NULL));
*ref = current_value.s;
return current_value.a;
}
/* Similar to _dl_lookup_symbol_skip but takes an additional argument
with the version we are looking for. */
ElfW(Addr)
_dl_lookup_versioned_symbol_skip (const char *undef_name,
const ElfW(Sym) **ref,
struct link_map *symbol_scope[],
const char *reference_name,
const struct r_found_version *version,
struct link_map *skip_map)
{
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { 0, NULL };
struct link_map **scope;
size_t i;
/* Search the relevant loaded objects for a definition. */
scope = symbol_scope;
for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i)
assert (i < (*scope)->l_ndupsearchlist);
if (! do_lookup (undef_name, hash, *ref, &current_value,
(*scope)->l_dupsearchlist, i, (*scope)->l_ndupsearchlist,
reference_name, version, skip_map, 0))
while (*++scope)
if (do_lookup (undef_name, hash, *ref, &current_value,
(*scope)->l_dupsearchlist, 0, (*scope)->l_ndupsearchlist,
reference_name, version, skip_map, 0))
break;
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);
}
*ref = current_value.s;
return current_value.a;
}
/* Cache the location of MAP's hash table. */
void
_dl_setup_hash (struct link_map *map)
{
ElfW(Symndx) *hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr);
ElfW(Symndx) nchain;
map->l_nbuckets = *hash++;
nchain = *hash++;
map->l_buckets = hash;
hash += map->l_nbuckets;
map->l_chain = hash;
}