1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-01 10:06:57 +03:00
1998-09-06 09:00  Ulrich Drepper  <drepper@cygnus.com>

	* version.h (VERSION): Bump to 2.0.96.

	Rewrite runtime linker to be truly thread-safe.  There is now no
	global variable specifying the scope.  We create all needed
	scopes at the time the link maps are created.
	* elf/Versions [GLIBC_2.1]: Add _dl_loaded and _dl_main_searchlist.
	* elf/link.h: Add struct r_scope_elem and use this for l_searchlist,
	l_symbolic_searchlist, l_scope, and l_local_scope elements in
	struct link_map.
	* elf/dl-close.c: Rewritten accordingly.
	* elf/dl-deps.c: Likewise.
	* elf/dl-error.c: Likewise.
	* elf/dl-init.c: Likewise.
	* elf/dl-load.c: Likewise.
	* elf/dl-lookup.c: Likewise.
	* elf/dl-object.c: Likewise.
	* elf/dl-open.c: Likewise.
	* elf/dl-reloc.c: Likewise.
	* elf/dl-runtime.c: Likewise.
	* elf/dl-support.c: Likewise.
	* elf/dl-symbol.c: Likewise.
	* elf/dl-version.c: Likewise.
	* elf/dlfcn.h: Likewise.
	* elf/dlsym.c: Likewise.
	* elf/dlvsym.c: Likewise.
	* elf/ldsodefs.h: Likewise.
	* elf/rtld.c: Likewise.
	* iconv/gconv_dl.c: Likewise.
	* nss/nsswitch.c: Likewise.
	* sysdeps/i386/dl-machine.h: Likewise.
	* sysdeps/unix/sysv/linux/i386/dl-librecon.h: Likewise.
This commit is contained in:
Ulrich Drepper
1998-09-06 09:16:53 +00:00
parent 9eb71e60ef
commit be93561004
27 changed files with 444 additions and 362 deletions

View File

@ -1,3 +1,37 @@
1998-09-06 09:00 Ulrich Drepper <drepper@cygnus.com>
* version.h (VERSION): Bump to 2.0.96.
Rewrite runtime linker to be truly thread-safe. There is now no
global variable specifying the scope. We create all needed
scopes at the time the link maps are created.
* elf/Versions [GLIBC_2.1]: Add _dl_loaded and _dl_main_searchlist.
* elf/link.h: Add struct r_scope_elem and use this for l_searchlist,
l_symbolic_searchlist, l_scope, and l_local_scope elements in
struct link_map.
* elf/dl-close.c: Rewritten accordingly.
* elf/dl-deps.c: Likewise.
* elf/dl-error.c: Likewise.
* elf/dl-init.c: Likewise.
* elf/dl-load.c: Likewise.
* elf/dl-lookup.c: Likewise.
* elf/dl-object.c: Likewise.
* elf/dl-open.c: Likewise.
* elf/dl-reloc.c: Likewise.
* elf/dl-runtime.c: Likewise.
* elf/dl-support.c: Likewise.
* elf/dl-symbol.c: Likewise.
* elf/dl-version.c: Likewise.
* elf/dlfcn.h: Likewise.
* elf/dlsym.c: Likewise.
* elf/dlvsym.c: Likewise.
* elf/ldsodefs.h: Likewise.
* elf/rtld.c: Likewise.
* iconv/gconv_dl.c: Likewise.
* nss/nsswitch.c: Likewise.
* sysdeps/i386/dl-machine.h: Likewise.
* sysdeps/unix/sysv/linux/i386/dl-librecon.h: Likewise.
1998-09-05 Mark Kettenis <kettenis@phys.uva.nl> 1998-09-05 Mark Kettenis <kettenis@phys.uva.nl>
* sysdeps/mach/hurd/i386/init-first.c (init1): Call * sysdeps/mach/hurd/i386/init-first.c (init1): Call

View File

@ -19,6 +19,7 @@ libc {
GLIBC_2.1 { GLIBC_2.1 {
# global variables # global variables
_dl_profile; _dl_profile_map; _dl_profile_output; _dl_start_profile; _dl_profile; _dl_profile_map; _dl_profile_output; _dl_start_profile;
_dl_loaded; _dl_main_searchlist;
# functions used in other libraries # functions used in other libraries
_dl_mcount; _dl_mcount_wrapper; _dl_mcount_wrapper_check; _dl_unload_cache; _dl_mcount; _dl_mcount_wrapper; _dl_mcount_wrapper_check; _dl_unload_cache;

View File

@ -57,8 +57,8 @@ _dl_close (struct link_map *map)
return; return;
} }
list = map->l_searchlist; list = map->l_searchlist.r_list;
nsearchlist = map->l_nsearchlist; nsearchlist = map->l_searchlist.r_nlist;
/* Call all termination functions at once. */ /* Call all termination functions at once. */
for (i = 0; i < nsearchlist; ++i) for (i = 0; i < nsearchlist; ++i)
@ -103,16 +103,18 @@ _dl_close (struct link_map *map)
if (imap->l_global) if (imap->l_global)
{ {
/* This object is in the global scope list. Remove it. */ /* This object is in the global scope list. Remove it. */
struct link_map **tail = _dl_global_scope_end; unsigned int cnt = _dl_main_searchlist->r_nlist;
do do
--tail; --cnt;
while (*tail != imap); while (_dl_main_searchlist->r_list[cnt] != imap);
while (tail < _dl_global_scope_end) while (cnt < _dl_main_searchlist->r_nlist)
{ {
tail[0] = tail[1]; _dl_main_searchlist->r_list[0]
++tail; = _dl_main_searchlist->r_list[1];
++cnt;
} }
--_dl_global_scope_end; --_dl_main_searchlist->r_nlist;
} }
/* We can unmap all the maps at once. We determined the /* We can unmap all the maps at once. We determined the
@ -135,8 +137,6 @@ _dl_close (struct link_map *map)
#endif #endif
if (imap->l_next) if (imap->l_next)
imap->l_next->l_prev = imap->l_prev; imap->l_next->l_prev = imap->l_prev;
if (imap->l_searchlist && imap->l_searchlist != list)
free (imap->l_searchlist);
if (imap->l_versions != NULL) if (imap->l_versions != NULL)
free (imap->l_versions); free (imap->l_versions);
@ -156,15 +156,14 @@ _dl_close (struct link_map *map)
while (lnp != NULL); while (lnp != NULL);
/* Remove the searchlists. */ /* Remove the searchlists. */
if (imap->l_dupsearchlist != imap->l_searchlist) if (imap->l_searchlist.r_duplist != imap->l_searchlist.r_list)
{ {
/* If a l_searchlist object exists there always also is /* If a r_list exists there always also is a r_duplist. */
a l_dupsearchlist object. */ assert (imap->l_searchlist.r_list != NULL);
assert (imap->l_dupsearchlist != NULL); free (imap->l_searchlist.r_duplist);
free (imap->l_dupsearchlist);
} }
if (imap != map && imap->l_searchlist != NULL) if (imap != map && imap->l_searchlist.r_list != NULL)
free (imap->l_searchlist); free (imap->l_searchlist.r_list);
free (imap); free (imap);
} }

View File

@ -372,32 +372,33 @@ _dl_map_object_deps (struct link_map *map,
/* Store the search list we built in the object. It will be used for /* Store the search list we built in the object. It will be used for
searches in the scope of this object. */ searches in the scope of this object. */
map->l_searchlist = malloc (nlist * sizeof (struct link_map *)); map->l_searchlist.r_list = malloc (nlist * sizeof (struct link_map *));
if (map->l_searchlist == NULL) if (map->l_searchlist.r_list == NULL)
_dl_signal_error (ENOMEM, map->l_name, _dl_signal_error (ENOMEM, map->l_name,
"cannot allocate symbol search list"); "cannot allocate symbol search list");
map->l_nsearchlist = nlist; map->l_searchlist.r_nlist = nlist;
for (nlist = 0, runp = known; runp; runp = runp->unique) for (nlist = 0, runp = known; runp; runp = runp->unique)
{ {
map->l_searchlist[nlist++] = runp->map; map->l_searchlist.r_list[nlist++] = runp->map;
/* Now clear all the mark bits we set in the objects on the search list /* Now clear all the mark bits we set in the objects on the search list
to avoid duplicates, so the next call starts fresh. */ to avoid duplicates, so the next call starts fresh. */
runp->map->l_reserved = 0; runp->map->l_reserved = 0;
} }
map->l_ndupsearchlist = nduplist; map->l_searchlist.r_nduplist = nduplist;
if (nlist == nduplist) if (nlist == nduplist)
map->l_dupsearchlist = map->l_searchlist; map->l_searchlist.r_duplist = map->l_searchlist.r_list;
else else
{ {
map->l_dupsearchlist = malloc (nduplist * sizeof (struct link_map *)); map->l_searchlist.r_duplist = malloc (nduplist
if (map->l_dupsearchlist == NULL) * sizeof (struct link_map *));
if (map->l_searchlist.r_duplist == NULL)
_dl_signal_error (ENOMEM, map->l_name, _dl_signal_error (ENOMEM, map->l_name,
"cannot allocate symbol search list"); "cannot allocate symbol search list");
for (nlist = 0, runp = known; runp; runp = runp->dup) for (nlist = 0, runp = known; runp; runp = runp->dup)
map->l_dupsearchlist[nlist++] = runp->map; map->l_searchlist.r_duplist[nlist++] = runp->map;
} }
} }

View File

