* csu/elf-init.c (__libc_csu_fini): Don't do anything here.

* sysdeps/generic/libc-start.c: Don't register program destructor here.
	* dlfcn/Makefile: Add rules to build dlfcn.c.
	(LDFLAGS-dl.so): Removed.
	* dlfcn/dlclose.c: _dl_close is now in ld.so, use function pointer
	table.
	* dlfcn/dlmopen.c: Likewise for _dl_open.
	* dlfcn/dlopen.c: Likewise.
	* dlfcn/dlopenold.c: Likewise.
	* elf/dl-libc.c: Likewise for _dl_open and _dl_close.
	* elf/Makefile (routines): Remove dl-open and dl-close.
	(dl-routines): Add dl-open, dl-close, and dl-trampoline.
	Add rules to build and run tst-audit1.
	* elf/tst-audit1.c: New file.
	* elf/tst-auditmod1.c: New file.
	* elf/Versions [libc]: Remove _dl_open and _dl_close.
	* elf/dl-close.c: Change for use inside ld.so instead of libc.so.
	* elf/dl-open.c: Likewise.
	* elf/dl-debug.c (_dl_debug_initialize): Allow reinitialization,
	signaled by nonzero parameter.
	* elf/dl-init.c: Fix use of r_state.
	* elf/dl-load.c: Likewise.

	* elf/dl-close.c: Add auditing checkpoints.
	* elf/dl-open.c: Likewise.
	* elf/dl-fini.c: Likewise.
	* elf/dl-load.c: Likewise.
	* elf/dl-sym.c: Likewise.
	* sysdeps/generic/libc-start.c: Likewise.
	* elf/dl-object.c: Allocate memory for auditing information.
	* elf/dl-reloc.c: Remove RESOLV.  We now always need the map.
	Correctly initialize slotinfo.
	* elf/dynamic-link.h: Adjust after removal of RESOLV.
	* sysdeps/hppa/dl-lookupcfg.h: Likewise.
	* sysdeps/ia64/dl-lookupcfg.h: Likewise.
	* sysdeps/powerpc/powerpc64/dl-lookupcfg.h: Removed.
	* elf/dl-runtime.c (_dl_fixup): Little cleanup.
	(_dl_profile_fixup): New parameters to point to register struct and
	variable for frame size.
	Add auditing checkpoints.
	(_dl_call_pltexit): New function.
	Don't define trampoline code here.
	* elf/rtld.c: Recognize LD_AUDIT.  Load modules on startup.
	Remove all the functions from _rtld_global_ro which only _dl_open
	and _dl_close needed.
	Add auditing checkpoints.
	* elf/link.h: Define symbols for auditing interfaces.
	* include/link.h: Likewise.
	* include/dlfcn.h: Define __RTLD_AUDIT.
	Remove prototypes for _dl_open and _dl_close.
	Adjust access to argc and argv in libdl.
	* dlfcn/dlfcn.c: New file.
	* sysdeps/generic/dl-lookupcfg.h: Remove all content now that RESOLVE
	is gone.
	* sysdeps/generic/ldsodefs.h: Add definitions for auditing interfaces.
	* sysdeps/generic/unsecvars.h: Add LD_AUDIT.
	* sysdeps/i386/dl-machine.h: Remove trampoline code here.
	Adjust for removal of RESOLVE.
	* sysdeps/x86_64/dl-machine.h: Likewise.
	* sysdeps/generic/dl-trampoline.c: New file.
	* sysdeps/i386/dl-trampoline.c: New file.
	* sysdeps/x86_64/dl-trampoline.c: New file.

	* sysdeps/generic/dl-tls.c: Cleanups.  Fixup for dtv_t change.
	Fix updating of DTV.
	* sysdeps/generic/libc-tls.c: Likewise.

	* sysdeps/arm/bits/link.h: Renamed to ...
	* sysdeps/arm/buts/linkmap.h: ...this.
	* sysdeps/generic/bits/link.h: Renamed to...
	* sysdeps/generic/bits/linkmap.h: ...this.
	* sysdeps/hppa/bits/link.h: Renamed to...
	* sysdeps/hppa/bits/linkmap.h: ...this.
	* sysdeps/hppa/i386/link.h: Renamed to...
	* sysdeps/hppa/i386/linkmap.h: ...this.
	* sysdeps/hppa/ia64/link.h: Renamed to...
	* sysdeps/hppa/ia64/linkmap.h: ...this.
	* sysdeps/hppa/s390/link.h: Renamed to...
	* sysdeps/hppa/s390/linkmap.h: ...this.
	* sysdeps/hppa/sh/link.h: Renamed to...
	* sysdeps/hppa/sh/linkmap.h: ...this.
	* sysdeps/hppa/x86_64/link.h: Renamed to...
	* sysdeps/hppa/x86_64/linkmap.h: ...this.
2005-01-06  Ulrich Drepper  <drepper@redhat.com>

	* allocatestack.c (init_one_static_tls): Adjust initialization of DTV
	entry for static tls deallocation fix.
	* sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which
	also contains information whether the memory pointed to is static
	TLS or not.
	* sysdeps/i386/tls.h: Likewise.
	* sysdeps/ia64/tls.h: Likewise.
	* sysdeps/powerpc/tls.h: Likewise.
	* sysdeps/s390/tls.h: Likewise.
	* sysdeps/sh/tls.h: Likewise.
	* sysdeps/sparc/tls.h: Likewise.
	* sysdeps/x86_64/tls.h: Likewise.
This commit is contained in:
Ulrich Drepper 2005-01-06 22:40:27 +00:00
parent f14038f2e2
commit 9dcafc5597
70 changed files with 2625 additions and 1012 deletions

View File

@ -1,4 +1 @@
struct link_map_machine
{
/* empty by default */
};
#error "Architecture-specific definition needed."

4
bits/linkmap.h Normal file
View File

@ -0,0 +1,4 @@
struct link_map_machine
{
/* empty by default */
};

View File

@ -1,5 +1,5 @@
/* Startup support for ELF initializers/finalizers in the main executable.
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
Copyright (C) 2002, 2003, 2004, 2005 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
@ -86,9 +86,13 @@ __libc_csu_init (void)
#endif
}
/* This function should not be used anymore. We run the executable's
destructor now just like any other. We cannot remove the function,
though. */
void
__libc_csu_fini (void)
{
#if 0
#ifdef HAVE_INITFINI_ARRAY
size_t i = __fini_array_end - __fini_array_start;
while (i-- > 0)
@ -96,4 +100,5 @@ __libc_csu_fini (void)
#endif
_fini ();
#endif
}

View File

@ -20,8 +20,8 @@ subdir := dlfcn
headers := bits/dlfcn.h dlfcn.h
extra-libs := libdl
libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
dlmopen
routines := $(patsubst %,s%,$(libdl-routines))
dlmopen dlfcn
routines := $(patsubst %,s%,$(filter-out dlfcn,$(libdl-routines)))
elide-routines.os := $(routines)
distribute := dlopenold.c glreflib1.c glreflib2.c failtestmod.c \
defaultmod1.c defaultmod2.c errmsg1mod.c modatexit.c \
@ -34,7 +34,7 @@ include ../Makeconfig
ifeq ($(versioning),yes)
libdl-routines += dlopenold
libdl-shared-only-routines := dlopenold
libdl-shared-only-routines := dlopenold dlfcn
endif
ifeq (yes,$(build-shared))
@ -65,8 +65,6 @@ generated := $(modules-names:=.so)
include ../Rules
LDFLAGS-dl.so = -Wl,-dynamic-linker,$(slibdir)/$(rtld-installed-name)
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
$(test-modules): $(objpfx)%.so: $(objpfx)%.os $(common-objpfx)shlib.lds
$(build-module)

View File

@ -19,6 +19,7 @@
02111-1307 USA. */
#include <dlfcn.h>
#include <ldsodefs.h>
#if !defined SHARED && defined IS_IN_libdl
@ -33,7 +34,7 @@ dlclose (void *handle)
static void
dlclose_doit (void *handle)
{
_dl_close (handle);
GLRO(dl_close) (handle);
}
int

33
dlfcn/dlfcn.c Normal file
View File

@ -0,0 +1,33 @@
/* 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>
int __dlfcn_argc attribute_hidden;
char **__dlfcn_argv attribute_hidden;
void
__attribute ((constuctor))
init (int argc, char *argv[])
{
__dlfcn_argc = argc;
__dlfcn_argv = argv;
}

View File

@ -21,6 +21,7 @@
#include <errno.h>
#include <libintl.h>
#include <stddef.h>
#include <unistd.h>
#include <ldsodefs.h>
#if !defined SHARED && defined IS_IN_libdl
@ -61,8 +62,10 @@ dlmopen_doit (void *a)
# 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);
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
args->caller,
args->nsid, __dlfcn_argc, __dlfcn_argv,
__environ);
}

View File

@ -19,6 +19,8 @@
#include <dlfcn.h>
#include <stddef.h>
#include <unistd.h>
#include <ldsodefs.h>
#if !defined SHARED && defined IS_IN_libdl
@ -56,8 +58,10 @@ 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->file == NULL ? LM_ID_BASE : NS);
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
args->caller,
args->file == NULL ? LM_ID_BASE : NS,
__dlfcn_argc, __dlfcn_argv, __environ);
}

View File

@ -19,6 +19,8 @@
#include <dlfcn.h>
#include <stddef.h>
#include <unistd.h>
#include <ldsodefs.h>
/* This file is for compatibility with glibc 2.0. Compile it only if
versioning is used. */
@ -50,8 +52,10 @@ 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->file == NULL ? LM_ID_BASE : NS);
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
args->caller,
args->file == NULL ? LM_ID_BASE : NS,
__dlfcn_argc, __dlfcn_argv, __environ);
}
extern void *__dlopen_nocheck (const char *file, int mode);

View File

@ -21,7 +21,7 @@
subdir := elf
headers = elf.h bits/elfclass.h link.h
routines = $(dl-routines) dl-open dl-close dl-support dl-iteratephdr \
routines = $(dl-routines) dl-support dl-iteratephdr \
dl-addr enbl-secure dl-profstub \
dl-origin dl-libc dl-sym dl-tsd
@ -30,7 +30,7 @@ routines = $(dl-routines) dl-open dl-close dl-support dl-iteratephdr \
dl-routines = $(addprefix dl-,load cache lookup object reloc deps \
runtime error init fini debug misc \
version profile conflict tls origin \
execstack caller)
execstack caller open close trampoline)
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
# But they are absent from the shared libc, because that code is in ld.so.
elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin
@ -83,7 +83,8 @@ distribute := rtld-Rules \
tst-array2dep.c tst-piemod1.c \
tst-execstack-mod.c tst-dlmodcount.c \
check-textrel.c dl-sysdep.h test-dlopenrpathmod.c \
tst-deep1mod1.c tst-deep1mod2.c tst-deep1mod3.c
tst-deep1mod1.c tst-deep1mod2.c tst-deep1mod3.c \
tst-auditmod1.c
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
@ -154,7 +155,8 @@ 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-dlmopen1 tst-dlmopen2 tst-dlmopen3
tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
tst-audit1
# reldep9
test-srcs = tst-pathopt
tests-vis-yes = vismain
@ -188,7 +190,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
reldep9mod1 reldep9mod2 reldep9mod3 \
tst-alignmod $(modules-execstack-$(have-z-execstack)) \
tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
tst-dlmopen1mod
tst-dlmopen1mod tst-auditmod1
ifeq (yes,$(have-initfini-array))
modules-names += tst-array2dep
endif
@ -773,3 +775,6 @@ $(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
$(objpfx)tst-dlmopen3: $(libdl)
$(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so

View File

@ -19,7 +19,7 @@ libc {
%endif
GLIBC_PRIVATE {
# functions used in other libraries
_dl_open; _dl_close; _dl_addr;
_dl_addr;
_dl_sym; _dl_vsym;
_dl_open_hook;
__libc_dlopen_mode; __libc_dlsym; __libc_dlclose;

View File

@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <bits/libc-lock.h>
#include <ldsodefs.h>
#include <sys/types.h>
@ -99,7 +100,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
void
internal_function
_dl_close (void *_map)
{
struct reldep_list
@ -112,6 +112,7 @@ _dl_close (void *_map)
} *reldeps = NULL;
struct link_map **list;
struct link_map *map = _map;
Lmid_t ns = map->l_ns;
unsigned int i;
unsigned int *new_opencount;
#ifdef USE_TLS
@ -139,7 +140,7 @@ _dl_close (void *_map)
{
/* There are still references to this object. Do nothing more. */
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
GLRO(dl_debug_printf) ("\nclosing file=%s; opencount == %u\n",
_dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
map->l_name, map->l_opencount);
/* Decrement the object's reference counter, not the dependencies'. */
@ -268,13 +269,17 @@ _dl_close (void *_map)
for (i = 0; list[i] != NULL; ++i)
{
struct link_map *imap = list[i];
/* All elements must be in the same namespace. */
assert (imap->l_ns == ns);
if (new_opencount[i] == 0 && imap->l_type == lt_loaded
&& (imap->l_flags_1 & DF_1_NODELETE) == 0)
{
/* When debugging print a message first. */
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
GLRO(dl_debug_printf) ("\ncalling fini: %s [%lu]\n\n",
imap->l_name, imap->l_ns);
_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
imap->l_name, ns);
/* Call its termination function. Do not do it for
half-cooked objects. */
@ -299,6 +304,22 @@ _dl_close (void *_map)
+ imap->l_info[DT_FINI]->d_un.d_ptr))) ();
}
#ifdef SHARED
/* Auditing checkpoint: we have a new object. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->objclose != NULL)
/* Return value is ignored. */
(void) afct->objclose (&imap->l_audit[cnt].cookie);
afct = afct->next;
}
}
#endif
/* This object must not be used anymore. We must remove the
reference from the scope. */
unsigned int j;
@ -365,9 +386,30 @@ _dl_close (void *_map)
assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
}
#ifdef SHARED
/* Auditing checkpoint: we will start deleting objects. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct link_map *head = GL(dl_ns)[ns]._ns_loaded;
struct audit_ifaces *afct = GLRO(dl_audit);
/* Do not call the functions for any auditing object. */
if (head->l_auditing == 0)
{
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_DELETE);
afct = afct->next;
}
}
}
#endif
/* Notify the debugger we are about to remove some loaded objects. */
_r_debug.r_state = RT_DELETE;
GLRO(dl_debug_state) ();
struct r_debug *r = _dl_debug_initialize (0);
r->r_state = RT_DELETE;
_dl_debug_state ();
#ifdef USE_TLS
size_t tls_free_start;
@ -389,21 +431,19 @@ _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_ns)[imap->l_ns]._ns_main_searchlist->r_nlist;
unsigned int cnt = GL(dl_ns)[ns]._ns_main_searchlist->r_nlist;
do
--cnt;
while (GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt]
!= imap);
while (GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt] != imap);
/* The object was already correctly registered. */
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_ns)[ns]._ns_main_searchlist->r_nlist)
GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt - 1]
= GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt];
--GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist;
--GL(dl_ns)[ns]._ns_main_searchlist->r_nlist;
}
#ifdef USE_TLS
@ -412,7 +452,8 @@ _dl_close (void *_map)
{
any_tls = true;
if (! remove_slotinfo (imap->l_tls_modid,
if (GL(dl_tls_dtv_slotinfo_list) != NULL
&& ! remove_slotinfo (imap->l_tls_modid,
GL(dl_tls_dtv_slotinfo_list), 0,
imap->l_init_called))
/* All dynamically loaded modules with TLS are unloaded. */
@ -499,12 +540,12 @@ _dl_close (void *_map)
else
{
#ifdef SHARED
assert (imap->l_ns != LM_ID_BASE);
assert (ns != LM_ID_BASE);
#endif
GL(dl_ns)[imap->l_ns]._ns_loaded = imap->l_next;
GL(dl_ns)[ns]._ns_loaded = imap->l_next;
}
--GL(dl_ns)[imap->l_ns]._ns_nloaded;
--GL(dl_ns)[ns]._ns_nloaded;
if (imap->l_next != NULL)
imap->l_next->l_prev = imap->l_prev;
@ -579,16 +620,36 @@ _dl_close (void *_map)
if (any_tls)
{
if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
__libc_fatal (_("TLS generation counter wrapped! Please report as described in <http://www.gnu.org/software/libc/bugs.html>."));
_dl_fatal_printf ("TLS generation counter wrapped! Please report as described in <http://www.gnu.org/software/libc/bugs.html>.\n");
if (tls_free_end == GL(dl_tls_static_used))
GL(dl_tls_static_used) = tls_free_start;
}
#endif
#ifdef SHARED
/* Auditing checkpoint: we have deleted all objects. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct link_map *head = GL(dl_ns)[ns]._ns_loaded;
/* Do not call the functions for any auditing object. */
if (head->l_auditing == 0)
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
afct = afct->next;
}
}
}
#endif
/* Notify the debugger those objects are finalized and gone. */
_r_debug.r_state = RT_CONSISTENT;
GLRO(dl_debug_state) ();
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
/* Now we can perhaps also remove the modules for which we had
dependencies because of symbol lookup. */
@ -612,7 +673,6 @@ _dl_close (void *_map)
/* Release the lock. */
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}
libc_hidden_def (_dl_close)
#ifdef USE_TLS

View File

@ -34,7 +34,7 @@ struct r_debug *
internal_function
_dl_debug_initialize (ElfW(Addr) ldbase)
{
if (_r_debug.r_brk == 0)
if (_r_debug.r_brk == 0 || ldbase != 0)
{
/* Tell the debugger where to find the map of loaded objects. */
_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;

View File

@ -53,7 +53,12 @@ _dl_fini (void)
/* Protect against concurrent loads and unloads. */
__rtld_lock_lock_recursive (GL(dl_load_lock));
unsigned int nmaps = 0;
unsigned int nloaded = GL(dl_ns)[cnt]._ns_nloaded;
/* No need to do anything for empty namespaces or those used for
auditing DSOs. */
if (nloaded == 0 || GL(dl_ns)[cnt]._ns_loaded->l_auditing)
goto out;
/* XXX Could it be (in static binaries) that there is no object
loaded? */
@ -76,6 +81,7 @@ _dl_fini (void)
unsigned int i;
struct link_map *l;
assert (nloaded != 0 || GL(dl_ns)[cnt]._ns_loaded == NULL);
for (l = GL(dl_ns)[cnt]._ns_loaded, i = 0; l != NULL; l = l->l_next)
/* Do not handle ld.so in secondary namespaces. */
if (l == l->l_real)
@ -90,7 +96,7 @@ _dl_fini (void)
}
assert (cnt != LM_ID_BASE || i == nloaded);
assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1);
unsigned int nmaps = i;
nmaps = i;
if (nmaps != 0)
{
@ -163,6 +169,7 @@ _dl_fini (void)
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. */
out:
__rtld_lock_unlock_recursive (GL(dl_load_lock));
/* 'maps' now contains the objects in the right order. Now call the
@ -176,19 +183,13 @@ _dl_fini (void)
/* 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;
if (l->l_info[DT_FINI_ARRAY] != NULL
|| l->l_info[DT_FINI] != NULL)
{
/* When debugging print a message first. */
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
0))
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);
@ -210,6 +211,23 @@ _dl_fini (void)
((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
}
#ifdef SHARED
/* Auditing checkpoint: another object closed. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->objclose != NULL)
/* Return value is ignored. */
(void) afct->objclose (&l->l_audit[cnt].cookie);
afct = afct->next;
}
}
#endif
}
/* Correct the previous increment. */
--l->l_opencount;
}

