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>
* sysdeps/mach/hurd/i386/init-first.c (init1): Call

View File

@ -19,6 +19,7 @@ libc {
GLIBC_2.1 {
# global variables
_dl_profile; _dl_profile_map; _dl_profile_output; _dl_start_profile;
_dl_loaded; _dl_main_searchlist;
# functions used in other libraries
_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;
}
list = map->l_searchlist;
nsearchlist = map->l_nsearchlist;
list = map->l_searchlist.r_list;
nsearchlist = map->l_searchlist.r_nlist;
/* Call all termination functions at once. */
for (i = 0; i < nsearchlist; ++i)
@ -103,16 +103,18 @@ _dl_close (struct link_map *map)
if (imap->l_global)
{
/* 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
--tail;
while (*tail != imap);
while (tail < _dl_global_scope_end)
--cnt;
while (_dl_main_searchlist->r_list[cnt] != imap);
while (cnt < _dl_main_searchlist->r_nlist)
{
tail[0] = tail[1];
++tail;
_dl_main_searchlist->r_list[0]
= _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
@ -135,8 +137,6 @@ _dl_close (struct link_map *map)
#endif
if (imap->l_next)
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)
free (imap->l_versions);
@ -156,15 +156,14 @@ _dl_close (struct link_map *map)
while (lnp != NULL);
/* 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
a l_dupsearchlist object. */
assert (imap->l_dupsearchlist != NULL);
free (imap->l_dupsearchlist);
/* If a r_list exists there always also is a r_duplist. */
assert (imap->l_searchlist.r_list != NULL);
free (imap->l_searchlist.r_duplist);
}
if (imap != map && imap->l_searchlist != NULL)
free (imap->l_searchlist);
if (imap != map && imap->l_searchlist.r_list != NULL)
free (imap->l_searchlist.r_list);
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
searches in the scope of this object. */
map->l_searchlist = malloc (nlist * sizeof (struct link_map *));
if (map->l_searchlist == NULL)
map->l_searchlist.r_list = malloc (nlist * sizeof (struct link_map *));
if (map->l_searchlist.r_list == NULL)
_dl_signal_error (ENOMEM, map->l_name,
"cannot allocate symbol search list");
map->l_nsearchlist = nlist;
map->l_searchlist.r_nlist = nlist;
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
to avoid duplicates, so the next call starts fresh. */
runp->map->l_reserved = 0;
}
map->l_ndupsearchlist = nduplist;
map->l_searchlist.r_nduplist = nduplist;
if (nlist == nduplist)
map->l_dupsearchlist = map->l_searchlist;
map->l_searchlist.r_duplist = map->l_searchlist.r_list;
else
{
map->l_dupsearchlist = malloc (nduplist * sizeof (struct link_map *));
if (map->l_dupsearchlist == NULL)
map->l_searchlist.r_duplist = malloc (nduplist
* sizeof (struct link_map *));
if (map->l_searchlist.r_duplist == NULL)
_dl_signal_error (ENOMEM, map->l_name,
"cannot allocate symbol search list");
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 <unistd.h>
#include <elf/ldsodefs.h>
#include <bits/libc-lock.h>
/* This structure communicates state between _dl_catch_error and
_dl_signal_error. */
@ -31,14 +32,57 @@ struct catch
jmp_buf env; /* longjmp here on error. */
};
/* This points to such a structure during a call to _dl_catch_error.
During implicit startup and run-time work for needed shared libraries,
this is null. */
/* Multiple threads at once can use the `_dl_catch_error' function. The
calls can come from the `_dl_map_object_deps', `_dlerror_run', or from
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;
#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
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;
@ -48,27 +92,30 @@ _dl_signal_error (int errcode,
const char *objname,
const char *errstring)
{
struct catch *lcatch;
if (! errstring)
errstring = "DYNAMIC LINKER BUG!!!";
if (catch)
lcatch = tsd_getspecific ();
if (lcatch != NULL)
{
/* We are inside _dl_catch_error. Return to it. We have to
duplicate the error string since it might be allocated on the
stack. */
size_t objname_len = objname ? strlen (objname) + 2 : 0;
size_t errstring_len = strlen (errstring) + 1;
catch->errstring = malloc (objname_len + errstring_len);
if (catch->errstring != NULL)
lcatch->errstring = malloc (objname_len + errstring_len);
if (lcatch->errstring != NULL)
{
if (objname_len > 0)
{
memcpy (catch->errstring, objname, objname_len - 2);
memcpy (catch->errstring + objname_len - 2, ": ", 2);
memcpy (lcatch->errstring, objname, objname_len - 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)
{
@ -106,19 +153,19 @@ _dl_catch_error (char **errstring,
inefficient. So we initialize `c' by hand. */
c.errstring = NULL;
old = catch;
old = tsd_getspecific ();
errcode = setjmp (c.env);
if (errcode == 0)
{
catch = &c;
tsd_setspecific (&c);
(*operate) (args);
catch = old;
tsd_setspecific (old);
*errstring = NULL;
return 0;
}
/* We get here only if we longjmp'd out of OPERATE. */
catch = old;
tsd_setspecific (old);
*errstring = c.errstring;
return errcode == -1 ? 0 : errcode;
}
@ -130,15 +177,15 @@ _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
struct catch *old_catch;
receiver_fct old_receiver;
old_catch = catch;
old_catch = tsd_getspecific ();
old_receiver = receiver;
/* Set the new values. */
catch = NULL;
tsd_setspecific (NULL);
receiver = fct;
(*operate) (args);
catch = old_catch;
tsd_setspecific (old_catch);
receiver = old_receiver;
}

View File

@ -26,7 +26,7 @@
ElfW(Addr)
internal_function
_dl_init_next (struct link_map *map)
_dl_init_next (struct r_scope_elem *searchlist)
{
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
breadth-first leaf-to-root order. */
i = map->l_nsearchlist;
i = searchlist->r_nlist;
while (i-- > 0)
{
struct link_map *l = map->l_searchlist[i];
struct link_map *l = searchlist->r_list[i];
if (l->l_init_called)
/* This object is all done. */
@ -53,8 +53,8 @@ _dl_init_next (struct link_map *map)
continue;
}
if (l->l_info[DT_INIT] &&
!(l->l_name[0] == '\0' && l->l_type == lt_executable))
if (l->l_info[DT_INIT]
&& (l->l_name[0] != '\0' || l->l_type != lt_executable))
{
/* Run this object's initializer. */
l->l_init_running = 1;

View File

@ -529,7 +529,12 @@ _dl_init_paths (const char *llp)
l = _dl_loaded;
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
from RPATH. */
@ -727,11 +732,10 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
#endif
/* 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)
lose (ENOMEM, "cannot create shared object descriptor");
l->l_opencount = 1;
l->l_loader = loader;
/* Extract the remaining details we need from the ELF header
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])
_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;
}
@ -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. */
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,
"cannot create shared object descriptor");
/* 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
do_lookup (const char *undef_name, unsigned long int hash,
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,
int reloc_type)
{
struct link_map **list = scope->l_searchlist;
size_t n = scope->l_nsearchlist;
struct link_map **list = scope->r_list;
size_t n = scope->r_nlist;
struct link_map *map;
for (; i < n; ++i)
@ -212,13 +212,13 @@ do_lookup (const char *undef_name, unsigned long int hash,
ElfW(Addr)
internal_function
_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,
int reloc_type)
{
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct link_map **scope;
struct r_scope_elem **scope;
/* Search the relevant loaded objects for a definition. */
for (scope = symbol_scope; *scope; ++scope)
@ -260,19 +260,19 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
ElfW(Addr)
internal_function
_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,
struct link_map *skip_map)
{
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct link_map **scope;
struct r_scope_elem **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);
for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
assert (i < (*scope)->r_nduplist);
if (! do_lookup (undef_name, hash, *ref, &current_value,
*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)
internal_function
_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 struct r_found_version *version,
int reloc_type)
{
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct link_map **scope;
struct r_scope_elem **scope;
/* Search the relevant loaded objects for a definition. */
for (scope = symbol_scope; *scope; ++scope)
@ -375,20 +375,20 @@ ElfW(Addr)
internal_function
_dl_lookup_versioned_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 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 = { NULL, NULL };
struct link_map **scope;
struct r_scope_elem **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);
for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
assert (i < (*scope)->r_nduplist);
if (! do_lookup (undef_name, hash, *ref, &current_value,
*scope, i, reference_name, version, skip_map, 0))

View File

@ -25,16 +25,17 @@
#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,
and enter it into the _dl_loaded list. */
struct link_map *
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;
struct link_map *new = calloc (sizeof *new, 1);
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;
new->l_libname = newname;
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;
_dl_loaded = new;
}
else
{
struct link_map *l = _dl_loaded;
l = _dl_loaded;
while (l->l_next)
l = l->l_next;
new->l_prev = l;
new->l_next = NULL;
/* new->l_next = NULL; Would be necesary but we use calloc. */
l->l_next = new;
}
/* Don't try to find the origin for the main map. */
if (realname[0] == '\0')
new->l_origin = NULL;
/* Add the global scope. */
new->l_scope[idx++] = &_dl_loaded->l_searchlist;
}
/* 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
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;

View File

@ -77,7 +77,7 @@ dl_open_worker (void *a)
/* Load the named object. */
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. */
return;
@ -97,21 +97,6 @@ dl_open_worker (void *a)
{
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
if (_dl_profile != NULL)
{
@ -122,7 +107,7 @@ dl_open_worker (void *a)
start the profiling. */
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)
/* We must prepare the profiling. */
@ -130,10 +115,8 @@ dl_open_worker (void *a)
}
else
#endif
(*reloc) (l, _dl_object_relocation_scope (l),
(mode & RTLD_BINDING_MASK) == RTLD_LAZY, 0);
*_dl_global_scope_end = NULL;
_dl_relocate_object (l, l->l_scope,
(mode & RTLD_BINDING_MASK) == RTLD_LAZY, 0);
}
if (l == new)
@ -146,50 +129,58 @@ dl_open_worker (void *a)
{
/* The symbols of the new object and its dependencies are to be
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)
{
/* This is the first dynamic object given global scope. */
_dl_global_scope_alloc = 8;
_dl_global_scope = malloc (_dl_global_scope_alloc
* sizeof (struct link_map *));
if (! _dl_global_scope)
struct link_map **new_global;
_dl_global_scope_alloc = _dl_main_searchlist->r_nlist + 8;
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:
new->l_global = 0;
_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. */
*_dl_global_scope_end++ = new;
/* We keep the list double-terminated so the last element
can be filled in for symbol lookups. */
_dl_global_scope_end[0] = NULL;
_dl_global_scope_end[1] = NULL;
/* Copy over the old entries. */
memcpy (new_global, _dl_main_searchlist->r_list,
(_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
_dl_main_searchlist->r_list = new_global;
}
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 ();
/* 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,
__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)
/* We must be the static _dl_open in libc.a. A static program that
has loaded a dynamic object now has competition. */
@ -241,9 +236,6 @@ _dl_open (const char *file, int mode)
/* Some error occured during loading. */
char *local_errstring;
/* Reset the global scope. */
*_dl_global_scope_end = NULL;
/* Remove the object from memory. It may be in an inconsistent
state if relocation failed, for example. */
if (args.map)

View File

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

View File

@ -19,63 +19,6 @@
#include <unistd.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"
#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);
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. */
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
@ -134,13 +74,13 @@ fixup (
if (version->hash != 0)
{
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);
break;
}
}
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);
}
@ -154,8 +94,6 @@ fixup (
/* Finally, fix up the plt itself. */
elf_machine_fixup_plt (l, reloc, rel_addr, value);
*_dl_global_scope_end = NULL;
return value;
}
@ -191,9 +129,6 @@ profile_fixup (
reloc_offset);
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. */
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
@ -210,14 +145,14 @@ profile_fixup (
if (version->hash != 0)
{
value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
&sym, scope, l->l_name,
version,
&sym, l->l_scope,
l->l_name, version,
ELF_MACHINE_JMP_SLOT);
break;
}
}
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);
}
@ -228,8 +163,6 @@ profile_fixup (
/* And now perhaps the relocation addend. */
value = elf_machine_plt_value (l, reloc, value);
*_dl_global_scope_end = NULL;
/* Store the result for later runs. */
*resultp = value;
}

View File

@ -66,6 +66,20 @@ void *__libc_stack_end;
/* Path where the binary is found. */
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));

View File

@ -28,7 +28,7 @@ _dl_symbol_value (struct link_map *map, const char *name)
{
ElfW(Addr) loadbase;
const ElfW(Sym) *ref = NULL;
struct link_map *scope[2] = { map, NULL };
loadbase = _dl_lookup_symbol (name, &ref, scope, map->l_name, 0);
loadbase = _dl_lookup_symbol (name, &ref, map->l_local_scope, map->l_name,
0);
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
a dependency of the current object. */
for (n = 0; n < map->l_nsearchlist; n++)
if (_dl_name_match_p (name, map->l_searchlist[n]))
return map->l_searchlist[n];
for (n = 0; n < map->l_searchlist.r_nlist; n++)
if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
return map->l_searchlist.r_list[n];
/* Should never happen. */
return NULL;

View File

@ -21,16 +21,23 @@
#define _DLFCN_H 1
#include <features.h>
#define __need_NULL
#include <stddef.h>
/* Collect various system dependand definitions and declarations. */
#include <bits/dlfcn.h>
/* If the first argument of `dlsym' is set to RTLD_NEXT the run-time
address of the symbol called NAME in the next shared object is
returned. The "next" relation is defined by the order the shared
objects were loaded. */
/* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT
the run-time address of the symbol called NAME in the next shared
object is returned. The "next" relation is defined by the order
the shared objects were loaded. */
#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
/* 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. */
extern char *dlerror __P ((void));
#ifdef __USE_GNU
/* Fill in *INFO with the following information about ADDRESS.
Returns 0 iff no shared object's segments contain that address. */
typedef struct
@ -68,7 +76,6 @@ typedef struct
} Dl_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
the function found using `dlsym' using the following macro since
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)
/* Search the global scope. */
args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
&(_dl_global_scope
?: _dl_default_scope)[2],
NULL, 0);
_dl_global_scope, NULL, 0);
else if (args->handle == RTLD_NEXT)
{
struct link_map *l, *match;
@ -65,19 +63,15 @@ RTLD_NEXT used in code not dynamically loaded"));
while (l->l_loader)
l = l->l_loader;
{
struct link_map *mapscope[2] = { l, NULL };
args->loadbase = _dl_lookup_symbol_skip (args->name, &args->ref,
mapscope, NULL, match);
}
args->loadbase = _dl_lookup_symbol_skip (args->name, &args->ref,
l->l_local_scope, NULL, match);
}
else
{
/* Search the scope of the given object. */
struct link_map *map = args->handle;
struct link_map *mapscope[2] = { map, NULL };
args->loadbase = _dl_lookup_symbol (args->name, &args->ref, mapscope,
map->l_name, 0);
args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
map->l_local_scope, map->l_name, 0);
}
}

View File

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

View File

@ -282,7 +282,7 @@ extern void _dl_close (struct link_map *map)
symbols can be chosen. */
extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
const ElfW(Sym) **sym,
struct link_map *symbol_scope[],
struct r_scope_elem *symbol_scope[],
const char *reference_name,
int reloc_type)
internal_function;
@ -290,7 +290,7 @@ extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
/* Lookup versioned symbol. */
extern ElfW(Addr) _dl_lookup_versioned_symbol (const char *undef,
const ElfW(Sym) **sym,
struct link_map *symbol_scope[],
struct r_scope_elem *symbol_scope[],
const char *reference_name,
const struct r_found_version *version,
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. */
extern ElfW(Addr) _dl_lookup_symbol_skip (const char *undef,
const ElfW(Sym) **sym,
struct link_map *symbol_scope[],
struct r_scope_elem *symbol_scope[],
const char *reference_name,
struct link_map *skip_this)
internal_function;
@ -308,7 +308,7 @@ extern ElfW(Addr) _dl_lookup_symbol_skip (const char *undef,
skip shared objects. */
extern ElfW(Addr) _dl_lookup_versioned_symbol_skip (const char *undef,
const ElfW(Sym) **sym,
struct link_map *symbol_scope[],
struct r_scope_elem *symbol_scope[],
const char *reference_name,
const struct r_found_version *version,
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. */
extern struct link_map _dl_rtld_map;
/* The list of objects currently loaded is the third element of the
`_dl_default_scope' array, and the fourth element is always null.
This leaves two slots before it that are used when resolving
DT_SYMBOLIC objects' references one after it for normal references
(see below). */
#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;
/* And a pointer to the map for the main map. */
extern struct link_map *_dl_loaded;
/* Array representing global scope. */
extern struct r_scope_elem *_dl_global_scope[2];
/* Direct pointer to the searchlist of the main object. */
extern struct r_scope_elem *_dl_main_searchlist;
/* 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,
int type) internal_function;
int type, struct link_map *loader)
internal_function;
/* Relocate the given object (if it hasn't already been).
SCOPE is passed to _dl_lookup_symbol in symbol lookups.
If LAZY is nonzero, don't relocate its PLT. */
extern void _dl_relocate_object (struct link_map *map,
struct link_map *scope[],
struct r_scope_elem *scope[],
int lazy, int consider_profiling);
/* 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)
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
initializers to be run, this returns zero. The functions are returned
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
initializer functions have completed. */

View File

@ -80,6 +80,24 @@ struct libname_list;
struct r_found_version;
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'
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. */
/* Array of DT_NEEDED dependencies and their dependencies, in
dependency order for symbol lookup. This is null before the
dependencies have been loaded. */
struct link_map **l_searchlist;
unsigned int l_nsearchlist;
dependency order for symbol lookup (with and without
duplicates). There is no entry before the dependencies have
been loaded. */
struct r_scope_elem l_searchlist;
/* We keep another list in which we keep duplicates. This is
needed in _dl_lookup_symbol_skip to implemented RTLD_NEXT. */
struct link_map **l_dupsearchlist;
unsigned int l_ndupsearchlist;
/* We need a special searchlist to process objects marked with
DT_SYMBOLIC. */
struct r_scope_elem l_symbolic_searchlist;
/* Dependent object that first caused this object to be loaded. */
struct link_map *l_loader;
@ -168,6 +185,14 @@ struct link_map
/* Start and finish of memory map for this object. l_map_start
need not be the same as l_addr. */
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 */

View File

@ -89,6 +89,14 @@ const char *_dl_inhibit_rpath; /* RPATH values which should be
ignored. */
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
libraries, cleared before the executable's entry point runs. This
must not be initialized to nonzero, because the unused dynamic
@ -201,7 +209,6 @@ struct map_args
/* Arguments to version_check_doit. */
struct version_check_args
{
struct link_map *main_map;
int doexit;
};
@ -210,22 +217,22 @@ relocate_doit (void *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);
}
static void
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);
}
static void
version_check_doit (void *a)
{
struct version_check_args *args = (struct version_check_args *)a;
if (_dl_check_all_versions (args->main_map, 1) && args->doexit)
struct version_check_args *args = (struct version_check_args *) a;
if (_dl_check_all_versions (_dl_loaded, 1) && args->doexit)
/* We cannot start the application. Abort now. */
_exit (1);
}
@ -234,11 +241,11 @@ version_check_doit (void *a)
static inline struct link_map *
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)
if (_dl_name_match_p (name, _dl_loaded->l_searchlist[n]))
return _dl_loaded->l_searchlist[n];
while (n-- > 0)
if (_dl_name_match_p (name, _dl_loaded->l_searchlist.r_list[n]))
return _dl_loaded->l_searchlist.r_list[n];
/* Should never happen. */
return NULL;
@ -289,7 +296,6 @@ dl_main (const ElfW(Phdr) *phdr,
ElfW(Addr) *user_entry)
{
const ElfW(Phdr) *ph;
struct link_map *main_map;
int lazy;
enum mode mode;
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];
(void) _dl_catch_error (&err_str, map_doit, &args);
main_map = args.main_map;
_dl_loaded = args.main_map;
if (err_str != NULL)
{
free (err_str);
@ -413,37 +419,37 @@ of this helper program; chances are you did not intend to run this program.\n\
}
}
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;
phent = main_map->l_phnum;
phdr = _dl_loaded->l_phdr;
phent = _dl_loaded->l_phnum;
/* We overwrite here a pointer to a malloc()ed string. But since
the malloc() implementation used at this point is the dummy
implementations which has no real free() function it does not
makes sense to free the old string first. */
main_map->l_name = (char *) "";
*user_entry = main_map->l_entry;
_dl_loaded->l_name = (char *) "";
*user_entry = _dl_loaded->l_entry;
}
else
{
/* Create a link_map for the executable itself.
This will be what dlopen on "" returns. */
main_map = _dl_new_object ((char *) "", "", lt_executable);
if (main_map == NULL)
_dl_loaded = _dl_new_object ((char *) "", "", lt_executable, NULL);
if (_dl_loaded == NULL)
_dl_sysdep_fatal ("cannot allocate memory for link map\n", NULL);
main_map->l_phdr = phdr;
main_map->l_phnum = phent;
main_map->l_entry = *user_entry;
main_map->l_opencount = 1;
_dl_loaded->l_phdr = phdr;
_dl_loaded->l_phnum = phent;
_dl_loaded->l_entry = *user_entry;
_dl_loaded->l_opencount = 1;
/* We delay initializing the path structure until we got the dynamic
information for the 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. */
main_map->l_map_start = ~0;
_dl_loaded->l_map_start = ~0;
/* Scan the program header table for the dynamic section. */
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:
/* 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;
case PT_DYNAMIC:
/* This tells us where to find the dynamic section,
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;
case PT_INTERP:
/* 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
against the dynamic linker as a shared library, will know that
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_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. */
{
ElfW(Addr) mapstart;
mapstart = main_map->l_addr + (ph->p_vaddr & ~(ph->p_align - 1));
if (main_map->l_map_start > mapstart)
main_map->l_map_start = mapstart;
mapstart = _dl_loaded->l_addr + (ph->p_vaddr & ~(ph->p_align - 1));
if (_dl_loaded->l_map_start > mapstart)
_dl_loaded->l_map_start = mapstart;
}
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? */
/* Extract the contents of the dynamic section for easy access. */
elf_get_dynamic_info (main_map->l_ld, main_map->l_info);
if (main_map->l_info[DT_HASH])
elf_get_dynamic_info (_dl_loaded->l_ld, _dl_loaded->l_info);
if (_dl_loaded->l_info[DT_HASH])
/* Set up our cache of pointers into the hash table. */
_dl_setup_hash (main_map);
_dl_setup_hash (_dl_loaded);
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
error if we were not able to load the binary or no interpreter
is specified (i.e., this is no dynamically linked binary. */
if (main_map->l_ld == NULL)
if (_dl_loaded->l_ld == NULL)
_exit (1);
/* 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
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 not invoked directly, the dynamic linker shared object file was
found by the PT_INTERP name. */
_dl_rtld_map.l_name = (char *) _dl_rtld_map.l_libname->name;
_dl_rtld_map.l_type = lt_library;
main_map->l_next = &_dl_rtld_map;
_dl_rtld_map.l_prev = main_map;
_dl_loaded->l_next = &_dl_rtld_map;
_dl_rtld_map.l_prev = _dl_loaded;
/* We have two ways to specify objects to preload: via environment
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'
&& (! __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);
if (new_map->l_opencount == 1)
/* 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)
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);
if (new_map->l_opencount == 1)
/* 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)
{
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);
if (new_map->l_opencount == 1)
/* 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
specified some libraries to load, these are inserted before the actual
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
/* 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
its symbol search order. */
i = 1;
while (main_map->l_searchlist[i] != &_dl_rtld_map)
while (_dl_loaded->l_searchlist.r_list[i] != &_dl_rtld_map)
++i;
_dl_rtld_map.l_prev = main_map->l_searchlist[i - 1];
_dl_rtld_map.l_next = (i + 1 < main_map->l_nsearchlist ?
main_map->l_searchlist[i + 1] : NULL);
_dl_rtld_map.l_prev = _dl_loaded->l_searchlist.r_list[i - 1];
_dl_rtld_map.l_next = (i + 1 < _dl_loaded->l_searchlist.r_nlist
? _dl_loaded->l_searchlist.r_list[i + 1]
: NULL);
assert (_dl_rtld_map.l_prev->l_next == _dl_rtld_map.l_next);
_dl_rtld_map.l_prev->l_next = &_dl_rtld_map;
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;
args.doexit = mode == normal;
args.main_map = main_map;
_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;
ElfW(Addr) loadbase = _dl_lookup_symbol (_dl_argv[i], &ref,
&_dl_default_scope[2],
_dl_loaded->l_scope,
"argument",
ELF_MACHINE_JMP_SLOT);
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;
_dl_receive_error (print_unresolved, relocate_doit,
&args);
*_dl_global_scope_end = NULL;
}
l = l->l_prev;
} while (l);
@ -890,11 +896,8 @@ of this helper program; chances are you did not intend to run this program.\n\
do
{
if (l != &_dl_rtld_map)
{
_dl_relocate_object (l, _dl_object_relocation_scope (l), lazy,
consider_profiling);
*_dl_global_scope_end = NULL;
}
_dl_relocate_object (l, l->l_scope, lazy, consider_profiling);
l = l->l_prev;
} 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)
/* There was an explicit ref to the dynamic linker as a shared lib.
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. */
struct r_debug *r = _dl_debug_initialize (_dl_rtld_map.l_addr);

View File

@ -100,10 +100,10 @@ static void
get_sym (void *a)
{
struct get_sym_args *args = (struct get_sym_args *) a;
struct link_map *scope[2] = { args->map, NULL };
args->ref = NULL;
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>
* 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
/* 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 int __libc_internal_tsd_set __P ((enum __libc_tsd_key_t,

View File

@ -292,10 +292,10 @@ static void
get_sym (void *a)
{
struct get_sym_args *args = (struct get_sym_args *) a;
struct link_map *scope[2] = { args->map, NULL };
args->ref = NULL;
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

View File

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

View File

@ -27,14 +27,16 @@
/* 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 \
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. */ \
const char *strtab = ((void *) main_map->l_addr \
+ main_map->l_info[DT_STRTAB]->d_un.d_ptr); \
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 \
&& strcmp (strtab + d->d_un.d_val, "libc.so.5") == 0) \
break; \