@ -22,6 +22,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <elf/ldsodefs.h> #include <elf/ldsodefs.h>
#include <bits/libc-lock.h>
/* This structure communicates state between _dl_catch_error and /* This structure communicates state between _dl_catch_error and
_dl_signal_error. */ _dl_signal_error. */
@ -31,14 +32,57 @@ struct catch
jmp_buf env; /* longjmp here on error. */ jmp_buf env; /* longjmp here on error. */
}; };
/* This points to such a structure during a call to _dl_catch_error. /* Multiple threads at once can use the `_dl_catch_error' function. The
During implicit startup and run-time work for needed shared libraries, calls can come from the `_dl_map_object_deps', `_dlerror_run', or from
this is null. */ any of the libc functionality which loads dynamic objects (NSS, iconv).
Therefore we have to be prepared to safe the state in thread-local
memory. `catch' will only be used for the non-threaded case.
Please note the horrible kludge we have to use to check for the
thread functions to be defined. The problem is that while running
ld.so standalone (i.e., before the relocation with the libc symbols
available) we do not have a real handling of undefined weak symbols.
All symbols are relocated, regardless of the availability. They are
relocated relative to the load address of the dynamic linker. Adding
this start address to zero (the value in the GOT for undefined symbols)
leads to an address which is the load address of ld.so. Once we have
relocated with the libc values the value is NULL if the function is
not available. Our "solution" is to regard NULL and the ld.so load
address as indicators for unavailable weak symbols. */
static struct catch *catch; static struct catch *catch;
#ifdef PIC
# define tsd_setspecific(data) \
if (__libc_internal_tsd_set != (void *) _dl_rtld_map.l_addr \
&& __libc_internal_tsd_set != NULL) \
__libc_internal_tsd_set (_LIBC_TSD_KEY_DL_ERROR, data); \
else \
catch = (data)
# define tsd_getspecific() \
(__libc_internal_tsd_set != (void *) _dl_rtld_map.l_addr \
&& __libc_internal_tsd_set != NULL \
? (struct catch *) __libc_internal_tsd_get (_LIBC_TSD_KEY_DL_ERROR) \
: catch)
#else
# define tsd_setspecific(data) \
if (__libc_internal_tsd_set != NULL) \
__libc_internal_tsd_set (_LIBC_TSD_KEY_DL_ERROR, data); \
else \
catch = (data)
# define tsd_getspecific() \
(__libc_internal_tsd_set != NULL \
? (struct catch *) __libc_internal_tsd_get (_LIBC_TSD_KEY_DL_ERROR) \
: catch)
#endif
/* This points to a function which is called when an error is /* This points to a function which is called when an error is
received. Unlike the handling of `catch' this function may return. received. Unlike the handling of `catch' this function may return.
The arguments will be the `errstring' and `objname'. */ The arguments will be the `errstring' and `objname'.
Since this functionality is not used in normal programs (only in ld.so)
we do not care about multi-threaded programs here. We keep this as a
global variable. */
static receiver_fct receiver; static receiver_fct receiver;
@ -48,27 +92,30 @@ _dl_signal_error (int errcode,
const char *objname, const char *objname,
const char *errstring) const char *errstring)
{ {
struct catch *lcatch;
if (! errstring) if (! errstring)
errstring = "DYNAMIC LINKER BUG!!!"; errstring = "DYNAMIC LINKER BUG!!!";
if (catch) lcatch = tsd_getspecific ();
if (lcatch != NULL)
{ {
/* We are inside _dl_catch_error. Return to it. We have to /* We are inside _dl_catch_error. Return to it. We have to
duplicate the error string since it might be allocated on the duplicate the error string since it might be allocated on the
stack. */ stack. */
size_t objname_len = objname ? strlen (objname) + 2 : 0; size_t objname_len = objname ? strlen (objname) + 2 : 0;
size_t errstring_len = strlen (errstring) + 1; size_t errstring_len = strlen (errstring) + 1;
catch->errstring = malloc (objname_len + errstring_len); lcatch->errstring = malloc (objname_len + errstring_len);
if (catch->errstring != NULL) if (lcatch->errstring != NULL)
{ {
if (objname_len > 0) if (objname_len > 0)
{ {
memcpy (catch->errstring, objname, objname_len - 2); memcpy (lcatch->errstring, objname, objname_len - 2);
memcpy (catch->errstring + objname_len - 2, ": ", 2); memcpy (lcatch->errstring + objname_len - 2, ": ", 2);
} }
memcpy (catch->errstring + objname_len, errstring, errstring_len); memcpy (lcatch->errstring + objname_len, errstring, errstring_len);
} }
longjmp (catch->env, errcode ?: -1); longjmp (lcatch->env, errcode ?: -1);
} }
else if (receiver) else if (receiver)
{ {
@ -106,19 +153,19 @@ _dl_catch_error (char **errstring,
inefficient. So we initialize `c' by hand. */ inefficient. So we initialize `c' by hand. */
c.errstring = NULL; c.errstring = NULL;
old = catch; old = tsd_getspecific ();
errcode = setjmp (c.env); errcode = setjmp (c.env);
if (errcode == 0) if (errcode == 0)
{ {
catch = &c; tsd_setspecific (&c);
(*operate) (args); (*operate) (args);
catch = old; tsd_setspecific (old);
*errstring = NULL; *errstring = NULL;
return 0; return 0;
} }
/* We get here only if we longjmp'd out of OPERATE. */ /* We get here only if we longjmp'd out of OPERATE. */
catch = old; tsd_setspecific (old);
*errstring = c.errstring; *errstring = c.errstring;
return errcode == -1 ? 0 : errcode; return errcode == -1 ? 0 : errcode;
} }
@ -130,15 +177,15 @@ _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
struct catch *old_catch; struct catch *old_catch;
receiver_fct old_receiver; receiver_fct old_receiver;
old_catch = catch; old_catch = tsd_getspecific ();
old_receiver = receiver; old_receiver = receiver;
/* Set the new values. */ /* Set the new values. */
catch = NULL; tsd_setspecific (NULL);
receiver = fct; receiver = fct;
(*operate) (args); (*operate) (args);
catch = old_catch; tsd_setspecific (old_catch);
receiver = old_receiver; receiver = old_receiver;
} }

View File

