mirror of
git://sourceware.org/git/glibc.git
synced 2025-04-12 14:21:18 +08:00
Update.
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:
parent
9eb71e60ef
commit
be93561004
34
ChangeLog
34
ChangeLog
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
@ -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, ¤t_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, ¤t_value,
|
||||
*scope, i, reference_name, version, skip_map, 0))
|
||||
|
@ -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;
|
||||
|
||||
|
108
elf/dl-open.c
108
elf/dl-open.c
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
17
elf/dlfcn.h
17
elf/dlfcn.h
@ -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
|
||||
|
16
elf/dlsym.c
16
elf/dlsym.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
21
elf/dlvsym.c
21
elf/dlvsym.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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. */
|
||||
|
41
elf/link.h
41
elf/link.h
@ -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 */
|
||||
|
115
elf/rtld.c
115
elf/rtld.c
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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\
|
||||
|
@ -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; \
|
||||
|
Loading…
x
Reference in New Issue
Block a user