[BZ #77]
Update. Add support for namespaces in the dynamic linker. * dlfcn/Makefile (libdl-routines): Add dlmopen. * dlfcn/Versions [libdl, GLIBC_2.3.4]: Add dlmopen. * dlfcn/dlfcn.h: Define Lmid_t, LM_ID_BASE, and LM_ID_NEWLM. Declare dlmopen. Document RTLD_DI_LMID. * dlfcn/dlinfo.c: Handle RTLD_DI_LMID. * dlfcn/dlmopen.c: New file. * dlfcn/dlopen.c: Pass new parameter to _dl_open. * dlfcn/dlopenold.c: Likewise. * elf/dl-addr.c: Adjust for removal of GL(dl_loaded). * elf/dl-caller.c: Likewise. * elf/dl-close.c: Likewise. * elf/dl-conflict.c: Likewise. * elf/dl-debug.c: Likewise. * elf/dl-lookup.c: Likewise. * elf/dl-sym.c: Likewise. * elf/dl-version.c: Likewise. * elf/do-lookup.h: Likewise. * elf/rtld.c: Likewise. * sysdeps/unix/sysv/linux/i386/dl-librecon.h: Likewise. * elf/dl-depsc: Likewise. Add new parameter to _dl_map_object. * elf/dl-fini.c: Call destructors in all namespaces. * elf/dl-iteratephdr.c: Compute total nloaded. Adjust for removal of GL(dl_loaded). * elf/dl-libc.c: Pass new parameter to _dl_open. Adjust for removal of GL(dl_loaded). * elf/dl-load.c (_dl_map_object_from_fd): Don't load ld.so a second time. Reuse the one from the main namespace in all others. Pass new parameter to _dl_new_object. Adjust for removal of GL(dl_loaded). * elf/dl-object.c: Take new parameter. Use it to initialize l_ns. Adjust for removal of GL(dl_loaded). * elf/dl-open.c (_dl_open): Take new parameter. Adjust for removal of GL(dl_loaded). * elf/dl-support.c: Replace global _dl_loaded etc variables with _dl_ns variable. * include/dlfcn.h: Adjust prototype of _dl_open. Define __LM_ID_CALLER. * include/link.h: Add l_real, l_ns, and l_direct_opencount elements. * sysdeps/generic/dl-tls.c: Bump TLS_STATIC_SURPLUS. Since libc is using TLS we need memory appropriate to the number of namespaces. * sysdeps/generic/ldsodefs.h (struct rtld_global): Replace _dl_loaded, _dl_nloaded, _dl_global_scope, _dl_main_searchlist, and _dl_global_scope_alloc with _dl_ns element. Define DL_NNS. Adjust prototypes of _dl_map_object and member in rtld_global_ro. * malloc/malloc.c: Include <dlfcn.h>. * malloc/arena.c (ptmalloc_init): If libc is not in primary namespace, never use brk. * elf/Makefile: Add rules to build and run tst-dlmopen1 and tst-dlmopen2. * elf/tst-dlmopen1.c: New file. * elf/tst-dlmopen1mod.c: New file. * elf/tst-dlmopen2.c: New file. * elf/dl-close.c: Improve reference counting by tracking direct loads. * elf/dl-lookup.c (add_dependency): Likewise. * elf/dl-open.c (dl_open_worker): Likewise. * elf/rtld.c (dl_main): Likewise. 2004-09-09 GOTO Masanori <gotom@debian.or.jp> [BZ #77] * elf/dl-close.c: Count down l_opencount to check not only for l_reldeps, but also l_initfini. 2004-10-13 Ulrich Drepper <drepper@redhat.com>
This commit is contained in:
parent
8e9185fb1c
commit
c0f62c5678
67
ChangeLog
67
ChangeLog
@ -1,3 +1,70 @@
|
||||
2004-10-13 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
Add support for namespaces in the dynamic linker.
|
||||
* dlfcn/Makefile (libdl-routines): Add dlmopen.
|
||||
* dlfcn/Versions [libdl, GLIBC_2.3.4]: Add dlmopen.
|
||||
* dlfcn/dlfcn.h: Define Lmid_t, LM_ID_BASE, and LM_ID_NEWLM.
|
||||
Declare dlmopen. Document RTLD_DI_LMID.
|
||||
* dlfcn/dlinfo.c: Handle RTLD_DI_LMID.
|
||||
* dlfcn/dlmopen.c: New file.
|
||||
* dlfcn/dlopen.c: Pass new parameter to _dl_open.
|
||||
* dlfcn/dlopenold.c: Likewise.
|
||||
* elf/dl-addr.c: Adjust for removal of GL(dl_loaded).
|
||||
* elf/dl-caller.c: Likewise.
|
||||
* elf/dl-close.c: Likewise.
|
||||
* elf/dl-conflict.c: Likewise.
|
||||
* elf/dl-debug.c: Likewise.
|
||||
* elf/dl-lookup.c: Likewise.
|
||||
* elf/dl-sym.c: Likewise.
|
||||
* elf/dl-version.c: Likewise.
|
||||
* elf/do-lookup.h: Likewise.
|
||||
* elf/rtld.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/i386/dl-librecon.h: Likewise.
|
||||
* elf/dl-depsc: Likewise. Add new parameter to _dl_map_object.
|
||||
* elf/dl-fini.c: Call destructors in all namespaces.
|
||||
* elf/dl-iteratephdr.c: Compute total nloaded. Adjust for removal of
|
||||
GL(dl_loaded).
|
||||
* elf/dl-libc.c: Pass new parameter to _dl_open. Adjust for removal
|
||||
of GL(dl_loaded).
|
||||
* elf/dl-load.c (_dl_map_object_from_fd): Don't load ld.so a second
|
||||
time. Reuse the one from the main namespace in all others.
|
||||
Pass new parameter to _dl_new_object.
|
||||
Adjust for removal of GL(dl_loaded).
|
||||
* elf/dl-object.c: Take new parameter. Use it to initialize l_ns.
|
||||
Adjust for removal of GL(dl_loaded).
|
||||
* elf/dl-open.c (_dl_open): Take new parameter.
|
||||
Adjust for removal of GL(dl_loaded).
|
||||
* elf/dl-support.c: Replace global _dl_loaded etc variables with
|
||||
_dl_ns variable.
|
||||
* include/dlfcn.h: Adjust prototype of _dl_open.
|
||||
Define __LM_ID_CALLER.
|
||||
* include/link.h: Add l_real, l_ns, and l_direct_opencount elements.
|
||||
* sysdeps/generic/dl-tls.c: Bump TLS_STATIC_SURPLUS. Since libc is
|
||||
using TLS we need memory appropriate to the number of namespaces.
|
||||
* sysdeps/generic/ldsodefs.h (struct rtld_global): Replace _dl_loaded,
|
||||
_dl_nloaded, _dl_global_scope, _dl_main_searchlist, and
|
||||
_dl_global_scope_alloc with _dl_ns element. Define DL_NNS.
|
||||
Adjust prototypes of _dl_map_object and member in rtld_global_ro.
|
||||
* malloc/malloc.c: Include <dlfcn.h>.
|
||||
* malloc/arena.c (ptmalloc_init): If libc is not in primary namespace,
|
||||
never use brk.
|
||||
* elf/Makefile: Add rules to build and run tst-dlmopen1 and
|
||||
tst-dlmopen2.
|
||||
* elf/tst-dlmopen1.c: New file.
|
||||
* elf/tst-dlmopen1mod.c: New file.
|
||||
* elf/tst-dlmopen2.c: New file.
|
||||
|
||||
* elf/dl-close.c: Improve reference counting by tracking direct loads.
|
||||
* elf/dl-lookup.c (add_dependency): Likewise.
|
||||
* elf/dl-open.c (dl_open_worker): Likewise.
|
||||
* elf/rtld.c (dl_main): Likewise.
|
||||
|
||||
2004-09-09 GOTO Masanori <gotom@debian.or.jp>
|
||||
|
||||
[BZ #77]
|
||||
* elf/dl-close.c: Count down l_opencount to check not only for
|
||||
l_reldeps, but also l_initfini.
|
||||
|
||||
2004-10-13 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* elf/dl-close.c (_dl_close): Update bug reporting instructions.
|
||||
|
@ -19,7 +19,8 @@
|
||||
subdir := dlfcn
|
||||
headers := bits/dlfcn.h dlfcn.h
|
||||
extra-libs := libdl
|
||||
libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo
|
||||
libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
|
||||
dlmopen
|
||||
distribute := dlopenold.c glreflib1.c glreflib2.c failtestmod.c \
|
||||
defaultmod1.c defaultmod2.c errmsg1mod.c modatexit.c \
|
||||
modcxaatexit.c modstatic.c \
|
||||
|
@ -8,4 +8,7 @@ libdl {
|
||||
GLIBC_2.3.3 {
|
||||
dladdr1; dlinfo;
|
||||
}
|
||||
GLIBC_2.3.4 {
|
||||
dlmopen;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* User functions for run-time dynamic loading.
|
||||
Copyright (C) 1995-1999,2000,2001,2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-1999,2000,2001,2003,2004 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@ -39,6 +39,14 @@
|
||||
the run-time address of the symbol called NAME in the global scope
|
||||
is returned. */
|
||||
# define RTLD_DEFAULT ((void *) 0)
|
||||
|
||||
|
||||
/* Type for namespace indeces. */
|
||||
typedef long int Lmid_t;
|
||||
|
||||
/* Special namespace ID values. */
|
||||
# define LM_ID_BASE 0 /* Initial namespace. */
|
||||
# define LM_ID_NEWLM -1 /* For dlmopen: request new namespace. */
|
||||
#endif
|
||||
|
||||
|
||||
@ -58,6 +66,9 @@ extern void *dlsym (void *__restrict __handle,
|
||||
__const char *__restrict __name) __THROW;
|
||||
|
||||
#ifdef __USE_GNU
|
||||
/* Like `dlopen', but request object to be allocated in a new namespace. */
|
||||
extern void *dlmopen (Lmid_t __nsid, __const char *__file, int __mode) __THROW;
|
||||
|
||||
/* Find the run-time address in the shared object HANDLE refers to
|
||||
of the symbol called NAME with VERSION. */
|
||||
extern void *dlvsym (void *__restrict __handle,
|
||||
@ -114,6 +125,9 @@ extern int dlinfo (void *__restrict __handle,
|
||||
/* These are the possible values for the REQUEST argument to `dlinfo'. */
|
||||
enum
|
||||
{
|
||||
/* Treat ARG as `lmid_t *'; store namespace ID for HANDLE there. */
|
||||
RTLD_DI_LMID = 1,
|
||||
|
||||
/* Treat ARG as `struct link_map **';
|
||||
store the `struct link_map *' for HANDLE there. */
|
||||
RTLD_DI_LINKMAP = 2,
|
||||
@ -130,7 +144,6 @@ enum
|
||||
expand $ORIGIN in this shared object's dependency file names. */
|
||||
RTLD_DI_ORIGIN = 6,
|
||||
|
||||
RTLD_DI_LMID = 1, /* Unsupported, defined by Solaris. */
|
||||
RTLD_DI_CONFIGADDR = 3 /* Unsupported, defined by Solaris. */
|
||||
};
|
||||
|
||||
|
@ -55,12 +55,15 @@ RTLD_SELF used in code not dynamically loaded"));
|
||||
|
||||
switch (args->request)
|
||||
{
|
||||
case RTLD_DI_LMID:
|
||||
case RTLD_DI_CONFIGADDR:
|
||||
default:
|
||||
GLRO(dl_signal_error) (0, NULL, NULL, N_("unsupported dlinfo request"));
|
||||
break;
|
||||
|
||||
case RTLD_DI_LMID:
|
||||
*(Lmid_t *) args->arg = l->l_ns;
|
||||
break;
|
||||
|
||||
case RTLD_DI_LINKMAP:
|
||||
*(struct link_map **) args->arg = l;
|
||||
break;
|
||||
|
69
dlfcn/dlmopen.c
Normal file
69
dlfcn/dlmopen.c
Normal file
@ -0,0 +1,69 @@
|
||||
/* Load a shared object at run time.
|
||||
Copyright (C) 1995,96,97,98,99,2000,2003,2004 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <stddef.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
struct dlmopen_args
|
||||
{
|
||||
/* Namespace ID. */
|
||||
Lmid_t nsid;
|
||||
/* The arguments for dlopen_doit. */
|
||||
const char *file;
|
||||
int mode;
|
||||
/* The return value of dlopen_doit. */
|
||||
void *new;
|
||||
/* Address of the caller. */
|
||||
const void *caller;
|
||||
};
|
||||
|
||||
static void
|
||||
dlmopen_doit (void *a)
|
||||
{
|
||||
struct dlmopen_args *args = (struct dlmopen_args *) a;
|
||||
|
||||
/* Non-shared code has no support for multiple namespaces. */
|
||||
if (args->nsid != LM_ID_BASE)
|
||||
#ifdef SHARED
|
||||
/* If trying to open the link map for the main executable the namespace
|
||||
must be the main one. */
|
||||
if (args->file == NULL)
|
||||
#endif
|
||||
GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace"));
|
||||
|
||||
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->caller, args->nsid);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
dlmopen (Lmid_t nsid, const char *file, int mode)
|
||||
{
|
||||
struct dlmopen_args args;
|
||||
args.nsid = nsid;
|
||||
args.file = file;
|
||||
args.mode = mode;
|
||||
args.caller = RETURN_ADDRESS (0);
|
||||
|
||||
return _dlerror_run (dlmopen_doit, &args) ? NULL : args.new;
|
||||
}
|
||||
static_link_warning (dlmopen)
|
@ -1,5 +1,5 @@
|
||||
/* Load a shared object at run time.
|
||||
Copyright (C) 1995,96,97,98,99,2000,2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995,96,97,98,99,2000,2003,2004 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@ -31,13 +31,22 @@ struct dlopen_args
|
||||
const void *caller;
|
||||
};
|
||||
|
||||
|
||||
/* Non-shared code has no support for multiple namespaces. */
|
||||
#ifdef SHARED
|
||||
# define NS __LM_ID_CALLER
|
||||
#else
|
||||
# define NS LM_ID_BASE
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
dlopen_doit (void *a)
|
||||
{
|
||||
struct dlopen_args *args = (struct dlopen_args *) a;
|
||||
|
||||
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->caller);
|
||||
args->caller, args->file == NULL ? LM_ID_BASE : NS);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Load a shared object at run time.
|
||||
Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-1999, 2000, 2004 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@ -37,13 +37,21 @@ struct dlopen_args
|
||||
};
|
||||
|
||||
|
||||
/* Non-shared code has no support for multiple namespaces. */
|
||||
#ifdef SHARED
|
||||
# define NS __LM_ID_CALLER
|
||||
#else
|
||||
# define NS LM_ID_BASE
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
dlopen_doit (void *a)
|
||||
{
|
||||
struct dlopen_args *args = (struct dlopen_args *) a;
|
||||
|
||||
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->caller);
|
||||
args->caller, args->file == NULL ? LM_ID_BASE : NS);
|
||||
}
|
||||
|
||||
extern void *__dlopen_nocheck (const char *file, int mode);
|
||||
|
12
elf/Makefile
12
elf/Makefile
@ -154,7 +154,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
|
||||
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
|
||||
$(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
|
||||
tst-dlopenrpath tst-deep1
|
||||
tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2
|
||||
# reldep9
|
||||
test-srcs = tst-pathopt
|
||||
tests-vis-yes = vismain
|
||||
@ -187,7 +187,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
reldep8mod1 reldep8mod2 reldep8mod3 \
|
||||
reldep9mod1 reldep9mod2 reldep9mod3 \
|
||||
tst-alignmod $(modules-execstack-$(have-z-execstack)) \
|
||||
tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3
|
||||
tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
|
||||
tst-dlmopen1mod
|
||||
ifeq (yes,$(have-initfini-array))
|
||||
modules-names += tst-array2dep
|
||||
endif
|
||||
@ -762,3 +763,10 @@ $(objpfx)tst-deep1: $(libdl) $(objpfx)tst-deep1mod1.so
|
||||
$(objpfx)tst-deep1.out: $(objpfx)tst-deep1mod2.so
|
||||
LDFLAGS-tst-deep1 += -rdynamic
|
||||
tst-deep1mod3.so-no-z-defs = yes
|
||||
|
||||
$(objpfx)tst-dlmopen1mod.so: $(libdl)
|
||||
$(objpfx)tst-dlmopen1: $(libdl)
|
||||
$(objpfx)tst-dlmopen1.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
$(objpfx)tst-dlmopen2: $(libdl)
|
||||
$(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
@ -38,26 +38,27 @@ _dl_addr (const void *address, Dl_info *info,
|
||||
|
||||
/* Find the highest-addressed object that ADDRESS is not below. */
|
||||
match = NULL;
|
||||
for (struct link_map *l = GL(dl_loaded); l; l = l->l_next)
|
||||
if (addr >= l->l_map_start && addr < l->l_map_end)
|
||||
{
|
||||
/* We know ADDRESS lies within L if in any shared object.
|
||||
Make sure it isn't past the end of L's segments. */
|
||||
size_t n = l->l_phnum;
|
||||
if (n > 0)
|
||||
{
|
||||
do
|
||||
--n;
|
||||
while (l->l_phdr[n].p_type != PT_LOAD);
|
||||
if (addr >= (l->l_addr +
|
||||
l->l_phdr[n].p_vaddr + l->l_phdr[n].p_memsz))
|
||||
/* Off the end of the highest-addressed shared object. */
|
||||
continue;
|
||||
}
|
||||
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
|
||||
for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l; l = l->l_next)
|
||||
if (addr >= l->l_map_start && addr < l->l_map_end)
|
||||
{
|
||||
/* We know ADDRESS lies within L if in any shared object.
|
||||
Make sure it isn't past the end of L's segments. */
|
||||
size_t n = l->l_phnum;
|
||||
if (n > 0)
|
||||
{
|
||||
do
|
||||
--n;
|
||||
while (l->l_phdr[n].p_type != PT_LOAD);
|
||||
if (addr >= (l->l_addr +
|
||||
l->l_phdr[n].p_vaddr + l->l_phdr[n].p_memsz))
|
||||
/* Off the end of the highest-addressed shared object. */
|
||||
continue;
|
||||
}
|
||||
|
||||
match = l;
|
||||
break;
|
||||
}
|
||||
match = l;
|
||||
break;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
if (match != NULL)
|
||||
|
@ -35,44 +35,46 @@ _dl_check_caller (const void *caller, enum allowmask mask)
|
||||
#endif
|
||||
static const char expected4[] = LD_SO;
|
||||
|
||||
for (struct link_map *l = GL(dl_loaded); l != NULL; l = l->l_next)
|
||||
if (caller >= (const void *) l->l_map_start
|
||||
&& caller < (const void *) l->l_text_end)
|
||||
{
|
||||
/* The address falls into this DSO's address range. Check the
|
||||
name. */
|
||||
if ((mask & allow_libc) && strcmp (expected1, l->l_name) == 0)
|
||||
return 0;
|
||||
if ((mask & allow_libdl) && strcmp (expected2, l->l_name) == 0)
|
||||
return 0;
|
||||
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
|
||||
for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
|
||||
l = l->l_next)
|
||||
if (caller >= (const void *) l->l_map_start
|
||||
&& caller < (const void *) l->l_text_end)
|
||||
{
|
||||
/* The address falls into this DSO's address range. Check the
|
||||
name. */
|
||||
if ((mask & allow_libc) && strcmp (expected1, l->l_name) == 0)
|
||||
return 0;
|
||||
if ((mask & allow_libdl) && strcmp (expected2, l->l_name) == 0)
|
||||
return 0;
|
||||
#ifdef LIBPTHREAD_SO
|
||||
if ((mask & allow_libpthread) && strcmp (expected3, l->l_name) == 0)
|
||||
return 0;
|
||||
if ((mask & allow_libpthread) && strcmp (expected3, l->l_name) == 0)
|
||||
return 0;
|
||||
#endif
|
||||
if ((mask & allow_ldso) && strcmp (expected4, l->l_name) == 0)
|
||||
return 0;
|
||||
if ((mask & allow_ldso) && strcmp (expected4, l->l_name) == 0)
|
||||
return 0;
|
||||
|
||||
struct libname_list *runp = l->l_libname;
|
||||
struct libname_list *runp = l->l_libname;
|
||||
|
||||
while (runp != NULL)
|
||||
{
|
||||
if ((mask & allow_libc) && strcmp (expected1, runp->name) == 0)
|
||||
return 0;
|
||||
if ((mask & allow_libdl) && strcmp (expected2, runp->name) == 0)
|
||||
return 0;
|
||||
while (runp != NULL)
|
||||
{
|
||||
if ((mask & allow_libc) && strcmp (expected1, runp->name) == 0)
|
||||
return 0;
|
||||
if ((mask & allow_libdl) && strcmp (expected2, runp->name) == 0)
|
||||
return 0;
|
||||
#ifdef LIBPTHREAD_SO
|
||||
if ((mask & allow_libpthread)
|
||||
&& strcmp (expected3, runp->name) == 0)
|
||||
return 0;
|
||||
if ((mask & allow_libpthread)
|
||||
&& strcmp (expected3, runp->name) == 0)
|
||||
return 0;
|
||||
#endif
|
||||
if ((mask & allow_ldso) && strcmp (expected4, runp->name) == 0)
|
||||
return 0;
|
||||
if ((mask & allow_ldso) && strcmp (expected4, runp->name) == 0)
|
||||
return 0;
|
||||
|
||||
runp = runp->next;
|
||||
}
|
||||
runp = runp->next;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Maybe the dynamic linker is not yet on the list. */
|
||||
if ((mask & allow_ldso) != 0
|
||||
|
141
elf/dl-close.c
141
elf/dl-close.c
@ -130,6 +130,10 @@ _dl_close (void *_map)
|
||||
/* Acquire the lock. */
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
|
||||
/* One less direct use. */
|
||||
assert (map->l_direct_opencount > 0);
|
||||
--map->l_direct_opencount;
|
||||
|
||||
/* Decrement the reference count. */
|
||||
if (map->l_opencount > 1 || map->l_type != lt_loaded)
|
||||
{
|
||||
@ -141,6 +145,12 @@ _dl_close (void *_map)
|
||||
/* Decrement the object's reference counter, not the dependencies'. */
|
||||
--map->l_opencount;
|
||||
|
||||
/* If the direct use counter reaches zero we have to decrement
|
||||
all the dependencies' usage counter. */
|
||||
if (map->l_direct_opencount == 0)
|
||||
for (i = 1; i < map->l_searchlist.r_nlist; ++i)
|
||||
--map->l_searchlist.r_list[i]->l_opencount;
|
||||
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
return;
|
||||
}
|
||||
@ -167,12 +177,13 @@ _dl_close (void *_map)
|
||||
for (i = 1; list[i] != NULL; ++i)
|
||||
if ((list[i]->l_flags_1 & DF_1_NODELETE) == 0
|
||||
/* Decrement counter. */
|
||||
&& --new_opencount[i] == 0)
|
||||
&& (assert (new_opencount[i] > 0), --new_opencount[i] == 0))
|
||||
{
|
||||
void mark_removed (struct link_map *remmap)
|
||||
{
|
||||
/* Test whether this object was also loaded directly. */
|
||||
if (remmap->l_searchlist.r_list != NULL)
|
||||
if (remmap->l_searchlist.r_list != NULL
|
||||
&& remmap->l_direct_opencount > 0)
|
||||
{
|
||||
/* In this case we have to decrement all the dependencies of
|
||||
this object. They are all in MAP's dependency list. */
|
||||
@ -184,6 +195,7 @@ _dl_close (void *_map)
|
||||
|| ! dep_list[j]->l_init_called)
|
||||
{
|
||||
assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
|
||||
assert (new_opencount[dep_list[j]->l_idx] > 0);
|
||||
if (--new_opencount[dep_list[j]->l_idx] == 0)
|
||||
{
|
||||
assert (dep_list[j]->l_type == lt_loaded);
|
||||
@ -197,17 +209,53 @@ _dl_close (void *_map)
|
||||
unsigned int j;
|
||||
for (j = 0; j < remmap->l_reldepsact; ++j)
|
||||
{
|
||||
struct link_map *depmap = remmap->l_reldeps[j];
|
||||
|
||||
/* Find out whether this object is in our list. */
|
||||
if (remmap->l_reldeps[j]->l_idx < nopencount
|
||||
&& (list[remmap->l_reldeps[j]->l_idx]
|
||||
== remmap->l_reldeps[j]))
|
||||
/* Yes, it is. */
|
||||
if (--new_opencount[remmap->l_reldeps[j]->l_idx] == 0)
|
||||
{
|
||||
/* This one is now gone, too. */
|
||||
assert (remmap->l_reldeps[j]->l_type == lt_loaded);
|
||||
mark_removed (remmap->l_reldeps[j]);
|
||||
}
|
||||
if (depmap->l_idx < nopencount
|
||||
&& list[depmap->l_idx] == depmap)
|
||||
{
|
||||
/* Yes, it is. If is has a search list, make a
|
||||
recursive call to handle this. */
|
||||
if (depmap->l_searchlist.r_list != NULL)
|
||||
{
|
||||
assert (new_opencount[depmap->l_idx] > 0);
|
||||
if (--new_opencount[depmap->l_idx] == 0)
|
||||
{
|
||||
/* This one is now gone, too. */
|
||||
assert (depmap->l_type == lt_loaded);
|
||||
mark_removed (depmap);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise we have to handle the dependency
|
||||
deallocation here. */
|
||||
unsigned int k;
|
||||
for (k = 0; depmap->l_initfini[k] != NULL; ++k)
|
||||
{
|
||||
struct link_map *rl = depmap->l_initfini[k];
|
||||
|
||||
if (rl->l_idx < nopencount
|
||||
& list[rl->l_idx] == rl)
|
||||
{
|
||||
assert (new_opencount[rl->l_idx] > 0);
|
||||
if (--new_opencount[rl->l_idx] == 0)
|
||||
{
|
||||
/* Another module to remove. */
|
||||
assert (rl->l_type == lt_loaded);
|
||||
mark_removed (rl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (rl->l_opencount > 0);
|
||||
if (--rl->l_opencount == 0)
|
||||
mark_removed (rl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,7 +273,8 @@ _dl_close (void *_map)
|
||||
{
|
||||
/* When debugging print a message first. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
||||
GLRO(dl_debug_printf) ("\ncalling fini: %s\n\n", imap->l_name);
|
||||
GLRO(dl_debug_printf) ("\ncalling fini: %s [%lu]\n\n",
|
||||
imap->l_name, imap->l_ns);
|
||||
|
||||
/* Call its termination function. Do not do it for
|
||||
half-cooked objects. */
|
||||
@ -340,18 +389,21 @@ _dl_close (void *_map)
|
||||
if (__builtin_expect (imap->l_global, 0))
|
||||
{
|
||||
/* This object is in the global scope list. Remove it. */
|
||||
unsigned int cnt = GL(dl_main_searchlist)->r_nlist;
|
||||
unsigned int cnt
|
||||
= GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist;
|
||||
|
||||
do
|
||||
--cnt;
|
||||
while (GL(dl_main_searchlist)->r_list[cnt] != imap);
|
||||
while (GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt]
|
||||
!= imap);
|
||||
|
||||
/* The object was already correctly registered. */
|
||||
while (++cnt < GL(dl_main_searchlist)->r_nlist)
|
||||
GL(dl_main_searchlist)->r_list[cnt - 1]
|
||||
= GL(dl_main_searchlist)->r_list[cnt];
|
||||
while (++cnt
|
||||
< GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist)
|
||||
GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt - 1]
|
||||
= GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt];
|
||||
|
||||
--GL(dl_main_searchlist)->r_nlist;
|
||||
--GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist;
|
||||
}
|
||||
|
||||
#ifdef USE_TLS
|
||||
@ -442,19 +494,18 @@ _dl_close (void *_map)
|
||||
DL_UNMAP (imap);
|
||||
|
||||
/* Finally, unlink the data structure and free it. */
|
||||
#ifdef SHARED
|
||||
/* We will unlink the first object only if this is a statically
|
||||
linked program. */
|
||||
assert (imap->l_prev != NULL);
|
||||
imap->l_prev->l_next = imap->l_next;
|
||||
#else
|
||||
if (imap->l_prev != NULL)
|
||||
imap->l_prev->l_next = imap->l_next;
|
||||
else
|
||||
GL(dl_loaded) = imap->l_next;
|
||||
{
|
||||
#ifdef SHARED
|
||||
assert (imap->l_ns != LM_ID_BASE);
|
||||
#endif
|
||||
--GL(dl_nloaded);
|
||||
if (imap->l_next)
|
||||
GL(dl_ns)[imap->l_ns]._ns_loaded = imap->l_next;
|
||||
}
|
||||
|
||||
--GL(dl_ns)[imap->l_ns]._ns_nloaded;
|
||||
if (imap->l_next != NULL)
|
||||
imap->l_next->l_prev = imap->l_prev;
|
||||
|
||||
free (imap->l_versions);
|
||||
@ -528,7 +579,7 @@ _dl_close (void *_map)
|
||||
if (any_tls)
|
||||
{
|
||||
if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
||||
__libc_fatal (_("TLS generation counter wrapped! Please send report as described in <http://www.gnu.org/software/libc/bugs.html>."));
|
||||
__libc_fatal (_("TLS generation counter wrapped! Please report as described in <http://www.gnu.org/software/libc/bugs.html>."));
|
||||
|
||||
if (tls_free_end == GL(dl_tls_static_used))
|
||||
GL(dl_tls_static_used) = tls_free_start;
|
||||
@ -596,22 +647,26 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
|
||||
|
||||
libc_freeres_fn (free_mem)
|
||||
{
|
||||
if (__builtin_expect (GL(dl_global_scope_alloc), 0) != 0
|
||||
&& (GL(dl_main_searchlist)->r_nlist
|
||||
== GLRO(dl_initial_searchlist).r_nlist))
|
||||
{
|
||||
/* All object dynamically loaded by the program are unloaded. Free
|
||||
the memory allocated for the global scope variable. */
|
||||
struct link_map **old = GL(dl_main_searchlist)->r_list;
|
||||
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
|
||||
if (__builtin_expect (GL(dl_ns)[ns]._ns_global_scope_alloc, 0) != 0
|
||||
&& (GL(dl_ns)[ns]._ns_main_searchlist->r_nlist
|
||||
// XXX Check whether we need NS-specific initial_searchlist
|
||||
== GLRO(dl_initial_searchlist).r_nlist))
|
||||
{
|
||||
/* All object dynamically loaded by the program are unloaded. Free
|
||||
the memory allocated for the global scope variable. */
|
||||
struct link_map **old = GL(dl_ns)[ns]._ns_main_searchlist->r_list;
|
||||
|
||||
/* Put the old map in. */
|
||||
GL(dl_main_searchlist)->r_list = GLRO(dl_initial_searchlist).r_list;
|
||||
/* Signal that the original map is used. */
|
||||
GL(dl_global_scope_alloc) = 0;
|
||||
/* Put the old map in. */
|
||||
GL(dl_ns)[ns]._ns_main_searchlist->r_list
|
||||
// XXX Check whether we need NS-specific initial_searchlist
|
||||
= GLRO(dl_initial_searchlist).r_list;
|
||||
/* Signal that the original map is used. */
|
||||
GL(dl_ns)[ns]._ns_global_scope_alloc = 0;
|
||||
|
||||
/* Now free the old map. */
|
||||
free (old);
|
||||
}
|
||||
/* Now free the old map. */
|
||||
free (old);
|
||||
}
|
||||
|
||||
#ifdef USE_TLS
|
||||
if (USE___THREAD || GL(dl_tls_dtv_slotinfo_list) != NULL)
|
||||
|
@ -54,8 +54,10 @@ _dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
|
||||
(map) = resolve_conflict_map; \
|
||||
} while (0)
|
||||
|
||||
/* Prelinking makes no sense for anything but the main namespace. */
|
||||
assert (l->l_ns == LM_ID_BASE);
|
||||
struct link_map *resolve_conflict_map __attribute__ ((__unused__))
|
||||
= GL(dl_loaded);
|
||||
= GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
|
||||
#include "dynamic-link.h"
|
||||
|
||||
|
@ -39,7 +39,9 @@ _dl_debug_initialize (ElfW(Addr) ldbase)
|
||||
/* Tell the debugger where to find the map of loaded objects. */
|
||||
_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;
|
||||
_r_debug.r_ldbase = ldbase;
|
||||
_r_debug.r_map = GL(dl_loaded);
|
||||
// XXX This is problematic. It means we cannot tell the debugger
|
||||
// XXX about namespaces other than the main one.
|
||||
_r_debug.r_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
_r_debug.r_brk = (ElfW(Addr)) &_dl_debug_state;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,8 @@ openaux (void *a)
|
||||
args->aux = _dl_map_object (args->map, args->name, 0,
|
||||
(args->map->l_type == lt_executable
|
||||
? lt_library : args->map->l_type),
|
||||
args->trace_mode, args->open_mode);
|
||||
args->trace_mode, args->open_mode,
|
||||
args->map->l_ns);
|
||||
}
|
||||
|
||||
static ptrdiff_t
|
||||
@ -510,7 +511,7 @@ _dl_map_object_deps (struct link_map *map,
|
||||
}
|
||||
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
|
||||
&& map == GL(dl_loaded))
|
||||
&& map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
|
||||
{
|
||||
/* If we are to compute conflicts, we have to build local scope
|
||||
for each library, not just the ultimate loader. */
|
||||
|
261
elf/dl-fini.c
261
elf/dl-fini.c
@ -32,10 +32,10 @@ internal_function
|
||||
_dl_fini (void)
|
||||
{
|
||||
/* Lots of fun ahead. We have to call the destructors for all still
|
||||
loaded objects. The problem is that the ELF specification now
|
||||
demands that dependencies between the modules are taken into account.
|
||||
I.e., the destructor for a module is called before the ones for any
|
||||
of its dependencies.
|
||||
loaded objects, in all namespaces. The problem is that the ELF
|
||||
specification now demands that dependencies between the modules
|
||||
are taken into account. I.e., the destructor for a module is
|
||||
called before the ones for any of its dependencies.
|
||||
|
||||
To make things more complicated, we cannot simply use the reverse
|
||||
order of the constructors. Since the user might have loaded objects
|
||||
@ -45,140 +45,179 @@ _dl_fini (void)
|
||||
unsigned int i;
|
||||
unsigned int nloaded;
|
||||
struct link_map *l;
|
||||
struct link_map **maps;
|
||||
struct link_map **maps = NULL;
|
||||
size_t maps_size = 0;
|
||||
|
||||
/* Protect against concurrent loads and unloads. */
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
|
||||
nloaded = GL(dl_nloaded);
|
||||
|
||||
/* XXX Could it be (in static binaries) that there is no object loaded? */
|
||||
assert (nloaded > 0);
|
||||
|
||||
/* Now we can allocate an array to hold all the pointers and copy
|
||||
the pointers in. */
|
||||
maps = (struct link_map **) alloca (nloaded * sizeof (struct link_map *));
|
||||
for (l = GL(dl_loaded), i = 0; l != NULL; l = l->l_next)
|
||||
/* We First run the destructors of the main namespaces, then the
|
||||
other ones. The order should not matter since the namespace
|
||||
content is supposed to be independent. But we can have auditing
|
||||
code in a auxiliaty namespace and we want it to monitor the
|
||||
destructors. */
|
||||
for (Lmid_t cnt = 0; cnt < DL_NNS; ++cnt)
|
||||
{
|
||||
assert (i < nloaded);
|
||||
/* Protect against concurrent loads and unloads. */
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
|
||||
maps[i++] = l;
|
||||
nloaded = GL(dl_ns)[cnt]._ns_nloaded;
|
||||
|
||||
/* Bump l_opencount of all objects so that they are not dlclose()ed
|
||||
from underneath us. */
|
||||
++l->l_opencount;
|
||||
}
|
||||
assert (i == nloaded);
|
||||
/* XXX Could it be (in static binaries) that there is no object
|
||||
loaded? */
|
||||
assert (cnt != LM_ID_BASE || nloaded > 0);
|
||||
|
||||
/* Now we have to do the sorting. */
|
||||
for (l = GL(dl_loaded)->l_next; l != NULL; l = l->l_next)
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int k;
|
||||
|
||||
/* Find the place in the 'maps' array. */
|
||||
for (j = 1; maps[j] != l; ++j)
|
||||
;
|
||||
|
||||
/* Find all object for which the current one is a dependency and
|
||||
move the found object (if necessary) in front. */
|
||||
for (k = j + 1; k < nloaded; ++k)
|
||||
/* Now we can allocate an array to hold all the pointers and copy
|
||||
the pointers in. */
|
||||
if (maps_size < nloaded * sizeof (struct link_map *))
|
||||
{
|
||||
struct link_map **runp = maps[k]->l_initfini;
|
||||
if (runp != NULL)
|
||||
if (maps_size == 0)
|
||||
{
|
||||
while (*runp != NULL)
|
||||
if (*runp == l)
|
||||
{
|
||||
struct link_map *here = maps[k];
|
||||
|
||||
/* Move it now. */
|
||||
memmove (&maps[j] + 1,
|
||||
&maps[j],
|
||||
(k - j) * sizeof (struct link_map *));
|
||||
maps[j++] = here;
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
++runp;
|
||||
maps_size = nloaded * sizeof (struct link_map *);
|
||||
maps = (struct link_map **) alloca (maps_size);
|
||||
}
|
||||
else
|
||||
maps = (struct link_map **)
|
||||
extend_alloca (maps, maps_size,
|
||||
nloaded * sizeof (struct link_map *));
|
||||
}
|
||||
|
||||
if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
|
||||
for (l = GL(dl_ns)[cnt]._ns_loaded, i = 0; l != NULL; l = l->l_next)
|
||||
{
|
||||
assert (i < nloaded);
|
||||
|
||||
/* Do not handle ld.so in secondary namespaces. */
|
||||
if (l == l->l_real)
|
||||
{
|
||||
unsigned int m = maps[k]->l_reldepsact;
|
||||
struct link_map **relmaps = maps[k]->l_reldeps;
|
||||
maps[i++] = l;
|
||||
|
||||
while (m-- > 0)
|
||||
/* Bump l_opencount of all objects so that they are not
|
||||
dlclose()ed from underneath us. */
|
||||
++l->l_opencount;
|
||||
}
|
||||
}
|
||||
assert (cnt != LM_ID_BASE || i == nloaded);
|
||||
assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1);
|
||||
unsigned int nmaps = i;
|
||||
|
||||
if (nmaps != 0)
|
||||
{
|
||||
/* Now we have to do the sorting. */
|
||||
l = GL(dl_ns)[cnt]._ns_loaded;
|
||||
if (cnt == LM_ID_BASE)
|
||||
/* The main executable always comes first. */
|
||||
l = l->l_next;
|
||||
for (; l != NULL; l = l->l_next)
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int k;
|
||||
|
||||
/* Find the place in the 'maps' array. */
|
||||
for (j = 1; maps[j] != l; ++j)
|
||||
;
|
||||
|
||||
/* Find all object for which the current one is a dependency and
|
||||
move the found object (if necessary) in front. */
|
||||
for (k = j + 1; k < nmaps; ++k)
|
||||
{
|
||||
if (relmaps[m] == l)
|
||||
struct link_map **runp = maps[k]->l_initfini;
|
||||
if (runp != NULL)
|
||||
{
|
||||
struct link_map *here = maps[k];
|
||||
while (*runp != NULL)
|
||||
if (*runp == l)
|
||||
{
|
||||
struct link_map *here = maps[k];
|
||||
|
||||
/* Move it now. */
|
||||
memmove (&maps[j] + 1,
|
||||
&maps[j],
|
||||
(k - j) * sizeof (struct link_map *));
|
||||
maps[j] = here;
|
||||
/* Move it now. */
|
||||
memmove (&maps[j] + 1,
|
||||
&maps[j],
|
||||
(k - j) * sizeof (struct link_map *));
|
||||
maps[j++] = here;
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
else
|
||||
++runp;
|
||||
}
|
||||
|
||||
if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
|
||||
{
|
||||
unsigned int m = maps[k]->l_reldepsact;
|
||||
struct link_map **relmaps = maps[k]->l_reldeps;
|
||||
|
||||
while (m-- > 0)
|
||||
{
|
||||
if (relmaps[m] == l)
|
||||
{
|
||||
struct link_map *here = maps[k];
|
||||
|
||||
/* Move it now. */
|
||||
memmove (&maps[j] + 1,
|
||||
&maps[j],
|
||||
(k - j) * sizeof (struct link_map *));
|
||||
maps[j] = here;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We do not rely on the linked list of loaded object anymore from
|
||||
this point on. We have our own list here (maps). The various
|
||||
members of this list cannot vanish since the open count is too
|
||||
high and will be decremented in this loop. So we release the
|
||||
lock so that some code which might be called from a destructor
|
||||
can directly or indirectly access the lock. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
/* We do not rely on the linked list of loaded object anymore from
|
||||
this point on. We have our own list here (maps). The various
|
||||
members of this list cannot vanish since the open count is too
|
||||
high and will be decremented in this loop. So we release the
|
||||
lock so that some code which might be called from a destructor
|
||||
can directly or indirectly access the lock. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
|
||||
/* 'maps' now contains the objects in the right order. Now call the
|
||||
destructors. We have to process this array from the front. */
|
||||
for (i = 0; i < nloaded; ++i)
|
||||
{
|
||||
l = maps[i];
|
||||
|
||||
if (l->l_init_called)
|
||||
/* 'maps' now contains the objects in the right order. Now call the
|
||||
destructors. We have to process this array from the front. */
|
||||
for (i = 0; i < nmaps; ++i)
|
||||
{
|
||||
/* Make sure nothing happens if we are called twice. */
|
||||
l->l_init_called = 0;
|
||||
l = maps[i];
|
||||
|
||||
/* Don't call the destructors for objects we are not supposed to. */
|
||||
if (l->l_name[0] == '\0' && l->l_type == lt_executable)
|
||||
continue;
|
||||
|
||||
/* Is there a destructor function? */
|
||||
if (l->l_info[DT_FINI_ARRAY] == NULL && l->l_info[DT_FINI] == NULL)
|
||||
continue;
|
||||
|
||||
/* When debugging print a message first. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
||||
_dl_debug_printf ("\ncalling fini: %s\n\n",
|
||||
l->l_name[0] ? l->l_name : rtld_progname);
|
||||
|
||||
/* First see whether an array is given. */
|
||||
if (l->l_info[DT_FINI_ARRAY] != NULL)
|
||||
if (l->l_init_called)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
(ElfW(Addr) *) (l->l_addr
|
||||
+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
/ sizeof (ElfW(Addr)));
|
||||
while (i-- > 0)
|
||||
((fini_t) array[i]) ();
|
||||
/* Make sure nothing happens if we are called twice. */
|
||||
l->l_init_called = 0;
|
||||
|
||||
/* Don't call the destructors for objects we are not
|
||||
supposed to. */
|
||||
if (l->l_name[0] == '\0' && l->l_type == lt_executable)
|
||||
continue;
|
||||
|
||||
/* Is there a destructor function? */
|
||||
if (l->l_info[DT_FINI_ARRAY] == NULL
|
||||
&& l->l_info[DT_FINI] == NULL)
|
||||
continue;
|
||||
|
||||
/* When debugging print a message first. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
|
||||
0))
|
||||
_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
|
||||
l->l_name[0] ? l->l_name : rtld_progname,
|
||||
cnt);
|
||||
|
||||
/* First see whether an array is given. */
|
||||
if (l->l_info[DT_FINI_ARRAY] != NULL)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
(ElfW(Addr) *) (l->l_addr
|
||||
+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
/ sizeof (ElfW(Addr)));
|
||||
while (i-- > 0)
|
||||
((fini_t) array[i]) ();
|
||||
}
|
||||
|
||||
/* Next try the old-style destructor. */
|
||||
if (l->l_info[DT_FINI] != NULL)
|
||||
((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
|
||||
}
|
||||
|
||||
/* Next try the old-style destructor. */
|
||||
if (l->l_info[DT_FINI] != NULL)
|
||||
((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
|
||||
/* Correct the previous increment. */
|
||||
--l->l_opencount;
|
||||
}
|
||||
|
||||
/* Correct the previous increment. */
|
||||
--l->l_opencount;
|
||||
}
|
||||
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0))
|
||||
|
@ -42,14 +42,32 @@ __dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
__libc_cleanup_push (cancel_handler, 0);
|
||||
|
||||
for (l = GL(dl_loaded); l != NULL; l = l->l_next)
|
||||
/* We have to determine the namespace of the caller since this determines
|
||||
which namespace is reported. */
|
||||
const void *caller = RETURN_ADDRESS (0);
|
||||
size_t nloaded = GL(dl_ns)[0]._ns_nloaded;
|
||||
Lmid_t ns = 0;
|
||||
for (Lmid_t cnt = DL_NNS - 1; cnt > 0; --cnt)
|
||||
for (struct link_map *l = GL(dl_ns)[cnt]._ns_loaded; l; l = l->l_next)
|
||||
{
|
||||
/* We have to count the total number of loaded objects. */
|
||||
nloaded += GL(dl_ns)[cnt]._ns_nloaded;
|
||||
|
||||
if (caller >= (const void *) l->l_map_start
|
||||
&& caller < (const void *) l->l_map_end)
|
||||
/* There must be exactly one DSO for the range of the virtual
|
||||
memory. Otherwise something is really broken. */
|
||||
ns = cnt;
|
||||
}
|
||||
|
||||
for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
|
||||
{
|
||||
info.dlpi_addr = l->l_addr;
|
||||
info.dlpi_name = l->l_name;
|
||||
info.dlpi_phdr = l->l_phdr;
|
||||
info.dlpi_phnum = l->l_phnum;
|
||||
info.dlpi_adds = GL(dl_load_adds);
|
||||
info.dlpi_subs = GL(dl_load_adds) - GL(dl_nloaded);
|
||||
info.dlpi_subs = GL(dl_load_adds) - nloaded;
|
||||
ret = callback (&info, sizeof (struct dl_phdr_info), data);
|
||||
if (ret)
|
||||
break;
|
||||
@ -87,7 +105,7 @@ dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
|
||||
info.dlpi_phdr = _dl_phdr;
|
||||
info.dlpi_phnum = _dl_phnum;
|
||||
info.dlpi_adds = GL(dl_load_adds);
|
||||
info.dlpi_subs = GL(dl_load_adds) - GL(dl_nloaded);
|
||||
info.dlpi_subs = GL(dl_load_adds) - GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
|
||||
ret = (*callback) (&info, sizeof (struct dl_phdr_info), data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -77,7 +77,7 @@ do_dlopen (void *ptr)
|
||||
{
|
||||
struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
|
||||
/* Open and relocate the shared object. */
|
||||
args->map = _dl_open (args->name, args->mode, NULL);
|
||||
args->map = _dl_open (args->name, args->mode, NULL, __LM_ID_CALLER);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -217,18 +217,19 @@ libc_freeres_fn (free_mem)
|
||||
}
|
||||
|
||||
/* Remove all additional names added to the objects. */
|
||||
for (l = GL(dl_loaded); l != NULL; l = l->l_next)
|
||||
{
|
||||
struct libname_list *lnp = l->l_libname->next;
|
||||
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
|
||||
for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
|
||||
{
|
||||
struct libname_list *lnp = l->l_libname->next;
|
||||
|
||||
l->l_libname->next = NULL;
|
||||
l->l_libname->next = NULL;
|
||||
|
||||
while (lnp != NULL)
|
||||
{
|
||||
struct libname_list *old = lnp;
|
||||
lnp = lnp->next;
|
||||
if (! old->dont_free)
|
||||
while (lnp != NULL)
|
||||
{
|
||||
struct libname_list *old = lnp;
|
||||
lnp = lnp->next;
|
||||
if (! old->dont_free)
|
||||
free (old);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -699,7 +699,7 @@ _dl_init_paths (const char *llp)
|
||||
|
||||
#ifdef SHARED
|
||||
/* This points to the map of the main object. */
|
||||
l = GL(dl_loaded);
|
||||
l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
if (l != NULL)
|
||||
{
|
||||
assert (l->l_type != lt_loaded);
|
||||
@ -795,10 +795,10 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
|
||||
if (l->l_prev == NULL)
|
||||
/* No other module loaded. This happens only in the static library,
|
||||
or in rtld under --verify. */
|
||||
GL(dl_loaded) = NULL;
|
||||
GL(dl_ns)[l->l_ns]._ns_loaded = NULL;
|
||||
else
|
||||
l->l_prev->l_next = NULL;
|
||||
--GL(dl_nloaded);
|
||||
--GL(dl_ns)[l->l_ns]._ns_nloaded;
|
||||
free (l);
|
||||
}
|
||||
free (realname);
|
||||
@ -815,7 +815,7 @@ static
|
||||
struct link_map *
|
||||
_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
char *realname, struct link_map *loader, int l_type,
|
||||
int mode, void **stack_endp)
|
||||
int mode, void **stack_endp, Lmid_t nsid)
|
||||
{
|
||||
struct link_map *l = NULL;
|
||||
const ElfW(Ehdr) *header;
|
||||
@ -839,7 +839,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
}
|
||||
|
||||
/* Look again to see if the real name matched another already loaded. */
|
||||
for (l = GL(dl_loaded); l; l = l->l_next)
|
||||
for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
|
||||
if (l->l_ino == st.st_ino && l->l_dev == st.st_dev)
|
||||
{
|
||||
/* The object is already loaded.
|
||||
@ -854,6 +854,31 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
return l;
|
||||
}
|
||||
|
||||
#ifdef SHARED
|
||||
/* When loading into a namespace other than the base one we must
|
||||
avoid loading ld.so since there can only be one copy. Ever. */
|
||||
if (__builtin_expect (nsid != LM_ID_BASE, 0)
|
||||
&& ((st.st_ino == GL(dl_rtld_map).l_ino
|
||||
&& st.st_dev == GL(dl_rtld_map).l_dev)
|
||||
|| _dl_name_match_p (name, &GL(dl_rtld_map))))
|
||||
{
|
||||
/* This is indeed ld.so. Create a new link_map which refers to
|
||||
the real one for almost everything. */
|
||||
l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
|
||||
if (l == NULL)
|
||||
goto fail_new;
|
||||
|
||||
/* Refer to the real descriptor. */
|
||||
l->l_real = &GL(dl_rtld_map);
|
||||
|
||||
/* No need to bump the refcount of the real object, ld.so will
|
||||
never be unloaded. */
|
||||
__close (fd);
|
||||
|
||||
return l;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mode & RTLD_NOLOAD)
|
||||
/* We are not supposed to load the object unless it is already
|
||||
loaded. So return now. */
|
||||
@ -861,7 +886,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
|
||||
/* Print debugging message. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
_dl_debug_printf ("file=%s; generating link map\n", name);
|
||||
_dl_debug_printf ("file=%s [%lu]; generating link map\n", name, nsid);
|
||||
|
||||
/* This is the ELF header. We read it in `open_verify'. */
|
||||
header = (void *) fbp->buf;
|
||||
@ -881,9 +906,10 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
#endif
|
||||
|
||||
/* Enter the new object in the list of loaded objects. */
|
||||
l = _dl_new_object (realname, name, l_type, loader, mode);
|
||||
if (__builtin_expect (! l, 0))
|
||||
l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
|
||||
if (__builtin_expect (l == NULL, 0))
|
||||
{
|
||||
fail_new:
|
||||
errstring = N_("cannot create shared object descriptor");
|
||||
goto call_lose_errno;
|
||||
}
|
||||
@ -1771,7 +1797,7 @@ open_path (const char *name, size_t namelen, int preloaded,
|
||||
struct link_map *
|
||||
internal_function
|
||||
_dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
int type, int trace_mode, int mode)
|
||||
int type, int trace_mode, int mode, Lmid_t nsid)
|
||||
{
|
||||
int fd;
|
||||
char *realname;
|
||||
@ -1779,8 +1805,11 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
struct link_map *l;
|
||||
struct filebuf fb;
|
||||
|
||||
assert (nsid >= 0);
|
||||
assert (nsid < DL_NNS);
|
||||
|
||||
/* Look for this name among those already loaded. */
|
||||
for (l = GL(dl_loaded); l; l = l->l_next)
|
||||
for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
|
||||
{
|
||||
/* If the requested name matches the soname of a loaded object,
|
||||
use that object. Elide this check for names that have not
|
||||
@ -1812,9 +1841,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
/* Display information if we are debugging. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
|
||||
&& loader != NULL)
|
||||
_dl_debug_printf ("\nfile=%s; needed by %s\n", name,
|
||||
_dl_debug_printf ("\nfile=%s [%lu]; needed by %s [%lu]\n", name, nsid,
|
||||
loader->l_name[0]
|
||||
? loader->l_name : rtld_progname);
|
||||
? loader->l_name : rtld_progname, loader->l_ns);
|
||||
|
||||
if (strchr (name, '/') == NULL)
|
||||
{
|
||||
@ -1823,7 +1852,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
size_t namelen = strlen (name) + 1;
|
||||
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
|
||||
_dl_debug_printf ("find library=%s; searching\n", name);
|
||||
_dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid);
|
||||
|
||||
fd = -1;
|
||||
|
||||
@ -1839,12 +1868,15 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
&realname, &fb);
|
||||
|
||||
/* If dynamically linked, try the DT_RPATH of the executable
|
||||
itself. */
|
||||
l = GL(dl_loaded);
|
||||
if (fd == -1 && l && l->l_type != lt_loaded && l != loader
|
||||
&& l->l_rpath_dirs.dirs != (void *) -1)
|
||||
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
|
||||
&realname, &fb);
|
||||
itself. NB: we do this for lookups in any namespace. */
|
||||
if (fd == -1)
|
||||
{
|
||||
l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
if (l && l->l_type != lt_loaded && l != loader
|
||||
&& l->l_rpath_dirs.dirs != (void *) -1)
|
||||
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
|
||||
&realname, &fb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try the LD_LIBRARY_PATH environment variable. */
|
||||
@ -1870,7 +1902,8 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
if (cached != NULL)
|
||||
{
|
||||
#ifdef SHARED
|
||||
l = loader ?: GL(dl_loaded);
|
||||
// XXX Correct to unconditionally default to namespace 0?
|
||||
l = loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
#else
|
||||
l = loader;
|
||||
#endif
|
||||
@ -1920,7 +1953,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
|
||||
/* Finally, try the default path. */
|
||||
if (fd == -1
|
||||
&& ((l = loader ?: GL(dl_loaded)) == NULL
|
||||
&& ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
|
||||
|| __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
|
||||
&& rtld_search_dirs.dirs != (void *) -1)
|
||||
fd = open_path (name, namelen, preloaded, &rtld_search_dirs,
|
||||
@ -1966,7 +1999,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, loader,
|
||||
mode)) == NULL)
|
||||
mode, nsid)) == NULL)
|
||||
_dl_signal_error (ENOMEM, name, NULL,
|
||||
N_("cannot create shared object descriptor"));
|
||||
/* Signal that this is a faked entry. */
|
||||
@ -1987,7 +2020,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
|
||||
void *stack_end = __libc_stack_end;
|
||||
return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode,
|
||||
&stack_end);
|
||||
&stack_end, nsid);
|
||||
}
|
||||
|
||||
|
||||
@ -2047,10 +2080,13 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
|
||||
while (l != NULL);
|
||||
|
||||
/* If dynamically linked, try the DT_RPATH of the executable itself. */
|
||||
l = GL(dl_loaded);
|
||||
if (l != NULL && l->l_type != lt_loaded && l != loader)
|
||||
if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
|
||||
add_path (&l->l_rpath_dirs, XXX_RPATH);
|
||||
if (loader->l_ns == LM_ID_BASE)
|
||||
{
|
||||
l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
if (l != NULL && l->l_type != lt_loaded && l != loader)
|
||||
if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
|
||||
add_path (&l->l_rpath_dirs, XXX_RPATH);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try the LD_LIBRARY_PATH environment variable. */
|
||||
|
@ -137,7 +137,7 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
|
||||
reference is still available. There is a brief period in
|
||||
which the object could have been removed since we found the
|
||||
definition. */
|
||||
runp = GL(dl_loaded);
|
||||
runp = GL(dl_ns)[undef_map->l_ns]._ns_loaded;
|
||||
while (runp != NULL && runp != map)
|
||||
runp = runp->l_next;
|
||||
|
||||
@ -182,13 +182,18 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
|
||||
for (list = map->l_initfini; *list != NULL; ++list)
|
||||
++(*list)->l_opencount;
|
||||
|
||||
/* As if it is opened through _dl_open. */
|
||||
++map->l_direct_opencount;
|
||||
|
||||
/* Display information if we are debugging. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
_dl_debug_printf ("\
|
||||
\nfile=%s; needed by %s (relocation dependency)\n\n",
|
||||
\nfile=%s [%lu]; needed by %s [%lu] (relocation dependency)\n\n",
|
||||
map->l_name[0] ? map->l_name : rtld_progname,
|
||||
map->l_ns,
|
||||
undef_map->l_name[0]
|
||||
? undef_map->l_name : rtld_progname);
|
||||
? undef_map->l_name : rtld_progname,
|
||||
undef_map->l_ns);
|
||||
}
|
||||
else
|
||||
/* Whoa, that was bad luck. We have to search again. */
|
||||
@ -408,8 +413,8 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
|
||||
struct sym_val val = { NULL, NULL };
|
||||
|
||||
if ((GLRO(dl_trace_prelink_map) == NULL
|
||||
|| GLRO(dl_trace_prelink_map) == GL(dl_loaded))
|
||||
&& undef_map != GL(dl_loaded))
|
||||
|| GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
|
||||
&& undef_map != GL(dl_ns)[LM_ID_BASE]._ns_loaded)
|
||||
{
|
||||
const unsigned long int hash = _dl_elf_hash (undef_name);
|
||||
|
||||
@ -421,12 +426,12 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
|
||||
conflict = 1;
|
||||
}
|
||||
|
||||
#ifdef USE_TLS
|
||||
# ifdef USE_TLS
|
||||
if (value->s
|
||||
&& (__builtin_expect (ELFW(ST_TYPE) (value->s->st_info)
|
||||
== STT_TLS, 0)))
|
||||
type_class = 4;
|
||||
#endif
|
||||
# endif
|
||||
|
||||
if (conflict
|
||||
|| GLRO(dl_trace_prelink_map) == undef_map
|
||||
|
@ -32,7 +32,7 @@
|
||||
struct link_map *
|
||||
internal_function
|
||||
_dl_new_object (char *realname, const char *libname, int type,
|
||||
struct link_map *loader, int mode)
|
||||
struct link_map *loader, int mode, Lmid_t nsid)
|
||||
{
|
||||
struct link_map *l;
|
||||
int idx;
|
||||
@ -45,6 +45,7 @@ _dl_new_object (char *realname, const char *libname, int type,
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
|
||||
new->l_real = new;
|
||||
new->l_libname = newname = (struct libname_list *) (new + 1);
|
||||
newname->name = (char *) memcpy (newname + 1, libname, libname_len);
|
||||
/* newname->next = NULL; We use calloc therefore not necessary. */
|
||||
@ -56,6 +57,7 @@ _dl_new_object (char *realname, const char *libname, int type,
|
||||
#if defined USE_TLS && NO_TLS_OFFSET != 0
|
||||
new->l_tls_offset = NO_TLS_OFFSET;
|
||||
#endif
|
||||
new->l_ns = nsid;
|
||||
|
||||
/* new->l_global = 0; We use calloc therefore not necessary. */
|
||||
|
||||
@ -68,9 +70,9 @@ _dl_new_object (char *realname, const char *libname, int type,
|
||||
/* Counter for the scopes we have to handle. */
|
||||
idx = 0;
|
||||
|
||||
if (GL(dl_loaded) != NULL)
|
||||
if (GL(dl_ns)[nsid]._ns_loaded != NULL)
|
||||
{
|
||||
l = GL(dl_loaded);
|
||||
l = GL(dl_ns)[nsid]._ns_loaded;
|
||||
while (l->l_next != NULL)
|
||||
l = l->l_next;
|
||||
new->l_prev = l;
|
||||
@ -78,11 +80,11 @@ _dl_new_object (char *realname, const char *libname, int type,
|
||||
l->l_next = new;
|
||||
|
||||
/* Add the global scope. */
|
||||
new->l_scope[idx++] = &GL(dl_loaded)->l_searchlist;
|
||||
new->l_scope[idx++] = &GL(dl_ns)[nsid]._ns_loaded->l_searchlist;
|
||||
}
|
||||
else
|
||||
GL(dl_loaded) = new;
|
||||
++GL(dl_nloaded);
|
||||
GL(dl_ns)[nsid]._ns_loaded = new;
|
||||
++GL(dl_ns)[nsid]._ns_nloaded;
|
||||
++GL(dl_load_adds);
|
||||
|
||||
/* If we have no loader the new object acts as it. */
|
||||
|
129
elf/dl-open.c
129
elf/dl-open.c
@ -72,6 +72,8 @@ struct dl_open_args
|
||||
/* This is the caller if _dl_open(). */
|
||||
const void *caller_dl_open;
|
||||
struct link_map *map;
|
||||
/* Namespace ID. */
|
||||
Lmid_t nsid;
|
||||
};
|
||||
|
||||
|
||||
@ -101,15 +103,17 @@ add_to_global (struct link_map *new)
|
||||
in an realloc() call. Therefore we allocate a completely new
|
||||
array the first time we have to add something to the locale scope. */
|
||||
|
||||
if (GL(dl_global_scope_alloc) == 0)
|
||||
if (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc == 0)
|
||||
{
|
||||
/* This is the first dynamic object given global scope. */
|
||||
GL(dl_global_scope_alloc) = GL(dl_main_searchlist)->r_nlist + to_add + 8;
|
||||
GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
|
||||
= GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add + 8;
|
||||
new_global = (struct link_map **)
|
||||
malloc (GL(dl_global_scope_alloc) * sizeof (struct link_map *));
|
||||
malloc (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
|
||||
* sizeof (struct link_map *));
|
||||
if (new_global == NULL)
|
||||
{
|
||||
GL(dl_global_scope_alloc) = 0;
|
||||
GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0;
|
||||
nomem:
|
||||
GLRO(dl_signal_error) (ENOMEM, new->l_libname->name, NULL,
|
||||
N_("cannot extend global scope"));
|
||||
@ -117,25 +121,26 @@ add_to_global (struct link_map *new)
|
||||
}
|
||||
|
||||
/* Copy over the old entries. */
|
||||
memcpy (new_global, GL(dl_main_searchlist)->r_list,
|
||||
(GL(dl_main_searchlist)->r_nlist * sizeof (struct link_map *)));
|
||||
|
||||
GL(dl_main_searchlist)->r_list = new_global;
|
||||
GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list
|
||||
= memcpy (new_global,
|
||||
GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
|
||||
(GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist
|
||||
* sizeof (struct link_map *)));
|
||||
}
|
||||
else if (GL(dl_main_searchlist)->r_nlist + to_add
|
||||
> GL(dl_global_scope_alloc))
|
||||
else if (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add
|
||||
> GL(dl_ns)[new->l_ns]._ns_global_scope_alloc)
|
||||
{
|
||||
/* We have to extend the existing array of link maps in the
|
||||
main map. */
|
||||
new_global = (struct link_map **)
|
||||
realloc (GL(dl_main_searchlist)->r_list,
|
||||
((GL(dl_global_scope_alloc) + to_add + 8)
|
||||
realloc (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
|
||||
((GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + to_add + 8)
|
||||
* sizeof (struct link_map *)));
|
||||
if (new_global == NULL)
|
||||
goto nomem;
|
||||
|
||||
GL(dl_global_scope_alloc) += to_add + 8;
|
||||
GL(dl_main_searchlist)->r_list = new_global;
|
||||
GL(dl_ns)[new->l_ns]._ns_global_scope_alloc += to_add + 8;
|
||||
GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list = new_global;
|
||||
}
|
||||
|
||||
/* Now add the new entries. */
|
||||
@ -146,9 +151,9 @@ add_to_global (struct link_map *new)
|
||||
if (map->l_global == 0)
|
||||
{
|
||||
map->l_global = 1;
|
||||
GL(dl_main_searchlist)->r_list[GL(dl_main_searchlist)->r_nlist]
|
||||
GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list[GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist]
|
||||
= map;
|
||||
++GL(dl_main_searchlist)->r_nlist;
|
||||
++GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist;
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,28 +180,34 @@ dl_open_worker (void *a)
|
||||
GLRO(dl_signal_error) (0, "dlopen", NULL, N_("invalid caller"));
|
||||
|
||||
/* Determine the caller's map if necessary. This is needed in case
|
||||
we have a DST or when the file name has no path in which case we
|
||||
need to look along the RUNPATH/RPATH of the caller. */
|
||||
we have a DST, when we don't know the namespace ID we have to put
|
||||
the new object in, or when the file name has no path in which
|
||||
case we need to look along the RUNPATH/RPATH of the caller. */
|
||||
const char *dst = strchr (file, '$');
|
||||
if (dst != NULL || strchr (file, '/') == NULL)
|
||||
if (dst != NULL || args->nsid == __LM_ID_CALLER
|
||||
|| strchr (file, '/') == NULL)
|
||||
{
|
||||
const void *caller_dlopen = args->caller_dlopen;
|
||||
|
||||
/* We have to find out from which object the caller is calling. */
|
||||
call_map = NULL;
|
||||
for (l = GL(dl_loaded); l; l = l->l_next)
|
||||
if (caller_dlopen >= (const void *) l->l_map_start
|
||||
&& caller_dlopen < (const void *) l->l_map_end)
|
||||
{
|
||||
/* There must be exactly one DSO for the range of the virtual
|
||||
memory. Otherwise something is really broken. */
|
||||
call_map = l;
|
||||
break;
|
||||
}
|
||||
/* We have to find out from which object the caller is calling.
|
||||
By default we assume this is the main application. */
|
||||
call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
|
||||
if (call_map == NULL)
|
||||
/* In this case we assume this is the main application. */
|
||||
call_map = GL(dl_loaded);
|
||||
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
|
||||
for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
|
||||
if (caller_dlopen >= (const void *) l->l_map_start
|
||||
&& caller_dlopen < (const void *) l->l_map_end)
|
||||
{
|
||||
/* There must be exactly one DSO for the range of the virtual
|
||||
memory. Otherwise something is really broken. */
|
||||
assert (ns == l->l_ns);
|
||||
call_map = l;
|
||||
goto found_caller;
|
||||
}
|
||||
|
||||
found_caller:
|
||||
if (args->nsid == __LM_ID_CALLER)
|
||||
args->nsid = call_map->l_ns;
|
||||
}
|
||||
|
||||
/* Maybe we have to expand a DST. */
|
||||
@ -238,7 +249,7 @@ dl_open_worker (void *a)
|
||||
|
||||
/* Load the named object. */
|
||||
args->map = new = GLRO(dl_map_object) (call_map, file, 0, lt_loaded, 0,
|
||||
mode | __RTLD_CALLMAP);
|
||||
mode | __RTLD_CALLMAP, args->nsid);
|
||||
|
||||
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
|
||||
set and the object is not already loaded. */
|
||||
@ -252,21 +263,30 @@ dl_open_worker (void *a)
|
||||
/* This happens only if we load a DSO for 'sprof'. */
|
||||
return;
|
||||
|
||||
/* This object is directly loaded. */
|
||||
++new->l_direct_opencount;
|
||||
|
||||
/* It was already open. */
|
||||
if (__builtin_expect (new->l_searchlist.r_list != NULL, 0))
|
||||
{
|
||||
/* Let the user know about the opencount. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
GLRO(dl_debug_printf) ("opening file=%s; opencount == %u\n\n",
|
||||
new->l_name, new->l_opencount);
|
||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_opencount);
|
||||
|
||||
/* If the user requested the object to be in the global namespace
|
||||
but it is not so far, add it now. */
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
(void) add_to_global (new);
|
||||
|
||||
/* Increment just the reference counter of the object. */
|
||||
++new->l_opencount;
|
||||
if (new->l_direct_opencount == 1)
|
||||
/* This is the only direct reference. Increment all the
|
||||
dependencies' reference counter. */
|
||||
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
++new->l_searchlist.r_list[i]->l_opencount;
|
||||
else
|
||||
/* Increment just the reference counter of the object. */
|
||||
++new->l_opencount;
|
||||
|
||||
return;
|
||||
}
|
||||
@ -277,8 +297,9 @@ dl_open_worker (void *a)
|
||||
|
||||
/* So far, so good. Now check the versions. */
|
||||
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
if (new->l_searchlist.r_list[i]->l_versions == NULL)
|
||||
(void) GLRO(dl_check_map_versions) (new->l_searchlist.r_list[i], 0, 0);
|
||||
if (new->l_searchlist.r_list[i]->l_real->l_versions == NULL)
|
||||
(void) GLRO(dl_check_map_versions) (new->l_searchlist.r_list[i]->l_real,
|
||||
0, 0);
|
||||
|
||||
#ifdef SCOPE_DEBUG
|
||||
show_scope (new);
|
||||
@ -295,7 +316,7 @@ dl_open_worker (void *a)
|
||||
l = l->l_next;
|
||||
while (1)
|
||||
{
|
||||
if (! l->l_relocated)
|
||||
if (! l->l_real->l_relocated)
|
||||
{
|
||||
#ifdef SHARED
|
||||
if (GLRO(dl_profile) != NULL)
|
||||
@ -349,7 +370,7 @@ dl_open_worker (void *a)
|
||||
loaded object to the scope. */
|
||||
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
if (++new->l_searchlist.r_list[i]->l_opencount > 1
|
||||
&& new->l_searchlist.r_list[i]->l_type == lt_loaded)
|
||||
&& new->l_real->l_searchlist.r_list[i]->l_type == lt_loaded)
|
||||
{
|
||||
struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
struct r_scope_elem **runp = imap->l_scope;
|
||||
@ -503,14 +524,14 @@ cannot create TLS data structures"));
|
||||
|
||||
/* Let the user know about the opencount. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
GLRO(dl_debug_printf) ("opening file=%s; opencount == %u\n\n",
|
||||
new->l_name, new->l_opencount);
|
||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_opencount);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
internal_function
|
||||
_dl_open (const char *file, int mode, const void *caller_dlopen)
|
||||
_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid)
|
||||
{
|
||||
struct dl_open_args args;
|
||||
const char *objname;
|
||||
@ -525,11 +546,29 @@ _dl_open (const char *file, int mode, const void *caller_dlopen)
|
||||
/* Make sure we are alone. */
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
|
||||
if (nsid == LM_ID_NEWLM)
|
||||
{
|
||||
/* Find a new namespace. */
|
||||
for (nsid = 1; nsid < DL_NNS; ++nsid)
|
||||
if (GL(dl_ns)[nsid]._ns_loaded == NULL)
|
||||
break;
|
||||
|
||||
if (nsid == DL_NNS)
|
||||
{
|
||||
/* No more namespace available. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
|
||||
GLRO(dl_signal_error) (EINVAL, file, NULL, N_("\
|
||||
no more namespaces available for dlmopen()"));
|
||||
}
|
||||
}
|
||||
|
||||
args.file = file;
|
||||
args.mode = mode;
|
||||
args.caller_dlopen = caller_dlopen;
|
||||
args.caller_dl_open = RETURN_ADDRESS (0);
|
||||
args.map = NULL;
|
||||
args.nsid = nsid;
|
||||
errcode = GLRO(dl_catch_error) (&objname, &errstring, dl_open_worker, &args);
|
||||
|
||||
#ifndef MAP_COPY
|
||||
|
@ -67,10 +67,8 @@ const char *_dl_origin_path;
|
||||
/* Nonzero if runtime lookup should not update the .got/.plt. */
|
||||
int _dl_bind_not;
|
||||
|
||||
/* Initially empty list of loaded objects. */
|
||||
struct link_map *_dl_loaded;
|
||||
/* Number of object in the _dl_loaded list. */
|
||||
unsigned int _dl_nloaded;
|
||||
/* Namespace information. */
|
||||
struct link_namespaces _dl_ns[DL_NNS];
|
||||
|
||||
/* Incremented whenever something may have been added to dl_loaded. */
|
||||
unsigned long long _dl_load_adds;
|
||||
@ -79,12 +77,6 @@ unsigned long long _dl_load_adds;
|
||||
main application but here we don't have something like this. So
|
||||
create a fake scope containing nothing. */
|
||||
struct r_scope_elem _dl_initial_searchlist;
|
||||
/* Variable which can be used in lookup to process the global scope. */
|
||||
struct r_scope_elem *_dl_global_scope[2] = { &_dl_initial_searchlist, 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 = &_dl_initial_searchlist;
|
||||
|
||||
#ifndef HAVE_INLINED_SYSCALLS
|
||||
/* Nonzero during startup. */
|
||||
@ -109,11 +101,6 @@ hp_timing_t _dl_cpuclock_offset;
|
||||
void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
|
||||
#endif
|
||||
|
||||
/* This is zero at program start to signal that the global scope map is
|
||||
allocated by rtld. Later it keeps the size of the map. It might be
|
||||
reset if in _dl_close if the last global object is removed. */
|
||||
size_t _dl_global_scope_alloc;
|
||||
|
||||
size_t _dl_pagesize;
|
||||
|
||||
unsigned int _dl_osversion;
|
||||
|
22
elf/dl-sym.c
22
elf/dl-sym.c
@ -69,17 +69,19 @@ do_sym (void *handle, const char *name, void *who,
|
||||
|
||||
/* If the address is not recognized the call comes from the main
|
||||
program (we hope). */
|
||||
struct link_map *match = GL(dl_loaded);
|
||||
struct link_map *match = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
|
||||
/* Find the highest-addressed object that CALLER is not below. */
|
||||
for (struct link_map *l = GL(dl_loaded); l != NULL; l = l->l_next)
|
||||
if (caller >= l->l_map_start && caller < l->l_map_end)
|
||||
{
|
||||
/* There must be exactly one DSO for the range of the virtual
|
||||
memory. Otherwise something is really broken. */
|
||||
match = l;
|
||||
break;
|
||||
}
|
||||
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
|
||||
for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
|
||||
l = l->l_next)
|
||||
if (caller >= l->l_map_start && caller < l->l_map_end)
|
||||
{
|
||||
/* There must be exactly one DSO for the range of the virtual
|
||||
memory. Otherwise something is really broken. */
|
||||
match = l;
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle == RTLD_DEFAULT)
|
||||
/* Search the global scope. */
|
||||
@ -88,7 +90,7 @@ do_sym (void *handle, const char *name, void *who,
|
||||
NULL);
|
||||
else if (handle == RTLD_NEXT)
|
||||
{
|
||||
if (__builtin_expect (match == GL(dl_loaded), 0))
|
||||
if (__builtin_expect (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded, 0))
|
||||
{
|
||||
if (match == NULL
|
||||
|| caller < match->l_map_start
|
||||
|
@ -59,7 +59,8 @@ find_needed (const char *name, struct link_map *map)
|
||||
struct link_map *tmap;
|
||||
unsigned int n;
|
||||
|
||||
for (tmap = GL(dl_loaded); tmap != NULL; tmap = tmap->l_next)
|
||||
for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL;
|
||||
tmap = tmap->l_next)
|
||||
if (_dl_name_match_p (name, tmap))
|
||||
return tmap;
|
||||
|
||||
@ -243,7 +244,7 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
? map->l_name : rtld_progname),
|
||||
aux->vna_hash,
|
||||
strtab + aux->vna_name,
|
||||
needed, verbose,
|
||||
needed->l_real, verbose,
|
||||
aux->vna_flags & VER_FLG_WEAK);
|
||||
|
||||
/* Compare the version index. */
|
||||
|
@ -42,7 +42,7 @@ do_lookup_x (const char *undef_name, unsigned long int hash,
|
||||
int num_versions = 0;
|
||||
const ElfW(Sym) *versioned_sym = NULL;
|
||||
|
||||
map = list[i];
|
||||
map = list[i]->l_real;
|
||||
|
||||
/* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
|
||||
if (skip != NULL && map == skip)
|
||||
|
245
elf/rtld.c
245
elf/rtld.c
@ -269,6 +269,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
|
||||
GL(dl_rtld_map).l_mach = info->l.l_mach;
|
||||
#endif
|
||||
_dl_setup_hash (&GL(dl_rtld_map));
|
||||
GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
|
||||
GL(dl_rtld_map).l_opencount = 1;
|
||||
GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin;
|
||||
GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
|
||||
@ -585,14 +586,16 @@ map_doit (void *a)
|
||||
{
|
||||
struct map_args *args = (struct map_args *) a;
|
||||
args->map = _dl_map_object (args->loader, args->str,
|
||||
args->is_preloaded, lt_library, 0, args->mode);
|
||||
args->is_preloaded, lt_library, 0, args->mode,
|
||||
LM_ID_BASE);
|
||||
}
|
||||
|
||||
static void
|
||||
version_check_doit (void *a)
|
||||
{
|
||||
struct version_check_args *args = (struct version_check_args *) a;
|
||||
if (_dl_check_all_versions (GL(dl_loaded), 1, args->dotrace) && args->doexit)
|
||||
if (_dl_check_all_versions (GL(dl_ns)[LM_ID_BASE]._ns_loaded, 1,
|
||||
args->dotrace) && args->doexit)
|
||||
/* We cannot start the application. Abort now. */
|
||||
_exit (1);
|
||||
}
|
||||
@ -601,11 +604,12 @@ version_check_doit (void *a)
|
||||
static inline struct link_map *
|
||||
find_needed (const char *name)
|
||||
{
|
||||
unsigned int n = GL(dl_loaded)->l_searchlist.r_nlist;
|
||||
struct r_scope_elem *scope = &GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_searchlist;
|
||||
unsigned int n = scope->r_nlist;
|
||||
|
||||
while (n-- > 0)
|
||||
if (_dl_name_match_p (name, GL(dl_loaded)->l_searchlist.r_list[n]))
|
||||
return GL(dl_loaded)->l_searchlist.r_list[n];
|
||||
if (_dl_name_match_p (name, scope->r_list[n]))
|
||||
return scope->r_list[n];
|
||||
|
||||
/* Should never happen. */
|
||||
return NULL;
|
||||
@ -685,6 +689,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
enum mode mode;
|
||||
struct link_map **preloads;
|
||||
unsigned int npreloads;
|
||||
struct link_map *main_map;
|
||||
size_t file_size;
|
||||
char *file;
|
||||
bool has_interp = false;
|
||||
@ -860,31 +865,35 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
{
|
||||
HP_TIMING_NOW (start);
|
||||
_dl_map_object (NULL, rtld_progname, 0, lt_library, 0,
|
||||
__RTLD_OPENEXEC);
|
||||
__RTLD_OPENEXEC, LM_ID_BASE);
|
||||
HP_TIMING_NOW (stop);
|
||||
|
||||
HP_TIMING_DIFF (load_time, start, stop);
|
||||
}
|
||||
|
||||
phdr = GL(dl_loaded)->l_phdr;
|
||||
phnum = GL(dl_loaded)->l_phnum;
|
||||
/* Now the map for the main executable is available. */
|
||||
main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
|
||||
phdr = main_map->l_phdr;
|
||||
phnum = main_map->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. */
|
||||
GL(dl_loaded)->l_name = (char *) "";
|
||||
*user_entry = GL(dl_loaded)->l_entry;
|
||||
main_map->l_name = (char *) "";
|
||||
*user_entry = main_map->l_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a link_map for the executable itself.
|
||||
This will be what dlopen on "" returns. */
|
||||
_dl_new_object ((char *) "", "", lt_executable, NULL, 0);
|
||||
if (GL(dl_loaded) == NULL)
|
||||
_dl_new_object ((char *) "", "", lt_executable, NULL, 0, LM_ID_BASE);
|
||||
main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
if (main_map == NULL)
|
||||
_dl_fatal_printf ("cannot allocate memory for link map\n");
|
||||
GL(dl_loaded)->l_phdr = phdr;
|
||||
GL(dl_loaded)->l_phnum = phnum;
|
||||
GL(dl_loaded)->l_entry = *user_entry;
|
||||
main_map->l_phdr = phdr;
|
||||
main_map->l_phnum = phnum;
|
||||
main_map->l_entry = *user_entry;
|
||||
|
||||
/* At this point we are in a bit of trouble. We would have to
|
||||
fill in the values for l_dev and l_ino. But in general we
|
||||
@ -905,12 +914,14 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
information for the program. */
|
||||
}
|
||||
|
||||
GL(dl_loaded)->l_map_end = 0;
|
||||
GL(dl_loaded)->l_text_end = 0;
|
||||
main_map->l_map_end = 0;
|
||||
main_map->l_text_end = 0;
|
||||
/* Perhaps the executable has no PT_LOAD header entries at all. */
|
||||
GL(dl_loaded)->l_map_start = ~0;
|
||||
main_map->l_map_start = ~0;
|
||||
/* We opened the file, account for it. */
|
||||
++GL(dl_loaded)->l_opencount;
|
||||
++main_map->l_opencount;
|
||||
/* And it was opened directly. */
|
||||
++main_map->l_direct_opencount;
|
||||
|
||||
/* Scan the program header table for the dynamic section. */
|
||||
for (ph = phdr; ph < &phdr[phnum]; ++ph)
|
||||
@ -918,12 +929,12 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
{
|
||||
case PT_PHDR:
|
||||
/* Find out the load address. */
|
||||
GL(dl_loaded)->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
|
||||
main_map->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. */
|
||||
GL(dl_loaded)->l_ld = (void *) GL(dl_loaded)->l_addr + ph->p_vaddr;
|
||||
main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
|
||||
break;
|
||||
case PT_INTERP:
|
||||
/* This "interpreter segment" was used by the program loader to
|
||||
@ -932,7 +943,7 @@ 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 *) GL(dl_loaded)->l_addr
|
||||
_dl_rtld_libname.name = ((const char *) main_map->l_addr
|
||||
+ ph->p_vaddr);
|
||||
/* _dl_rtld_libname.next = NULL; Already zero. */
|
||||
GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
|
||||
@ -968,17 +979,16 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
ElfW(Addr) allocend;
|
||||
|
||||
/* Remember where the main program starts in memory. */
|
||||
mapstart = (GL(dl_loaded)->l_addr
|
||||
+ (ph->p_vaddr & ~(ph->p_align - 1)));
|
||||
if (GL(dl_loaded)->l_map_start > mapstart)
|
||||
GL(dl_loaded)->l_map_start = 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;
|
||||
|
||||
/* Also where it ends. */
|
||||
allocend = GL(dl_loaded)->l_addr + ph->p_vaddr + ph->p_memsz;
|
||||
if (GL(dl_loaded)->l_map_end < allocend)
|
||||
GL(dl_loaded)->l_map_end = allocend;
|
||||
if ((ph->p_flags & PF_X) && allocend > GL(dl_loaded)->l_text_end)
|
||||
GL(dl_loaded)->l_text_end = allocend;
|
||||
allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
|
||||
if (main_map->l_map_end < allocend)
|
||||
main_map->l_map_end = allocend;
|
||||
if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
|
||||
main_map->l_text_end = allocend;
|
||||
}
|
||||
break;
|
||||
#ifdef USE_TLS
|
||||
@ -989,18 +999,18 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
here since we read the PT_TLS entry already in
|
||||
_dl_start_final. But the result is repeatable so do not
|
||||
check for this special but unimportant case. */
|
||||
GL(dl_loaded)->l_tls_blocksize = ph->p_memsz;
|
||||
GL(dl_loaded)->l_tls_align = ph->p_align;
|
||||
main_map->l_tls_blocksize = ph->p_memsz;
|
||||
main_map->l_tls_align = ph->p_align;
|
||||
if (ph->p_align == 0)
|
||||
GL(dl_loaded)->l_tls_firstbyte_offset = 0;
|
||||
main_map->l_tls_firstbyte_offset = 0;
|
||||
else
|
||||
GL(dl_loaded)->l_tls_firstbyte_offset = (ph->p_vaddr
|
||||
& (ph->p_align - 1));
|
||||
GL(dl_loaded)->l_tls_initimage_size = ph->p_filesz;
|
||||
GL(dl_loaded)->l_tls_initimage = (void *) ph->p_vaddr;
|
||||
main_map->l_tls_firstbyte_offset = (ph->p_vaddr
|
||||
& (ph->p_align - 1));
|
||||
main_map->l_tls_initimage_size = ph->p_filesz;
|
||||
main_map->l_tls_initimage = (void *) ph->p_vaddr;
|
||||
|
||||
/* This image gets the ID one. */
|
||||
GL(dl_tls_max_dtv_idx) = GL(dl_loaded)->l_tls_modid = 1;
|
||||
GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@ -1009,21 +1019,21 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
break;
|
||||
|
||||
case PT_GNU_RELRO:
|
||||
GL(dl_loaded)->l_relro_addr = ph->p_vaddr;
|
||||
GL(dl_loaded)->l_relro_size = ph->p_memsz;
|
||||
main_map->l_relro_addr = ph->p_vaddr;
|
||||
main_map->l_relro_size = ph->p_memsz;
|
||||
break;
|
||||
}
|
||||
#ifdef USE_TLS
|
||||
/* Adjust the address of the TLS initialization image in case
|
||||
the executable is actually an ET_DYN object. */
|
||||
if (GL(dl_loaded)->l_tls_initimage != NULL)
|
||||
GL(dl_loaded)->l_tls_initimage
|
||||
= (char *) GL(dl_loaded)->l_tls_initimage + GL(dl_loaded)->l_addr;
|
||||
if (main_map->l_tls_initimage != NULL)
|
||||
main_map->l_tls_initimage
|
||||
= (char *) main_map->l_tls_initimage + main_map->l_addr;
|
||||
#endif
|
||||
if (! GL(dl_loaded)->l_map_end)
|
||||
GL(dl_loaded)->l_map_end = ~0;
|
||||
if (! GL(dl_loaded)->l_text_end)
|
||||
GL(dl_loaded)->l_text_end = ~0;
|
||||
if (! main_map->l_map_end)
|
||||
main_map->l_map_end = ~0;
|
||||
if (! main_map->l_text_end)
|
||||
main_map->l_text_end = ~0;
|
||||
if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name)
|
||||
{
|
||||
/* We were invoked directly, so the program might not have a
|
||||
@ -1038,9 +1048,9 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
if (! rtld_is_main)
|
||||
{
|
||||
/* Extract the contents of the dynamic section for easy access. */
|
||||
elf_get_dynamic_info (GL(dl_loaded), NULL);
|
||||
elf_get_dynamic_info (main_map, NULL);
|
||||
/* Set up our cache of pointers into the hash table. */
|
||||
_dl_setup_hash (GL(dl_loaded));
|
||||
_dl_setup_hash (main_map);
|
||||
}
|
||||
|
||||
if (__builtin_expect (mode, normal) == verify)
|
||||
@ -1049,7 +1059,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 (GL(dl_loaded)->l_ld == NULL)
|
||||
if (main_map->l_ld == NULL)
|
||||
_exit (1);
|
||||
|
||||
/* We allow here some platform specific code. */
|
||||
@ -1072,16 +1082,16 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
found by the PT_INTERP name. */
|
||||
GL(dl_rtld_map).l_name = (char *) GL(dl_rtld_map).l_libname->name;
|
||||
GL(dl_rtld_map).l_type = lt_library;
|
||||
GL(dl_loaded)->l_next = &GL(dl_rtld_map);
|
||||
GL(dl_rtld_map).l_prev = GL(dl_loaded);
|
||||
++GL(dl_nloaded);
|
||||
main_map->l_next = &GL(dl_rtld_map);
|
||||
GL(dl_rtld_map).l_prev = main_map;
|
||||
++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
|
||||
++GL(dl_load_adds);
|
||||
|
||||
/* If LD_USE_LOAD_BIAS env variable has not been seen, default
|
||||
to not using bias for non-prelinked PIEs and libraries
|
||||
and using it for executables or prelinked PIEs or libraries. */
|
||||
if (GLRO(dl_use_load_bias) == (ElfW(Addr)) -2)
|
||||
GLRO(dl_use_load_bias) = (GL(dl_loaded)->l_addr == 0) ? -1 : 0;
|
||||
GLRO(dl_use_load_bias) = main_map->l_addr == 0 ? -1 : 0;
|
||||
|
||||
/* Set up the program header information for the dynamic linker
|
||||
itself. It is needed in the dl_iterate_phdr() callbacks. */
|
||||
@ -1125,8 +1135,9 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
&& (__builtin_expect (! INTUSE(__libc_enable_secure), 1)
|
||||
|| strchr (p, '/') == NULL))
|
||||
{
|
||||
struct link_map *new_map = _dl_map_object (GL(dl_loaded), p, 1,
|
||||
lt_library, 0, 0);
|
||||
struct link_map *new_map = _dl_map_object (main_map, p, 1,
|
||||
lt_library, 0, 0,
|
||||
LM_ID_BASE);
|
||||
if (++new_map->l_opencount == 1)
|
||||
/* It is no duplicate. */
|
||||
++npreloads;
|
||||
@ -1208,7 +1219,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
struct map_args args;
|
||||
|
||||
args.str = p;
|
||||
args.loader = GL(dl_loaded);
|
||||
args.loader = main_map;
|
||||
args.is_preloaded = 1;
|
||||
args.mode = 0;
|
||||
|
||||
@ -1231,8 +1242,9 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
if (problem != NULL)
|
||||
{
|
||||
char *p = strndupa (problem, file_size - (problem - file));
|
||||
struct link_map *new_map = _dl_map_object (GL(dl_loaded), p, 1,
|
||||
lt_library, 0, 0);
|
||||
struct link_map *new_map = _dl_map_object (main_map, p, 1,
|
||||
lt_library, 0, 0,
|
||||
LM_ID_BASE);
|
||||
if (++new_map->l_opencount == 1)
|
||||
/* It is no duplicate. */
|
||||
++npreloads;
|
||||
@ -1272,7 +1284,7 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
We just want our data structures to describe it as if we had just
|
||||
mapped and relocated it normally. */
|
||||
struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
|
||||
0);
|
||||
0, LM_ID_BASE);
|
||||
if (__builtin_expect (l != NULL, 1))
|
||||
{
|
||||
static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
|
||||
@ -1337,18 +1349,18 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
specified some libraries to load, these are inserted before the actual
|
||||
dependencies in the executable's searchlist for symbol resolution. */
|
||||
HP_TIMING_NOW (start);
|
||||
_dl_map_object_deps (GL(dl_loaded), preloads, npreloads, mode == trace, 0);
|
||||
_dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (diff, start, stop);
|
||||
HP_TIMING_ACCUM_NT (load_time, diff);
|
||||
|
||||
/* Mark all objects as being in the global scope and set the open
|
||||
counter. */
|
||||
for (i = GL(dl_loaded)->l_searchlist.r_nlist; i > 0; )
|
||||
for (i = main_map->l_searchlist.r_nlist; i > 0; )
|
||||
{
|
||||
--i;
|
||||
GL(dl_loaded)->l_searchlist.r_list[i]->l_global = 1;
|
||||
++GL(dl_loaded)->l_searchlist.r_list[i]->l_opencount;
|
||||
main_map->l_searchlist.r_list[i]->l_global = 1;
|
||||
++main_map->l_searchlist.r_list[i]->l_opencount;
|
||||
}
|
||||
|
||||
#ifndef MAP_ANON
|
||||
@ -1369,13 +1381,13 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
chain in symbol search order because gdb uses the chain's order as
|
||||
its symbol search order. */
|
||||
i = 1;
|
||||
while (GL(dl_loaded)->l_searchlist.r_list[i] != &GL(dl_rtld_map))
|
||||
while (main_map->l_searchlist.r_list[i] != &GL(dl_rtld_map))
|
||||
++i;
|
||||
GL(dl_rtld_map).l_prev = GL(dl_loaded)->l_searchlist.r_list[i - 1];
|
||||
GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
|
||||
if (__builtin_expect (mode, normal) == normal)
|
||||
{
|
||||
GL(dl_rtld_map).l_next = (i + 1 < GL(dl_loaded)->l_searchlist.r_nlist
|
||||
? GL(dl_loaded)->l_searchlist.r_list[i + 1]
|
||||
GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
|
||||
? main_map->l_searchlist.r_list[i + 1]
|
||||
: NULL);
|
||||
#ifdef NEED_DL_SYSINFO
|
||||
if (sysinfo_map != NULL
|
||||
@ -1459,7 +1471,7 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
GL(dl_tls_dtv_slotinfo_list)->next = NULL;
|
||||
|
||||
/* Fill in the information from the loaded modules. */
|
||||
for (l = GL(dl_loaded), i = 0; l != NULL; l = l->l_next)
|
||||
for (l = main_map, i = 0; l != NULL; l = l->l_next)
|
||||
if (l->l_tls_blocksize != 0)
|
||||
/* This is a module with TLS data. Store the map reference.
|
||||
The generation counter is zero. */
|
||||
@ -1495,7 +1507,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
|
||||
if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
|
||||
{
|
||||
struct r_scope_elem *scope = &GL(dl_loaded)->l_searchlist;
|
||||
struct r_scope_elem *scope = &main_map->l_searchlist;
|
||||
|
||||
for (i = 0; i < scope->r_nlist; i++)
|
||||
{
|
||||
@ -1531,7 +1543,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
/* Look through the dependencies of the main executable
|
||||
and determine which of them is not actually
|
||||
required. */
|
||||
struct link_map *l = GL(dl_loaded);
|
||||
struct link_map *l = main_map;
|
||||
|
||||
/* Relocate the main executable. */
|
||||
struct relocate_args args = { .l = l, .lazy = GLRO(dl_lazy) };
|
||||
@ -1539,7 +1551,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
|
||||
/* This loop depends on the dependencies of the executable to
|
||||
correspond in number and order to the DT_NEEDED entries. */
|
||||
ElfW(Dyn) *dyn = GL(dl_loaded)->l_ld;
|
||||
ElfW(Dyn) *dyn = main_map->l_ld;
|
||||
bool first = true;
|
||||
while (dyn->d_tag != DT_NULL)
|
||||
{
|
||||
@ -1564,11 +1576,11 @@ cannot allocate TLS data structures for initial thread");
|
||||
|
||||
_exit (first != true);
|
||||
}
|
||||
else if (! GL(dl_loaded)->l_info[DT_NEEDED])
|
||||
else if (! main_map->l_info[DT_NEEDED])
|
||||
_dl_printf ("\tstatically linked\n");
|
||||
else
|
||||
{
|
||||
for (l = GL(dl_loaded)->l_next; l; l = l->l_next)
|
||||
for (l = main_map->l_next; l; l = l->l_next)
|
||||
if (l->l_faked)
|
||||
/* The library was not found. */
|
||||
_dl_printf ("\t%s => not found\n", l->l_libname->name);
|
||||
@ -1589,8 +1601,8 @@ cannot allocate TLS data structures for initial thread");
|
||||
ElfW(Addr) loadbase;
|
||||
lookup_t result;
|
||||
|
||||
result = _dl_lookup_symbol_x (INTUSE(_dl_argv)[i], GL(dl_loaded),
|
||||
&ref, GL(dl_loaded)->l_scope, NULL,
|
||||
result = _dl_lookup_symbol_x (INTUSE(_dl_argv)[i], main_map,
|
||||
&ref, main_map->l_scope, NULL,
|
||||
ELF_RTYPE_CLASS_PLT,
|
||||
DL_LOOKUP_ADD_DEPENDENCY, NULL);
|
||||
|
||||
@ -1613,7 +1625,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
|
||||
args.lazy = GLRO(dl_lazy);
|
||||
|
||||
l = GL(dl_loaded);
|
||||
l = main_map;
|
||||
while (l->l_next)
|
||||
l = l->l_next;
|
||||
do
|
||||
@ -1629,7 +1641,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
|
||||
if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
|
||||
&& GL(dl_rtld_map).l_opencount > 1)
|
||||
_dl_relocate_object (&GL(dl_rtld_map), GL(dl_loaded)->l_scope,
|
||||
_dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
@ -1639,9 +1651,9 @@ cannot allocate TLS data structures for initial thread");
|
||||
/* Print more information. This means here, print information
|
||||
about the versions needed. */
|
||||
int first = 1;
|
||||
struct link_map *map = GL(dl_loaded);
|
||||
struct link_map *map;
|
||||
|
||||
for (map = GL(dl_loaded); map != NULL; map = map->l_next)
|
||||
for (map = main_map; map != NULL; map = map->l_next)
|
||||
{
|
||||
const char *strtab;
|
||||
ElfW(Dyn) *dyn = map->l_info[VERNEEDTAG];
|
||||
@ -1709,28 +1721,27 @@ cannot allocate TLS data structures for initial thread");
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
if (GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)]
|
||||
if (main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]
|
||||
&& ! __builtin_expect (GLRO(dl_profile) != NULL, 0))
|
||||
{
|
||||
ElfW(Lib) *liblist, *liblistend;
|
||||
struct link_map **r_list, **r_listend, *l;
|
||||
const char *strtab = (const void *) D_PTR (GL(dl_loaded),
|
||||
l_info[DT_STRTAB]);
|
||||
const char *strtab = (const void *) D_PTR (main_map, l_info[DT_STRTAB]);
|
||||
|
||||
assert (GL(dl_loaded)->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL);
|
||||
assert (main_map->l_info[VALIDX (DT_GNU_LIBLISTSZ)] != NULL);
|
||||
liblist = (ElfW(Lib) *)
|
||||
GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr;
|
||||
main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr;
|
||||
liblistend = (ElfW(Lib) *)
|
||||
((char *) liblist
|
||||
+ GL(dl_loaded)->l_info [VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val);
|
||||
r_list = GL(dl_loaded)->l_searchlist.r_list;
|
||||
r_listend = r_list + GL(dl_loaded)->l_searchlist.r_nlist;
|
||||
((char *) liblist +
|
||||
main_map->l_info[VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val);
|
||||
r_list = main_map->l_searchlist.r_list;
|
||||
r_listend = r_list + main_map->l_searchlist.r_nlist;
|
||||
|
||||
for (; r_list < r_listend && liblist < liblistend; r_list++)
|
||||
{
|
||||
l = *r_list;
|
||||
|
||||
if (l == GL(dl_loaded))
|
||||
if (l == main_map)
|
||||
continue;
|
||||
|
||||
/* If the library is not mapped where it should, fail. */
|
||||
@ -1767,9 +1778,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
/* Initialize _r_debug. */
|
||||
struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr);
|
||||
{
|
||||
struct link_map *l;
|
||||
|
||||
l = GL(dl_loaded);
|
||||
struct link_map *l = main_map;
|
||||
|
||||
#ifdef ELF_MACHINE_DEBUG_SETUP
|
||||
|
||||
@ -1793,18 +1802,18 @@ cannot allocate TLS data structures for initial thread");
|
||||
}
|
||||
|
||||
/* Now set up the variable which helps the assembler startup code. */
|
||||
GL(dl_main_searchlist) = &GL(dl_loaded)->l_searchlist;
|
||||
GL(dl_global_scope)[0] = &GL(dl_loaded)->l_searchlist;
|
||||
GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist = &main_map->l_searchlist;
|
||||
GL(dl_ns)[LM_ID_BASE]._ns_global_scope[0] = &main_map->l_searchlist;
|
||||
|
||||
/* Save the information about the original global scope list since
|
||||
we need it in the memory handling later. */
|
||||
GLRO(dl_initial_searchlist) = *GL(dl_main_searchlist);
|
||||
GLRO(dl_initial_searchlist) = *GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist;
|
||||
|
||||
if (prelinked)
|
||||
{
|
||||
struct link_map *l;
|
||||
|
||||
if (GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
|
||||
if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
|
||||
{
|
||||
ElfW(Rela) *conflict, *conflictend;
|
||||
#ifndef HP_TIMING_NONAVAIL
|
||||
@ -1813,20 +1822,20 @@ cannot allocate TLS data structures for initial thread");
|
||||
#endif
|
||||
|
||||
HP_TIMING_NOW (start);
|
||||
assert (GL(dl_loaded)->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
|
||||
assert (main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
|
||||
conflict = (ElfW(Rela) *)
|
||||
GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
|
||||
main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
|
||||
conflictend = (ElfW(Rela) *)
|
||||
((char *) conflict
|
||||
+ GL(dl_loaded)->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
|
||||
_dl_resolve_conflicts (GL(dl_loaded), conflict, conflictend);
|
||||
+ main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
|
||||
_dl_resolve_conflicts (main_map, conflict, conflictend);
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (relocate_time, start, stop);
|
||||
}
|
||||
|
||||
|
||||
/* Mark all the objects so we know they have been already relocated. */
|
||||
for (l = GL(dl_loaded); l != NULL; l = l->l_next)
|
||||
for (l = main_map; l != NULL; l = l->l_next)
|
||||
{
|
||||
l->l_relocated = 1;
|
||||
if (l->l_relro_size)
|
||||
@ -1857,7 +1866,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
/* If we are profiling we also must do lazy reloaction. */
|
||||
GLRO(dl_lazy) |= consider_profiling;
|
||||
|
||||
l = GL(dl_loaded);
|
||||
l = main_map;
|
||||
while (l->l_next)
|
||||
l = l->l_next;
|
||||
|
||||
@ -1906,7 +1915,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
/* There was an explicit ref to the dynamic linker as a shared lib.
|
||||
Re-relocate ourselves with user-controlled symbol definitions. */
|
||||
HP_TIMING_NOW (start);
|
||||
_dl_relocate_object (&GL(dl_rtld_map), GL(dl_loaded)->l_scope, 0, 0);
|
||||
_dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (add, start, stop);
|
||||
HP_TIMING_ACCUM_NT (relocate_time, add);
|
||||
@ -2323,20 +2332,24 @@ print_statistics (hp_timing_t *rtld_total_timep)
|
||||
#endif
|
||||
|
||||
unsigned long int num_relative_relocations = 0;
|
||||
struct r_scope_elem *scope = &GL(dl_loaded)->l_searchlist;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < scope->r_nlist; i++)
|
||||
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
|
||||
{
|
||||
struct link_map *l = scope->r_list [i];
|
||||
struct r_scope_elem *scope = &GL(dl_ns)[ns]._ns_loaded->l_searchlist;
|
||||
|
||||
if (!l->l_addr)
|
||||
continue;
|
||||
for (unsigned int i = 0; i < scope->r_nlist; i++)
|
||||
{
|
||||
struct link_map *l = scope->r_list [i];
|
||||
|
||||
if (l->l_info[VERSYMIDX (DT_RELCOUNT)])
|
||||
num_relative_relocations += l->l_info[VERSYMIDX (DT_RELCOUNT)]->d_un.d_val;
|
||||
if (l->l_info[VERSYMIDX (DT_RELACOUNT)])
|
||||
num_relative_relocations += l->l_info[VERSYMIDX (DT_RELACOUNT)]->d_un.d_val;
|
||||
if (!l->l_addr)
|
||||
continue;
|
||||
|
||||
if (l->l_info[VERSYMIDX (DT_RELCOUNT)])
|
||||
num_relative_relocations
|
||||
+= l->l_info[VERSYMIDX (DT_RELCOUNT)]->d_un.d_val;
|
||||
if (l->l_info[VERSYMIDX (DT_RELACOUNT)])
|
||||
num_relative_relocations
|
||||
+= l->l_info[VERSYMIDX (DT_RELACOUNT)]->d_un.d_val;
|
||||
}
|
||||
}
|
||||
|
||||
_dl_debug_printf (" number of relocations: %lu\n"
|
||||
|
80
elf/tst-dlmopen1.c
Normal file
80
elf/tst-dlmopen1.c
Normal file
@ -0,0 +1,80 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <gnu/lib-names.h>
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
void *h = dlopen (LIBC_SO, RTLD_LAZY|RTLD_NOLOAD);
|
||||
if (h == NULL)
|
||||
{
|
||||
printf ("cannot get handle for %s: %s\n", LIBC_SO, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
Lmid_t ns = -10;
|
||||
if (dlinfo (h, RTLD_DI_LMID, &ns) != 0)
|
||||
{
|
||||
printf ("dlinfo for %s in %s failed: %s\n",
|
||||
LIBC_SO, __func__, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ns != LM_ID_BASE)
|
||||
{
|
||||
printf ("namespace for %s not LM_ID_BASE\n", LIBC_SO);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (dlclose (h) != 0)
|
||||
{
|
||||
printf ("dlclose for %s in %s failed: %s\n",
|
||||
LIBC_SO, __func__, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
h = dlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so", RTLD_LAZY);
|
||||
if (h == NULL)
|
||||
{
|
||||
printf ("cannot get handle for %s: %s\n",
|
||||
"tst-dlmopen1mod.so", dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
ns = -10;
|
||||
if (dlinfo (h, RTLD_DI_LMID, &ns) != 0)
|
||||
{
|
||||
printf ("dlinfo for %s in %s failed: %s\n",
|
||||
"tst-dlmopen1mod.so", __func__, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ns == LM_ID_BASE)
|
||||
{
|
||||
printf ("namespace for %s is LM_ID_BASE\n", LIBC_SO);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int (*fct) (Lmid_t) = dlsym (h, "foo");
|
||||
if (fct == NULL)
|
||||
{
|
||||
printf ("could not find %s: %s\n", "foo", dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fct (ns) != 0)
|
||||
return 1;
|
||||
|
||||
if (dlclose (h) != 0)
|
||||
{
|
||||
printf ("dlclose for %s in %s failed: %s\n",
|
||||
LIBC_SO, __func__, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
38
elf/tst-dlmopen1mod.c
Normal file
38
elf/tst-dlmopen1mod.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <gnu/lib-names.h>
|
||||
|
||||
|
||||
int
|
||||
foo (Lmid_t ns2)
|
||||
{
|
||||
void *h = dlopen (LIBC_SO, RTLD_LAZY|RTLD_NOLOAD);
|
||||
if (h == NULL)
|
||||
{
|
||||
printf ("cannot get handle for %s: %s\n", LIBC_SO, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
Lmid_t ns = -10;
|
||||
if (dlinfo (h, RTLD_DI_LMID, &ns) != 0)
|
||||
{
|
||||
printf ("dlinfo for %s in %s failed: %s\n",
|
||||
LIBC_SO, __func__, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ns != ns2)
|
||||
{
|
||||
printf ("namespace for %s not LM_ID_BASE\n", LIBC_SO);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (dlclose (h) != 0)
|
||||
{
|
||||
printf ("dlclose for %s in %s failed: %s\n",
|
||||
LIBC_SO, __func__, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
70
elf/tst-dlmopen2.c
Normal file
70
elf/tst-dlmopen2.c
Normal file
@ -0,0 +1,70 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <gnu/lib-names.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
for (int i = 1; i <= 10; ++i)
|
||||
{
|
||||
void *h[DL_NNS - 1];
|
||||
char used[DL_NNS];
|
||||
|
||||
printf ("round %d\n", i);
|
||||
|
||||
memset (used, '\0', sizeof (used));
|
||||
used[LM_ID_BASE] = 1;
|
||||
|
||||
for (int j = 0; j < DL_NNS - 1; ++j)
|
||||
{
|
||||
h[j] = dlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
|
||||
RTLD_LAZY);
|
||||
if (h[j] == NULL)
|
||||
{
|
||||
printf ("round %d, namespace %d: load failed: %s\n",
|
||||
i, j, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
Lmid_t ns;
|
||||
if (dlinfo (h[j], RTLD_DI_LMID, &ns) != 0)
|
||||
{
|
||||
printf ("round %d, namespace %d: dlinfo failed: %s\n",
|
||||
i, j, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
if (ns < 0 || ns >= DL_NNS)
|
||||
{
|
||||
printf ("round %d, namespace %d: invalid namespace %ld",
|
||||
i, j, (long int) ns);
|
||||
result = 1;
|
||||
}
|
||||
else if (used[ns] != 0)
|
||||
{
|
||||
printf ("\
|
||||
round %d, namespace %d: duplicate allocate of namespace %ld",
|
||||
i, j, (long int) ns);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
used[ns] = 1;
|
||||
}
|
||||
|
||||
for (int j = 0; j < DL_NNS - 1; ++j)
|
||||
if (dlclose (h[j]) != 0)
|
||||
{
|
||||
printf ("round %d, namespace %d: close failed: %s\n",
|
||||
i, j, dlerror ());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
@ -8,6 +8,8 @@
|
||||
#define __RTLD_OPENEXEC 0x20000000
|
||||
#define __RTLD_CALLMAP 0x10000000
|
||||
|
||||
#define __LM_ID_CALLER -2
|
||||
|
||||
/* Now define the internal interfaces. */
|
||||
extern void *__dlvsym (void *__handle, __const char *__name,
|
||||
__const char *__version);
|
||||
@ -31,7 +33,8 @@ libc_hidden_proto (_dl_addr)
|
||||
/* Open the shared object NAME, relocate it, and run its initializer if it
|
||||
hasn't already been run. MODE is as for `dlopen' (see <dlfcn.h>). If
|
||||
the object is already opened, returns its existing map. */
|
||||
extern void *_dl_open (const char *name, int mode, const void *caller)
|
||||
extern void *_dl_open (const char *name, int mode, const void *caller,
|
||||
Lmid_t nsid)
|
||||
internal_function;
|
||||
libc_hidden_proto (_dl_open)
|
||||
|
||||
|
@ -129,6 +129,14 @@ struct link_map
|
||||
/* All following members are internal to the dynamic linker.
|
||||
They may change without notice. */
|
||||
|
||||
/* This is an element which is only ever different from a pointer to
|
||||
the very same copy of this type for ld.so when it is used in more
|
||||
than one namespace. */
|
||||
struct link_map *l_real;
|
||||
|
||||
/* Number of the namespace this link map belongs to. */
|
||||
Lmid_t l_ns;
|
||||
|
||||
struct libname_list *l_libname;
|
||||
/* Indexed pointers to dynamic section.
|
||||
[0,DT_NUM) are indexed by the processor-independent tags.
|
||||
@ -169,7 +177,8 @@ struct link_map
|
||||
Elf_Symndx l_nbuckets;
|
||||
const Elf_Symndx *l_buckets, *l_chain;
|
||||
|
||||
unsigned int l_opencount; /* Reference count for dlopen/dlclose. */
|
||||
unsigned int l_opencount; /* Counter for direct and indirect usage. */
|
||||
unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose. */
|
||||
enum /* Where this object came from. */
|
||||
{
|
||||
lt_executable, /* The main executable program. */
|
||||
|
@ -339,7 +339,16 @@ ptmalloc_init_minimal (void)
|
||||
mp_.pagesize = malloc_getpagesize;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _LIBC
|
||||
# ifdef SHARED
|
||||
static void *
|
||||
__failing_morecore (ptrdiff_t d)
|
||||
{
|
||||
return (void *) MORECORE_FAILURE;
|
||||
}
|
||||
# endif
|
||||
|
||||
# if defined SHARED && defined USE_TLS && !USE___THREAD
|
||||
# include <stdbool.h>
|
||||
|
||||
@ -419,6 +428,14 @@ ptmalloc_init (void)
|
||||
mutex_init(&main_arena.mutex);
|
||||
main_arena.next = &main_arena;
|
||||
|
||||
#if defined _LIBC && defined SHARED
|
||||
/* In case this libc copy is in a non-default namespace, never use brk. */
|
||||
Dl_info di;
|
||||
struct link_map *l;
|
||||
if (_dl_addr (ptmalloc_init, &di, &l, NULL) != 0 && l->l_ns != LM_ID_BASE)
|
||||
__morecore = __failing_morecore;
|
||||
#endif
|
||||
|
||||
mutex_init(&list_lock);
|
||||
tsd_key_create(&arena_key, NULL);
|
||||
tsd_setspecific(arena_key, (Void_t *)&main_arena);
|
||||
|
@ -289,9 +289,13 @@ extern "C" {
|
||||
|
||||
/* For writev and struct iovec. */
|
||||
#include <sys/uio.h>
|
||||
/* For syslog. */
|
||||
/* For syslog. */
|
||||
#include <sys/syslog.h>
|
||||
|
||||
/* For various dynamic linking things. */
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
||||
/*
|
||||
Debugging:
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
/* Amount of excess space to allocate in the static TLS area
|
||||
to allow dynamic loading of modules defining IE-model TLS data. */
|
||||
# define TLS_STATIC_SURPLUS 64
|
||||
# define TLS_STATIC_SURPLUS 64 + DL_NNS * 100
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
# define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
@ -216,18 +216,27 @@ struct rtld_global
|
||||
/* Don't change the order of the following elements. 'dl_loaded'
|
||||
must remain the first element. Forever. */
|
||||
|
||||
/* And a pointer to the map for the main map. */
|
||||
EXTERN struct link_map *_dl_loaded;
|
||||
/* Number of object in the _dl_loaded list. */
|
||||
EXTERN unsigned int _dl_nloaded;
|
||||
/* 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;
|
||||
/* This is zero at program start to signal that the global scope map is
|
||||
allocated by rtld. Later it keeps the size of the map. It might be
|
||||
reset if in _dl_close if the last global object is removed. */
|
||||
EXTERN size_t _dl_global_scope_alloc;
|
||||
/* Non-shared code has no support for multiple namespaces. */
|
||||
#ifdef SHARED
|
||||
# define DL_NNS 16
|
||||
#else
|
||||
# define DL_NNS 1
|
||||
#endif
|
||||
EXTERN struct link_namespaces
|
||||
{
|
||||
/* And a pointer to the map for the main map. */
|
||||
struct link_map *_ns_loaded;
|
||||
/* Number of object in the _dl_loaded list. */
|
||||
unsigned int _ns_nloaded;
|
||||
/* Array representing global scope. */
|
||||
struct r_scope_elem *_ns_global_scope[2];
|
||||
/* Direct pointer to the searchlist of the main object. */
|
||||
struct r_scope_elem *_ns_main_searchlist;
|
||||
/* This is zero at program start to signal that the global scope map is
|
||||
allocated by rtld. Later it keeps the size of the map. It might be
|
||||
reset if in _dl_close if the last global object is removed. */
|
||||
size_t _ns_global_scope_alloc;
|
||||
} _dl_ns[DL_NNS];
|
||||
|
||||
/* During the program run we must not modify the global data of
|
||||
loaded shared object simultanously in two threads. Therefore we
|
||||
@ -477,7 +486,7 @@ struct rtld_global_ro
|
||||
char *(*_dl_dst_substitute) (struct link_map *, const char *, char *, int);
|
||||
struct link_map *(internal_function *_dl_map_object) (struct link_map *,
|
||||
const char *, int,
|
||||
int, int, int);
|
||||
int, int, int, Lmid_t);
|
||||
void (internal_function *_dl_map_object_deps) (struct link_map *,
|
||||
struct link_map **,
|
||||
unsigned int, int, int);
|
||||
@ -658,7 +667,8 @@ extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *),
|
||||
value to allow additional security checks. */
|
||||
extern struct link_map *_dl_map_object (struct link_map *loader,
|
||||
const char *name, int preloaded,
|
||||
int type, int trace_mode, int mode)
|
||||
int type, int trace_mode, int mode,
|
||||
Lmid_t nsid)
|
||||
internal_function attribute_hidden;
|
||||
|
||||
/* Call _dl_map_object on the dependencies of MAP, and set up
|
||||
@ -723,7 +733,7 @@ extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name)
|
||||
and enter it into the _dl_main_map list. */
|
||||
extern struct link_map *_dl_new_object (char *realname, const char *libname,
|
||||
int type, struct link_map *loader,
|
||||
int mode)
|
||||
int mode, Lmid_t nsid)
|
||||
internal_function attribute_hidden;
|
||||
|
||||
/* Relocate the given object (if it hasn't already been).
|
||||
|
@ -28,15 +28,15 @@
|
||||
/* 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 (GL(dl_loaded)->l_info[DT_NEEDED]) \
|
||||
if (main_map->l_info[DT_NEEDED]) \
|
||||
{ \
|
||||
/* We have dependencies. */ \
|
||||
const ElfW(Dyn) *d; \
|
||||
const char *strtab; \
|
||||
\
|
||||
strtab = (const char *) D_PTR (GL(dl_loaded), l_info[DT_STRTAB]); \
|
||||
strtab = (const char *) D_PTR (main_map, l_info[DT_STRTAB]); \
|
||||
\
|
||||
for (d = GL(dl_loaded)->l_ld; d->d_tag != DT_NULL; ++d) \
|
||||
for (d = main_map->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