@ -26,7 +26,7 @@
ElfW(Addr) ElfW(Addr)
internal_function internal_function
_dl_init_next (struct link_map *map) _dl_init_next (struct r_scope_elem *searchlist)
{ {
unsigned int i; unsigned int i;
@ -34,10 +34,10 @@ _dl_init_next (struct link_map *map)
dependency order, so processing that list from back to front gets us dependency order, so processing that list from back to front gets us
breadth-first leaf-to-root order. */ breadth-first leaf-to-root order. */
i = map->l_nsearchlist; i = searchlist->r_nlist;
while (i-- > 0) while (i-- > 0)
{ {
struct link_map *l = map->l_searchlist[i]; struct link_map *l = searchlist->r_list[i];
if (l->l_init_called) if (l->l_init_called)
/* This object is all done. */ /* This object is all done. */
@ -53,8 +53,8 @@ _dl_init_next (struct link_map *map)
continue; continue;
} }
if (l->l_info[DT_INIT] && if (l->l_info[DT_INIT]
!(l->l_name[0] == '\0' && l->l_type == lt_executable)) && (l->l_name[0] != '\0' || l->l_type != lt_executable))
{ {
/* Run this object's initializer. */ /* Run this object's initializer. */
l->l_init_running = 1; l->l_init_running = 1;

View File

@ -529,7 +529,12 @@ _dl_init_paths (const char *llp)
l = _dl_loaded; l = _dl_loaded;
if (l != NULL) if (l != NULL)
{ {
if (l->l_type != lt_loaded && l->l_info[DT_RPATH]) /* We should never get here when initializing in a static application.
If this is a dynamically linked application _dl_loaded always
points to the main map which is not dlopen()ed. */
assert (l->l_type != lt_loaded);
if (l->l_info[DT_RPATH])
{ {
/* Allocate room for the search path and fill in information /* Allocate room for the search path and fill in information
from RPATH. */ from RPATH. */
@ -727,11 +732,10 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
#endif #endif
/* Enter the new object in the list of loaded objects. */ /* Enter the new object in the list of loaded objects. */
l = _dl_new_object (realname, name, l_type); l = _dl_new_object (realname, name, l_type, loader);
if (! l) if (! l)
lose (ENOMEM, "cannot create shared object descriptor"); lose (ENOMEM, "cannot create shared object descriptor");
l->l_opencount = 1; l->l_opencount = 1;
l->l_loader = loader;
/* Extract the remaining details we need from the ELF header /* Extract the remaining details we need from the ELF header
and then read in the program header table. */ and then read in the program header table. */
@ -973,6 +977,35 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
if (l->l_info[DT_HASH]) if (l->l_info[DT_HASH])
_dl_setup_hash (l); _dl_setup_hash (l);
/* If this object has DT_SYMBOLIC set modify now its scope. We don't
have to do this for the main map. */
if (l->l_info[DT_SYMBOLIC] && &l->l_searchlist != l->l_scope[0])
{
/* Create an appropriate searchlist. It contains only this map.
XXX This is the definition of DT_SYMBOLIC in SysVr4. The old
GNU ld.so implementation had a different interpretation which
is more reasonable. We are prepared to add this possibility
back as part of a GNU extension of the ELF format. */
l->l_symbolic_searchlist.r_list =
(struct link_map **) malloc (sizeof (struct link_map *));
if (l->l_symbolic_searchlist.r_list == NULL)
lose (ENOMEM, "cannot create searchlist");
l->l_symbolic_searchlist.r_list[0] = l;
l->l_symbolic_searchlist.r_nlist = 1;
l->l_symbolic_searchlist.r_duplist = l->l_symbolic_searchlist.r_list;
l->l_symbolic_searchlist.r_nduplist = 1;
/* Now move the existing entries one back. */
memmove (&l->l_scope[1], &l->l_scope[0],
3 * sizeof (struct r_scope_elem *));
/* Now add the new entry. */
l->l_scope[0] = &l->l_symbolic_searchlist;
}
return l; return l;
} }
@ -1280,7 +1313,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
/* Enter the new object in the list of loaded objects. */ /* Enter the new object in the list of loaded objects. */
if ((name_copy = local_strdup (name)) == NULL if ((name_copy = local_strdup (name)) == NULL
|| (l = _dl_new_object (name_copy, name, type)) == NULL) || (l = _dl_new_object (name_copy, name, type, loader)) == NULL)
_dl_signal_error (ENOMEM, name, _dl_signal_error (ENOMEM, name,
"cannot create shared object descriptor"); "cannot create shared object descriptor");
/* We use an opencount of 0 as a sign for the faked entry. */ /* We use an opencount of 0 as a sign for the faked entry. */

View File

@ -63,12 +63,12 @@ struct sym_val
static inline int static inline int
do_lookup (const char *undef_name, unsigned long int hash, do_lookup (const char *undef_name, unsigned long int hash,
const ElfW(Sym) *ref, struct sym_val *result, const ElfW(Sym) *ref, struct sym_val *result,
struct link_map *scope, size_t i, const char *reference_name, struct r_scope_elem *scope, size_t i, const char *reference_name,
const struct r_found_version *version, struct link_map *skip, const struct r_found_version *version, struct link_map *skip,
int reloc_type) int reloc_type)
{ {
struct link_map **list = scope->l_searchlist; struct link_map **list = scope->r_list;
size_t n = scope->l_nsearchlist; size_t n = scope->r_nlist;
struct link_map *map; struct link_map *map;
for (; i < n; ++i) for (; i < n; ++i)
@ -212,13 +212,13 @@ do_lookup (const char *undef_name, unsigned long int hash,
ElfW(Addr) ElfW(Addr)
internal_function internal_function
_dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref, _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
struct link_map *symbol_scope[], struct r_scope_elem *symbol_scope[],
const char *reference_name, const char *reference_name,
int reloc_type) int reloc_type)
{ {
const unsigned long int hash = _dl_elf_hash (undef_name); const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL }; struct sym_val current_value = { NULL, NULL };
struct link_map **scope; struct r_scope_elem **scope;
/* Search the relevant loaded objects for a definition. */ /* Search the relevant loaded objects for a definition. */
for (scope = symbol_scope; *scope; ++scope) for (scope = symbol_scope; *scope; ++scope)
@ -260,19 +260,19 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
ElfW(Addr) ElfW(Addr)
internal_function internal_function
_dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref, _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
struct link_map *symbol_scope[], struct r_scope_elem *symbol_scope[],
const char *reference_name, const char *reference_name,
struct link_map *skip_map) struct link_map *skip_map)
{ {
const unsigned long int hash = _dl_elf_hash (undef_name); const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL }; struct sym_val current_value = { NULL, NULL };
struct link_map **scope; struct r_scope_elem **scope;
size_t i; size_t i;
/* Search the relevant loaded objects for a definition. */ /* Search the relevant loaded objects for a definition. */
scope = symbol_scope; scope = symbol_scope;
for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i) for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
assert (i < (*scope)->l_ndupsearchlist); assert (i < (*scope)->r_nduplist);
if (! do_lookup (undef_name, hash, *ref, &current_value, if (! do_lookup (undef_name, hash, *ref, &current_value,
*scope, i, reference_name, NULL, skip_map, 0)) *scope, i, reference_name, NULL, skip_map, 0))
@ -309,14 +309,14 @@ _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
ElfW(Addr) ElfW(Addr)
internal_function internal_function
_dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref, _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
struct link_map *symbol_scope[], struct r_scope_elem *symbol_scope[],
const char *reference_name, const char *reference_name,
const struct r_found_version *version, const struct r_found_version *version,
int reloc_type) int reloc_type)
{ {
const unsigned long int hash = _dl_elf_hash (undef_name); const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL }; struct sym_val current_value = { NULL, NULL };
struct link_map **scope; struct r_scope_elem **scope;
/* Search the relevant loaded objects for a definition. */ /* Search the relevant loaded objects for a definition. */
for (scope = symbol_scope; *scope; ++scope) for (scope = symbol_scope; *scope; ++scope)
@ -375,20 +375,20 @@ ElfW(Addr)
internal_function internal_function
_dl_lookup_versioned_symbol_skip (const char *undef_name, _dl_lookup_versioned_symbol_skip (const char *undef_name,
const ElfW(Sym) **ref, const ElfW(Sym) **ref,
struct link_map *symbol_scope[], struct r_scope_elem *symbol_scope[],
const char *reference_name, const char *reference_name,
const struct r_found_version *version, const struct r_found_version *version,
struct link_map *skip_map) struct link_map *skip_map)
{ {
const unsigned long int hash = _dl_elf_hash (undef_name); const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL }; struct sym_val current_value = { NULL, NULL };
struct link_map **scope; struct r_scope_elem **scope;
size_t i; size_t i;
/* Search the relevant loaded objects for a definition. */ /* Search the relevant loaded objects for a definition. */
scope = symbol_scope; scope = symbol_scope;
for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i) for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
assert (i < (*scope)->l_ndupsearchlist); assert (i < (*scope)->r_nduplist);
if (! do_lookup (undef_name, hash, *ref, &current_value, if (! do_lookup (undef_name, hash, *ref, &current_value,
*scope, i, reference_name, version, skip_map, 0)) *scope, i, reference_name, version, skip_map, 0))

View File

@ -25,16 +25,17 @@
#include <assert.h> #include <assert.h>
/* List of objects currently loaded is [2] of this, aka _dl_loaded. */
struct link_map *_dl_default_scope[5];
/* Allocate a `struct link_map' for a new object being loaded, /* Allocate a `struct link_map' for a new object being loaded,
and enter it into the _dl_loaded list. */ and enter it into the _dl_loaded list. */
struct link_map * struct link_map *
internal_function internal_function
_dl_new_object (char *realname, const char *libname, int type) _dl_new_object (char *realname, const char *libname, int type,
struct link_map *loader)
{ {
struct link_map *l;
int idx;
size_t libname_len = strlen (libname) + 1; size_t libname_len = strlen (libname) + 1;
struct link_map *new = calloc (sizeof *new, 1); struct link_map *new = calloc (sizeof *new, 1);
struct libname_list *newname = malloc (sizeof *newname + libname_len); struct libname_list *newname = malloc (sizeof *newname + libname_len);
@ -46,26 +47,37 @@ _dl_new_object (char *realname, const char *libname, int type)
newname->next = NULL; newname->next = NULL;
new->l_libname = newname; new->l_libname = newname;
new->l_type = type; new->l_type = type;
new->l_loader = loader;
if (_dl_loaded == NULL) /* Counter for the scopes we have to handle. */
idx = 0;
if (_dl_loaded != NULL)
{ {
new->l_prev = new->l_next = NULL; l = _dl_loaded;
_dl_loaded = new;
}
else
{
struct link_map *l = _dl_loaded;
while (l->l_next) while (l->l_next)
l = l->l_next; l = l->l_next;
new->l_prev = l; new->l_prev = l;
new->l_next = NULL; /* new->l_next = NULL; Would be necesary but we use calloc. */
l->l_next = new; l->l_next = new;
}
/* Don't try to find the origin for the main map. */ /* Add the global scope. */
if (realname[0] == '\0') new->l_scope[idx++] = &_dl_loaded->l_searchlist;
new->l_origin = NULL; }
/* This is our local scope. */
if (loader != NULL)
{
while (loader->l_loader != NULL)
loader = loader->l_loader;
new->l_scope[idx] = &loader->l_searchlist;
}
else else
new->l_scope[idx] = &new->l_searchlist;
new->l_local_scope[0] = new->l_scope[idx];
/* Don't try to find the origin for the main map which has the name "". */
if (realname[0] != '\0')
{ {
char *origin; char *origin;

View File

@ -77,7 +77,7 @@ dl_open_worker (void *a)
/* Load the named object. */ /* Load the named object. */
args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0); args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0);
if (new->l_searchlist) if (new->l_searchlist.r_list)
/* It was already open. */ /* It was already open. */
return; return;
@ -97,21 +97,6 @@ dl_open_worker (void *a)
{ {
if (! l->l_relocated) if (! l->l_relocated)
{ {
/* We use an indirect call call for _dl_relocate_object because
we must avoid using the PLT in the call. If our PLT entry for
_dl_relocate_object hasn't been used yet, then the dynamic
linker fixup routine will clobber _dl_global_scope during its
work. We must be sure that nothing will require a PLT fixup
between when _dl_object_relocation_scope returns and when we
enter the dynamic linker's code (_dl_relocate_object). */
__typeof (_dl_relocate_object) *reloc = &_dl_relocate_object;
/* GCC is very clever. If we wouldn't add some magic it would
simply optimize away our nice little variable `reloc' and we
would result in a not working binary. So let's swing the
magic ward. */
asm ("" : "=r" (reloc) : "0" (reloc));
#ifdef PIC #ifdef PIC
if (_dl_profile != NULL) if (_dl_profile != NULL)
{ {
@ -122,7 +107,7 @@ dl_open_worker (void *a)
start the profiling. */ start the profiling. */
struct link_map *old_profile_map = _dl_profile_map; struct link_map *old_profile_map = _dl_profile_map;
(*reloc) (l, _dl_object_relocation_scope (l), 1, 1); _dl_relocate_object (l, l->l_scope, 1, 1);
if (old_profile_map == NULL && _dl_profile_map != NULL) if (old_profile_map == NULL && _dl_profile_map != NULL)
/* We must prepare the profiling. */ /* We must prepare the profiling. */
@ -130,10 +115,8 @@ dl_open_worker (void *a)
} }
else else
#endif #endif
(*reloc) (l, _dl_object_relocation_scope (l), _dl_relocate_object (l, l->l_scope,
(mode & RTLD_BINDING_MASK) == RTLD_LAZY, 0); (mode & RTLD_BINDING_MASK) == RTLD_LAZY, 0);
*_dl_global_scope_end = NULL;
} }
if (l == new) if (l == new)
@ -146,50 +129,58 @@ dl_open_worker (void *a)
{ {
/* The symbols of the new object and its dependencies are to be /* The symbols of the new object and its dependencies are to be
introduced into the global scope that will be used to resolve introduced into the global scope that will be used to resolve
references from other dynamically-loaded objects. */ references from other dynamically-loaded objects.
The global scope is the searchlist in the main link map. We
extend this list if necessary. There is one problem though:
since this structure was allocated very early (before the libc
is loaded) the memory it uses is allocated by the malloc()-stub
in the ld.so. When we come here these functions are not used
anymore. Instead the malloc() implementation of the libc is
used. But this means the block from the main map cannot be used
in an realloc() call. Therefore we allocate a completely new
array the first time we have to add something to the locale scope. */
if (_dl_global_scope_alloc == 0) if (_dl_global_scope_alloc == 0)
{ {
/* This is the first dynamic object given global scope. */ /* This is the first dynamic object given global scope. */
_dl_global_scope_alloc = 8; struct link_map **new_global;
_dl_global_scope = malloc (_dl_global_scope_alloc
* sizeof (struct link_map *)); _dl_global_scope_alloc = _dl_main_searchlist->r_nlist + 8;
if (! _dl_global_scope) new_global = (struct link_map **)
malloc (_dl_global_scope_alloc * sizeof (struct link_map *));
if (new_global == NULL)
{ {
_dl_global_scope = _dl_default_scope; _dl_global_scope_alloc = 0;
nomem: nomem:
new->l_global = 0; new->l_global = 0;
_dl_signal_error (ENOMEM, file, "cannot extend global scope"); _dl_signal_error (ENOMEM, file, "cannot extend global scope");
} }
_dl_global_scope[2] = _dl_default_scope[2];
_dl_global_scope[3] = new;
_dl_global_scope[4] = NULL;
_dl_global_scope[5] = NULL;
_dl_global_scope_end = &_dl_global_scope [4];
}
else
{
if (_dl_global_scope_end + 3
> _dl_global_scope + _dl_global_scope_alloc)
{
/* Must extend the list. */
struct link_map **new = realloc (_dl_global_scope,
_dl_global_scope_alloc * 2
* sizeof (struct link_map *));
if (! new)
goto nomem;
_dl_global_scope = new;
_dl_global_scope_end = new + _dl_global_scope_alloc - 2;
_dl_global_scope_alloc *= 2;
}
/* Append the new object and re-terminate the list. */ /* Copy over the old entries. */
*_dl_global_scope_end++ = new; memcpy (new_global, _dl_main_searchlist->r_list,
/* We keep the list double-terminated so the last element (_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
can be filled in for symbol lookups. */
_dl_global_scope_end[0] = NULL; _dl_main_searchlist->r_list = new_global;
_dl_global_scope_end[1] = NULL;
} }
else if (_dl_main_searchlist->r_nlist == _dl_global_scope_alloc)
{
/* We have to extend the existing array of link maps in the
main map. */
struct link_map **new_global;
new_global = (struct link_map **)
malloc ((_dl_global_scope_alloc + 8) * sizeof (struct link_map *));
if (new_global == NULL)
goto nomem;
_dl_global_scope_alloc += 8;
_dl_main_searchlist->r_list = new_global;
}
/* Now add the new entry. */
_dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = new;
/* XXX Do we have to add something to r_dupsearchlist??? --drepper */
} }
@ -201,10 +192,14 @@ dl_open_worker (void *a)
_dl_debug_state (); _dl_debug_state ();
/* Run the initializer functions of new objects. */ /* Run the initializer functions of new objects. */
while (init = _dl_init_next (new)) while (init = _dl_init_next (&new->l_searchlist))
(*(void (*) (int, char **, char **)) init) (__libc_argc, __libc_argv, (*(void (*) (int, char **, char **)) init) (__libc_argc, __libc_argv,
__environ); __environ);
if (new->l_global)
/* Now we can make the new map available in the global scope. */
++_dl_main_searchlist->r_nlist;
if (_dl_sysdep_start == NULL) if (_dl_sysdep_start == NULL)
/* We must be the static _dl_open in libc.a. A static program that /* We must be the static _dl_open in libc.a. A static program that
has loaded a dynamic object now has competition. */ has loaded a dynamic object now has competition. */
@ -241,9 +236,6 @@ _dl_open (const char *file, int mode)
/* Some error occured during loading. */ /* Some error occured during loading. */
char *local_errstring; char *local_errstring;
/* Reset the global scope. */
*_dl_global_scope_end = NULL;
/* Remove the object from memory. It may be in an inconsistent /* Remove the object from memory. It may be in an inconsistent
state if relocation failed, for example. */ state if relocation failed, for example. */
if (args.map) if (args.map)

View File

@ -27,8 +27,8 @@
void void
_dl_relocate_object (struct link_map *l, struct link_map *scope[], int lazy, _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
int consider_profiling) int lazy, int consider_profiling)
{ {
if (l->l_relocated) if (l->l_relocated)
return; return;

View File

@ -19,63 +19,6 @@
#include <unistd.h> #include <unistd.h>
#include <elf/ldsodefs.h> #include <elf/ldsodefs.h>
/* The global scope we will use for symbol lookups.
This will be modified by _dl_open if RTLD_GLOBAL is used. */
struct link_map **_dl_global_scope = _dl_default_scope;
struct link_map **_dl_global_scope_end = &_dl_default_scope[3];
/* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into
_dl_global_scope that should be passed to _dl_lookup_symbol for symbol
references made in the object L's relocations. */
inline struct link_map **
internal_function
_dl_object_relocation_scope (struct link_map *l)
{
if (l->l_info[DT_SYMBOLIC])
{
/* This object's global references are to be resolved first
in the object itself, and only secondarily in more global
scopes. */
if (! l->l_searchlist)
/* We must construct the searchlist for this object. */
_dl_map_object_deps (l, NULL, 0, 0);
/* The primary scope is this object itself and its
dependencies.
XXX This is wrong. Only the object must be searched, not
the dependencies. --drepper */
_dl_global_scope[0] = l;
/* Secondary is the dependency tree that reached L; the object
requested directly by the user is at the root of that tree. */
while (l->l_loader)
l = l->l_loader;
_dl_global_scope[1] = l;
/* Finally, the global scope follows. */
return _dl_global_scope;
}
else
{
/* Use first the global scope, and then the scope of the root of the
dependency tree that first caused this object to be loaded. */
while (l->l_loader)
l = l->l_loader;
/* There is no point in searching the same list twice. This isn't
guaranteed to always find all duplicates if new objects are added
to the global scope, but is good enough most of the time. */
if (_dl_global_scope[2] != l)
*_dl_global_scope_end = l;
return &_dl_global_scope[2];
}
}
#include "dynamic-link.h" #include "dynamic-link.h"
#if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL #if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL
@ -115,9 +58,6 @@ fixup (
void *const rel_addr = (void *)(l->l_addr + reloc->r_offset); void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
ElfW(Addr) value; ElfW(Addr) value;
/* Set up the scope to find symbols referenced by this object. */
struct link_map **scope = _dl_object_relocation_scope (l);
/* Sanity check that we're really looking at a PLT relocation. */ /* Sanity check that we're really looking at a PLT relocation. */
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
@ -134,13 +74,13 @@ fixup (
if (version->hash != 0) if (version->hash != 0)
{ {
value = _dl_lookup_versioned_symbol(strtab + sym->st_name, value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
&sym, scope, l->l_name, &sym, l->l_scope, l->l_name,
version, ELF_MACHINE_JMP_SLOT); version, ELF_MACHINE_JMP_SLOT);
break; break;
} }
} }
case 0: case 0:
value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope, value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
l->l_name, ELF_MACHINE_JMP_SLOT); l->l_name, ELF_MACHINE_JMP_SLOT);
} }
@ -154,8 +94,6 @@ fixup (
/* Finally, fix up the plt itself. */ /* Finally, fix up the plt itself. */
elf_machine_fixup_plt (l, reloc, rel_addr, value); elf_machine_fixup_plt (l, reloc, rel_addr, value);
*_dl_global_scope_end = NULL;
return value; return value;
} }
@ -191,9 +129,6 @@ profile_fixup (
reloc_offset); reloc_offset);
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
/* Set up the scope to find symbols referenced by this object. */
struct link_map **scope = _dl_object_relocation_scope (l);
/* Sanity check that we're really looking at a PLT relocation. */ /* Sanity check that we're really looking at a PLT relocation. */
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
@ -210,14 +145,14 @@ profile_fixup (
if (version->hash != 0) if (version->hash != 0)
{ {
value = _dl_lookup_versioned_symbol(strtab + sym->st_name, value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
&sym, scope, l->l_name, &sym, l->l_scope,
version, l->l_name, version,
ELF_MACHINE_JMP_SLOT); ELF_MACHINE_JMP_SLOT);
break; break;
} }
} }
case 0: case 0:
value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope, value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
l->l_name, ELF_MACHINE_JMP_SLOT); l->l_name, ELF_MACHINE_JMP_SLOT);
} }
@ -228,8 +163,6 @@ profile_fixup (
/* And now perhaps the relocation addend. */ /* And now perhaps the relocation addend. */
value = elf_machine_plt_value (l, reloc, value); value = elf_machine_plt_value (l, reloc, value);
*_dl_global_scope_end = NULL;
/* Store the result for later runs. */ /* Store the result for later runs. */
*resultp = value; *resultp = value;
} }