View File

@ -93,7 +93,6 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
{
ElfW(Dyn) *preinit_array = main_map->l_info[DT_PREINIT_ARRAY];
ElfW(Dyn) *preinit_array_size = main_map->l_info[DT_PREINIT_ARRAYSZ];
struct r_debug *r;
unsigned int i;
if (__builtin_expect (GL(dl_initfirst) != NULL, 0))
@ -120,13 +119,6 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
((init_t) addrs[cnt]) (argc, argv, env);
}
/* Notify the debugger we have added some objects. We need to call
_dl_debug_initialize in a static program in case dynamic linking has
not been used before. */
r = _dl_debug_initialize (0);
r->r_state = RT_ADD;
_dl_debug_state ();
/* Stupid users forced the ELF specification to be changed. It now
says that the dynamic loader is responsible for determining the
order in which the constructors have to run. The constructors
@ -141,10 +133,6 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
while (i-- > 0)
call_init (main_map->l_initfini[i], argc, argv, env);
/* Notify the debugger all new objects are now ready to go. */
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
#ifndef HAVE_INLINED_SYSCALLS
/* Finished starting up. */
INTUSE(_dl_starting_up) = 0;

View File

@ -22,6 +22,11 @@
#include <stdlib.h>
#include <ldsodefs.h>
extern int __libc_argc attribute_hidden;
extern char **__libc_argv attribute_hidden;
extern char **__environ;
/* The purpose of this file is to provide wrappers around the dynamic
linker error mechanism (similar to dlopen() et al in libdl) which
are usable from within libc. Generally we want to throw away the
@ -77,7 +82,8 @@ 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, __LM_ID_CALLER);
args->map = GLRO(dl_open) (args->name, args->mode, NULL, __LM_ID_CALLER,
__libc_argc, __libc_argv, __environ);
}
static void
@ -93,7 +99,7 @@ do_dlsym (void *ptr)
static void
do_dlclose (void *ptr)
{
_dl_close ((struct link_map *) ptr);
GLRO(dl_close) ((struct link_map *) ptr);
}
/* This code is to support __libc_dlopen from __libc_dlopen'ed shared
@ -119,7 +125,7 @@ do_dlsym_private (void *ptr)
struct r_found_version vers;
vers.name = "GLIBC_PRIVATE";
vers.hidden = 1;
/* vers.hash = _dl_elf_hash (version); */
/* vers.hash = _dl_elf_hash (vers.name); */
vers.hash = 0x0963cf85;
vers.filename = NULL;

View File

@ -827,6 +827,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
/* Initialize to keep the compiler happy. */
const char *errstring = NULL;
int errval = 0;
struct r_debug *r = _dl_debug_initialize (0);
bool make_consistent = false;
/* Get file information. */
if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st) < 0, 0))
@ -835,6 +837,12 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
call_lose_errno:
errval = errno;
call_lose:
if (make_consistent)
{
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
}
lose (errval, fd, name, realname, l, errstring);
}
@ -905,6 +913,39 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
}
#endif
/* Signal that we are going to add new objects. */
if (r->r_state == RT_CONSISTENT)
{
#ifdef SHARED
/* Auditing checkpoint: we are going to add new objects. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
/* Do not call the functions for any auditing object. */
if (head->l_auditing == 0)
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_ADD);
afct = afct->next;
}
}
}
#endif
/* Notify the debugger we have added some objects. We need to
call _dl_debug_initialize in a static program in case dynamic
linking has not been used before. */
r->r_state = RT_ADD;
_dl_debug_state ();
make_consistent = true;
}
else
assert (r->r_state == RT_ADD);
/* Enter the new object in the list of loaded objects. */
l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
if (__builtin_expect (l == NULL, 0))
@ -1044,7 +1085,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
}
# ifdef SHARED
if (l->l_prev == NULL)
if (l->l_prev == NULL || (mode && __RTLD_AUDIT) != 0)
/* We are loading the executable itself when the dynamic linker
was executed directly. The setup will happen later. */
break;
@ -1424,6 +1465,26 @@ cannot enable executable stack as shared object requires");
add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
+ l->l_info[DT_SONAME]->d_un.d_val));
#ifdef SHARED
/* Auditing checkpoint: we have a new object. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->objopen != NULL)
{
l->l_audit[cnt].bindflags
= afct->objopen (l, nsid, &l->l_audit[cnt].cookie);
l->l_audit_any_plt |= l->l_audit[cnt].bindflags != 0;
}
afct = afct->next;
}
}
#endif
return l;
}
@ -1471,7 +1532,8 @@ print_search_path (struct r_search_path_elem **list,
this could mean there is something wrong in the installation and the
user might want to know about this. */
static int
open_verify (const char *name, struct filebuf *fbp)
open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
int whatcode)
{
/* This is the expected ELF header. */
#define ELF32_CLASS ELFCLASS32
@ -1500,13 +1562,34 @@ open_verify (const char *name, struct filebuf *fbp)
ElfW(Word) type;
char vendor[4];
} expected_note = { 4, 16, 1, "GNU" };
int fd;
/* Initialize it to make the compiler happy. */
const char *errstring = NULL;
int errval = 0;
#ifdef SHARED
/* Give the auditing libraries a chance. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0) && whatcode != 0
&& loader->l_auditing == 0)
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->objsearch != NULL)
{
name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
whatcode);
if (name == NULL)
/* Ignore the path. */
return -1;
}
afct = afct->next;
}
}
#endif
/* Open the file. We always open files read-only. */
fd = __open (name, O_RDONLY);
int fd = __open (name, O_RDONLY);
if (fd != -1)
{
ElfW(Ehdr) *ehdr;
@ -1664,7 +1747,7 @@ open_verify (const char *name, struct filebuf *fbp)
static int
open_path (const char *name, size_t namelen, int preloaded,
struct r_search_path_struct *sps, char **realname,
struct filebuf *fbp)
struct filebuf *fbp, struct link_map *loader, int whatcode)
{
struct r_search_path_elem **dirs = sps->dirs;
char *buf;
@ -1708,12 +1791,16 @@ open_path (const char *name, size_t namelen, int preloaded,
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
_dl_debug_printf (" trying file=%s\n", buf);
fd = open_verify (buf, fbp);
fd = open_verify (buf, fbp, loader, whatcode);
if (this_dir->status[cnt] == unknown)
{
if (fd != -1)
this_dir->status[cnt] = existing;
else
/* Do not update the directory information when loading
auditing code. We must try to disturb the program as
little as possible. */
else if (loader == NULL
|| GL(dl_ns)[loader->l_ns]._ns_loaded->l_audit == 0)
{
/* We failed to open machine dependent library. Let's
test whether there is any directory at all. */
@ -1731,7 +1818,7 @@ open_path (const char *name, size_t namelen, int preloaded,
}
/* Remember whether we found any existing directory. */
here_any |= this_dir->status[cnt] == existing;
here_any |= this_dir->status[cnt] != nonexisting;
if (fd != -1 && __builtin_expect (preloaded, 0)
&& INTUSE(__libc_enable_secure))
@ -1847,6 +1934,32 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
loader->l_name[0]
? loader->l_name : rtld_progname, loader->l_ns);
#ifdef SHARED
/* Give the auditing libraries a chance to change the name before we
try anything. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0)
&& (loader == NULL || loader->l_auditing == 0))
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->objsearch != NULL)
{
name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
LA_SER_ORIG);
if (name == NULL)
{
/* Do not try anything further. */
fd = -1;
goto no_file;
}
}
afct = afct->next;
}
}
#endif
if (strchr (name, '/') == NULL)
{
/* Search for NAME in several places. */
@ -1867,7 +1980,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
for (l = loader; fd == -1 && l; l = l->l_loader)
if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
&realname, &fb);
&realname, &fb, loader, LA_SER_RUNPATH);
/* If dynamically linked, try the DT_RPATH of the executable
itself. NB: we do this for lookups in any namespace. */
@ -1877,21 +1990,24 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
if (l && l->l_type != lt_loaded && l != loader
&& cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
&realname, &fb);
&realname, &fb, loader ?: l, LA_SER_RUNPATH);
}
}
/* Try the LD_LIBRARY_PATH environment variable. */
if (fd == -1 && env_path_list.dirs != (void *) -1)
fd = open_path (name, namelen, preloaded, &env_path_list,
&realname, &fb);
&realname, &fb,
loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
LA_SER_LIBPATH);
/* Look at the RUNPATH information for this binary. */
if (fd == -1 && loader != NULL
&& cache_rpath (loader, &loader->l_runpath_dirs,
DT_RUNPATH, "RUNPATH"))
fd = open_path (name, namelen, preloaded,
&loader->l_runpath_dirs, &realname, &fb);
&loader->l_runpath_dirs, &realname, &fb, loader,
LA_SER_RUNPATH);
if (fd == -1
&& (__builtin_expect (! preloaded, 1)
@ -1939,7 +2055,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
if (cached != NULL)
{
fd = open_verify (cached, &fb);
fd = open_verify (cached,
&fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
LA_SER_CONFIG);
if (__builtin_expect (fd != -1, 1))
{
realname = local_strdup (cached);
@ -1959,7 +2077,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|| __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,
&realname, &fb);
&realname, &fb, l, LA_SER_DEFAULT);
/* Add another newline when we are tracing the library loading. */
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
@ -1975,12 +2093,16 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
fd = -1;
else
{
fd = open_verify (realname, &fb);
fd = open_verify (realname, &fb,
loader ?: GL(dl_ns)[nsid]._ns_loaded, 0);
if (__builtin_expect (fd, 0) == -1)
free (realname);
}
}
#ifdef SHARED
no_file:
#endif
/* In case the LOADER information has only been provided to get to
the appropriate RUNPATH/RPATH information we do not need it
anymore. */

View File

@ -39,14 +39,24 @@ _dl_new_object (char *realname, const char *libname, int type,
size_t libname_len = strlen (libname) + 1;
struct link_map *new;
struct libname_list *newname;
#ifdef SHARED
/* We create the map for the executable before we know whether we have
auditing libraries and if yes, how many. Assume the worst. */
unsigned int naudit = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC)
? DL_NNS : 0);
size_t audit_space = naudit * sizeof (new->l_audit[0]);
#else
# define audit_space 0
#endif
new = (struct link_map *) calloc (sizeof (*new) + sizeof (*newname)
+ libname_len, 1);
new = (struct link_map *) calloc (sizeof (*new) + audit_space
+ sizeof (*newname) + libname_len, 1);
if (new == NULL)
return NULL;
new->l_real = new;
new->l_libname = newname = (struct libname_list *) (new + 1);
new->l_libname = newname = (struct libname_list *) ((char *) (new + 1)
+ audit_space);
newname->name = (char *) memcpy (newname + 1, libname, libname_len);
/* newname->next = NULL; We use calloc therefore not necessary. */
newname->dont_free = 1;
@ -59,6 +69,14 @@ _dl_new_object (char *realname, const char *libname, int type,
#endif
new->l_ns = nsid;
#ifdef SHARED
for (unsigned int cnt = 0; cnt < naudit; ++cnt)
{
new->l_audit[cnt].cookie = (uintptr_t) new;
/* new->l_audit[cnt].bindflags = 0; */
}
#endif
/* new->l_global = 0; We use calloc therefore not necessary. */
/* Use the 'l_scope_mem' array by default for the the 'l_scope'

View File

@ -49,11 +49,6 @@ weak_extern (BP_SYM (_dl_sysdep_start))
extern int __libc_multiple_libcs; /* Defined in init-first.c. */
extern int __libc_argc attribute_hidden;
extern char **__libc_argv attribute_hidden;
extern char **__environ;
/* Undefine the following for debugging. */
/* #define SCOPE_DEBUG 1 */
#ifdef SCOPE_DEBUG
@ -74,6 +69,10 @@ struct dl_open_args
struct link_map *map;
/* Namespace ID. */
Lmid_t nsid;
/* Original parameters to the program and the current environment. */
int argc;
char **argv;
char **env;
};
@ -115,7 +114,7 @@ add_to_global (struct link_map *new)
{
GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0;
nomem:
GLRO(dl_signal_error) (ENOMEM, new->l_libname->name, NULL,
_dl_signal_error (ENOMEM, new->l_libname->name, NULL,
N_("cannot extend global scope"));
return 1;
}
@ -171,13 +170,16 @@ dl_open_worker (void *a)
int lazy;
unsigned int i;
#ifdef USE_TLS
bool any_tls;
bool any_tls = false;
#endif
struct link_map *call_map = NULL;
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
/* Check whether _dl_open() has been called from a valid DSO. */
if (__check_caller (args->caller_dl_open, allow_libc|allow_libdl) != 0)
GLRO(dl_signal_error) (0, "dlopen", NULL, N_("invalid caller"));
if (__check_caller (args->caller_dl_open,
allow_libc|allow_libdl|allow_ldso) != 0)
_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, when we don't know the namespace ID we have to put
@ -226,9 +228,9 @@ dl_open_worker (void *a)
char *new_file;
/* DSTs must not appear in SUID/SGID programs. */
if (__libc_enable_secure)
if (INTUSE(__libc_enable_secure))
/* This is an error. */
GLRO(dl_signal_error) (0, "dlopen", NULL,
_dl_signal_error (0, "dlopen", NULL,
N_("DST not allowed in SUID/SGID programs"));
@ -244,7 +246,7 @@ dl_open_worker (void *a)
/* If the substitution failed don't try to load. */
if (*new_file == '\0')
GLRO(dl_signal_error) (0, "dlopen", NULL,
_dl_signal_error (0, "dlopen", NULL,
N_("empty dynamic string token substitution"));
/* Now we have a new file name. */
@ -256,7 +258,7 @@ dl_open_worker (void *a)
}
/* Load the named object. */
args->map = new = GLRO(dl_map_object) (call_map, file, 0, lt_loaded, 0,
args->map = new = _dl_map_object (call_map, file, 0, lt_loaded, 0,
mode | __RTLD_CALLMAP, args->nsid);
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
@ -279,7 +281,7 @@ dl_open_worker (void *a)
{
/* 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 [%lu]; opencount=%u\n\n",
_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
@ -296,23 +298,50 @@ dl_open_worker (void *a)
/* Increment just the reference counter of the object. */
++new->l_opencount;
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
return;
}
/* Load that object's dependencies. */
GLRO(dl_map_object_deps) (new, NULL, 0, 0,
_dl_map_object_deps (new, NULL, 0, 0,
mode & (__RTLD_DLOPEN | RTLD_DEEPBIND));
/* 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_real->l_versions == NULL)
(void) GLRO(dl_check_map_versions) (new->l_searchlist.r_list[i]->l_real,
(void) _dl_check_map_versions (new->l_searchlist.r_list[i]->l_real,
0, 0);
#ifdef SCOPE_DEBUG
show_scope (new);
#endif
#ifdef SHARED
/* Auditing checkpoint: we have added all objects. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct link_map *head = GL(dl_ns)[new->l_ns]._ns_loaded;
/* Do not call the functions for any auditing object. */
if (head->l_auditing == 0)
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
afct = afct->next;
}
}
}
#endif
/* Notify the debugger all new objects are now ready to go. */
struct r_debug *r = _dl_debug_initialize (0);
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
/* Only do lazy relocation if `LD_BIND_NOW' is not set. */
lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && GLRO(dl_lazy);
@ -336,12 +365,12 @@ dl_open_worker (void *a)
start the profiling. */
struct link_map *old_profile_map = GL(dl_profile_map);
GLRO(dl_relocate_object) (l, l->l_scope, 1, 1);
_dl_relocate_object (l, l->l_scope, 1, 1);
if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
{
/* We must prepare the profiling. */
GLRO(dl_start_profile) ();
_dl_start_profile ();
/* Prevent unloading the object. */
GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
@ -349,7 +378,7 @@ dl_open_worker (void *a)
}
else
#endif
GLRO(dl_relocate_object) (l, l->l_scope, lazy, 0);
_dl_relocate_object (l, l->l_scope, lazy, 0);
}
if (l == new)
@ -357,22 +386,6 @@ dl_open_worker (void *a)
l = l->l_prev;
}
#ifdef USE_TLS
/* Do static TLS initialization now if it has been delayed because
the TLS template might not be fully relocated at _dl_allocate_static_tls
time. */
for (l = new; l; l = l->l_next)
if (l->l_need_tls_init)
{
l->l_need_tls_init = 0;
GL(dl_init_static_tls) (l);
}
/* We normally don't bump the TLS generation counter. There must be
actually a need to do this. */
any_tls = false;
#endif
/* Increment the open count for all dependencies. If the file is
not loaded as a dependency here add the search list of the newly
loaded object to the scope. */
@ -412,7 +425,7 @@ dl_open_worker (void *a)
newp = (struct r_scope_elem **)
malloc (new_size * sizeof (struct r_scope_elem *));
if (newp == NULL)
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
_dl_signal_error (ENOMEM, "dlopen", NULL,
N_("cannot create scope list"));
imap->l_scope = memcpy (newp, imap->l_scope,
cnt * sizeof (imap->l_scope[0]));
@ -423,7 +436,7 @@ dl_open_worker (void *a)
realloc (imap->l_scope,
new_size * sizeof (struct r_scope_elem *));
if (newp == NULL)
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
_dl_signal_error (ENOMEM, "dlopen", NULL,
N_("cannot create scope list"));
imap->l_scope = newp;
}
@ -441,76 +454,35 @@ dl_open_worker (void *a)
> 0, 0))
{
/* Now that we know the object is loaded successfully add
modules containing TLS data to the dtv info table. We
modules containing TLS data to the slot info table. We
might have to increase its size. */
struct dtv_slotinfo_list *listp;
struct dtv_slotinfo_list *prevp;
size_t idx = new->l_searchlist.r_list[i]->l_tls_modid;
_dl_add_to_slotinfo (new->l_searchlist.r_list[i]);
assert (new->l_searchlist.r_list[i]->l_type == lt_loaded);
/* Find the place in the dtv slotinfo list. */
listp = GL(dl_tls_dtv_slotinfo_list);
prevp = NULL; /* Needed to shut up gcc. */
do
if (new->l_searchlist.r_list[i]->l_need_tls_init)
{
/* Does it fit in the array of this list element? */
if (idx < listp->len)
break;
idx -= listp->len;
prevp = listp;
listp = listp->next;
new->l_searchlist.r_list[i]->l_need_tls_init = 0;
# ifdef SHARED
/* Update the slot information data for at least the
generation of the DSO we are allocating data for. */
_dl_update_slotinfo (new->l_searchlist.r_list[i]->l_tls_modid);
# endif
GL(dl_init_static_tls) (new->l_searchlist.r_list[i]);
assert (new->l_searchlist.r_list[i]->l_need_tls_init == 0);
}
while (listp != NULL);
if (listp == NULL)
{
/* When we come here it means we have to add a new element
to the slotinfo list. And the new module must be in
the first slot. */
assert (idx == 0);
listp = prevp->next = (struct dtv_slotinfo_list *)
malloc (sizeof (struct dtv_slotinfo_list)
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
if (listp == NULL)
{
/* We ran out of memory. We will simply fail this
call but don't undo anything we did so far. The
application will crash or be terminated anyway very
soon. */
/* We have to do this since some entries in the dtv
slotinfo array might already point to this
generation. */
++GL(dl_tls_generation);
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL, N_("\
cannot create TLS data structures"));
}
listp->len = TLS_SLOTINFO_SURPLUS;
listp->next = NULL;
memset (listp->slotinfo, '\0',
TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
}
/* Add the information into the slotinfo data structure. */
listp->slotinfo[idx].map = new->l_searchlist.r_list[i];
listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
/* We have to bump the generation counter. */
any_tls = true;
}
/* Bump the generation number if necessary. */
if (any_tls)
if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
__libc_fatal (_("TLS generation counter wrapped! Please report this."));
if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0))
_dl_fatal_printf (N_("\
TLS generation counter wrapped! Please report this."));
#endif
/* Run the initializer functions of new objects. */
GLRO(dl_init) (new, __libc_argc, __libc_argv, __environ);
_dl_init (new, args->argc, args->argv, args->env);
/* Now we can make the new map available in the global scope. */
if (mode & RTLD_GLOBAL)
@ -532,14 +504,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 [%lu]; opencount=%u\n\n",
_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, Lmid_t nsid)
_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
int argc, char *argv[], char *env[])
{
struct dl_open_args args;
const char *objname;
@ -548,12 +520,13 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid)
if ((mode & RTLD_BINDING_MASK) == 0)
/* One of the flags must be set. */
GLRO(dl_signal_error) (EINVAL, file, NULL,
N_("invalid mode for dlopen()"));
_dl_signal_error (EINVAL, file, NULL, N_("invalid mode for dlopen()"));
/* Make sure we are alone. */
__rtld_lock_lock_recursive (GL(dl_load_lock));
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
if (nsid == LM_ID_NEWLM)
{
/* Find a new namespace. */
@ -566,15 +539,17 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid)
/* No more namespace available. */
__rtld_lock_unlock_recursive (GL(dl_load_lock));
GLRO(dl_signal_error) (EINVAL, file, NULL, N_("\
_dl_signal_error (EINVAL, file, NULL, N_("\
no more namespaces available for dlmopen()"));
}
}
/* Never allow loading a DSO in a namespace which is empty. Such
direct placements is only causing problems. */
direct placements is only causing problems. Also don't allow
loading into a namespace used for auditing. */
else if (nsid != LM_ID_BASE && nsid != __LM_ID_CALLER
&& GL(dl_ns)[nsid]._ns_nloaded == 0)
GLRO(dl_signal_error) (EINVAL, file, NULL,
&& (GL(dl_ns)[nsid]._ns_nloaded == 0
|| GL(dl_ns)[nsid]._ns_loaded->l_auditing))
_dl_signal_error (EINVAL, file, NULL,
N_("invalid target namespace in dlmopen()"));
args.file = file;
@ -583,11 +558,14 @@ no more namespaces available for dlmopen()"));
args.caller_dl_open = RETURN_ADDRESS (0);
args.map = NULL;
args.nsid = nsid;
errcode = GLRO(dl_catch_error) (&objname, &errstring, dl_open_worker, &args);
args.argc = argc;
args.argv = argv;
args.env = env;
errcode = _dl_catch_error (&objname, &errstring, dl_open_worker, &args);
#ifndef MAP_COPY
/* We must munmap() the cache file. */
GLRO(dl_unload_cache) ();
_dl_unload_cache ();
#endif
/* Release the lock. */
@ -603,20 +581,21 @@ no more namespaces available for dlmopen()"));
state if relocation failed, for example. */
if (args.map)
{
unsigned int i;
/* Increment open counters for all objects since this
sometimes has not happened yet. */
if (args.map->l_searchlist.r_list[0]->l_opencount == 0)
for (i = 0; i < args.map->l_searchlist.r_nlist; ++i)
for (unsigned int i = 0; i < args.map->l_searchlist.r_nlist; ++i)
++args.map->l_searchlist.r_list[i]->l_opencount;
#ifdef USE_TLS
/* Maybe some of the modules which were loaded uses TLS.
/* Maybe some of the modules which were loaded use TLS.
Since it will be removed in the following _dl_close call
we have to mark the dtv array as having gaps to fill
the holes. This is a pessimistic assumption which won't
hurt if not true. */
we have to mark the dtv array as having gaps to fill the
holes. This is a pessimistic assumption which won't hurt
if not true. There is no need to do this when we are
loading the auditing DSOs since TLS has not yet been set
up. */
if ((mode & __RTLD_AUDIT) == 0)
GL(dl_tls_dtv_gaps) = true;
#endif
@ -639,20 +618,23 @@ no more namespaces available for dlmopen()"));
memcpy (local_errstring, errstring, len_errstring);
}
if (errstring != _dl_out_of_memory)
if (errstring != INTUSE(_dl_out_of_memory))
free ((char *) errstring);
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
/* Reraise the error. */
GLRO(dl_signal_error) (errcode, objname, NULL, local_errstring);
_dl_signal_error (errcode, objname, NULL, local_errstring);
}
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
#ifndef SHARED
DL_STATIC_INIT (args.map);
#endif
return args.map;
}
libc_hidden_def (_dl_open)
#ifdef SCOPE_DEBUG