View File

@ -66,6 +66,20 @@ void *__libc_stack_end;
/* Path where the binary is found. */ /* Path where the binary is found. */
const char *_dl_origin_path; const char *_dl_origin_path;
/* Initially empty list of loaded objects. */
struct link_map *_dl_loaded;
/* Fake scope. In dynamically linked binaries this is the scope of the
main application but here we don't have something like this. So
create a fake scope containing nothing. */
static struct r_scope_elem fake_scope;
/* Variable which can be used in lookup to process the global scope. */
struct r_scope_elem *_dl_global_scope[2] = { &fake_scope, NULL };
/* This is a global pointer to this structure which is public. It is
used by dlopen/dlclose to add and remove objects from what is regarded
to be the global scope. */
struct r_scope_elem *_dl_main_searchlist = &fake_scope;
static void non_dynamic_init (void) __attribute__ ((unused)); static void non_dynamic_init (void) __attribute__ ((unused));

View File

@ -28,7 +28,7 @@ _dl_symbol_value (struct link_map *map, const char *name)
{ {
ElfW(Addr) loadbase; ElfW(Addr) loadbase;
const ElfW(Sym) *ref = NULL; const ElfW(Sym) *ref = NULL;
struct link_map *scope[2] = { map, NULL }; loadbase = _dl_lookup_symbol (name, &ref, map->l_local_scope, map->l_name,
loadbase = _dl_lookup_symbol (name, &ref, scope, map->l_name, 0); 0);
return loadbase + ref->st_value; return loadbase + ref->st_value;
} }

View File

@ -61,9 +61,9 @@ find_needed (const char *name, struct link_map *map)
/* The required object is not in the global scope, look to see if it is /* The required object is not in the global scope, look to see if it is
a dependency of the current object. */ a dependency of the current object. */
for (n = 0; n < map->l_nsearchlist; n++) for (n = 0; n < map->l_searchlist.r_nlist; n++)
if (_dl_name_match_p (name, map->l_searchlist[n])) if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
return map->l_searchlist[n]; return map->l_searchlist.r_list[n];
/* Should never happen. */ /* Should never happen. */
return NULL; return NULL;

View File

@ -21,16 +21,23 @@
#define _DLFCN_H 1 #define _DLFCN_H 1
#include <features.h> #include <features.h>
#define __need_NULL
#include <stddef.h>
/* Collect various system dependand definitions and declarations. */ /* Collect various system dependand definitions and declarations. */
#include <bits/dlfcn.h> #include <bits/dlfcn.h>
/* If the first argument of `dlsym' is set to RTLD_NEXT the run-time /* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT
address of the symbol called NAME in the next shared object is the run-time address of the symbol called NAME in the next shared
returned. The "next" relation is defined by the order the shared object is returned. The "next" relation is defined by the order
objects were loaded. */ the shared objects were loaded. */
#define RTLD_NEXT ((void *) -1l) #define RTLD_NEXT ((void *) -1l)
/* If the first argument to `dlsym' or `dlvsym' is set to RTLD_DEFAULT
the run-time address of the symbol called NAME in the global scope
is returned. */
#define RTLD_DEFAULT NULL
__BEGIN_DECLS __BEGIN_DECLS
/* Open the shared object FILE and map it in; return a handle that can be /* Open the shared object FILE and map it in; return a handle that can be
@ -57,6 +64,7 @@ extern void *dlvsym __P ((void *__handle, __const char *__name,
the error string so that a following call returns null. */ the error string so that a following call returns null. */
extern char *dlerror __P ((void)); extern char *dlerror __P ((void));
#ifdef __USE_GNU
/* Fill in *INFO with the following information about ADDRESS. /* Fill in *INFO with the following information about ADDRESS.
Returns 0 iff no shared object's segments contain that address. */ Returns 0 iff no shared object's segments contain that address. */
typedef struct typedef struct
@ -68,7 +76,6 @@ typedef struct
} Dl_info; } Dl_info;
extern int dladdr __P ((const void *__address, Dl_info *__info)); extern int dladdr __P ((const void *__address, Dl_info *__info));
#ifdef __USE_GNU
/* To support profiling of shared objects it is a good idea to call /* To support profiling of shared objects it is a good idea to call
the function found using `dlsym' using the following macro since the function found using `dlsym' using the following macro since
these calls do not use the PLT. But this would mean the dynamic these calls do not use the PLT. But this would mean the dynamic

View File

@ -44,9 +44,7 @@ dlsym_doit (void *a)
if (args->handle == NULL) if (args->handle == NULL)
/* Search the global scope. */ /* Search the global scope. */
args->loadbase = _dl_lookup_symbol (args->name, &args->ref, args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
&(_dl_global_scope _dl_global_scope, NULL, 0);
?: _dl_default_scope)[2],
NULL, 0);
else if (args->handle == RTLD_NEXT) else if (args->handle == RTLD_NEXT)
{ {
struct link_map *l, *match; struct link_map *l, *match;
@ -65,19 +63,15 @@ RTLD_NEXT used in code not dynamically loaded"));
while (l->l_loader) while (l->l_loader)
l = l->l_loader; l = l->l_loader;
{ args->loadbase = _dl_lookup_symbol_skip (args->name, &args->ref,
struct link_map *mapscope[2] = { l, NULL }; l->l_local_scope, NULL, match);
args->loadbase = _dl_lookup_symbol_skip (args->name, &args->ref,
mapscope, NULL, match);
}
} }
else else
{ {
/* Search the scope of the given object. */ /* Search the scope of the given object. */
struct link_map *map = args->handle; struct link_map *map = args->handle;
struct link_map *mapscope[2] = { map, NULL }; args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
args->loadbase = _dl_lookup_symbol (args->name, &args->ref, mapscope, map->l_local_scope, map->l_name, 0);
map->l_name, 0);
} }
} }

View File

@ -46,8 +46,7 @@ dlvsym_doit (void *a)
if (args->handle == NULL) if (args->handle == NULL)
/* Search the global scope. */ /* Search the global scope. */
args->loadbase = _dl_lookup_versioned_symbol (args->name, &args->ref, args->loadbase = _dl_lookup_versioned_symbol (args->name, &args->ref,
&(_dl_global_scope _dl_global_scope,
?: _dl_default_scope)[2],
NULL, &args->version, 0); NULL, &args->version, 0);
else if (args->handle == RTLD_NEXT) else if (args->handle == RTLD_NEXT)
{ {
@ -67,23 +66,19 @@ RTLD_NEXT used in code not dynamically loaded"));
while (l->l_loader) while (l->l_loader)
l = l->l_loader; l = l->l_loader;
{ args->loadbase = _dl_lookup_versioned_symbol_skip (args->name,
struct link_map *mapscope[2] = { l, NULL }; &args->ref,
args->loadbase = _dl_lookup_versioned_symbol_skip (args->name, l->l_local_scope,
&args->ref, NULL, &args->version,
mapscope, match);
NULL,
&args->version,
match);
}
} }
else else
{ {
/* Search the scope of the given object. */ /* Search the scope of the given object. */
struct link_map *map = args->handle; struct link_map *map = args->handle;
struct link_map *mapscope[2] = { map, NULL };
args->loadbase = _dl_lookup_versioned_symbol (args->name, &args->ref, args->loadbase = _dl_lookup_versioned_symbol (args->name, &args->ref,
mapscope, map->l_name, map->l_local_scope,
map->l_name,
&args->version, 0); &args->version, 0);
} }
} }

View File