View File

@ -48,8 +48,6 @@ void
internal_function __attribute_noinline__
_dl_allocate_static_tls (struct link_map *map)
{
size_t offset;
/* If the alignment requirements are too high fail. */
if (map->l_tls_align > GL(dl_tls_static_align))
{
@ -71,7 +69,7 @@ cannot allocate memory in static TLS block"));
n = (freebytes - blsize) / map->l_tls_align;
offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
- map->l_tls_firstbyte_offset);
map->l_tls_offset = GL(dl_tls_static_used) = offset;
@ -79,7 +77,7 @@ cannot allocate memory in static TLS block"));
size_t used;
size_t check;
offset = roundup (GL(dl_tls_static_used), map->l_tls_align);
size_t offset = roundup (GL(dl_tls_static_used), map->l_tls_align);
used = offset + map->l_tls_blocksize;
check = used;
/* dl_tls_static_used includes the TCB at the beginning. */
@ -93,8 +91,20 @@ cannot allocate memory in static TLS block"));
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
if (map->l_relocated)
/* If the object is not yet relocated we cannot initialize the
static TLS region. Delay it. */
if (map->l_real->l_relocated)
{
#ifdef SHARED
if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation),
0))
/* Update the slot information data for at least the generation of
the DSO we are allocating data for. */
(void) _dl_update_slotinfo (map->l_tls_modid);
#endif
GL(dl_init_static_tls) (map);
}
else
map->l_need_tls_init = 1;
}
@ -114,7 +124,8 @@ _dl_nothread_init_static_tls (struct link_map *map)
# endif
/* Fill in the DTV slot so that a later LD/GD access will find it. */
THREAD_DTV ()[map->l_tls_modid].pointer = dest;
THREAD_DTV ()[map->l_tls_modid].pointer.val = dest;
THREAD_DTV ()[map->l_tls_modid].pointer.is_static = true;
/* Initialize the memory. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
@ -137,11 +148,17 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
/* Initialize it to make the compiler happy. */
const char *errstring = NULL;
#ifdef SHARED
/* If we are auditing, install the same handlers we need for profiling. */
consider_profiling |= GLRO(dl_audit) != NULL;
#endif
if (l->l_relocated)
return;
/* If DT_BIND_NOW is set relocate all references in this object. We
do not do this if we are profiling, of course. */
// XXX Correct for auditing?
if (!consider_profiling
&& __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
lazy = 0;
@ -225,29 +242,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
l->l_lookup_cache.ret = (*ref); \
l->l_lookup_cache.value = _lr; })) \
: l)
#define RESOLVE(ref, version, r_type) \
(ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \
? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0) \
&& elf_machine_type_class (r_type) == l->l_lookup_cache.type_class) \
? (bump_num_cache_relocations (), \
(*ref) = l->l_lookup_cache.ret, \
l->l_lookup_cache.value) \
: ({ lookup_t _lr; \
int _tc = elf_machine_type_class (r_type); \
l->l_lookup_cache.type_class = _tc; \
l->l_lookup_cache.sym = (*ref); \
const struct r_found_version *v = NULL; \
int flags = DL_LOOKUP_ADD_DEPENDENCY; \
if ((version) != NULL && (version)->hash != 0) \
{ \
v = (version); \
flags = 0; \
} \
_lr = _dl_lookup_symbol_x (strtab + (*ref)->st_name, l, (ref), \
scope, v, _tc, flags, NULL); \
l->l_lookup_cache.ret = (*ref); \
l->l_lookup_cache.value = _lr; })) \
: l->l_addr)
/* This macro is used as a callback from elf_machine_rel{a,} when a
static TLS reloc is about to be performed. Since (in dl-load.c) we
@ -276,20 +270,19 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
will be NULL. */
if (l->l_info[DT_PLTRELSZ] == NULL)
{
errstring = N_("%s: profiler found no PLTREL in object %s\n");
errstring = N_("%s: no PLTREL found in object %s\n");
fatal:
_dl_fatal_printf (errstring,
rtld_progname ?: "<program name unknown>",
l->l_name);
}
l->l_reloc_result =
(ElfW(Addr) *) calloc (sizeof (ElfW(Addr)),
l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]),
l->l_info[DT_PLTRELSZ]->d_un.d_val);
if (l->l_reloc_result == NULL)
{
errstring = N_("\
%s: profiler out of memory shadowing PLTREL of %s\n");
%s: out of memory to store relocation results for %s\n");
goto fatal;
}
}

View File

@ -1,5 +1,5 @@
/* On-demand PLT fixup for shared objects.
Copyright (C) 1995-2002, 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 1995-2002, 2003, 2004, 2005 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
@ -51,9 +51,9 @@
function. */
#ifndef ELF_MACHINE_NO_PLT
static ElfW(Addr)
__attribute ((used, noinline)) ARCH_FIXUP_ATTRIBUTE
fixup (
ElfW(Addr)
__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
_dl_fixup (
# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
# endif
@ -80,8 +80,6 @@ fixup (
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
{
const struct r_found_version *version = NULL;
// XXX Why exactly do we have the differentiation of the flags here?
int flags = DL_LOOKUP_ADD_DEPENDENCY;
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
{
@ -91,8 +89,6 @@ fixup (
version = &l->l_versions[ndx];
if (version->hash == 0)
version = NULL;
else
flags = 0;
}
result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
@ -109,9 +105,7 @@ fixup (
/* We already found the symbol. The module (and therefore its load
address) is also known. */
value = l->l_addr + sym->st_value;
#ifdef DL_LOOKUP_RETURNS_MAP
result = l;
#endif
}
/* And now perhaps the relocation addend. */
@ -127,45 +121,45 @@ fixup (
#if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
static ElfW(Addr)
__attribute ((used, noinline)) ARCH_FIXUP_ATTRIBUTE
profile_fixup (
ElfW(Addr)
__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
_dl_profile_fixup (
#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
#endif
struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr)
struct link_map *l, ElfW(Word) reloc_offset,
ElfW(Addr) retaddr, const void *regs, long int *framesizep)
{
void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = INTUSE(_dl_mcount);
ElfW(Addr) *resultp;
lookup_t result;
ElfW(Addr) value;
/* This is the address in the array where we store the result of previous
relocations. */
resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
struct reloc_result *reloc_result
= &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
ElfW(Addr) *resultp = &reloc_result->addr;
value = *resultp;
ElfW(Addr) value = *resultp;
if (value == 0)
{
/* This is the first time we have to relocate this object. */
const ElfW(Sym) *const symtab
= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
const char *strtab = (const char *) D_PTR (l, l_info[DT_STRTAB]);
const PLTREL *const reloc
= (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
const ElfW(Sym) *refsym = &symtab[ELFW(R_SYM) (reloc->r_info)];
const ElfW(Sym) *defsym = refsym;
lookup_t result;
/* Sanity check that we're really looking at a PLT relocation. */
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
/* Look up the target symbol. If the symbol is marked STV_PROTECTED
don't look in the global scope. */
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
if (__builtin_expect (ELFW(ST_VISIBILITY) (refsym->st_other), 0) == 0)
{
const struct r_found_version *version = NULL;
// XXX Why exactly do we have the differentiation of the flags here?
int flags = DL_LOOKUP_ADD_DEPENDENCY;
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
{
@ -175,11 +169,9 @@ profile_fixup (
version = &l->l_versions[ndx];
if (version->hash == 0)
version = NULL;
else
flags = 0;
}
result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
result = _dl_lookup_symbol_x (strtab + refsym->st_name, l, &defsym,
l->l_scope, version,
ELF_RTYPE_CLASS_PLT,
DL_LOOKUP_ADD_DEPENDENCY, NULL);
@ -187,25 +179,185 @@ profile_fixup (
/* Currently result contains the base load address (or link map)
of the object that defines sym. Now add in the symbol
offset. */
value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0);
value = (defsym != NULL
? LOOKUP_VALUE_ADDRESS (result) + defsym->st_value : 0);
}
else
{
/* We already found the symbol. The module (and therefore its load
address) is also known. */
value = l->l_addr + sym->st_value;
#ifdef DL_LOOKUP_RETURNS_MAP
value = l->l_addr + refsym->st_value;
result = l;
#endif
}
/* And now perhaps the relocation addend. */
value = elf_machine_plt_value (l, reloc, value);
#ifdef SHARED
/* Auditing checkpoint: we have a new binding. Provide the
auditing libraries the possibility to change the value and
tell us whether further auditing is wanted. */
if (defsym != NULL && GLRO(dl_naudit) > 0)
{
reloc_result->bound = result;
/* Compute index of the symbol entry in the symbol table of
the DSO with the definition. */
reloc_result->boundndx = (defsym
- (ElfW(Sym) *) D_PTR (result,
l_info[DT_SYMTAB]));
/* Determine whether any of the two participating DSOs is
interested in auditing. */
if ((l->l_audit_any_plt | result->l_audit_any_plt) != 0)
{
unsigned int altvalue = 0;
struct audit_ifaces *afct = GLRO(dl_audit);
/* Synthesize a symbol record where the st_value field is
the result. */
ElfW(Sym) sym = *defsym;
sym.st_value = value;
/* Keep track whether there is any interest in tracing
the call in the lower two bits. */
assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
const char *strtab2 = (const void *) D_PTR (result,
l_info[DT_STRTAB]);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
/* XXX Check whether both DSOs must request action or
only one */
if ((l->l_audit[cnt].bindflags & LA_FLG_BINDFROM) != 0
&& (result->l_audit[cnt].bindflags & LA_FLG_BINDTO) != 0)
{
unsigned int flags = altvalue;
if (afct->symbind != NULL)
{
uintptr_t new_value
= afct->symbind (&sym, reloc_result->boundndx,
&l->l_audit[cnt].cookie,
&result->l_audit[cnt].cookie,
&flags,
strtab2 + defsym->st_name);
if (new_value != (uintptr_t) sym.st_value)
{
altvalue = LA_SYMB_ALTVALUE;
sym.st_value = new_value;
}
}
/* Remember the results for every audit library and
store a summary in the first two bits. */
reloc_result->enterexit
&= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
reloc_result->enterexit
|= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
<< ((cnt + 1) * 2));
}
else
/* If the bind flags say this auditor is not interested,
set the bits manually. */
reloc_result->enterexit
|= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
<< ((cnt + 1) * 2));
afct = afct->next;
}
reloc_result->flags = altvalue;
value = sym.st_value;
}
else
/* Set all bits since this symbol binding is not interesting. */
reloc_result->enterexit = (1u << DL_NNS) - 1;
}
#endif
/* Store the result for later runs. */
if (__builtin_expect (! GLRO(dl_bind_not), 1))
*resultp = value;
}
/* By default we do not call the pltexit function. */
long int framesize = -1;
#ifdef SHARED
/* Auditing checkpoint: report the PLT entering and allow the
auditors to change the value. */
if (value != 0 && GLRO(dl_naudit) > 0
/* Don't do anything if no auditor wants to intercept this call. */
&& (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
{
ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
l_info[DT_SYMTAB])
+ reloc_result->boundndx);
/* Set up the sym parameter. */
ElfW(Sym) sym = *defsym;
sym.st_value = value;
/* Get the symbol name. */
const char *strtab = (const void *) D_PTR (reloc_result->bound,
l_info[DT_STRTAB]);
const char *symname = strtab + sym.st_name;
/* Keep track of overwritten addresses. */
unsigned int altvalue = reloc_result->flags;
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->ARCH_LA_PLTENTER != NULL
&& (reloc_result->enterexit
& (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
{
unsigned int flags = altvalue;
long int new_framesize = -1;
uintptr_t new_value
= afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
&l->l_audit[cnt].cookie,
&reloc_result->bound->l_audit[cnt].cookie,
regs, &flags, symname,
&new_framesize);
if (new_value != (uintptr_t) sym.st_value)
{
altvalue = LA_SYMB_ALTVALUE;
sym.st_value = new_value;
}
/* Remember the results for every audit library and
store a summary in the first two bits. */
reloc_result->enterexit
|= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
<< (2 * (cnt + 1)));
if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT
<< (2 * (cnt + 1))))
== 0 && new_framesize != -1 && framesize != -2)
{
/* If this is the first call providing information,
use it. */
if (framesize == -1)
framesize = new_framesize;
/* If two pltenter calls provide conflicting information,
use the larger value. */
else if (new_framesize != framesize)
framesize = MAX (new_framesize, framesize);
}
}
afct = afct->next;
}
value = sym.st_value;
}
#endif
/* Store the frame size information. */
*framesizep = framesize;
(*mcount_fct) (retaddr, value);
return value;
@ -214,9 +366,45 @@ profile_fixup (
#endif /* PROF && ELF_MACHINE_NO_PLT */
/* This macro is defined in dl-machine.h to define the entry point called
by the PLT. The `fixup' function above does the real work, but a little
more twiddling is needed to get the stack right and jump to the address
finally resolved. */
#include <stdio.h>
void
ARCH_FIXUP_ATTRIBUTE
_dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_offset,
const void *inregs, void *outregs)
{
#ifdef SHARED
/* This is the address in the array where we store the result of previous
relocations. */
// XXX Maybe the bound information must be stored on the stack since
// XXX with bind_not a new value could have been stored in the meantime.
struct reloc_result *reloc_result
= &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
l_info[DT_SYMTAB])
+ reloc_result->boundndx);
ELF_MACHINE_RUNTIME_TRAMPOLINE
/* Set up the sym parameter. */
ElfW(Sym) sym = *defsym;
/* Get the symbol name. */
const char *strtab = (const void *) D_PTR (reloc_result->bound,
l_info[DT_STRTAB]);
const char *symname = strtab + sym.st_name;
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->ARCH_LA_PLTEXIT != NULL
&& (reloc_result->enterexit
& (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
{
afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
&l->l_audit[cnt].cookie,
&reloc_result->bound->l_audit[cnt].cookie,
inregs, outregs, symname);
}
afct = afct->next;
}
#endif
}

View File

@ -116,14 +116,69 @@ RTLD_NEXT used in code not dynamically loaded"));
if (ref != NULL)
{
void *value;
#if defined USE_TLS && defined SHARED
if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
/* The found symbol is a thread-local storage variable.
Return the address for to the current thread. */
return _dl_tls_symaddr (result, ref);
value = _dl_tls_symaddr (result, ref);
else
#endif
value = DL_SYMBOL_ADDRESS (result, ref);
#ifdef SHARED
/* Auditing checkpoint: we have a new binding. Provide the
auditing libraries the possibility to change the value and
tell us whether further auditing is wanted. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
const char *strtab = (const char *) D_PTR (result,
l_info[DT_STRTAB]);
/* Compute index of the symbol entry in the symbol table of
the DSO with the definition. */
unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
l_info[DT_SYMTAB]));
if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
{
unsigned int altvalue = 0;
struct audit_ifaces *afct = GLRO(dl_audit);
/* Synthesize a symbol record where the st_value field is
the result. */
ElfW(Sym) sym = *ref;
sym.st_value = (ElfW(Addr)) value;
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->symbind != NULL
&& ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
!= 0
|| ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
!= 0)))
{
unsigned int flags = altvalue | LA_SYMB_DLSYM;
uintptr_t new_value
= afct->symbind (&sym, ndx,
&match->l_audit[cnt].cookie,
&result->l_audit[cnt].cookie,
&flags, strtab + ref->st_name);
if (new_value != (uintptr_t) sym.st_value)
{
altvalue = LA_SYMB_ALTVALUE;
sym.st_value = new_value;
}
}
afct = afct->next;
}
value = (void *) sym.st_value;
}
}
#endif
return DL_SYMBOL_ADDRESS (result, ref);
return value;
}
return NULL;

View File

@ -20,7 +20,7 @@
#include <elf.h>
#include <assert.h>
#ifdef RESOLVE
#ifdef RESOLVE_MAP
/* We pass reloc_addr as a pointer to void, as opposed to a pointer to
ElfW(Addr), because not all architectures can assume that the
relocated address is properly aligned, whereas the compiler is
@ -64,7 +64,7 @@ elf_machine_lazy_rel (struct link_map *map,
/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
#ifndef RESOLVE
#ifndef RESOLVE_MAP
static
#else
auto
@ -199,7 +199,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
#endif
}
#ifdef RESOLVE
#ifdef RESOLVE_MAP
# ifdef RTLD_BOOTSTRAP
# define ELF_DURING_STARTUP (1)

View File

@ -1,6 +1,6 @@
/* Data structure for communication from the run-time dynamic linker for
loaded ELF shared objects.
Copyright (C) 1995-1999, 2000, 2001, 2004 Free Software Foundation, Inc.
Copyright (C) 1995-2001, 2004, 2005 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
@ -33,6 +33,7 @@
#define _ElfW_1(e,w,t) e##w##t
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
#include <bits/link.h>
/* Rendezvous structure used by the run-time dynamic linker to communicate
details of shared object loading to the debugger. If the executable's
@ -94,6 +95,47 @@ struct link_map
#ifdef __USE_GNU
/* Version numbers for la_version handshake interface. */
#define LAV_CURRENT 1
/* Activity types signaled through la_activity. */
enum
{
LA_ACT_CONSISTENT, /* Link map consistent again. */
LA_ACT_ADD, /* New object will be added. */
LA_ACT_DELETE /* Objects will be removed. */
};
/* Values representing origin of name for dynamic loading. */
enum
{
LA_SER_ORIG = 0x01, /* Original name. */
LA_SER_LIBPATH = 0x02, /* Directory from LD_LIBRARY_PATH. */
LA_SER_RUNPATH = 0x04, /* Directory from RPATH/RUNPATH. */
LA_SER_CONFIG = 0x08, /* Found through ldconfig. */
LA_SER_DEFAULT = 0x40, /* Default directory. */
LA_SER_SECURE = 0x80 /* Unused. */
};
/* Values for la_objopen return value. */
enum
{
LA_FLG_BINDTO = 0x01, /* Audit symbols bound to this object. */
LA_FLG_BINDFROM = 0x02 /* Audit symbols bound from this object. */
};
/* Values for la_symbind flags parameter. */
enum
{
LA_SYMB_NOPLTENTER = 0x01, /* la_pltenter will not be called. */
LA_SYMB_NOPLTEXIT = 0x02, /* la_pltexit will not be called. */
LA_SYMB_STRUCTCALL = 0x04, /* Return value is a structure. */
LA_SYMB_DLSYM = 0x08, /* Binding due to dlsym call. */
LA_SYMB_ALTVALUE = 0x10 /* Value has been changed by a previous
la_symbind call. */
};
struct dl_phdr_info
{
ElfW(Addr) dlpi_addr;
@ -114,9 +156,28 @@ struct dl_phdr_info
__BEGIN_DECLS
extern int dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
size_t size, void *data),
void *data);
extern int dl_iterate_phdr (int (*__callback) (struct dl_phdr_info *,
size_t, void *),
void *__data);
/* Prototypes for the ld.so auditing interfaces. These are not
defined anywhere in ld.so but instead have to be provided by the
auditing DSO. */
extern unsigned int la_version (unsigned int __version);
extern void la_activity (uintptr_t *__cookie, unsigned int __flag);
extern char *la_objsearch (const char *__name, uintptr_t *__cookie,
unsigned int __flag);
extern unsigned int la_objopen (struct link_map *__map, Lmid_t __lmid,
uintptr_t *__cookie);
extern void la_preinit (uintptr_t *__cookie);
extern uintptr_t la_symbind32 (Elf32_Sym *__sym, unsigned int __ndx,
uintptr_t *__refcook, uintptr_t *__defcook,
unsigned int *__flags, const char *__symname);
extern uintptr_t la_symbind64 (Elf64_Sym *__sym, unsigned int __ndx,
uintptr_t *__refcook, uintptr_t *__defcook,
unsigned int *__flags, const char *__symname);
extern unsigned int la_objclose (uintptr_t *__cookie);
__END_DECLS

View File

@ -79,6 +79,13 @@ INTDEF(_dl_argv)
/* Nonzero if we were run directly. */
unsigned int _dl_skip_args attribute_relro attribute_hidden;
/* List of auditing DSOs. */
static struct audit_list
{
const char *name;
struct audit_list *next;
} *audit_list;
#ifndef HAVE_INLINED_SYSCALLS
/* Set nonzero during loading and initialization of executable and
libraries, cleared before the executable's entry point runs. This
@ -126,25 +133,14 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
._dl_fpu_control = _FPU_DEFAULT,
/* Function pointers. */
._dl_get_origin = _dl_get_origin,
._dl_dst_count = _dl_dst_count,
._dl_dst_substitute = _dl_dst_substitute,
._dl_map_object = _dl_map_object,
._dl_map_object_deps = _dl_map_object_deps,
._dl_relocate_object = _dl_relocate_object,
._dl_check_map_versions = _dl_check_map_versions,
._dl_init = _dl_init,
._dl_debug_state = _dl_debug_state,
#ifndef MAP_COPY
._dl_unload_cache = _dl_unload_cache,
#endif
._dl_debug_printf = _dl_debug_printf,
._dl_catch_error = _dl_catch_error,
._dl_signal_error = _dl_signal_error,
._dl_start_profile = _dl_start_profile,
._dl_mcount = _dl_mcount_internal,
._dl_lookup_symbol_x = _dl_lookup_symbol_x,
._dl_check_caller = _dl_check_caller
._dl_check_caller = _dl_check_caller,
._dl_open = _dl_open,
._dl_close = _dl_close
};
/* If we would use strong_alias here the compiler would see a
non-hidden definition. This would undo the effect of the previous
@ -514,6 +510,7 @@ _dl_start (void *arg)
data access using the global offset table. */
ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0);
bootstrap_map.l_relocated = 1;
}
/* Please note that we don't allow profiling of this object and
@ -566,6 +563,19 @@ struct map_args
struct link_map *map;
};
struct dlmopen_args
{
const char *fname;
struct link_map *map;
};
struct lookup_args
{
const char *name;
struct link_map *map;
void *result;
};
/* Arguments to version_check_doit. */
struct version_check_args
{
@ -590,6 +600,28 @@ map_doit (void *a)
LM_ID_BASE);
}
static void
dlmopen_doit (void *a)
{
struct dlmopen_args *args = (struct dlmopen_args *) a;
args->map = _dl_open (args->fname, RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT,
dl_main, LM_ID_NEWLM, _dl_argc, INTUSE(_dl_argv),
__environ);
}
static void
lookup_doit (void *a)
{
struct lookup_args *args = (struct lookup_args *) a;
const ElfW(Sym) *ref = NULL;
args->result = NULL;
lookup_t l = _dl_lookup_symbol_x (args->name, args->map, &ref,
args->map->l_local_scope, NULL, 0,
DL_LOOKUP_RETURN_NEWEST, NULL);
if (ref != NULL)
args->result = DL_SYMBOL_ADDRESS (l, ref);
}
static void
version_check_doit (void *a)
{
@ -648,6 +680,80 @@ match_version (const char *string, struct link_map *map)
return 0;
}
#ifdef USE_TLS
static bool tls_init_tp_called;
static void *
init_tls (void)
{
/* Number of elements in the static TLS block. */
GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
/* Do not do this twice. The audit interface might have required
the DTV interfaces to be set up early. */
if (GL(dl_initial_dtv) != NULL)
return NULL;
/* Allocate the array which contains the information about the
dtv slots. We allocate a few entries more than needed to
avoid the need for reallocation. */
size_t nelem = GL(dl_tls_max_dtv_idx) + 1 + TLS_SLOTINFO_SURPLUS;
/* Allocate. */
GL(dl_tls_dtv_slotinfo_list) = (struct dtv_slotinfo_list *)
calloc (sizeof (struct dtv_slotinfo_list)
+ nelem * sizeof (struct dtv_slotinfo), 1);
/* No need to check the return value. If memory allocation failed
the program would have been terminated. */
struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
GL(dl_tls_dtv_slotinfo_list)->len = nelem;
GL(dl_tls_dtv_slotinfo_list)->next = NULL;
/* Fill in the information from the loaded modules. No namespace
but the base one can be filled at this time. */
assert (GL(dl_ns)[LM_ID_BASE + 1]._ns_loaded == NULL);
int i = 0;
for (struct link_map *l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; 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. */
slotinfo[i].map = l;
/* slotinfo[i].gen = 0; */
++i;
}
assert (i == GL(dl_tls_max_dtv_idx));
/* Compute the TLS offsets for the various blocks. */
_dl_determine_tlsoffset ();
/* Construct the static TLS block and the dtv for the initial
thread. For some platforms this will include allocating memory
for the thread descriptor. The memory for the TLS block will
never be freed. It should be allocated accordingly. The dtv
array can be changed if dynamic loading requires it. */
void *tcbp = _dl_allocate_tls_storage ();
if (tcbp == NULL)
_dl_fatal_printf ("\
cannot allocate TLS data structures for initial thread");
/* Store for detection of the special case by __tls_get_addr
so it knows not to pass this dtv to the normal realloc. */
GL(dl_initial_dtv) = GET_DTV (tcbp);
/* And finally install it for the main thread. If ld.so itself uses
TLS we know the thread pointer was initialized earlier. */
const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
if (__builtin_expect (lossage != NULL, 0))
_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
tls_init_tp_called = true;
return tcbp;
}
#endif
#ifdef _LIBC_REENTRANT
/* _dl_error_catch_tsd points to this for the single-threaded case.
It's reset by the thread library for multithreaded programs. */
@ -702,7 +808,7 @@ dl_main (const ElfW(Phdr) *phdr,
hp_timing_t diff;
#endif
#ifdef USE_TLS
void *tcbp;
void *tcbp = NULL;
#endif
#ifdef _LIBC_REENTRANT
@ -826,6 +932,7 @@ of this helper program; chances are you did not intend to run this program.\n\
objects. */
_dl_init_paths (library_path);
/* The initialization of _dl_stack_flags done below assumes the
executable's PT_GNU_STACK may have been honored by the kernel, and
so a PT_GNU_STACK with PF_X set means the stack started out with
@ -887,10 +994,10 @@ of this helper program; chances are you did not intend to run this program.\n\
{
/* Create a link_map for the executable itself.
This will be what dlopen on "" returns. */
_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");
main_map
= _dl_new_object ((char *) "", "", lt_executable, NULL, 0, LM_ID_BASE);
assert (main_map != NULL);
assert (main_map == GL(dl_ns)[LM_ID_BASE]._ns_loaded);
main_map->l_phdr = phdr;
main_map->l_phnum = phnum;
main_map->l_entry = *user_entry;
@ -991,8 +1098,9 @@ of this helper program; chances are you did not intend to run this program.\n\
main_map->l_text_end = allocend;
}
break;
#ifdef USE_TLS
case PT_TLS:
#ifdef USE_TLS
if (ph->p_memsz > 0)
{
/* Note that in the case the dynamic linker we duplicate work
@ -1012,8 +1120,12 @@ of this helper program; chances are you did not intend to run this program.\n\
/* This image gets the ID one. */
GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
}
break;
#else
_dl_fatal_printf ("\
ld.so does not support TLS, but program uses it!\n");
#endif
break;
case PT_GNU_STACK:
GL(dl_stack_flags) = ph->p_flags;
break;
@ -1045,6 +1157,26 @@ of this helper program; chances are you did not intend to run this program.\n\
else
assert (GL(dl_rtld_map).l_libname); /* How else did we get here? */
/* If the current libname is different from the SONAME, add the
latter as well. */
if (GL(dl_rtld_map).l_info[DT_SONAME] != NULL
&& strcmp (GL(dl_rtld_map).l_libname->name,
(const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
+ GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val) != 0)
{
static struct libname_list newname;
newname.name = ((char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
+ GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_ptr);
newname.next = NULL;
newname.dont_free = 1;
assert (GL(dl_rtld_map).l_libname->next == NULL);
GL(dl_rtld_map).l_libname->next = &newname;
}
/* The ld.so must be relocated since otherwise loading audit modules
will fail since they reuse the very same ld.so. */
assert (GL(dl_rtld_map).l_relocated);
if (! rtld_is_main)
{
/* Extract the contents of the dynamic section for easy access. */
@ -1074,6 +1206,10 @@ of this helper program; chances are you did not intend to run this program.\n\
objects. */
_dl_init_paths (library_path);
/* Initialize _r_debug. */
struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr);
r->r_state = RT_CONSISTENT;
/* Put the link_map for ourselves on the chain so it can be found by
name. Note that at this point the global chain of link maps contains
exactly one element, which is pointed to by dl_loaded. */
@ -1101,6 +1237,7 @@ of this helper program; chances are you did not intend to run this program.\n\
GL(dl_rtld_map).l_phdr = rtld_phdr;
GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
/* PT_GNU_RELRO is usually the last phdr. */
size_t cnt = rtld_ehdr->e_phnum;
while (cnt-- > 0)
@ -1111,6 +1248,204 @@ of this helper program; chances are you did not intend to run this program.\n\
break;
}
#ifdef USE_TLS
/* Add the dynamic linker to the TLS list if it also uses TLS. */
if (GL(dl_rtld_map).l_tls_blocksize != 0)
/* Assign a module ID. Do this before loading any audit modules. */
GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
#endif
/* If we have auditing DSOs to load, do it now. */
if (__builtin_expect (audit_list != NULL, 0))
{
/* Iterate over all entries in the list. The order is important. */
struct audit_ifaces *last_audit = NULL;
struct audit_list *al = audit_list->next;
do
{
#ifdef USE_TLS
int tls_idx = GL(dl_tls_max_dtv_idx);
/* Now it is time to determine the layout of the static TLS
block and allocate it for the initial thread. Note that we
always allocate the static block, we never defer it even if
no DF_STATIC_TLS bit is set. The reason is that we know
glibc will use the static model. */
# ifndef TLS_INIT_TP_EXPENSIVE
# define TLS_INIT_TP_EXPENSIVE 0
# endif
/* Since we start using the auditing DSOs right away we need to
initialize the data structures now. */
if (!TLS_INIT_TP_EXPENSIVE)
tcbp = init_tls ();
#endif
struct dlmopen_args dlmargs;
dlmargs.fname = al->name;
dlmargs.map = NULL;
const char *objname;
const char *err_str = NULL;
(void) _dl_catch_error (&objname, &err_str, dlmopen_doit, &dlmargs);
if (__builtin_expect (err_str != NULL, 0))
{
not_loaded:
_dl_error_printf ("\
ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
al->name, err_str);
free ((char *) err_str);
}
else
{
struct lookup_args largs;
largs.name = "la_version";
largs.map = dlmargs.map;
/* Check whether the interface version matches. */
(void) _dl_catch_error (&objname, &err_str, lookup_doit, &largs);
unsigned int (*laversion) (unsigned int);
unsigned int lav;
if (err_str == NULL
&& (laversion = largs.result) != NULL
&& (lav = laversion (LAV_CURRENT)) > 0
&& lav <= LAV_CURRENT)
{
/* Allocate structure for the callback function pointers.
This call can never fail. */
union
{
struct audit_ifaces ifaces;
#define naudit_ifaces 8
void (*fptr[naudit_ifaces]) (void);
} *newp = malloc (sizeof (*newp));
/* Names of the auditing interfaces. All in one
long string. */
static const char audit_iface_names[] =
"la_activity\0"
"la_objsearch\0"
"la_objopen\0"
"la_preinit\0"
#if __ELF_NATIVE_CLASS == 32
"la_symbind32\0"
#elif __ELF_NATIVE_CLASS == 64
"la_symbind64\0"
#else
# error "__ELF_NATIVE_CLASS must be defined"
#endif
#define STRING(s) __STRING (s)
"la_" STRING (ARCH_LA_PLTENTER) "\0"
"la_" STRING (ARCH_LA_PLTEXIT) "\0"
"la_objclose\0";
unsigned int cnt = 0;
const char *cp = audit_iface_names;
do
{
largs.name = cp;
(void) _dl_catch_error (&objname, &err_str, lookup_doit,
&largs);
/* Store the pointer. */
if (err_str == NULL && largs.result != NULL)
{
newp->fptr[cnt] = largs.result;
/* The dynamic linker link map is statically
allocated, initialize the data now. */
GL(dl_rtld_map).l_audit[cnt].cookie
= (intptr_t) &GL(dl_rtld_map);
}
else
newp->fptr[cnt] = NULL;
++cnt;
cp = (char *) rawmemchr (cp, '\0') + 1;
}
while (*cp != '\0');
assert (cnt == naudit_ifaces);
/* Now append the new auditing interface to the list. */
newp->ifaces.next = NULL;
if (last_audit == NULL)
last_audit = GLRO(dl_audit) = &newp->ifaces;
else
last_audit = last_audit->next = &newp->ifaces;
++GLRO(dl_naudit);
/* Mark the DSO as being used for auditing. */
dlmargs.map->l_auditing = 1;
}
else
{
/* We cannot use the DSO, it does not have the
appropriate interfaces or it expects something
more recent. */
#ifndef NDEBUG
Lmid_t ns = dlmargs.map->l_ns;
#endif
_dl_close (dlmargs.map);
/* Make sure the namespace has been cleared entirely. */
assert (GL(dl_ns)[ns]._ns_loaded == NULL);
assert (GL(dl_ns)[ns]._ns_nloaded == 0);
#ifdef USE_TLS
GL(dl_tls_max_dtv_idx) = tls_idx;
#endif
goto not_loaded;
}
}
al = al->next;
}
while (al != audit_list->next);
/* If we have any auditing modules, announce that we already
have two objects loaded. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct link_map *ls[2] = { main_map, &GL(dl_rtld_map) };
for (unsigned int outer = 0; outer < 2; ++outer)
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->objopen != NULL)
{
ls[outer]->l_audit[cnt].bindflags
= afct->objopen (ls[outer], LM_ID_BASE,
&ls[outer]->l_audit[cnt].cookie);
ls[outer]->l_audit_any_plt
|= ls[outer]->l_audit[cnt].bindflags != 0;
}
afct = afct->next;
}
}
}
}
/* We start adding objects. */
r->r_state = RT_ADD;
_dl_debug_state ();
/* Auditing checkpoint: we are ready to signal that the initial map
is being constructed. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
afct->activity (&main_map->l_audit[cnt].cookie, LA_ACT_ADD);
afct = afct->next;
}
}
/* We have two ways to specify objects to preload: via environment
variable and via the file /etc/ld.so.preload. The latter can also
be used when security is enabled. */
@ -1310,6 +1645,9 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
&& ph->p_vaddr + ph->p_memsz >= l->l_text_end)
l->l_text_end = ph->p_vaddr + ph->p_memsz;
}
else
/* There must be no TLS segment. */
assert (ph->p_type != PT_TLS);
}
l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso);
l->l_addr = l->l_map_start - l->l_addr;
@ -1425,20 +1763,6 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
}
#ifdef USE_TLS
/* Now it is time to determine the layout of the static TLS block
and allocate it for the initial thread. Note that we always
allocate the static block, we never defer it even if no
DF_STATIC_TLS bit is set. The reason is that we know glibc will
use the static model. First add the dynamic linker to the list
if it also uses TLS. */
if (GL(dl_rtld_map).l_tls_blocksize != 0)
/* Assign a module ID. */
GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
# ifndef TLS_INIT_TP_EXPENSIVE
# define TLS_INIT_TP_EXPENSIVE 0
# endif
/* We do not initialize any of the TLS functionality unless any of the
initial modules uses TLS. This makes dynamic loading of modules with
TLS impossible, but to support it requires either eagerly doing setup
@ -1446,57 +1770,9 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever
used. Trying to do it lazily is too hairy to try when there could be
multiple threads (from a non-TLS-using libpthread). */
if (!TLS_INIT_TP_EXPENSIVE || GL(dl_tls_max_dtv_idx) > 0)
{
struct link_map *l;
size_t nelem;
struct dtv_slotinfo *slotinfo;
/* Number of elements in the static TLS block. */
GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
/* Allocate the array which contains the information about the
dtv slots. We allocate a few entries more than needed to
avoid the need for reallocation. */
nelem = GL(dl_tls_max_dtv_idx) + 1 + TLS_SLOTINFO_SURPLUS;
/* Allocate. */
GL(dl_tls_dtv_slotinfo_list) = (struct dtv_slotinfo_list *)
malloc (sizeof (struct dtv_slotinfo_list)
+ nelem * sizeof (struct dtv_slotinfo));
/* No need to check the return value. If memory allocation failed
the program would have been terminated. */
slotinfo = memset (GL(dl_tls_dtv_slotinfo_list)->slotinfo, '\0',
nelem * sizeof (struct dtv_slotinfo));
GL(dl_tls_dtv_slotinfo_list)->len = nelem;
GL(dl_tls_dtv_slotinfo_list)->next = NULL;
/* Fill in the information from the loaded modules. */
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. */
slotinfo[++i].map = l;
assert (i == GL(dl_tls_max_dtv_idx));
/* Compute the TLS offsets for the various blocks. */
_dl_determine_tlsoffset ();
/* Construct the static TLS block and the dtv for the initial
thread. For some platforms this will include allocating memory
for the thread descriptor. The memory for the TLS block will
never be freed. It should be allocated accordingly. The dtv
array can be changed if dynamic loading requires it. */
tcbp = _dl_allocate_tls_storage ();
if (tcbp == NULL)
_dl_fatal_printf ("\
cannot allocate TLS data structures for initial thread");
/* Store for detection of the special case by __tls_get_addr
so it knows not to pass this dtv to the normal realloc. */
GL(dl_initial_dtv) = GET_DTV (tcbp);
}
bool was_tls_init_tp_called = tls_init_tp_called;
if (tcbp == NULL && (!TLS_INIT_TP_EXPENSIVE || GL(dl_tls_max_dtv_idx) > 0))
tcbp = init_tls ();
#endif
if (__builtin_expect (mode, normal) != normal)
@ -1777,8 +2053,6 @@ 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 = main_map;
@ -1813,8 +2087,6 @@ cannot allocate TLS data structures for initial thread");
if (prelinked)
{
struct link_map *l;
if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
{
ElfW(Rela) *conflict, *conflictend;
@ -1837,11 +2109,15 @@ cannot allocate TLS data structures for initial thread");
/* Mark all the objects so we know they have been already relocated. */
for (l = main_map; l != NULL; l = l->l_next)
for (struct link_map *l = main_map; l != NULL; l = l->l_next)
{
l->l_relocated = 1;
if (l->l_relro_size)
_dl_protect_relro (l);
/* Add object to slot information data if necessasy. */
if (l->l_tls_blocksize != 0 && tls_init_tp_called)
_dl_add_to_slotinfo (l);
}
_dl_sysdep_start_cleanup ();
@ -1857,7 +2133,6 @@ cannot allocate TLS data structures for initial thread");
the dynamic linker out of order because it has no copy relocs (we
know that because it is self-contained). */
struct link_map *l;
int consider_profiling = GLRO(dl_profile) != NULL;
#ifndef HP_TIMING_NONAVAIL
hp_timing_t start;
@ -1868,7 +2143,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 = main_map;
struct link_map *l = main_map;
while (l->l_next)
l = l->l_next;
@ -1890,6 +2165,10 @@ cannot allocate TLS data structures for initial thread");
_dl_relocate_object (l, l->l_scope, GLRO(dl_lazy),
consider_profiling);
/* Add object to slot information data if necessasy. */
if (l->l_tls_blocksize != 0 && tls_init_tp_called)
_dl_add_to_slotinfo (l);
l = l->l_prev;
}
while (l);
@ -1917,6 +2196,8 @@ 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);
/* Mark the link map as not yet relocated again. */
GL(dl_rtld_map).l_relocated = 0;
_dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
HP_TIMING_NOW (stop);
HP_TIMING_DIFF (add, start, stop);
@ -1931,6 +2212,9 @@ cannot allocate TLS data structures for initial thread");
#ifdef USE_TLS
if (GL(dl_tls_max_dtv_idx) > 0 || USE___THREAD || !TLS_INIT_TP_EXPENSIVE)
{
if (!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
++GL(dl_tls_generation);
/* Now that we have completed relocation, the initializer data
for the TLS blocks has its final values and we can copy them
into the main thread's TLS area, which we allocated above. */
@ -1938,16 +2222,42 @@ cannot allocate TLS data structures for initial thread");
/* And finally install it for the main thread. If ld.so itself uses
TLS we know the thread pointer was initialized earlier. */
if (! tls_init_tp_called)
{
const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
if (__builtin_expect (lossage != NULL, 0))
_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
_dl_fatal_printf ("cannot set up thread-local storage: %s\n",
lossage);
}
}
else
#endif
NONTLS_INIT_TP;
/* Notify the debugger that all objects are now mapped in. */
r->r_state = RT_ADD;
#ifdef SHARED
/* Auditing checkpoint: we have added all objects. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
/* Do not call the functions for any auditing object. */
if (head->l_auditing == 0)
{
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
afct = afct->next;
}
}
}
#endif
/* Notify the debugger all new objects are now ready to go. We must re-get
the address since by now the variable might be in another object. */
r = _dl_debug_initialize (0);
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
#ifndef MAP_COPY
@ -2079,6 +2389,32 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n");
}
}
static void
process_dl_audit (char *str)
{
/* The parameter is a colon separated list of DSO names. */
char *p;
while ((p = (strsep) (&str, ":")) != NULL)
if (p[0] != '\0'
&& (__builtin_expect (! INTUSE(__libc_enable_secure), 1)
|| strchr (p, '/') == NULL))
{
/* This is using the local malloc, not the system malloc. The
memory can never be freed. */
struct audit_list *newp = malloc (sizeof (*newp));
newp->name = p;
if (audit_list == NULL)
audit_list = newp->next = newp;
else
{
newp->next = audit_list->next;
audit_list = audit_list->next = newp;
}
}
}
/* Process all environments variables the dynamic linker must recognize.
Since all of them start with `LD_' we are a bit smarter while finding
all the entries. */
@ -2121,8 +2457,13 @@ process_envvars (enum mode *modep)
case 5:
/* Debugging of the dynamic linker? */
if (memcmp (envline, "DEBUG", 5) == 0)
{
process_dl_debug (&envline[6]);
break;
}
if (memcmp (envline, "AUDIT", 5) == 0)
process_dl_audit (&envline[6]);
break;
case 7:
/* Print information about versions. */