@ -282,7 +282,7 @@ extern void _dl_close (struct link_map *map)
symbols can be chosen. */ symbols can be chosen. */
extern ElfW(Addr) _dl_lookup_symbol (const char *undef, extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
const ElfW(Sym) **sym, const ElfW(Sym) **sym,
struct link_map *symbol_scope[], struct r_scope_elem *symbol_scope[],
const char *reference_name, const char *reference_name,
int reloc_type) int reloc_type)
internal_function; internal_function;
@ -290,7 +290,7 @@ extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
/* Lookup versioned symbol. */ /* Lookup versioned symbol. */
extern ElfW(Addr) _dl_lookup_versioned_symbol (const char *undef, extern ElfW(Addr) _dl_lookup_versioned_symbol (const char *undef,
const ElfW(Sym) **sym, const ElfW(Sym) **sym,
struct link_map *symbol_scope[], struct r_scope_elem *symbol_scope[],
const char *reference_name, const char *reference_name,
const struct r_found_version *version, const struct r_found_version *version,
int reloc_type) int reloc_type)
@ -299,7 +299,7 @@ extern ElfW(Addr) _dl_lookup_versioned_symbol (const char *undef,
/* For handling RTLD_NEXT we must be able to skip shared objects. */ /* For handling RTLD_NEXT we must be able to skip shared objects. */
extern ElfW(Addr) _dl_lookup_symbol_skip (const char *undef, extern ElfW(Addr) _dl_lookup_symbol_skip (const char *undef,
const ElfW(Sym) **sym, const ElfW(Sym) **sym,
struct link_map *symbol_scope[], struct r_scope_elem *symbol_scope[],
const char *reference_name, const char *reference_name,
struct link_map *skip_this) struct link_map *skip_this)
internal_function; internal_function;
@ -308,7 +308,7 @@ extern ElfW(Addr) _dl_lookup_symbol_skip (const char *undef,
skip shared objects. */ skip shared objects. */
extern ElfW(Addr) _dl_lookup_versioned_symbol_skip (const char *undef, extern ElfW(Addr) _dl_lookup_versioned_symbol_skip (const char *undef,
const ElfW(Sym) **sym, const ElfW(Sym) **sym,
struct link_map *symbol_scope[], struct r_scope_elem *symbol_scope[],
const char *reference_name, const char *reference_name,
const struct r_found_version *version, const struct r_found_version *version,
struct link_map *skip_this) struct link_map *skip_this)
@ -325,46 +325,24 @@ extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name)
/* Structure describing the dynamic linker itself. */ /* Structure describing the dynamic linker itself. */
extern struct link_map _dl_rtld_map; extern struct link_map _dl_rtld_map;
/* And a pointer to the map for the main map. */
/* The list of objects currently loaded is the third element of the extern struct link_map *_dl_loaded;
`_dl_default_scope' array, and the fourth element is always null. /* Array representing global scope. */
This leaves two slots before it that are used when resolving extern struct r_scope_elem *_dl_global_scope[2];
DT_SYMBOLIC objects' references one after it for normal references /* Direct pointer to the searchlist of the main object. */
(see below). */ extern struct r_scope_elem *_dl_main_searchlist;
#define _dl_loaded (_dl_default_scope[2])
extern struct link_map *_dl_default_scope[5];
/* Null-terminated list of objects in the dynamic `global scope'. The
list starts at [2]; i.e. &_dl_global_scope[2] is the argument
passed to _dl_lookup_symbol to search the global scope. To search
a specific object and its dependencies in preference to the global
scope, fill in the [1] slot and pass its address; for two specific
object scopes, fill [0] and [1]. The list is double-terminated; to
search the global scope and then a specific object and its
dependencies, set *_dl_global_scope_end. This variable initially
points to _dl_default_scope, and _dl_loaded is always kept in [2]
of this list. A new list is malloc'd when new objects are loaded
with RTLD_GLOBAL. */
extern struct link_map **_dl_global_scope, **_dl_global_scope_end;
extern size_t _dl_global_scope_alloc; /* Number of slots malloc'd. */
/* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into
_dl_global_scope that should be passed to _dl_lookup_symbol for symbol
references made in the object MAP's relocations. */
extern struct link_map **_dl_object_relocation_scope (struct link_map *map)
internal_function;
/* Allocate a `struct link_map' for a new object being loaded, /* Allocate a `struct link_map' for a new object being loaded,
and enter it into the _dl_loaded list. */ and enter it into the _dl_main_map list. */
extern struct link_map *_dl_new_object (char *realname, const char *libname, extern struct link_map *_dl_new_object (char *realname, const char *libname,
int type) internal_function; int type, struct link_map *loader)
internal_function;
/* Relocate the given object (if it hasn't already been). /* Relocate the given object (if it hasn't already been).
SCOPE is passed to _dl_lookup_symbol in symbol lookups. SCOPE is passed to _dl_lookup_symbol in symbol lookups.
If LAZY is nonzero, don't relocate its PLT. */ If LAZY is nonzero, don't relocate its PLT. */
extern void _dl_relocate_object (struct link_map *map, extern void _dl_relocate_object (struct link_map *map,
struct link_map *scope[], struct r_scope_elem *scope[],
int lazy, int consider_profiling); int lazy, int consider_profiling);
/* Check the version dependencies of all objects available through /* Check the version dependencies of all objects available through
@ -377,11 +355,11 @@ extern int _dl_check_all_versions (struct link_map *map, int verbose)
extern int _dl_check_map_versions (struct link_map *map, int verbose) extern int _dl_check_map_versions (struct link_map *map, int verbose)
internal_function; internal_function;
/* Return the address of the next initializer function for MAP or one of /* Return the address of the next initializer function for SCOPE or one of
its dependencies that has not yet been run. When there are no more its dependencies that has not yet been run. When there are no more
initializers to be run, this returns zero. The functions are returned initializers to be run, this returns zero. The functions are returned
in the order they should be called. */ in the order they should be called. */
extern ElfW(Addr) _dl_init_next (struct link_map *map) internal_function; extern ElfW(Addr) _dl_init_next (struct r_scope_elem *scope) internal_function;
/* Call the finalizer functions of all shared objects whose /* Call the finalizer functions of all shared objects whose
initializer functions have completed. */ initializer functions have completed. */

View File

@ -80,6 +80,24 @@ struct libname_list;
struct r_found_version; struct r_found_version;
struct r_search_path_elem; struct r_search_path_elem;
/* Forward declaration. */
struct link_map;
/* Structure to describe a single list of scope elements. The lookup
functions get passed an array of pointers to such structures. */
struct r_scope_elem
{
/* Array of maps for the scope. */
struct link_map **r_list;
/* Number of entries in the scope. */
unsigned int r_nlist;
/* Array of maps which also includes duplicates. */
struct link_map **r_duplist;
/* Number of elements in this list. */
unsigned int r_nduplist;
};
/* Structure describing a loaded shared object. The `l_next' and `l_prev' /* Structure describing a loaded shared object. The `l_next' and `l_prev'
members form a chain of all the shared objects loaded at startup. members form a chain of all the shared objects loaded at startup.
@ -119,15 +137,14 @@ struct link_map
ElfW(Half) l_phnum; /* Number of program header entries. */ ElfW(Half) l_phnum; /* Number of program header entries. */
/* Array of DT_NEEDED dependencies and their dependencies, in /* Array of DT_NEEDED dependencies and their dependencies, in
dependency order for symbol lookup. This is null before the dependency order for symbol lookup (with and without
dependencies have been loaded. */ duplicates). There is no entry before the dependencies have
struct link_map **l_searchlist; been loaded. */
unsigned int l_nsearchlist; struct r_scope_elem l_searchlist;
/* We keep another list in which we keep duplicates. This is /* We need a special searchlist to process objects marked with
needed in _dl_lookup_symbol_skip to implemented RTLD_NEXT. */ DT_SYMBOLIC. */
struct link_map **l_dupsearchlist; struct r_scope_elem l_symbolic_searchlist;
unsigned int l_ndupsearchlist;
/* Dependent object that first caused this object to be loaded. */ /* Dependent object that first caused this object to be loaded. */
struct link_map *l_loader; struct link_map *l_loader;
@ -168,6 +185,14 @@ struct link_map
/* Start and finish of memory map for this object. l_map_start /* Start and finish of memory map for this object. l_map_start
need not be the same as l_addr. */ need not be the same as l_addr. */
ElfW(Addr) l_map_start, l_map_end; ElfW(Addr) l_map_start, l_map_end;
/* This is an array defining the lookup scope for this link map.
There are at most three different scope lists. */
struct r_scope_elem *l_scope[4];
/* A similar array, this time only with the local scope. This is
used occasionally. */
struct r_scope_elem *l_local_scope[2];
}; };
#endif /* link.h */ #endif /* link.h */

View File