1
elf/tst-audit1.c Normal file
View File

@ -0,0 +1 @@
#include "../io/pwd.c"

153
elf/tst-auditmod1.c Normal file
View File

@ -0,0 +1,153 @@
#include <dlfcn.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <gnu/lib-names.h>
unsigned int
la_version (unsigned int v)
{
setlinebuf (stdout);
printf ("version: %u\n", v);
char buf[20];
sprintf (buf, "%u", v);
return v;
}
void
la_activity (uintptr_t *cookie, unsigned int flag)
{
if (flag == LA_ACT_CONSISTENT)
printf ("activity: consistent\n");
else if (flag == LA_ACT_ADD)
printf ("activity: add\n");
else if (flag == LA_ACT_DELETE)
printf ("activity: delete\n");
else
printf ("activity: unknown activity %u\n", flag);
}
char *
la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag)
{
char buf[100];
const char *flagstr;
if (flag == LA_SER_ORIG)
flagstr = "LA_SET_ORIG";
else if (flag == LA_SER_LIBPATH)
flagstr = "LA_SER_LIBPATH";
else if (flag == LA_SER_RUNPATH)
flagstr = "LA_SER_RUNPATH";
else if (flag == LA_SER_CONFIG)
flagstr = "LA_SER_CONFIG";
else if (flag == LA_SER_DEFAULT)
flagstr = "LA_SER_DEFAULT";
else if (flag == LA_SER_SECURE)
flagstr = "LA_SER_SECURE";
else
{
sprintf (buf, "unknown flag %d", flag);
flagstr = buf;
}
printf ("objsearch: %s, %s\n", name, flagstr);
return (char *) name;
}
unsigned int
la_objopen (struct link_map *l, Lmid_t lmid, uintptr_t *cookie)
{
printf ("objopen: %ld, %s\n", lmid, l->l_name);
return 3;
}
void
la_preinit (uintptr_t *cookie)
{
printf ("preinit\n");
}
unsigned int
la_objclose (uintptr_t *cookie)
{
printf ("objclose\n");
return 0;
}
uintptr_t
la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, unsigned int *flags, const char *symname)
{
printf ("symbind32: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
symname, (long int) sym->st_value, ndx, *flags);
return sym->st_value;
}
uintptr_t
la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, unsigned int *flags, const char *symname)
{
printf ("symbind64: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
symname, (long int) sym->st_value, ndx, *flags);
return sym->st_value;
}
#ifdef __i386__
Elf32_Addr
la_i86_gnu_pltenter (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, La_i86_regs *regs,
unsigned int *flags, const char *symname,
long int *framesizep)
{
printf ("i86_pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
symname, (long int) sym->st_value, ndx, *flags);
return sym->st_value;
}
unsigned int
la_i86_gnu_pltexit (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, const La_i86_regs *inregs,
La_i86_retval *outregs, const char *symname)
{
printf ("i86_pltexit: symname=%s, st_value=%#lx, ndx=%u, retval=%tu\n",
symname, (long int) sym->st_value, ndx, outregs->lrv_eax);
return 0;
}
#endif
#ifdef __x86_64__
uintptr_t
la_x86_64_gnu_pltenter (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, La_x86_64_regs *regs,
unsigned int *flags, const char *symname,
long int *framesizep)
{
printf ("x86_64_pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
symname, (long int) sym->st_value, ndx, *flags);
return sym->st_value;
}
unsigned int
la_x86_64_gnu_pltexit (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, const La_x86_64_regs *inregs,
La_x86_64_retval *outregs, const char *symname)
{
printf ("x86_64_pltexit: symname=%s, st_value=%#lx, ndx=%u, retval=%tu\n",
symname, (long int) sym->st_value, ndx, outregs->lrv_rax);
return 0;
}
#endif

View File

@ -7,9 +7,24 @@
#define __RTLD_SPROF 0x40000000
#define __RTLD_OPENEXEC 0x20000000
#define __RTLD_CALLMAP 0x10000000
#define __RTLD_AUDIT 0x08000000
#define __LM_ID_CALLER -2
#ifdef SHARED
/* Locally stored program arguments. */
extern int __dlfcn_argc attribute_hidden;
extern char **__dlfcn_argv attribute_hidden;
#else
/* These variables are defined and initialized in the startup code. */
extern int __libc_argc attribute_hidden;
extern char **__libc_argv attribute_hidden;
# define __dlfcn_argc __libc_argc
# define __dlfcn_argv __libc_argv
#endif
/* Now define the internal interfaces. */
#define __libc_dlopen(name) \
@ -29,18 +44,8 @@ extern int _dl_addr (const void *address, Dl_info *info,
libc_hidden_proto (_dl_addr)
#endif
/* 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,
Lmid_t nsid)
internal_function;
libc_hidden_proto (_dl_open)
/* Close an object previously opened by _dl_open. */
extern void _dl_close (void *map)
internal_function;
libc_hidden_proto (_dl_close)
extern void _dl_close (void *map) attribute_hidden;
/* Look up NAME in shared object HANDLE (which may be RTLD_DEFAULT or
RTLD_NEXT). WHO is the calling function, for RTLD_NEXT. Returns

View File

@ -34,6 +34,7 @@
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
#include <bits/link.h>
#include <bits/linkmap.h>
#include <dl-lookupcfg.h>
#include <tls.h> /* Defines USE_TLS. */
@ -199,6 +200,10 @@ struct link_map
should be called on this link map
when relocation finishes. */
unsigned int l_used:1; /* Nonzero if the DSO is used. */
unsigned int l_auditing:1; /* Nonzero if the DSO is used in auditing. */
unsigned int l_audit_any_plt:1; /* Nonzero if at least one audit module
is interested in the PLT interception.*/
/* Array with version names. */
unsigned int l_nversions;
struct r_found_version *l_versions;
@ -207,7 +212,14 @@ struct link_map
struct r_search_path_struct l_rpath_dirs;
/* Collected results of relocation while profiling. */
ElfW(Addr) *l_reloc_result;
struct reloc_result
{
ElfW(Addr) addr;
struct link_map *bound;
unsigned int boundndx;
uint32_t enterexit;
unsigned int flags;
} *l_reloc_result;
/* Pointer to the version information if available. */
ElfW(Versym) *l_versyms;
@ -263,11 +275,7 @@ struct link_map
{
const ElfW(Sym) *sym;
int type_class;
#ifdef DL_LOOKUP_RETURNS_MAP
struct link_map *value;
#else
ElfW(Addr) value;
#endif
const ElfW(Sym) *ret;
} l_lookup_cache;
@ -297,8 +305,65 @@ struct link_map
done. */
ElfW(Addr) l_relro_addr;
size_t l_relro_size;
/* Audit information. This array apparent must be the last in the
structure. Never add something after it. */
struct auditstate
{
uintptr_t cookie;
unsigned int bindflags;
} l_audit[0];
};
/* Version numbers for la_version handshake interface. */
#define LAV_CURRENT 1
/* Activity types signaled through la_activity. */
enum
{
LA_ACT_CONSISTENT,
LA_ACT_ADD,
LA_ACT_DELETE
};
/* Values representing origin of name for dynamic loading. */
enum
{
LA_SER_ORIG = 0x01, /* Original name. */
LA_SER_LIBPATH = 0x02, /* Directory from LD_LIBRARY_PATH. */
LA_SER_RUNPATH = 0x04, /* Directory from RPATH/RUNPATH. */
LA_SER_CONFIG = 0x08, /* Found through ldconfig. */
LA_SER_DEFAULT = 0x40, /* Default directory. */
LA_SER_SECURE = 0x80 /* Unused. */
};
/* Values for la_objopen return value. */
enum
{
LA_FLG_BINDTO = 0x01, /* Audit symbols bound to this object. */
LA_FLG_BINDFROM = 0x02 /* Audit symbols bound from this object. */
};
/* Values for la_symbind flags parameter. */
enum
{
LA_SYMB_NOPLTENTER = 0x01, /* la_pltenter will not be called. */
LA_SYMB_NOPLTEXIT = 0x02, /* la_pltexit will not be called. */
LA_SYMB_STRUCTCALL = 0x04, /* Return value is a structure. */
LA_SYMB_DLSYM = 0x08, /* Binding due to dlsym call. */
LA_SYMB_ALTVALUE = 0x10 /* Value has been changed by a previous
la_symbind call. */
};
#if __ELF_NATIVE_CLASS == 32
# define symbind symbind32
# define pltenter plt
#elif __ELF_NATIVE_CLASS == 64
# define symbind symbind64
#else
# error "__ELF_NATIVE_CLASS must be defined"
#endif
struct dl_phdr_info
{
ElfW(Addr) dlpi_addr;

View File

@ -1,3 +1,18 @@
2005-01-06 Ulrich Drepper <drepper@redhat.com>
* allocatestack.c (init_one_static_tls): Adjust initialization of DTV
entry for static tls deallocation fix.
* sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which
also contains information whether the memory pointed to is static
TLS or not.
* sysdeps/i386/tls.h: Likewise.
* sysdeps/ia64/tls.h: Likewise.
* sysdeps/powerpc/tls.h: Likewise.
* sysdeps/s390/tls.h: Likewise.
* sysdeps/sh/tls.h: Likewise.
* sysdeps/sparc/tls.h: Likewise.
* sysdeps/x86_64/tls.h: Likewise.
2004-12-27 Ulrich Drepper <drepper@redhat.com>
* init.c (__pthread_initialize_minimal_internal): Use __sigemptyset.

View File

@ -920,7 +920,8 @@ init_one_static_tls (struct pthread *curp, struct link_map *map)
# endif
/* Fill in the DTV slot so that a later LD/GD access will find it. */
dtv[map->l_tls_modid].pointer = dest;
dtv[map->l_tls_modid].pointer.val = dest;
dtv[map->l_tls_modid].pointer.is_static = true;
/* Initialize the memory. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),

View File

@ -1,5 +1,5 @@
/* Definition for thread-local data handling. NPTL/Alpha version.
Copyright (C) 2003 Free Software Foundation, Inc.
Copyright (C) 2003, 2005 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
@ -23,6 +23,7 @@
# include <dl-sysdep.h>
#ifndef __ASSEMBLER__
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
@ -30,7 +31,11 @@
typedef union dtv
{
size_t counter;
void *pointer;
struct
{
void *val;
bool is_static;
} pointer;
} dtv_t;
#else /* __ASSEMBLER__ */

View File

@ -22,6 +22,7 @@
#include <dl-sysdep.h>
#ifndef __ASSEMBLER__
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
# include <stdlib.h>
@ -32,7 +33,11 @@
typedef union dtv
{
size_t counter;
void *pointer;
struct
{
void *val;
bool is_static;
} pointer;
} dtv_t;

View File

@ -1,5 +1,5 @@
/* Definition for thread-local data handling. nptl/IA-64 version.
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005 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
@ -22,6 +22,7 @@
#include <dl-sysdep.h>
#ifndef __ASSEMBLER__
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
# include <stdlib.h>
@ -32,7 +33,11 @@
typedef union dtv
{
size_t counter;
void *pointer;
struct
{
void *val;
bool is_static;
} pointer;
} dtv_t;

View File

@ -1,5 +1,5 @@
/* Definition for thread-local data handling. NPTL/PowerPC version.
Copyright (C) 2003 Free Software Foundation, Inc.
Copyright (C) 2003, 2005 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
@ -23,6 +23,7 @@
# include <dl-sysdep.h>
#ifndef __ASSEMBLER__
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
@ -30,7 +31,11 @@
typedef union dtv
{
size_t counter;
void *pointer;
struct
{
void *val;
bool is_static;
} pointer;
} dtv_t;
#else /* __ASSEMBLER__ */

View File

@ -1,5 +1,5 @@
/* Definition for thread-local data handling. NPTL/s390 version.
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005 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
@ -22,6 +22,7 @@
#include <dl-sysdep.h>
#ifndef __ASSEMBLER__
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
# include <stdlib.h>
@ -32,7 +33,11 @@
typedef union dtv
{
size_t counter;
void *pointer;
struct
{
void *val;
bool is_static;
} pointer;
} dtv_t;

View File

@ -1,5 +1,5 @@
/* Definition for thread-local data handling. NPTL/SH version.
Copyright (C) 2003 Free Software Foundation, Inc.
Copyright (C) 2003, 2005 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
@ -23,6 +23,7 @@
# include <dl-sysdep.h>
#ifndef __ASSEMBLER__
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
@ -30,7 +31,11 @@
typedef union dtv
{
size_t counter;
void *pointer;
struct
{
void *val;
bool is_static;
} pointer;
} dtv_t;
typedef struct

View File

@ -1,5 +1,5 @@
/* Definitions for thread-local data handling. NPTL/sparc version.
Copyright (C) 2003 Free Software Foundation, Inc.
Copyright (C) 2003, 2005 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
@ -22,6 +22,7 @@
#include <dl-sysdep.h>
#ifndef __ASSEMBLER__
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
# include <stdlib.h>
@ -31,7 +32,11 @@
typedef union dtv
{
size_t counter;
void *pointer;
struct
{
void *val;
bool is_static;
} pointer;
} dtv_t;
typedef struct

View File

@ -1,5 +1,5 @@
/* Definition for thread-local data handling. nptl/x86_64 version.
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
Copyright (C) 2002, 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
@ -22,6 +22,7 @@
#include <asm/prctl.h> /* For ARCH_SET_FS. */
#ifndef __ASSEMBLER__
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
# include <stdlib.h>
@ -31,7 +32,11 @@
typedef union dtv
{
size_t counter;
void *pointer;
struct
{
void *val;
bool is_static;
} pointer;
} dtv_t;

View File

@ -1,4 +0,0 @@
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt */
};

View File

@ -0,0 +1,4 @@
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt */
};

View File

@ -1,4 +1 @@
struct link_map_machine
{
/* empty by default */
};
#error "Architecture-specific definition needed."

View File

@ -0,0 +1,4 @@
struct link_map_machine
{
/* empty by default */
};

View File

@ -1,5 +1,5 @@
/* Configuration of lookup functions.
Copyright (C) 2002 Free Software Foundation, Inc.
Copyright (C) 2002, 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
@ -17,16 +17,4 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* Some platforms need more information from the symbol lookup function
than just the address. But this is not generally the case.
However, because of how _dl_sym and _dl_tls_symaddr are written, every
platform needs it when we support TLS. */
#include <tls.h> /* Defines USE_TLS (or doesn't). */
#ifdef USE_TLS
# define DL_LOOKUP_RETURNS_MAP
#else
# undef DL_LOOKUP_RETURNS_MAP
#endif
/* Nothing special. */

View File

@ -1,5 +1,5 @@
/* Thread-local storage handling in the ELF dynamic linker. Generic version.
Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2002, 2003, 2004, 2005 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
@ -18,6 +18,8 @@
02111-1307 USA. */
#include <assert.h>
#include <errno.h>
#include <libintl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
@ -116,10 +118,9 @@ void
internal_function
_dl_determine_tlsoffset (void)
{
struct dtv_slotinfo *slotinfo;
size_t max_align = TLS_TCB_ALIGN;
size_t offset, freetop = 0, freebottom = 0;
size_t cnt;
size_t freetop = 0;
size_t freebottom = 0;
/* The first element of the dtv slot info list is allocated. */
assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
@ -127,7 +128,7 @@ _dl_determine_tlsoffset (void)
dl_tls_dtv_slotinfo_list list. */
assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL);
slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
/* Determining the offset of the various parts of the static TLS
block has several dependencies. In addition we have to work
@ -159,9 +160,9 @@ _dl_determine_tlsoffset (void)
# if TLS_TCB_AT_TP
/* We simply start with zero. */
offset = 0;
size_t offset = 0;
for (cnt = 1; slotinfo[cnt].map != NULL; ++cnt)
for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
{
assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
@ -206,9 +207,9 @@ _dl_determine_tlsoffset (void)
+ TLS_TCB_SIZE);
# elif TLS_DTV_AT_TP
/* The TLS blocks start right after the TCB. */
offset = TLS_TCB_SIZE;
size_t offset = TLS_TCB_SIZE;
for (cnt = 1; slotinfo[cnt].map != NULL; ++cnt)
for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
{
assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
@ -225,8 +226,8 @@ _dl_determine_tlsoffset (void)
if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop)
{
slotinfo[cnt].map->l_tls_offset = off - firstbyte;
freebottom = off + slotinfo[cnt].map->l_tls_blocksize
- firstbyte;
freebottom = (off + slotinfo[cnt].map->l_tls_blocksize
- firstbyte);
continue;
}
}
@ -357,14 +358,14 @@ _dl_allocate_tls_storage (void)
/* Clear the TCB data structure. We can't ask the caller (i.e.
libpthread) to do it, because we will initialize the DTV et al. */
memset (result, 0, TLS_TCB_SIZE);
memset (result, '\0', TLS_TCB_SIZE);
# elif TLS_DTV_AT_TP
result = (char *) result + size - GL(dl_tls_static_size);
/* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it.
We can't ask the caller (i.e. libpthread) to do it, because we will
initialize the DTV et al. */
memset ((char *) result - TLS_PRE_TCB_SIZE, 0,
memset ((char *) result - TLS_PRE_TCB_SIZE, '\0',
TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
# endif
@ -388,10 +389,11 @@ _dl_allocate_tls_init (void *result)
dtv_t *dtv = GET_DTV (result);
struct dtv_slotinfo_list *listp;
size_t total = 0;
size_t maxgen = 0;
/* We have to look prepare the dtv for all currently loaded
modules using TLS. For those which are dynamically loaded we
add the values indicating deferred allocation. */
/* We have to prepare the dtv for all currently loaded modules using
TLS. For those which are dynamically loaded we add the values
indicating deferred allocation. */
listp = GL(dl_tls_dtv_slotinfo_list);
while (1)
{
@ -411,11 +413,16 @@ _dl_allocate_tls_init (void *result)
/* Unused entry. */
continue;
/* Keep track of the maximum generation number. This might
not be the generation counter. */
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
if (map->l_tls_offset == NO_TLS_OFFSET)
{
/* For dynamically loaded modules we simply store
the value indicating deferred allocation. */
dtv[map->l_tls_modid].pointer = TLS_DTV_UNALLOCATED;
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[map->l_tls_modid].pointer.is_static = false;
continue;
}
@ -431,7 +438,8 @@ _dl_allocate_tls_init (void *result)
# endif
/* Copy the initialization image and clear the BSS part. */
dtv[map->l_tls_modid].pointer = dest;
dtv[map->l_tls_modid].pointer.val = dest;
dtv[map->l_tls_modid].pointer.is_static = true;
memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0',
map->l_tls_blocksize - map->l_tls_initimage_size);
@ -445,6 +453,9 @@ _dl_allocate_tls_init (void *result)
assert (listp != NULL);
}
/* The DTV version is up-to-date now. */
dtv[0].counter = maxgen;
return result;
}
rtld_hidden_def (_dl_allocate_tls_init)
@ -466,6 +477,12 @@ _dl_deallocate_tls (void *tcb, bool dealloc_tcb)
{
dtv_t *dtv = GET_DTV (tcb);
/* We need to free the memory allocated for non-static TLS. */
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
if (! dtv[1 + cnt].pointer.is_static
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
free (dtv[1 + cnt].pointer.val);
/* The array starts with dtv[-1]. */
#ifdef SHARED
if (dtv != GL(dl_initial_dtv))
@ -524,38 +541,30 @@ allocate_and_init (struct link_map *map)
}
/* The generic dynamic and local dynamic model cannot be used in
statically linked applications. */
void *
__tls_get_addr (GET_ADDR_ARGS)
struct link_map *
_dl_update_slotinfo (unsigned long int req_modid)
{
dtv_t *dtv = THREAD_DTV ();
struct link_map *the_map = NULL;
void *p;
if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
{
struct dtv_slotinfo_list *listp;
size_t idx;
dtv_t *dtv = THREAD_DTV ();
/* The global dl_tls_dtv_slotinfo array contains for each module
index the generation counter current when the entry was
created. This array never shrinks so that all module indices
which were valid at some time can be used to access it.
Before the first use of a new module index in this function
the array was extended appropriately. Access also does not
have to be guarded against modifications of the array. It is
assumed that pointer-size values can be read atomically even
in SMP environments. It is possible that other threads at
the same time dynamically load code and therefore add to the
slotinfo list. This is a problem since we must not pick up
any information about incomplete work. The solution to this
is to ignore all dtv slots which were created after the one
we are currently interested. We know that dynamic loading
for this module is completed and this is the last load
operation we know finished. */
idx = GET_ADDR_MODULE;
listp = GL(dl_tls_dtv_slotinfo_list);
index the generation counter current when the entry was created.
This array never shrinks so that all module indices which were
valid at some time can be used to access it. Before the first
use of a new module index in this function the array was extended
appropriately. Access also does not have to be guarded against
modifications of the array. It is assumed that pointer-size
values can be read atomically even in SMP environments. It is
possible that other threads at the same time dynamically load
code and therefore add to the slotinfo list. This is a problem
since we must not pick up any information about incomplete work.
The solution to this is to ignore all dtv slots which were
created after the one we are currently interested. We know that
dynamic loading for this module is completed and this is the last
load operation we know finished. */
unsigned long int idx = req_modid;
struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
while (idx >= listp->len)
{
idx -= listp->len;
@ -564,10 +573,10 @@ __tls_get_addr (GET_ADDR_ARGS)
if (dtv[0].counter < listp->slotinfo[idx].gen)
{
/* The generation counter for the slot is higher than what
the current dtv implements. We have to update the whole
dtv but only those entries with a generation counter <=
the one for the entry we need. */
/* The generation counter for the slot is higher than what the
current dtv implements. We have to update the whole dtv but
only those entries with a generation counter <= the one for
the entry we need. */
size_t new_gen = listp->slotinfo[idx].gen;
size_t total = 0;
@ -575,42 +584,39 @@ __tls_get_addr (GET_ADDR_ARGS)
listp = GL(dl_tls_dtv_slotinfo_list);
do
{
size_t cnt;
for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
for (size_t cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
{
size_t gen = listp->slotinfo[cnt].gen;
struct link_map *map;
size_t modid;
if (gen > new_gen)
/* This is a slot for a generation younger than
the one we are handling now. It might be
incompletely set up so ignore it. */
/* This is a slot for a generation younger than the
one we are handling now. It might be incompletely
set up so ignore it. */
continue;
/* If the entry is older than the current dtv layout
we know we don't have to handle it. */
/* If the entry is older than the current dtv layout we
know we don't have to handle it. */
if (gen <= dtv[0].counter)
continue;
/* If there is no map this means the entry is empty. */
map = listp->slotinfo[cnt].map;
struct link_map *map = listp->slotinfo[cnt].map;
if (map == NULL)
{
/* If this modid was used at some point the memory
might still be allocated. */
if (dtv[total + cnt].pointer != TLS_DTV_UNALLOCATED)
if (! dtv[total + cnt].pointer.is_static
&& dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED)
{
free (dtv[total + cnt].pointer);
dtv[total + cnt].pointer = TLS_DTV_UNALLOCATED;
free (dtv[total + cnt].pointer.val);
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
}
continue;
}
/* Check whether the current dtv array is large enough. */
modid = map->l_tls_modid;
size_t modid = map->l_tls_modid;
assert (total + cnt == modid);
if (dtv[-1].counter < modid)
{
@ -659,18 +665,20 @@ __tls_get_addr (GET_ADDR_ARGS)
dtv entry free it. */
/* XXX Ideally we will at some point create a memory
pool. */
if (dtv[modid].pointer != TLS_DTV_UNALLOCATED)
if (! dtv[modid].pointer.is_static
&& dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
/* Note that free is called for NULL is well. We
deallocate even if it is this dtv entry we are
supposed to load. The reason is that we call
memalign and not malloc. */
free (dtv[modid].pointer);
free (dtv[modid].pointer.val);
/* This module is loaded dynamically- We defer
memory allocation. */
dtv[modid].pointer = TLS_DTV_UNALLOCATED;
/* This module is loaded dynamically- We defer memory
allocation. */
dtv[modid].pointer.is_static = false;
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
if (modid == GET_ADDR_MODULE)
if (modid == req_modid)
the_map = map;
}
@ -681,9 +689,24 @@ __tls_get_addr (GET_ADDR_ARGS)
/* This will be the new maximum generation counter. */
dtv[0].counter = new_gen;
}
return the_map;
}
p = dtv[GET_ADDR_MODULE].pointer;
/* The generic dynamic and local dynamic model cannot be used in
statically linked applications. */
void *
__tls_get_addr (GET_ADDR_ARGS)
{
dtv_t *dtv = THREAD_DTV ();
struct link_map *the_map = NULL;
void *p;
if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
p = dtv[GET_ADDR_MODULE].pointer.val;
if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
{
@ -703,11 +726,74 @@ __tls_get_addr (GET_ADDR_ARGS)
the_map = listp->slotinfo[idx].map;
}
p = dtv[GET_ADDR_MODULE].pointer = allocate_and_init (the_map);
p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
dtv[GET_ADDR_MODULE].pointer.is_static = false;
}
return (char *) p + GET_ADDR_OFFSET;
}
# endif
void
_dl_add_to_slotinfo (struct link_map *l)
{
/* Now that we know the object is loaded successfully add
modules containing TLS data to the dtv info table. We
might have to increase its size. */
struct dtv_slotinfo_list *listp;
struct dtv_slotinfo_list *prevp;
size_t idx = l->l_tls_modid;
/* Find the place in the dtv slotinfo list. */
listp = GL(dl_tls_dtv_slotinfo_list);
prevp = NULL; /* Needed to shut up gcc. */
do
{
/* Does it fit in the array of this list element? */
if (idx < listp->len)
break;
idx -= listp->len;
prevp = listp;
listp = listp->next;
}
while (listp != NULL);
if (listp == NULL)
{
/* When we come here it means we have to add a new element
to the slotinfo list. And the new module must be in
the first slot. */
assert (idx == 0);
listp = prevp->next = (struct dtv_slotinfo_list *)
malloc (sizeof (struct dtv_slotinfo_list)
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
if (listp == NULL)
{
/* We ran out of memory. We will simply fail this
call but don't undo anything we did so far. The
application will crash or be terminated anyway very
soon. */
/* We have to do this since some entries in the dtv
slotinfo array might already point to this
generation. */
++GL(dl_tls_generation);
_dl_signal_error (ENOMEM, "dlopen", NULL, N_("\
cannot create TLS data structures"));
}
listp->len = TLS_SLOTINFO_SURPLUS;
listp->next = NULL;
memset (listp->slotinfo, '\0',
TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
}
/* Add the information into the slotinfo data structure. */
listp->slotinfo[idx].map = l;
listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
}
#endif /* use TLS */

View File

@ -0,0 +1 @@
#error "Architecture specific PLT trampolines must be defined."

View File

@ -52,23 +52,15 @@ __BEGIN_DECLS
most architectures the entry is already relocated - but for some not
and we need to relocate at access time. */
#ifdef DL_RO_DYN_SECTION
# define D_PTR(map,i) (map->i->d_un.d_ptr + map->l_addr)
# define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr)
#else
# define D_PTR(map,i) map->i->d_un.d_ptr
# define D_PTR(map, i) (map)->i->d_un.d_ptr
#endif
/* On some platforms more information than just the address of the symbol
is needed from the lookup functions. In this case we return the whole
link map. */
#ifdef DL_LOOKUP_RETURNS_MAP
/* Result of the lookup functions and how to retrieve the base address. */
typedef struct link_map *lookup_t;
# define LOOKUP_VALUE(map) map
# define LOOKUP_VALUE_ADDRESS(map) (map ? map->l_addr : 0)
#else
typedef ElfW(Addr) lookup_t;
# define LOOKUP_VALUE(map) map->l_addr
# define LOOKUP_VALUE_ADDRESS(address) address
#endif
# define LOOKUP_VALUE_ADDRESS(map) ((map) ? (map)->l_addr : 0)
/* on some architectures a pointer to a function is not just a pointer
to the actual code of the function but rather an architecture
@ -182,6 +174,55 @@ enum allowmask
};
/* Type for list of auditing interfaces. */
struct La_i86_regs;
struct La_i86_retval;
struct La_x86_64_regs;
struct La_x86_64_retval;
struct audit_ifaces
{
void (*activity) (uintptr_t *, unsigned int);
char *(*objsearch) (const char *, uintptr_t *, unsigned int);
unsigned int (*objopen) (struct link_map *, Lmid_t, uintptr_t *);
void (*preinit) (uintptr_t *);
union
{
uintptr_t (*symbind32) (Elf32_Sym *, unsigned int, uintptr_t *,
uintptr_t *, unsigned int *, const char *);
uintptr_t (*symbind64) (Elf64_Sym *, unsigned int, uintptr_t *,
uintptr_t *, unsigned int *, const char *);
};
union
{
uintptr_t (*i86_gnu_pltenter) (Elf32_Sym *, unsigned int, uintptr_t *,
uintptr_t *, const struct La_i86_regs *,
unsigned int *, const char *name,
long int *framesizep);
uintptr_t (*x86_64_gnu_pltenter) (Elf64_Sym *, unsigned int, uintptr_t *,
uintptr_t *,
const struct La_x86_64_regs *,
unsigned int *, const char *name,
long int *framesizep);
};
union
{
unsigned int (*i86_gnu_pltexit) (Elf32_Sym *, unsigned int, uintptr_t *,
uintptr_t *, const struct La_i86_regs *,
struct La_i86_retval *, const char *);
unsigned int (*x86_64_gnu_pltexit) (Elf64_Sym *, unsigned int, uintptr_t *,
uintptr_t *,
const struct La_x86_64_regs *,
struct La_x86_64_retval *,
const char *);
};
unsigned int (*objclose) (uintptr_t *);
struct audit_ifaces *next;
};
/* Test whether given NAME matches any of the names of the given object. */
extern int _dl_name_match_p (const char *__name, struct link_map *__map)
internal_function;
@ -224,7 +265,7 @@ struct rtld_global
#endif
EXTERN struct link_namespaces
{
/* And a pointer to the map for the main map. */
/* 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;
@ -277,8 +318,12 @@ struct rtld_global
EXTERN void **(*_dl_error_catch_tsd) (void) __attribute__ ((const));
#endif
/* Structure describing the dynamic linker itself. */
/* Structure describing the dynamic linker itself. We need to
reserve memory for the data the audit libraries need. */
EXTERN struct link_map _dl_rtld_map;
#ifdef SHARED
struct auditstate audit_data[DL_NNS];
#endif
#if defined SHARED && defined _LIBC_REENTRANT \
&& defined __rtld_lock_default_lock_recursive
@ -311,6 +356,7 @@ struct rtld_global
struct dtv_slotinfo
{
size_t gen;
bool is_static;
struct link_map *map;
} slotinfo[0];
} *_dl_tls_dtv_slotinfo_list;
@ -483,32 +529,12 @@ struct rtld_global_ro
call the function instead of going through the PLT. The result
is that we can avoid exporting the functions and we do not jump
PLT relocations in libc.so. */
const char *(*_dl_get_origin) (void);
size_t (*_dl_dst_count) (const char *, int);
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, Lmid_t);
void (internal_function *_dl_map_object_deps) (struct link_map *,
struct link_map **,
unsigned int, int, int);
void (*_dl_relocate_object) (struct link_map *, struct r_scope_elem *[],
int, int);
int (internal_function *_dl_check_map_versions) (struct link_map *, int,
int);
void (internal_function *_dl_init) (struct link_map *, int, char **,
char **);
void (*_dl_debug_state) (void);
#ifndef MAP_COPY
void (*_dl_unload_cache) (void);
#endif
void (*_dl_debug_printf) (const char *, ...)
__attribute__ ((__format__ (__printf__, 1, 2)));
int (internal_function *_dl_catch_error) (const char **, const char **,
void (*) (void *), void *);
void (internal_function *_dl_signal_error) (int, const char *, const char *,
const char *);
void (internal_function *_dl_start_profile) (void);
void (*_dl_mcount) (ElfW(Addr) frompc, ElfW(Addr) selfpc);
lookup_t (internal_function *_dl_lookup_symbol_x) (const char *,
struct link_map *,
@ -518,7 +544,13 @@ struct rtld_global_ro
int, int,
struct link_map *);
int (*_dl_check_caller) (const void *, enum allowmask);
void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen,
Lmid_t nsid, int argc, char *argv[], char *env[]);
void (*_dl_close) (void *map);
/* List of auditing interfaces. */
struct audit_ifaces *_dl_audit;
unsigned int _dl_naudit;
};
# define __rtld_global_attribute__
# ifdef IS_IN_rtld
@ -911,6 +943,20 @@ extern char *_dl_dst_substitute (struct link_map *l, const char *name,
extern int _dl_check_caller (const void *caller, enum allowmask mask)
attribute_hidden;
/* 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,
Lmid_t nsid, int argc, char *argv[], char *env[])
attribute_hidden;
/* Add module to slot information data. */
extern void _dl_add_to_slotinfo (struct link_map *l) attribute_hidden;
/* Update slot information data for at least the generation of the
module with the given index. */
extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid);
__END_DECLS
#endif /* ldsodefs.h */

View File

@ -80,6 +80,10 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
void *__unbounded stack_end)
__attribute__ ((noreturn));
/* Note: the fini parameter is ignored here. It used to be registered
with __cxa_atexit. This had the disadvantage that finalizers were
called in more than one place. */
STATIC int
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
int argc, char *__unbounded *__unbounded ubp_av,
@ -158,10 +162,6 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
__libc_init_first (argc, argv, __environ);
#endif
/* Register the destructor of the program, if any. */
if (fini)
__cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
#ifndef SHARED
/* Some security at this point. Prevent starting a SUID binary where
the standard file descriptors are not opened. We have to do this
@ -183,6 +183,22 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
#endif
);
#ifdef SHARED
/* Auditing checkpoint: we have a new object. */
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
{
struct audit_ifaces *afct = GLRO(dl_audit);
struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->preinit != NULL)
afct->preinit (&head->l_audit[cnt].cookie);
afct = afct->next;
}
}
#endif
#ifdef SHARED
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);

View File

@ -1,5 +1,5 @@
/* Initialization code for TLS in statically linked application.
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
Copyright (C) 2002, 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
@ -178,17 +178,18 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
/* Initialize the TLS block. */
# if TLS_TCB_AT_TP
static_dtv[2].pointer = ((char *) tlsblock + tcb_offset
static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset
- roundup (memsz, align ?: 1));
static_map.l_tls_offset = roundup (memsz, align ?: 1);
# elif TLS_DTV_AT_TP
static_dtv[2].pointer = (char *) tlsblock + tcb_offset;
static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset;
static_map.l_tls_offset = tcb_offset;
# else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
static_dtv[2].pointer.is_static = true;
/* sbrk gives us zero'd memory, so we don't need to clear the remainder. */
memcpy (static_dtv[2].pointer, initimage, filesz);
memcpy (static_dtv[2].pointer.val, initimage, filesz);
/* Install the pointer to the dtv. */

View File

@ -2,18 +2,19 @@
all stuffed in a single string which means they have to be terminated
with a '\0' explicitly. */
#define UNSECURE_ENVVARS \
"LD_PRELOAD\0" \
"LD_LIBRARY_PATH\0" \
"LD_ORIGIN_PATH\0" \
"LD_DEBUG\0" \
"LD_DEBUG_OUTPUT\0" \
"LD_PROFILE\0" \
"LD_USE_LOAD_BIAS\0" \
"LD_DYNAMIC_WEAK\0" \
"LD_SHOW_AUXV\0" \
"GCONV_PATH\0" \
"GETCONF_DIR\0" \
"HOSTALIASES\0" \
"LD_AUDIT\0" \
"LD_DEBUG\0" \
"LD_DEBUG_OUTPUT\0" \
"LD_DYNAMIC_WEAK\0" \
"LD_LIBRARY_PATH\0" \
"LD_ORIGIN_PATH\0" \
"LD_PRELOAD\0" \
"LD_PROFILE\0" \
"LD_SHOW_AUXV\0" \
"LD_USE_LOAD_BIAS\0" \
"LOCALDOMAIN\0" \
"LOCPATH\0" \
"MALLOC_TRACE\0" \

View File

@ -1,6 +0,0 @@
/* Used to store the function descriptor table */
struct link_map_machine
{
size_t fptr_table_len;
ElfW(Addr) *fptr_table;
};

View File

@ -0,0 +1,6 @@
/* Used to store the function descriptor table */
struct link_map_machine
{
size_t fptr_table_len;
ElfW(Addr) *fptr_table;
};

View File

@ -1,5 +1,5 @@
/* Configuration of lookup functions.
Copyright (C) 2000 Free Software Foundation, Inc.
Copyright (C) 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
@ -17,9 +17,6 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* Like IA-64, PA-RISC needs more information from the symbol lookup
function than just the address. */
#define DL_LOOKUP_RETURNS_MAP
#define ELF_FUNCTION_PTR_IS_SPECIAL
#define DL_UNMAP_IS_SPECIAL
@ -66,4 +63,3 @@ void _dl_unmap (struct link_map *map);
((Elf32_Addr)(addr) & 2 ? (addr) : DL_AUTO_FUNCTION_ADDRESS (map, addr))
#define DL_DT_FINI_ADDRESS(map, addr) \
((Elf32_Addr)(addr) & 2 ? (addr) : DL_AUTO_FUNCTION_ADDRESS (map, addr))

View File

@ -1,5 +1,60 @@
struct link_map_machine
/* Copyright (C) 2004, 2005 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. */
#ifndef _LINK_H
# error "Never include <bits/link.h> directly; use <link.h> instead."
#endif
/* Registers for entry into PLT on IA-32. */
typedef struct La_i86_regs
{
Elf32_Addr plt; /* Address of .plt + 0x16 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};
uint32_t lr_edx;
uint32_t lr_ecx;
uint32_t lr_eax;
uint32_t lr_ebp;
uint32_t lr_esp;
} La_i86_regs;
/* Return values for calls from PLT on IA-32. */
typedef struct La_i86_retval
{
uint32_t lrv_eax;
uint32_t lrv_edx;
long double lrv_st0;
long double lrv_st1;
} La_i86_retval;
__BEGIN_DECLS
extern Elf32_Addr la_i86_gnu_pltenter (Elf32_Sym *__sym, unsigned int __ndx,
uintptr_t *__refcook,
uintptr_t *__defcook,
La_i86_regs *__regs,
unsigned int *__flags,
const char *__symname,
long int *__framesizep);
extern unsigned int la_i86_gnu_pltexit (Elf32_Sym *__sym, unsigned int __ndx,
uintptr_t *__refcook,
uintptr_t *__defcook,
const La_i86_regs *__inregs,
La_i86_retval *__outregs,
const char *symname);
__END_DECLS

View File

@ -0,0 +1,5 @@
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 0x16 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};

View File

@ -129,7 +129,8 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
{
got[2] = (Elf32_Addr) &_dl_runtime_profile;
if (_dl_name_match_p (GLRO(dl_profile), l))
if (GLRO(dl_profile) != NULL
&& _dl_name_match_p (GLRO(dl_profile), l))
/* This is the object we are looking for. Say that we really
want profiling and the timers are started. */
GL(dl_profile_map) = l;
@ -154,112 +155,18 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
destroys the passed register information. */
/* GKM FIXME: Fix trampoline to pass bounds so we can do
without the `__unbounded' qualifier. */
#define ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), unused))
#define ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), stdcall, unused))
static ElfW(Addr) fixup (struct link_map *__unbounded l,
extern ElfW(Addr) _dl_fixup (struct link_map *__unbounded l,
ElfW(Word) reloc_offset)
ARCH_FIXUP_ATTRIBUTE;
static ElfW(Addr) profile_fixup (struct link_map *l, ElfW(Word) reloc_offset,
ElfW(Addr) retaddr)
extern ElfW(Addr) _dl_profile_fixup (struct link_map *l,
ElfW(Word) reloc_offset,
ElfW(Addr) retaddr, const void *regs,
long int *framesizep)
ARCH_FIXUP_ATTRIBUTE;
# endif
/* This code is used in dl-runtime.c to call the `fixup' function
and then redirect to the address it returns. */
# if !defined PROF && !__BOUNDED_POINTERS__
# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
.text\n\
.globl _dl_runtime_resolve\n\
.type _dl_runtime_resolve, @function\n\
" CFI_STARTPROC "\n\
.align 16\n\
_dl_runtime_resolve:\n\
" CFI_ADJUST_CFA_OFFSET (8) "\n\
pushl %eax # Preserve registers otherwise clobbered.\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
pushl %ecx\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
pushl %edx\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
movl 16(%esp), %edx # Copy args pushed by PLT in register. Note\n\
movl 12(%esp), %eax # that `fixup' takes its parameters in regs.\n\
call fixup # Call resolver.\n\
popl %edx # Get register content back.\n\
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
popl %ecx\n\
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
xchgl %eax, (%esp) # Get %eax contents end store function address.\n\
ret $8 # Jump to function address.\n\
" CFI_ENDPROC "\n\
.size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
\n\
.globl _dl_runtime_profile\n\
.type _dl_runtime_profile, @function\n\
" CFI_STARTPROC "\n\
.align 16\n\
_dl_runtime_profile:\n\
" CFI_ADJUST_CFA_OFFSET (8) "\n\
pushl %eax # Preserve registers otherwise clobbered.\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
pushl %ecx\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
pushl %edx\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
movl 20(%esp), %ecx # Load return address\n\
movl 16(%esp), %edx # Copy args pushed by PLT in register. Note\n\
movl 12(%esp), %eax # that `fixup' takes its parameters in regs.\n\
call profile_fixup # Call resolver.\n\
popl %edx # Get register content back.\n\
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
popl %ecx\n\
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
xchgl %eax, (%esp) # Get %eax contents end store function address.\n\
ret $8 # Jump to function address.\n\
" CFI_ENDPROC "\n\
.size _dl_runtime_profile, .-_dl_runtime_profile\n\
.previous\n\
");
# else
# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
.text\n\
.globl _dl_runtime_resolve\n\
.globl _dl_runtime_profile\n\
.type _dl_runtime_resolve, @function\n\
.type _dl_runtime_profile, @function\n\
" CFI_STARTPROC "\n\
.align 16\n\
_dl_runtime_resolve:\n\
_dl_runtime_profile:\n\
" CFI_ADJUST_CFA_OFFSET (8) "\n\
pushl %eax # Preserve registers otherwise clobbered.\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
pushl %ecx\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
pushl %edx\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
movl 16(%esp), %edx # Push the arguments for `fixup'\n\
movl 12(%esp), %eax\n\
pushl %edx\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
pushl %eax\n\
" CFI_ADJUST_CFA_OFFSET (4) "\n\
call fixup # Call resolver.\n\
popl %edx # Pop the parameters\n\
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
popl %ecx\n\
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
popl %edx # Get register content back.\n\
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
popl %ecx\n\
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
xchgl %eax, (%esp) # Get %eax contents end store function address.\n\
ret $8 # Jump to function address.\n\
" CFI_ENDPROC "\n\
.size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
.size _dl_runtime_profile, .-_dl_runtime_profile\n\
.previous\n\
");
# endif
#endif
/* Mask identifying addresses reserved for the user program,
@ -375,9 +282,14 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
return value;
}
/* Names of the architecture-specific auditing callback functions. */
#define ARCH_LA_PLTENTER i86_gnu_pltenter
#define ARCH_LA_PLTEXIT i86_gnu_pltexit
#endif /* !dl_machine_h */
#ifdef RESOLVE
#ifdef RESOLVE_MAP
/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
Prelinked libraries may use Elf32_Rela though. */
@ -422,7 +334,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
#endif /* !RTLD_BOOTSTRAP and have no -z combreloc */
{
const Elf32_Sym *const refsym = sym;
#if defined USE_TLS && !defined RTLD_BOOTSTRAP
#ifndef RTLD_BOOTSTRAP
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
#else
@ -549,14 +461,8 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
# ifndef RESOLVE_CONFLICT_FIND_MAP
const Elf32_Sym *const refsym = sym;
# endif
# ifdef USE_TLS
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
# else
Elf32_Addr value = RESOLVE (&sym, version, r_type);
if (sym != NULL)
value += sym->st_value;
# endif
switch (ELF32_R_TYPE (reloc->r_info))
{
@ -692,4 +598,4 @@ elf_machine_lazy_rela (struct link_map *map,
#endif /* !RTLD_BOOTSTRAP */
#endif /* RESOLVE */
#endif /* RESOLVE_MAP */

View File

@ -0,0 +1,182 @@
/* PLT trampolines. i386 version.
Copyright (C) 2004, 2005 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 <sysdep.h>
.text
.globl _dl_runtime_resolve
.type _dl_runtime_resolve, @function
cfi_startproc
.align 16
_dl_runtime_resolve:
cfi_adjust_cfa_offset (8)
pushl %eax # Preserve registers otherwise clobbered.
cfi_adjust_cfa_offset (4)
pushl %ecx
cfi_adjust_cfa_offset (4)
pushl %edx
cfi_adjust_cfa_offset (4)
movl 16(%esp), %edx # Copy args pushed by PLT in register. Note
movl 12(%esp), %eax # that `fixup' takes its parameters in regs.
call _dl_fixup # Call resolver.
popl %edx # Get register content back.
cfi_adjust_cfa_offset (-4)
popl %ecx
cfi_adjust_cfa_offset (-4)
xchgl %eax, (%esp) # Get %eax contents end store function address.
ret $8 # Jump to function address.
cfi_endproc
.size _dl_runtime_resolve, .-_dl_runtime_resolve
.globl _dl_runtime_profile
.type _dl_runtime_profile, @function
cfi_startproc
.align 16
_dl_runtime_profile:
cfi_adjust_cfa_offset (8)
pushl %esp
cfi_adjust_cfa_offset (4)
addl $8, (%esp) # Account for the pushed PLT data
pushl %ebp
cfi_adjust_cfa_offset (4)
pushl %eax # Preserve registers otherwise clobbered.
cfi_adjust_cfa_offset (4)
pushl %ecx
cfi_adjust_cfa_offset (4)
pushl %edx
cfi_adjust_cfa_offset (4)
movl %esp, %ecx
subl $8, %esp
cfi_adjust_cfa_offset (8)
movl $-1, 4(%esp)
leal 4(%esp), %edx
movl %edx, (%esp)
pushl %ecx # Address of the register structure
cfi_adjust_cfa_offset (4)
movl 40(%esp), %ecx # Load return address
movl 36(%esp), %edx # Copy args pushed by PLT in register. Note
movl 32(%esp), %eax # that `fixup' takes its parameters in regs.
call _dl_profile_fixup # Call resolver.
cfi_adjust_cfa_offset (-8)
movl (%esp), %edx
testl %edx, %edx
jns 1f
popl %edx
cfi_adjust_cfa_offset (-4)
popl %edx # Get register content back.
cfi_adjust_cfa_offset (-4)
popl %ecx
cfi_adjust_cfa_offset (-4)
xchgl %eax, (%esp) # Get %eax contents end store function address.
ret $16 # Jump to function address.
/*
+32 return address
+28 PLT1
+24 PLT2
+20 %esp
+16 %ebp
+12 %eax
+8 %ecx
+4 %edx
%esp free
*/
cfi_adjust_cfa_offset (12)
1: movl %ebx, (%esp)
cfi_rel_offset (3, 0)
movl %edx, %ebx # This is the frame buffer size
pushl %edi
cfi_adjust_cfa_offset (4)
cfi_rel_offset (7, 0)
pushl %esi
cfi_adjust_cfa_offset (4)
cfi_rel_offset (6, 0)
leal 44(%esp), %esi
movl %ebx, %ecx
movl %esp, %edi
subl %ebx, %edi
andl $0xfffffff0, %edi # Align stack
movl %esp, %ebx
cfi_def_cfa_register (3)
movl %edi, %esp
shrl $2, %ecx
rep
movsl
movl (%edi), %esi
cfi_restore (6)
movl 4(%edi), %edi
cfi_restore (7)
/*
%ebx+40 return address
%ebx+36 PLT1
%ebx+32 PLT2
%ebx+28 %esp
%ebx+24 %ebp
%ebx+20 %eax
%ebx+16 %ecx
%ebx+12 %edx
%ebx+8 %ebx
%ebx+4 free
%ebx free
%esp copied stack frame
*/
movl %eax, (%ebx)
movl 12(%ebx), %edx
movl 16(%ebx), %ecx
movl 20(%ebx), %eax
call *(%ebx)
movl %ebx, %esp
cfi_def_cfa_register (4)
movl 8(%esp), %ebx
cfi_restore (3)
/*
+40 return address
+36 PLT1
+32 PLT2
+28 %esp
+24 %ebp
+20 %eax
+16 %ecx
+12 %edx
+8 free
+4 free
%esp free
*/
subl $20, %esp
cfi_adjust_cfa_offset (20)
movl %eax, (%esp)
movl %edx, 4(%esp)
fstpt 8(%esp)
fstpt 20(%esp)
pushl %esp
cfi_adjust_cfa_offset (4)
leal 36(%esp), %ecx
movl 56(%esp), %eax
movl 60(%esp), %edx
call _dl_call_pltexit
movl (%esp), %eax
movl 4(%esp), %edx
fldt 20(%esp)
fldt 8(%esp)
addl $60, %esp
cfi_adjust_cfa_offset (-60)
ret
cfi_endproc
.size _dl_runtime_profile, .-_dl_runtime_profile

View File

@ -1,5 +0,0 @@
struct link_map_machine
{
size_t fptr_table_len;
Elf64_Addr *fptr_table;
};

View File

@ -0,0 +1,5 @@
struct link_map_machine
{
size_t fptr_table_len;
Elf64_Addr *fptr_table;
};

View File

@ -1,5 +1,5 @@
/* Configuration of lookup functions.
Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
Copyright (C) 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
@ -17,9 +17,6 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* The ia64 need more information from the symbol lookup function
than just the address. */
#define DL_LOOKUP_RETURNS_MAP
#define ELF_FUNCTION_PTR_IS_SPECIAL
#define DL_UNMAP_IS_SPECIAL

4
sysdeps/linkmap.h Normal file
View File

@ -0,0 +1,4 @@
struct link_map_machine
{
/* empty by default */
};

View File

@ -1,22 +0,0 @@
/* Configuration of lookup functions. PowerPC64 version.
Copyright (C) 2002 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. */
/* Return the symbol map from the symbol lookup function. */
#define DL_LOOKUP_RETURNS_MAP 1

View File

@ -1,13 +0,0 @@
#if __WORDSIZE == 64
struct link_map_machine
{
Elf64_Addr plt; /* Address of .plt + 0x2e */
Elf64_Addr gotplt; /* Address of .got + 0x18 */
};
#else
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 0x2c */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};
#endif

View File

@ -0,0 +1,13 @@
#if __WORDSIZE == 64
struct link_map_machine
{
Elf64_Addr plt; /* Address of .plt + 0x2e */
Elf64_Addr gotplt; /* Address of .got + 0x18 */
};
#else
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 0x2c */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};
#endif

View File

@ -1,5 +0,0 @@
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 36 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};

View File

@ -0,0 +1,5 @@
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 36 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};

View File

@ -1,14 +1,112 @@
#if __WORDSIZE == 64
struct link_map_machine
/* Copyright (C) 2004, 2005 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. */
#ifndef _LINK_H
# error "Never include <bits/link.h> directly; use <link.h> instead."
#endif
#if __ELF_NATIVE_CLASS == 32
/* Registers for entry into PLT on IA-32. */
typedef struct La_i86_regs
{
Elf64_Addr plt; /* Address of .plt + 0x16 */
Elf64_Addr gotplt; /* Address of .got + 0x18 */
};
uint32_t lr_edx;
uint32_t lr_ecx;
uint32_t lr_eax;
uint32_t lr_ebp;
uint32_t lr_esp;
} La_i86_regs;
/* Return values for calls from PLT on IA-32. */
typedef struct La_i86_retval
{
uint32_t lrv_eax;
uint32_t lrv_edx;
long double lrv_st0;
long double lrv_st1;
} La_i86_retval;
__BEGIN_DECLS
extern Elf32_Addr la_i86_gnu_pltenter (Elf32_Sym *__sym, unsigned int __ndx,
uintptr_t *__refcook,
uintptr_t *__defcook,
La_i86_regs *__regs,
unsigned int *__flags,
const char *__symname,
long int *__framesizep);
extern unsigned int la_i86_gnu_pltexit (Elf32_Sym *__sym, unsigned int __ndx,
uintptr_t *__refcook,
uintptr_t *__defcook,
const La_i86_regs *__inregs,
La_i86_retval *__outregs,
const char *symname);
__END_DECLS
#else
struct link_map_machine
/* Registers for entry into PLT on x86-64. */
typedef float La_x86_64_xmm __attribute__ ((__mode__ (__V4SF__)));
typedef struct La_x86_64_regs
{
Elf32_Addr plt; /* Address of .plt + 0x16 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};
uint64_t lr_rdx;
uint64_t lr_r8;
uint64_t lr_r9;
uint64_t lr_rcx;
uint64_t lr_rsi;
uint64_t lr_rdi;
uint64_t lr_rbp;
uint64_t lr_rsp;
La_x86_64_xmm lr_xmm[8];
} La_x86_64_regs;
/* Return values for calls from PLT on x86-64. */
typedef struct La_x86_64_retval
{
uint64_t lrv_rax;
uint64_t lrv_rdx;
La_x86_64_xmm lrv_xmm0;
La_x86_64_xmm lrv_xmm1;
long double lrv_st0;
long double lrv_st1;
} La_x86_64_retval;
__BEGIN_DECLS
extern Elf64_Addr la_x86_64_gnu_pltenter (Elf64_Sym *__sym,
unsigned int __ndx,
uintptr_t *__refcook,
uintptr_t *__defcook,
La_x86_64_regs *__regs,
unsigned int *__flags,
const char *__symname,
long int *__framesizep);
extern unsigned int la_x86_64_gnu_pltexit (Elf64_Sym *__sym,
unsigned int __ndx,
uintptr_t *__refcook,
uintptr_t *__defcook,
const La_x86_64_regs *__inregs,
La_x86_64_retval *__outregs,
const char *symname);
__END_DECLS
#endif

View File

@ -0,0 +1,14 @@
#if __WORDSIZE == 64
struct link_map_machine
{
Elf64_Addr plt; /* Address of .plt + 0x16 */
Elf64_Addr gotplt; /* Address of .got + 0x18 */
};
#else
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 0x16 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};
#endif

View File

@ -116,7 +116,8 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
{
got[2] = (Elf64_Addr) &_dl_runtime_profile;
if (_dl_name_match_p (GLRO(dl_profile), l))
if (GLRO(dl_profile) != NULL
&& _dl_name_match_p (GLRO(dl_profile), l))
/* This is the object we are looking for. Say that we really
want profiling and the timers are started. */
GL(dl_profile_map) = l;
@ -130,128 +131,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
return lazy;
}
/* This code is used in dl-runtime.c to call the `fixup' function
and then redirect to the address it returns. */
#ifndef PROF
# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
.text\n\
.globl _dl_runtime_resolve\n\
.type _dl_runtime_resolve, @function\n\
.align 16\n\
" CFI_STARTPROC "\n\
_dl_runtime_resolve:\n\
subq $56,%rsp\n\
" CFI_ADJUST_CFA_OFFSET(72)" # Incorporate PLT\n\
movq %rax,(%rsp) # Preserve registers otherwise clobbered.\n\
movq %rcx,8(%rsp)\n\
movq %rdx,16(%rsp)\n\
movq %rsi,24(%rsp)\n\
movq %rdi,32(%rsp)\n\
movq %r8,40(%rsp)\n\
movq %r9,48(%rsp)\n\
movq 64(%rsp), %rsi # Copy args pushed by PLT in register.\n\
movq %rsi,%r11 # Multiply by 24\n\
addq %r11,%rsi\n\
addq %r11,%rsi\n\
shlq $3, %rsi\n\
movq 56(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset\n\
call fixup # Call resolver.\n\
movq %rax, %r11 # Save return value\n\
movq 48(%rsp),%r9 # Get register content back.\n\
movq 40(%rsp),%r8\n\
movq 32(%rsp),%rdi\n\
movq 24(%rsp),%rsi\n\
movq 16(%rsp),%rdx\n\
movq 8(%rsp),%rcx\n\
movq (%rsp),%rax\n\
addq $72,%rsp # Adjust stack(PLT did 2 pushes)\n\
" CFI_ADJUST_CFA_OFFSET(-72)" \n\
jmp *%r11 # Jump to function address.\n\
" CFI_ENDPROC "\n\
.size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
\n\
.globl _dl_runtime_profile\n\
.type _dl_runtime_profile, @function\n\
.align 16\n\
" CFI_STARTPROC "\n\
_dl_runtime_profile:\n\
subq $56,%rsp\n\
" CFI_ADJUST_CFA_OFFSET(72)" # Incorporate PLT\n\
movq %rax,(%rsp) # Preserve registers otherwise clobbered.\n\
movq %rcx,8(%rsp)\n\
movq %rdx,16(%rsp)\n\
movq %rsi,24(%rsp)\n\
movq %rdi,32(%rsp)\n\
movq %r8,40(%rsp)\n\
movq %r9,48(%rsp)\n\
movq 72(%rsp), %rdx # Load return address if needed\n\
movq 64(%rsp), %rsi # Copy args pushed by PLT in register.\n\
movq %rsi,%r11 # Multiply by 24\n\
addq %r11,%rsi\n\
addq %r11,%rsi\n\
shlq $3, %rsi\n\
movq 56(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset\n\
call profile_fixup # Call resolver.\n\
movq %rax, %r11 # Save return value\n\
movq 48(%rsp),%r9 # Get register content back.\n\
movq 40(%rsp),%r8\n\
movq 32(%rsp),%rdi\n\
movq 24(%rsp),%rsi\n\
movq 16(%rsp),%rdx\n\
movq 8(%rsp),%rcx\n\
movq (%rsp),%rax\n\
addq $72,%rsp # Adjust stack\n\
" CFI_ADJUST_CFA_OFFSET(-72)"\n\
jmp *%r11 # Jump to function address.\n\
" CFI_ENDPROC "\n\
.size _dl_runtime_profile, .-_dl_runtime_profile\n\
.previous\n\
");
#else
# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
.text\n\
.globl _dl_runtime_resolve\n\
.globl _dl_runtime_profile\n\
.type _dl_runtime_resolve, @function\n\
.type _dl_runtime_profile, @function\n\
.align 16\n\
" CFI_STARTPROC "\n\
_dl_runtime_resolve:\n\
_dl_runtime_profile:\n\
subq $56,%rsp\n\
" CFI_ADJUST_CFA_OFFSET(72)" # Incorporate PLT\n\
movq %rax,(%rsp) # Preserve registers otherwise clobbered.\n\
movq %rcx,8(%rsp)\n\
movq %rdx,16(%rsp)\n\
movq %rsi,24(%rsp)\n\
movq %rdi,32(%rsp)\n\
movq %r8,40(%rsp)\n\
movq %r9,48(%rsp)\n\
movq 64(%rsp), %rsi # Copy args pushed by PLT in register.\n\
movq %rsi,%r11 # Multiply by 24\n\
addq %r11,%rsi\n\
addq %r11,%rsi\n\
shlq $3, %rsi\n\
movq 56(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset\n\
call fixup # Call resolver.\n\
movq %rax, %r11 # Save return value\n\
movq 48(%rsp),%r9 # Get register content back.\n\
movq 40(%rsp),%r8\n\
movq 32(%rsp),%rdi\n\
movq 24(%rsp),%rsi\n\
movq 16(%rsp),%rdx\n\
movq 8(%rsp),%rcx\n\
movq (%rsp),%rax\n\
addq $72,%rsp # Adjust stack\n\
" CFI_ADJUST_CFA_OFFSET(-72)"\n\
jmp *%r11 # Jump to function address.\n\
" CFI_ENDPROC "\n\
.size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
.size _dl_runtime_profile, .-_dl_runtime_profile\n\
.previous\n\
");
#endif
/* Initial entry point code for the dynamic linker.
The C function `_dl_start' is the real entry point;
its return value is the user program's entry point. */
@ -348,9 +227,14 @@ elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
return value;
}
/* Names of the architecture-specific auditing callback functions. */
#define ARCH_LA_PLTENTER x86_64_gnu_pltenter
#define ARCH_LA_PLTEXIT x86_64_gnu_pltexit
#endif /* !dl_machine_h */
#ifdef RESOLVE
#ifdef RESOLVE_MAP
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
MAP is the object containing the reloc. */
@ -390,7 +274,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
#ifndef RTLD_BOOTSTRAP
const Elf64_Sym *const refsym = sym;
#endif
#if defined USE_TLS && !defined RTLD_BOOTSTRAP
#ifndef RTLD_BOOTSTRAP
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Elf64_Addr value = (sym == NULL ? 0
: (Elf64_Addr) sym_map->l_addr + sym->st_value);
@ -553,4 +437,4 @@ elf_machine_lazy_rel (struct link_map *map,
_dl_reloc_bad_type (map, r_type, 1);
}
#endif /* RESOLVE */
#endif /* RESOLVE_MAP */

View File

@ -0,0 +1,188 @@
/* PLT trampolines. x86-64 version.
Copyright (C) 2004, 2005 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 <sysdep.h>
.text
.globl _dl_runtime_resolve
.type _dl_runtime_resolve, @function
.align 16
cfi_startproc
_dl_runtime_resolve:
subq $56,%rsp
cfi_adjust_cfa_offset(72) # Incorporate PLT
movq %rax,(%rsp) # Preserve registers otherwise clobbered.
movq %rcx, 8(%rsp)
movq %rdx, 16(%rsp)
movq %rsi, 24(%rsp)
movq %rdi, 32(%rsp)
movq %r8, 40(%rsp)
movq %r9, 48(%rsp)
movq 64(%rsp), %rsi # Copy args pushed by PLT in register.
movq %rsi, %r11 # Multiply by 24
addq %r11, %rsi
addq %r11, %rsi
shlq $3, %rsi
movq 56(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset
call _dl_fixup # Call resolver.
movq %rax, %r11 # Save return value
movq 48(%rsp), %r9 # Get register content back.
movq 40(%rsp), %r8
movq 32(%rsp), %rdi
movq 24(%rsp), %rsi
movq 16(%rsp), %rdx
movq 8(%rsp), %rcx
movq (%rsp), %rax
addq $72, %rsp # Adjust stack(PLT did 2 pushes)
cfi_adjust_cfa_offset(-72)
jmp *%r11 # Jump to function address.
cfi_endproc
.size _dl_runtime_resolve, .-_dl_runtime_resolve
.globl _dl_runtime_profile
.type _dl_runtime_profile, @function
.align 16
cfi_startproc
_dl_runtime_profile:
subq $80, %rsp
cfi_adjust_cfa_offset(96) # Incorporate PLT
movq %rax, (%rsp) # Preserve registers otherwise clobbered.
movq %rdx, 8(%rsp)
movq %r8, 16(%rsp)
movq %r9, 24(%rsp)
movq %rcx, 32(%rsp)
movq %rsi, 40(%rsp)
movq %rdi, 48(%rsp)
movq %rbp, 56(%rsp) # Information for auditors.
leaq 96(%rsp), %rax
movq %rax, 64(%rsp)
leaq 8(%rsp), %rcx
movq 96(%rsp), %rdx # Load return address if needed
movq 88(%rsp), %rsi # Copy args pushed by PLT in register.
movq %rsi,%r11 # Multiply by 24
addq %r11,%rsi
addq %r11,%rsi
shlq $3, %rsi
movq 80(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset
leaq 72(%rsp), %r8
call _dl_profile_fixup # Call resolver.
movq %rax, %r11 # Save return value
movq 8(%rsp), %rdx # Get back register content.
movq 16(%rsp), %r8
movq 24(%rsp), %r9
movq (%rsp),%rax
movq 72(%rsp), %r10
testq %r10, %r10
jns 1f
movq 32(%rsp), %rcx
movq 40(%rsp), %rsi
movq 48(%rsp), %rdi
addq $96,%rsp # Adjust stack
cfi_adjust_cfa_offset (-96)
jmp *%r11 # Jump to function address.
/*
+96 return address
+88 PLT2
+80 PLT1
+72 free
+64 %rsp
+56 %rbp
+48 %rdi
+40 %rsi
+32 %rcx
+24 %r9
+16 %r8
+8 %rdx
%esp %rax
*/
cfi_adjust_cfa_offset (96)
1: movq %rbx, 72(%rsp)
cfi_rel_offset (1, 72)
leaq 104(%rsp), %rsi
movq %rsp, %rbx
cfi_def_cfa_register (1)
subq %r10, %rsp
movq %rsp, %rdi
movq %r10, %rcx
shrq $3, %rcx
rep
movsq
andq $0xfffffffffffffff0, %rsp
movq 32(%rbx), %rcx
movq 40(%rbx), %rsi
movq 48(%rbx), %rdi
call *%r11
movq %rbx, %rsp
cfi_def_cfa_register (7)
subq $72, %rsp
cfi_adjust_cfa_offset (72)
movq %rsp, %rcx
movq %rax, (%rcx)
movq %rdx, 8(%rcx)
/* Even though the stack is correctly aligned to allow using movaps
we use movups. Some callers might provide an incorrectly aligned
stack and we do not want to have it blow up here. */
movups %xmm0, 16(%rcx)
movups %xmm1, 32(%rcx)
fstpt 48(%rcx)
fstpt 64(%rcx)
/*
+168 return address
+160 PLT2
+152 PLT1
+144 free
+136 %rsp
+128 %rbp
+120 %rdi
+112 %rsi
+104 %rcx
+96 %r9
+88 %r8
+80 %rdx
+64 %st1 result
+48 %st result
+32 %xmm1 result
+16 %xmm0 result
+8 %rdx result
%esp %rax result
*/
leaq 80(%rsp), %rdx
movq 144(%rsp), %rbx
cfi_restore (1)
movq 160(%rsp), %rsi # Copy args pushed by PLT in register.
movq %rsi,%r11 # Multiply by 24
addq %r11,%rsi
addq %r11,%rsi
shlq $3, %rsi
movq 152(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset
call _dl_call_pltexit
movq (%rsp), %rax
movq 8(%rsp), %rdx
movups 16(%rsp), %xmm0
movups 32(%rsp), %xmm1
fldt 64(%rsp)
fldt 48(%rsp)
addq $168, %rsp
cfi_adjust_cfa_offset (-168)
retq
cfi_endproc
.size _dl_runtime_profile, .-_dl_runtime_profile