@ -89,6 +89,14 @@ const char *_dl_inhibit_rpath; /* RPATH values which should be
ignored. */ ignored. */
const char *_dl_origin_path; const char *_dl_origin_path;
/* This is a pointer to the map for the main object and through it to
all loaded objects. */
struct link_map *_dl_loaded;
/* Pointer to the l_searchlist element of the link map of the main object. */
struct r_scope_elem *_dl_main_searchlist;
/* Array which is used when looking up in the global scope. */
struct r_scope_elem *_dl_global_scope[2];
/* Set nonzero during loading and initialization of executable and /* Set nonzero during loading and initialization of executable and
libraries, cleared before the executable's entry point runs. This libraries, cleared before the executable's entry point runs. This
must not be initialized to nonzero, because the unused dynamic must not be initialized to nonzero, because the unused dynamic
@ -201,7 +209,6 @@ struct map_args
/* Arguments to version_check_doit. */ /* Arguments to version_check_doit. */
struct version_check_args struct version_check_args
{ {
struct link_map *main_map;
int doexit; int doexit;
}; };
@ -210,22 +217,22 @@ relocate_doit (void *a)
{ {
struct relocate_args *args = (struct relocate_args *) a; struct relocate_args *args = (struct relocate_args *) a;
_dl_relocate_object (args->l, _dl_object_relocation_scope (args->l), _dl_relocate_object (args->l, args->l->l_scope,
args->lazy, 0); args->lazy, 0);
} }
static void static void
map_doit (void *a) map_doit (void *a)
{ {
struct map_args *args = (struct map_args *)a; struct map_args *args = (struct map_args *) a;
args->main_map = _dl_map_object (NULL, args->str, 0, lt_library, 0); args->main_map = _dl_map_object (NULL, args->str, 0, lt_library, 0);
} }
static void static void
version_check_doit (void *a) version_check_doit (void *a)
{ {
struct version_check_args *args = (struct version_check_args *)a; struct version_check_args *args = (struct version_check_args *) a;
if (_dl_check_all_versions (args->main_map, 1) && args->doexit) if (_dl_check_all_versions (_dl_loaded, 1) && args->doexit)
/* We cannot start the application. Abort now. */ /* We cannot start the application. Abort now. */
_exit (1); _exit (1);
} }
@ -234,11 +241,11 @@ version_check_doit (void *a)
static inline struct link_map * static inline struct link_map *
find_needed (const char *name) find_needed (const char *name)
{ {
unsigned int n; unsigned int n = _dl_loaded->l_searchlist.r_nlist;
for (n = 0; n < _dl_loaded->l_nsearchlist; ++n) while (n-- > 0)
if (_dl_name_match_p (name, _dl_loaded->l_searchlist[n])) if (_dl_name_match_p (name, _dl_loaded->l_searchlist.r_list[n]))
return _dl_loaded->l_searchlist[n]; return _dl_loaded->l_searchlist.r_list[n];
/* Should never happen. */ /* Should never happen. */
return NULL; return NULL;
@ -289,7 +296,6 @@ dl_main (const ElfW(Phdr) *phdr,
ElfW(Addr) *user_entry) ElfW(Addr) *user_entry)
{ {
const ElfW(Phdr) *ph; const ElfW(Phdr) *ph;
struct link_map *main_map;
int lazy; int lazy;
enum mode mode; enum mode mode;
struct link_map **preloads; struct link_map **preloads;
@ -405,7 +411,7 @@ of this helper program; chances are you did not intend to run this program.\n\
args.str = _dl_argv[0]; args.str = _dl_argv[0];
(void) _dl_catch_error (&err_str, map_doit, &args); (void) _dl_catch_error (&err_str, map_doit, &args);
main_map = args.main_map; _dl_loaded = args.main_map;
if (err_str != NULL) if (err_str != NULL)
{ {
free (err_str); free (err_str);
@ -413,37 +419,37 @@ of this helper program; chances are you did not intend to run this program.\n\
} }
} }
else else
main_map = _dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0); _dl_loaded = _dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0);
phdr = main_map->l_phdr; phdr = _dl_loaded->l_phdr;
phent = main_map->l_phnum; phent = _dl_loaded->l_phnum;
/* We overwrite here a pointer to a malloc()ed string. But since /* We overwrite here a pointer to a malloc()ed string. But since
the malloc() implementation used at this point is the dummy the malloc() implementation used at this point is the dummy
implementations which has no real free() function it does not implementations which has no real free() function it does not
makes sense to free the old string first. */ makes sense to free the old string first. */
main_map->l_name = (char *) ""; _dl_loaded->l_name = (char *) "";
*user_entry = main_map->l_entry; *user_entry = _dl_loaded->l_entry;
} }
else else
{ {
/* Create a link_map for the executable itself. /* Create a link_map for the executable itself.
This will be what dlopen on "" returns. */ This will be what dlopen on "" returns. */
main_map = _dl_new_object ((char *) "", "", lt_executable); _dl_loaded = _dl_new_object ((char *) "", "", lt_executable, NULL);
if (main_map == NULL) if (_dl_loaded == NULL)
_dl_sysdep_fatal ("cannot allocate memory for link map\n", NULL); _dl_sysdep_fatal ("cannot allocate memory for link map\n", NULL);
main_map->l_phdr = phdr; _dl_loaded->l_phdr = phdr;
main_map->l_phnum = phent; _dl_loaded->l_phnum = phent;
main_map->l_entry = *user_entry; _dl_loaded->l_entry = *user_entry;
main_map->l_opencount = 1; _dl_loaded->l_opencount = 1;
/* We delay initializing the path structure until we got the dynamic /* We delay initializing the path structure until we got the dynamic
information for the program. */ information for the program. */
} }
/* It is not safe to load stuff after the main program. */ /* It is not safe to load stuff after the main program. */
main_map->l_map_end = ~0; _dl_loaded->l_map_end = ~0;
/* Perhaps the executable has no PT_LOAD header entries at all. */ /* Perhaps the executable has no PT_LOAD header entries at all. */
main_map->l_map_start = ~0; _dl_loaded->l_map_start = ~0;
/* Scan the program header table for the dynamic section. */ /* Scan the program header table for the dynamic section. */
for (ph = phdr; ph < &phdr[phent]; ++ph) for (ph = phdr; ph < &phdr[phent]; ++ph)
@ -451,12 +457,12 @@ of this helper program; chances are you did not intend to run this program.\n\
{ {
case PT_PHDR: case PT_PHDR:
/* Find out the load address. */ /* Find out the load address. */
main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr; _dl_loaded->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
break; break;
case PT_DYNAMIC: case PT_DYNAMIC:
/* This tells us where to find the dynamic section, /* This tells us where to find the dynamic section,
which tells us everything we need to do. */ which tells us everything we need to do. */
main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr; _dl_loaded->l_ld = (void *) _dl_loaded->l_addr + ph->p_vaddr;
break; break;
case PT_INTERP: case PT_INTERP:
/* This "interpreter segment" was used by the program loader to /* This "interpreter segment" was used by the program loader to
@ -465,7 +471,8 @@ of this helper program; chances are you did not intend to run this program.\n\
dlopen call or DT_NEEDED entry, for something that wants to link dlopen call or DT_NEEDED entry, for something that wants to link
against the dynamic linker as a shared library, will know that against the dynamic linker as a shared library, will know that
the shared object is already loaded. */ the shared object is already loaded. */
_dl_rtld_libname.name = (const char *) main_map->l_addr + ph->p_vaddr; _dl_rtld_libname.name = ((const char *) _dl_loaded->l_addr
+ ph->p_vaddr);
_dl_rtld_libname.next = NULL; _dl_rtld_libname.next = NULL;
_dl_rtld_map.l_libname = &_dl_rtld_libname; _dl_rtld_map.l_libname = &_dl_rtld_libname;
@ -491,9 +498,9 @@ of this helper program; chances are you did not intend to run this program.\n\
/* Remember where the main program starts in memory. */ /* Remember where the main program starts in memory. */
{ {
ElfW(Addr) mapstart; ElfW(Addr) mapstart;
mapstart = main_map->l_addr + (ph->p_vaddr & ~(ph->p_align - 1)); mapstart = _dl_loaded->l_addr + (ph->p_vaddr & ~(ph->p_align - 1));
if (main_map->l_map_start > mapstart) if (_dl_loaded->l_map_start > mapstart)
main_map->l_map_start = mapstart; _dl_loaded->l_map_start = mapstart;
} }
break; break;
} }
@ -509,10 +516,10 @@ of this helper program; chances are you did not intend to run this program.\n\
assert (_dl_rtld_map.l_libname); /* How else did we get here? */ assert (_dl_rtld_map.l_libname); /* How else did we get here? */
/* Extract the contents of the dynamic section for easy access. */ /* Extract the contents of the dynamic section for easy access. */
elf_get_dynamic_info (main_map->l_ld, main_map->l_info); elf_get_dynamic_info (_dl_loaded->l_ld, _dl_loaded->l_info);
if (main_map->l_info[DT_HASH]) if (_dl_loaded->l_info[DT_HASH])
/* Set up our cache of pointers into the hash table. */ /* Set up our cache of pointers into the hash table. */
_dl_setup_hash (main_map); _dl_setup_hash (_dl_loaded);
if (mode == verify) if (mode == verify)
{ {
@ -520,7 +527,7 @@ of this helper program; chances are you did not intend to run this program.\n\
executable using us as the program interpreter. Exit with an executable using us as the program interpreter. Exit with an
error if we were not able to load the binary or no interpreter error if we were not able to load the binary or no interpreter
is specified (i.e., this is no dynamically linked binary. */ is specified (i.e., this is no dynamically linked binary. */
if (main_map->l_ld == NULL) if (_dl_loaded->l_ld == NULL)
_exit (1); _exit (1);
/* We allow here some platform specific code. */ /* We allow here some platform specific code. */
@ -537,14 +544,14 @@ of this helper program; chances are you did not intend to run this program.\n\
/* Put the link_map for ourselves on the chain so it can be found by /* Put the link_map for ourselves on the chain so it can be found by
name. Note that at this point the global chain of link maps contains name. Note that at this point the global chain of link maps contains
exactly one element, which is pointed to by main_map. */ exactly one element, which is pointed to by _dl_loaded. */
if (! _dl_rtld_map.l_name) if (! _dl_rtld_map.l_name)
/* If not invoked directly, the dynamic linker shared object file was /* If not invoked directly, the dynamic linker shared object file was
found by the PT_INTERP name. */ found by the PT_INTERP name. */
_dl_rtld_map.l_name = (char *) _dl_rtld_map.l_libname->name; _dl_rtld_map.l_name = (char *) _dl_rtld_map.l_libname->name;
_dl_rtld_map.l_type = lt_library; _dl_rtld_map.l_type = lt_library;
main_map->l_next = &_dl_rtld_map; _dl_loaded->l_next = &_dl_rtld_map;
_dl_rtld_map.l_prev = main_map; _dl_rtld_map.l_prev = _dl_loaded;
/* We have two ways to specify objects to preload: via environment /* We have two ways to specify objects to preload: via environment
variable and via the file /etc/ld.so.preload. The later can also variable and via the file /etc/ld.so.preload. The later can also
@ -565,7 +572,7 @@ of this helper program; chances are you did not intend to run this program.\n\
if (p[0] != '\0' if (p[0] != '\0'
&& (! __libc_enable_secure || strchr (p, '/') == NULL)) && (! __libc_enable_secure || strchr (p, '/') == NULL))
{ {
struct link_map *new_map = _dl_map_object (main_map, p, 1, struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1,
lt_library, 0); lt_library, 0);
if (new_map->l_opencount == 1) if (new_map->l_opencount == 1)
/* It is no duplicate. */ /* It is no duplicate. */
@ -627,7 +634,7 @@ of this helper program; chances are you did not intend to run this program.\n\
while ((p = strsep (&runp, ": \t\n")) != NULL) while ((p = strsep (&runp, ": \t\n")) != NULL)
if (p[0] != '\0') if (p[0] != '\0')
{ {
struct link_map *new_map = _dl_map_object (main_map, p, 1, struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1,
lt_library, 0); lt_library, 0);
if (new_map->l_opencount == 1) if (new_map->l_opencount == 1)
/* It is no duplicate. */ /* It is no duplicate. */
@ -638,7 +645,7 @@ of this helper program; chances are you did not intend to run this program.\n\
if (problem != NULL) if (problem != NULL)
{ {
char *p = strndupa (problem, file_size - (problem - file)); char *p = strndupa (problem, file_size - (problem - file));
struct link_map *new_map = _dl_map_object (main_map, p, 1, struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1,
lt_library, 0); lt_library, 0);
if (new_map->l_opencount == 1) if (new_map->l_opencount == 1)
/* It is no duplicate. */ /* It is no duplicate. */
@ -667,7 +674,7 @@ of this helper program; chances are you did not intend to run this program.\n\
/* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD /* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD
specified some libraries to load, these are inserted before the actual specified some libraries to load, these are inserted before the actual
dependencies in the executable's searchlist for symbol resolution. */ dependencies in the executable's searchlist for symbol resolution. */
_dl_map_object_deps (main_map, preloads, npreloads, mode == trace); _dl_map_object_deps (_dl_loaded, preloads, npreloads, mode == trace);
#ifndef MAP_ANON #ifndef MAP_ANON
/* We are done mapping things, so close the zero-fill descriptor. */ /* We are done mapping things, so close the zero-fill descriptor. */
@ -687,11 +694,12 @@ of this helper program; chances are you did not intend to run this program.\n\
chain in symbol search order because gdb uses the chain's order as chain in symbol search order because gdb uses the chain's order as
its symbol search order. */ its symbol search order. */
i = 1; i = 1;
while (main_map->l_searchlist[i] != &_dl_rtld_map) while (_dl_loaded->l_searchlist.r_list[i] != &_dl_rtld_map)
++i; ++i;
_dl_rtld_map.l_prev = main_map->l_searchlist[i - 1]; _dl_rtld_map.l_prev = _dl_loaded->l_searchlist.r_list[i - 1];
_dl_rtld_map.l_next = (i + 1 < main_map->l_nsearchlist ? _dl_rtld_map.l_next = (i + 1 < _dl_loaded->l_searchlist.r_nlist
main_map->l_searchlist[i + 1] : NULL); ? _dl_loaded->l_searchlist.r_list[i + 1]
: NULL);
assert (_dl_rtld_map.l_prev->l_next == _dl_rtld_map.l_next); assert (_dl_rtld_map.l_prev->l_next == _dl_rtld_map.l_next);
_dl_rtld_map.l_prev->l_next = &_dl_rtld_map; _dl_rtld_map.l_prev->l_next = &_dl_rtld_map;
if (_dl_rtld_map.l_next) if (_dl_rtld_map.l_next)
@ -706,7 +714,6 @@ of this helper program; chances are you did not intend to run this program.\n\
{ {
struct version_check_args args; struct version_check_args args;
args.doexit = mode == normal; args.doexit = mode == normal;
args.main_map = main_map;
_dl_receive_error (print_missing_version, version_check_doit, &args); _dl_receive_error (print_missing_version, version_check_doit, &args);
} }
@ -745,7 +752,7 @@ of this helper program; chances are you did not intend to run this program.\n\
{ {
const ElfW(Sym) *ref = NULL; const ElfW(Sym) *ref = NULL;
ElfW(Addr) loadbase = _dl_lookup_symbol (_dl_argv[i], &ref, ElfW(Addr) loadbase = _dl_lookup_symbol (_dl_argv[i], &ref,
&_dl_default_scope[2], _dl_loaded->l_scope,
"argument", "argument",
ELF_MACHINE_JMP_SLOT); ELF_MACHINE_JMP_SLOT);
char buf[20], *bp; char buf[20], *bp;
@ -780,7 +787,6 @@ of this helper program; chances are you did not intend to run this program.\n\
args.l = l; args.l = l;
_dl_receive_error (print_unresolved, relocate_doit, _dl_receive_error (print_unresolved, relocate_doit,
&args); &args);
*_dl_global_scope_end = NULL;
} }
l = l->l_prev; l = l->l_prev;
} while (l); } while (l);
@ -890,11 +896,8 @@ of this helper program; chances are you did not intend to run this program.\n\
do do
{ {
if (l != &_dl_rtld_map) if (l != &_dl_rtld_map)
{ _dl_relocate_object (l, l->l_scope, lazy, consider_profiling);
_dl_relocate_object (l, _dl_object_relocation_scope (l), lazy,
consider_profiling);
*_dl_global_scope_end = NULL;
}
l = l->l_prev; l = l->l_prev;
} while (l); } while (l);
@ -908,9 +911,13 @@ of this helper program; chances are you did not intend to run this program.\n\
if (_dl_rtld_map.l_opencount > 0) if (_dl_rtld_map.l_opencount > 0)
/* There was an explicit ref to the dynamic linker as a shared lib. /* There was an explicit ref to the dynamic linker as a shared lib.
Re-relocate ourselves with user-controlled symbol definitions. */ Re-relocate ourselves with user-controlled symbol definitions. */
_dl_relocate_object (&_dl_rtld_map, &_dl_default_scope[2], 0, 0); _dl_relocate_object (&_dl_rtld_map, _dl_loaded->l_scope, 0, 0);
} }
/* Now set up the variable which helps the assembler startup code. */
_dl_main_searchlist = &_dl_loaded->l_searchlist;
_dl_global_scope[0] = &_dl_loaded->l_searchlist;
{ {
/* Initialize _r_debug. */ /* Initialize _r_debug. */
struct r_debug *r = _dl_debug_initialize (_dl_rtld_map.l_addr); struct r_debug *r = _dl_debug_initialize (_dl_rtld_map.l_addr);

View File

@ -100,10 +100,10 @@ static void
get_sym (void *a) get_sym (void *a)
{ {
struct get_sym_args *args = (struct get_sym_args *) a; struct get_sym_args *args = (struct get_sym_args *) a;
struct link_map *scope[2] = { args->map, NULL };
args->ref = NULL; args->ref = NULL;
args->loadbase = _dl_lookup_symbol (args->name, &args->ref, args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
scope, args->map->l_name, 0); args->map->l_local_scope,
args->map->l_name, 0);
} }

View File

@ -1,3 +1,8 @@
1998-09-06 09:08 Ulrich Drepper <drepper@cygnus.com>
* sysdeps/pthread/bits/libc-lock.h (enum __libc_tsd_key_t): Add
_LIBC_TSD_KEY_DL_ERROR.
1998-08-31 Ulrich Drepper <drepper@cygnus.com> 1998-08-31 Ulrich Drepper <drepper@cygnus.com>
* sysdeps/i386/i686/pt-machine.h (testandset): Add memory clobber. * sysdeps/i386/i686/pt-machine.h (testandset): Add memory clobber.

View File

@ -152,7 +152,9 @@ typedef pthread_key_t __libc_key_t;
#ifdef _LIBC #ifdef _LIBC
/* Fast thread-specific data internal to libc. */ /* Fast thread-specific data internal to libc. */
enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0, _LIBC_TSD_KEY_N }; enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
_LIBC_TSD_KEY_DL_ERROR,
_LIBC_TSD_KEY_N };
extern void *__libc_internal_tsd_get __P ((enum __libc_tsd_key_t)); extern void *__libc_internal_tsd_get __P ((enum __libc_tsd_key_t));
extern int __libc_internal_tsd_set __P ((enum __libc_tsd_key_t, extern int __libc_internal_tsd_set __P ((enum __libc_tsd_key_t,

View File

@ -292,10 +292,10 @@ static void
get_sym (void *a) get_sym (void *a)
{ {
struct get_sym_args *args = (struct get_sym_args *) a; struct get_sym_args *args = (struct get_sym_args *) a;
struct link_map *scope[2] = { args->map, NULL };
args->ref = NULL; args->ref = NULL;
args->loadbase = _dl_lookup_symbol (args->name, &args->ref, args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
scope, args->map->l_name, 0); args->map->l_local_scope,
args->map->l_name, 0);
} }
#endif #endif

View File

@ -227,9 +227,10 @@ _dl_start_user:\n\
leal (%esp,%eax,4), %esp\n\ leal (%esp,%eax,4), %esp\n\
# Push back the modified argument count.\n\ # Push back the modified argument count.\n\
pushl %ecx\n\ pushl %ecx\n\
# Push _dl_default_scope[2] as argument in _dl_init_next call below.\n\ # Push the searchlist of the main object as argument in\n\
movl _dl_default_scope@GOT(%ebx), %eax\n\ # _dl_init_next call below.\n\
movl 8(%eax), %esi\n\ movl _dl_main_searchlist@GOT(%ebx), %eax\n\
movl (%eax), %esi\n\
0: movl %esi,%eax\n\ 0: movl %esi,%eax\n\
# Call _dl_init_next to return the address of an initializer\n\ # Call _dl_init_next to return the address of an initializer\n\
# function to run.\n\ # function to run.\n\

View File

@ -27,14 +27,16 @@
/* We have to find out whether the binary is linked against \ /* We have to find out whether the binary is linked against \
libc 5 or glibc. We do this by looking at all the DT_NEEDED \ libc 5 or glibc. We do this by looking at all the DT_NEEDED \
entries. If one is libc.so.5 this is a libc 5 linked binary. */ \ entries. If one is libc.so.5 this is a libc 5 linked binary. */ \
if (main_map->l_info[DT_NEEDED]) \ if (_dl_loaded->l_info[DT_NEEDED]) \
{ \ { \
/* We have dependencies. */ \ /* We have dependencies. */ \
const char *strtab = ((void *) main_map->l_addr \
+ main_map->l_info[DT_STRTAB]->d_un.d_ptr); \
const ElfW(Dyn) *d; \ const ElfW(Dyn) *d; \
const char *strtab; \
\ \
for (d = main_map->l_ld; d->d_tag != DT_NULL; ++d) \ strtab = ((void *) _dl_loaded->l_addr \
+ _dl_loaded->l_info[DT_STRTAB]->d_un.d_ptr); \
\
for (d = _dl_loaded->l_ld; d->d_tag != DT_NULL; ++d) \
if (d->d_tag == DT_NEEDED \ if (d->d_tag == DT_NEEDED \
&& strcmp (strtab + d->d_un.d_val, "libc.so.5") == 0) \ && strcmp (strtab + d->d_un.d_val, "libc.so.5") == 0) \
break; \ break; \