summaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile31
-rw-r--r--elf/Versions2
-rw-r--r--elf/dl-close.c115
-rw-r--r--elf/dl-debug.c25
-rw-r--r--elf/dl-fini.c94
-rw-r--r--elf/dl-init.c12
-rw-r--r--elf/dl-libc.c14
-rw-r--r--elf/dl-load.c181
-rw-r--r--elf/dl-object.c24
-rw-r--r--elf/dl-open.c238
-rw-r--r--elf/dl-reloc.c65
-rw-r--r--elf/dl-runtime.c285
-rw-r--r--elf/dl-sym.c59
-rw-r--r--elf/dynamic-link.h6
-rw-r--r--elf/ldconfig.c4
-rw-r--r--elf/ldd.bash.in4
-rw-r--r--elf/link.h69
-rw-r--r--elf/rtld.c549
-rw-r--r--elf/sprof.c4
-rw-r--r--elf/tst-align2.c157
-rw-r--r--elf/tst-alignmod2.c60
-rw-r--r--elf/tst-audit1.c1
-rw-r--r--elf/tst-auditmod1.c190
23 files changed, 1741 insertions, 448 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 87172d367d..47e6ea4d58 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -20,8 +20,8 @@
subdir := elf
-headers = elf.h bits/elfclass.h link.h
-routines = $(dl-routines) dl-open dl-close dl-support dl-iteratephdr \
+headers = elf.h bits/elfclass.h link.h bits/link.h
+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
@@ -72,7 +72,7 @@ distribute := rtld-Rules \
tst-tlsmod1.c tst-tlsmod2.c tst-tlsmod3.c tst-tlsmod4.c \
tst-tlsmod5.c tst-tlsmod6.c tst-tlsmod7.c tst-tlsmod8.c \
tst-tlsmod9.c tst-tlsmod10.c tst-tlsmod11.c \
- tst-tlsmod12.c tst-tls10.h tst-alignmod.c \
+ tst-tlsmod12.c tst-tls10.h tst-alignmod.c tst-alignmod2.c \
circlemod1.c circlemod1a.c circlemod2.c circlemod2a.c \
circlemod3.c circlemod3a.c nodlopenmod2.c \
tls-macros.h \
@@ -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
@@ -153,8 +154,9 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
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-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
+ tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
+ tst-audit1
# reldep9
test-srcs = tst-pathopt
tests-vis-yes = vismain
@@ -163,7 +165,7 @@ tests-nodlopen-yes = nodlopen nodlopen2
tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
endif
ifeq (yesyes,$(have-fpie)$(build-shared))
-tests += tst-pie1
+tests: $(objpfx)tst-pie1.out
endif
modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
testobj1_1 failobj constload2 constload3 unloadmod \
@@ -186,9 +188,10 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
circlemod3 circlemod3a \
reldep8mod1 reldep8mod2 reldep8mod3 \
reldep9mod1 reldep9mod2 reldep9mod3 \
- tst-alignmod $(modules-execstack-$(have-z-execstack)) \
+ tst-alignmod tst-alignmod2 \
+ $(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
@@ -668,9 +671,12 @@ $(objpfx)tst-tls14: $(objpfx)tst-tlsmod14a.so $(libdl)
$(objpfx)tst-tls14.out:$(objpfx)tst-tlsmod14b.so
CFLAGS-tst-align.c = $(stack-align-test-flags)
+CFLAGS-tst-align2.c = $(stack-align-test-flags)
CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
+CFLAGS-tst-alignmod2.c = $(stack-align-test-flags)
$(objpfx)tst-align: $(libdl)
$(objpfx)tst-align.out: $(objpfx)tst-alignmod.so
+$(objpfx)tst-align2: $(objpfx)tst-alignmod2.so
ifdef libdl
$(objpfx)tst-tls9-static: $(common-objpfx)dlfcn/libdl.a
@@ -732,6 +738,8 @@ $(objpfx)tst-pie1: $(objpfx)tst-pie1.o $(objpfx)tst-piemod1.so
-L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) \
-o $@ $(objpfx)tst-pie1.o $(objpfx)tst-piemod1.so \
$(common-objpfx)libc_nonshared.a
+
+generated += tst-pie1 tst-pie1.out tst-pie1.o
endif
check-textrel-CFLAGS = -O -Wall -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
@@ -773,3 +781,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
diff --git a/elf/Versions b/elf/Versions
index e24b2de04c..aaacf3e4ea 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -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;
diff --git a/elf/dl-close.c b/elf/dl-close.c
index c823b17642..eb5e805dd4 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -1,5 +1,5 @@
/* Close a shared object opened by `_dl_open'.
- Copyright (C) 1996-2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1996-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
@@ -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,8 +140,8 @@ _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",
- map->l_name, map->l_opencount);
+ _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
+ map->l_name, map->l_opencount);
/* Decrement the object's reference counter, not the dependencies'. */
--map->l_opencount;
@@ -265,16 +266,23 @@ _dl_close (void *_map)
assert (new_opencount[0] == 0);
/* Call all termination functions at once. */
+#ifdef SHARED
+ bool do_audit = GLRO(dl_naudit) > 0 && !GL(dl_ns)[ns]._ns_loaded->l_auditing;
+#endif
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 +307,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 (do_audit, 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 +389,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 (do_audit, 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, ns);
+ r->r_state = RT_DELETE;
+ _dl_debug_state ();
#ifdef USE_TLS
size_t tls_free_start;
@@ -389,21 +434,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,9 +455,10 @@ _dl_close (void *_map)
{
any_tls = true;
- if (! remove_slotinfo (imap->l_tls_modid,
- GL(dl_tls_dtv_slotinfo_list), 0,
- imap->l_init_called))
+ 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. */
GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
@@ -499,12 +543,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 +623,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 (do_audit, 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 +676,6 @@ _dl_close (void *_map)
/* Release the lock. */
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}
-libc_hidden_def (_dl_close)
#ifdef USE_TLS
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index bd6ee69189..bc7d793435 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -1,5 +1,5 @@
/* Communicate dynamic linker state to the debugger at runtime.
- Copyright (C) 1996, 1998, 2000, 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998,2000,2002,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
@@ -32,20 +32,25 @@ struct r_debug _r_debug;
struct r_debug *
internal_function
-_dl_debug_initialize (ElfW(Addr) ldbase)
+_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
{
- if (_r_debug.r_brk == 0)
+ struct r_debug *r;
+
+ if (ns == LM_ID_BASE)
+ r = &_r_debug;
+ else
+ r = &GL(dl_ns)[ns]._ns_debug;
+
+ if (r->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 */;
- _r_debug.r_ldbase = ldbase;
- // XXX This is problematic. It means we cannot tell the debugger
- // XXX about namespaces other than the main one.
- _r_debug.r_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
- _r_debug.r_brk = (ElfW(Addr)) &_dl_debug_state;
+ r->r_version = 1 /* R_DEBUG_VERSION XXX */;
+ r->r_ldbase = ldbase ?: _r_debug.r_ldbase;
+ r->r_map = GL(dl_ns)[ns]._ns_loaded;
+ r->r_brk = (ElfW(Addr)) &_dl_debug_state;
}
- return &_r_debug;
+ return r;
}
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index f43f4a00ed..b3282089a9 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -1,5 +1,5 @@
/* Call the termination functions of loaded shared objects.
- Copyright (C) 1995,96,1998-2002,2004 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,1998-2002,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
@@ -48,12 +48,25 @@ _dl_fini (void)
/* We run the destructors of the main namespaces last. As for the
other namespaces, we pick run the destructors in them in reverse
order of the namespace ID. */
+#ifdef SHARED
+ int do_audit = 0;
+ again:
+#endif
for (Lmid_t cnt = DL_NNS - 1; cnt >= 0; --cnt)
{
/* 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
+#ifdef SHARED
+ || GL(dl_ns)[cnt]._ns_loaded->l_auditing != do_audit
+#endif
+ )
+ goto out;
/* XXX Could it be (in static binaries) that there is no object
loaded? */
@@ -76,6 +89,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 +104,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 +177,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,38 +191,49 @@ _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;
-
- /* When debugging print a message first. */
- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
- 0))
- _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
- l->l_name[0] ? l->l_name : rtld_progname,
- cnt);
-
- /* First see whether an array is given. */
- if (l->l_info[DT_FINI_ARRAY] != NULL)
+ if (l->l_info[DT_FINI_ARRAY] != NULL
+ || l->l_info[DT_FINI] != NULL)
{
- ElfW(Addr) *array =
- (ElfW(Addr) *) (l->l_addr
- + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
- unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
- / sizeof (ElfW(Addr)));
- while (i-- > 0)
- ((fini_t) array[i]) ();
+ /* When debugging print a message first. */
+ if (__builtin_expect (GLRO(dl_debug_mask)
+ & DL_DEBUG_IMPCALLS, 0))
+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ l->l_name[0] ? l->l_name : rtld_progname,
+ cnt);
+
+ /* First see whether an array is given. */
+ if (l->l_info[DT_FINI_ARRAY] != NULL)
+ {
+ ElfW(Addr) *array =
+ (ElfW(Addr) *) (l->l_addr
+ + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
+ unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
+ / sizeof (ElfW(Addr)));
+ while (i-- > 0)
+ ((fini_t) array[i]) ();
+ }
+
+ /* Next try the old-style destructor. */
+ if (l->l_info[DT_FINI] != NULL)
+ ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
}
- /* Next try the old-style destructor. */
- if (l->l_info[DT_FINI] != NULL)
- ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
+#ifdef SHARED
+ /* Auditing checkpoint: another object closed. */
+ if (!do_audit && __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. */
@@ -215,6 +241,14 @@ _dl_fini (void)
}
}
+#ifdef SHARED
+ if (! do_audit && GLRO(dl_naudit) > 0)
+ {
+ do_audit = 1;
+ goto again;
+ }
+#endif
+
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0))
_dl_debug_printf ("\nruntime linker statistics:\n"
" final number of relocations: %lu\n"
diff --git a/elf/dl-init.c b/elf/dl-init.c
index e700dffb3a..e7b67570fd 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -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;
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index 8a3f542e01..5e76069139 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -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
@@ -109,7 +115,7 @@ struct dl_open_hook
#ifdef SHARED
extern struct dl_open_hook *_dl_open_hook;
libc_hidden_proto (_dl_open_hook);
-struct dl_open_hook *_dl_open_hook __attribute__((nocommon));
+struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon));
libc_hidden_data_def (_dl_open_hook);
#else
static void
@@ -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;
diff --git a/elf/dl-load.c b/elf/dl-load.c
index eb1a7919fb..f307dada2e 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1,5 +1,5 @@
/* Map in a shared object's segments from the file.
- 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
@@ -36,6 +36,7 @@
#include <dl-osinfo.h>
#include <stackinfo.h>
#include <caller.h>
+#include <sysdep.h>
#include <dl-dst.h>
@@ -105,13 +106,11 @@ ELF_PREFERRED_ADDRESS_DATA;
int __stack_prot attribute_hidden attribute_relro
- = (PROT_READ|PROT_WRITE
#if _STACK_GROWS_DOWN && defined PROT_GROWSDOWN
- |PROT_GROWSDOWN
+ = PROT_GROWSDOWN;
#elif _STACK_GROWS_UP && defined PROT_GROWSUP
- |PROT_GROWSUP
+ = PROT_GROWSUP;
#endif
- );
/* Type for the buffer we put the ELF header and hopefully the program
@@ -827,6 +826,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, nsid);
+ bool make_consistent = false;
/* Get file information. */
if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st) < 0, 0))
@@ -835,6 +836,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 +912,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 +1084,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;
@@ -1318,21 +1358,25 @@ cannot allocate TLS data structures for initial thread");
protection of the variable which contains the flags used in
the mprotect calls. */
#ifdef HAVE_Z_RELRO
- if (mode & __RTLD_DLOPEN)
+ if ((mode & (__RTLD_DLOPEN | __RTLD_AUDIT)) == __RTLD_DLOPEN)
{
uintptr_t p = ((uintptr_t) &__stack_prot) & ~(GLRO(dl_pagesize) - 1);
size_t s = (uintptr_t) &__stack_prot - p + sizeof (int);
__mprotect ((void *) p, s, PROT_READ|PROT_WRITE);
if (__builtin_expect (__check_caller (RETURN_ADDRESS (0),
- allow_ldso|allow_libc) == 0,
+ allow_ldso) == 0,
0))
- __stack_prot |= PROT_EXEC;
+ __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
__mprotect ((void *) p, s, PROT_READ);
}
else
#endif
- __stack_prot |= PROT_EXEC;
+ __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
+
+#ifdef check_consistency
+ check_consistency ();
+#endif
errval = (*GL(dl_make_stack_executable_hook)) (stack_endp);
if (errval)
@@ -1424,6 +1468,27 @@ 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)
+ && !GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
+ {
+ 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 +1536,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 +1566,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 +1751,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 +1795,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 +1822,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))
@@ -1788,7 +1879,12 @@ open_path (const char *name, size_t namelen, int preloaded,
must not be freed using the general free() in libc. */
if (sps->malloced)
free (sps->dirs);
- sps->dirs = (void *) -1;
+#ifdef HAVE_Z_RELRO
+ /* rtld_search_dirs is attribute_relro, therefore avoid writing
+ into it. */
+ if (sps != &rtld_search_dirs)
+#endif
+ sps->dirs = (void *) -1;
}
return -1;
@@ -1847,6 +1943,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 +1989,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 +1999,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 +2064,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 +2086,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 +2102,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. */
diff --git a/elf/dl-object.c b/elf/dl-object.c
index b46ebdc33f..86f7a8e4d9 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -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'
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 7e890ad7f7..4de20720ed 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -1,5 +1,5 @@
/* Load a shared object at runtime, relocate it, and run its initializer.
- Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1996-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
@@ -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,8 +114,8 @@ 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,
- N_("cannot extend global scope"));
+ _dl_signal_error (ENOMEM, new->l_libname->name, NULL,
+ N_("cannot extend global scope"));
return 1;
}
@@ -171,13 +170,14 @@ 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;
/* 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
@@ -218,6 +218,8 @@ dl_open_worker (void *a)
}
}
+ assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
+
/* Maybe we have to expand a DST. */
if (__builtin_expect (dst != NULL, 0))
{
@@ -226,10 +228,10 @@ 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,
- N_("DST not allowed in SUID/SGID programs"));
+ _dl_signal_error (0, "dlopen", NULL,
+ N_("DST not allowed in SUID/SGID programs"));
/* Determine how much space we need. We have to allocate the
@@ -244,8 +246,8 @@ 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,
- N_("empty dynamic string token substitution"));
+ _dl_signal_error (0, "dlopen", NULL,
+ N_("empty dynamic string token substitution"));
/* Now we have a new file name. */
file = new_file;
@@ -256,8 +258,8 @@ dl_open_worker (void *a)
}
/* Load the named object. */
- args->map = new = GLRO(dl_map_object) (call_map, file, 0, lt_loaded, 0,
- mode | __RTLD_CALLMAP, args->nsid);
+ 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
set and the object is not already loaded. */
@@ -279,8 +281,8 @@ 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",
- new->l_name, new->l_ns, new->l_opencount);
+ _dl_debug_printf ("opening file=%s [%lu]; opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_opencount);
/* If the user requested the object to be in the global namespace
but it is not so far, add it now. */
@@ -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, args->nsid)->r_state == RT_CONSISTENT);
+
return;
}
/* Load that object's dependencies. */
- GLRO(dl_map_object_deps) (new, NULL, 0, 0,
- mode & (__RTLD_DLOPEN | RTLD_DEEPBIND));
+ _dl_map_object_deps (new, NULL, 0, 0,
+ mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT));
/* 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,
- 0, 0);
+ (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, args->nsid);
+ 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,8 +425,8 @@ 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,
- N_("cannot create scope list"));
+ _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,8 +436,8 @@ 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,
- N_("cannot create scope list"));
+ _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;
-
- assert (new->l_searchlist.r_list[i]->l_type == lt_loaded);
+ _dl_add_to_slotinfo (new->l_searchlist.r_list[i]);
- /* 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",
- new->l_name, new->l_ns, new->l_opencount);
+ _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,8 +520,7 @@ _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));
@@ -566,16 +537,20 @@ _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()"));
}
+
+ _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
}
/* 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,
- N_("invalid target namespace in dlmopen()"));
+ && (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;
args.mode = mode;
@@ -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,21 +581,22 @@ 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. */
- GL(dl_tls_dtv_gaps) = 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
_dl_close (args.map);
@@ -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, args.nsid)->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, args.nsid)->r_state == RT_CONSISTENT);
+
#ifndef SHARED
DL_STATIC_INIT (args.map);
#endif
return args.map;
}
-libc_hidden_def (_dl_open)
#ifdef SCOPE_DEBUG
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 4004316c5a..b680683198 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -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,15 +69,15 @@ 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
- - map->l_tls_firstbyte_offset);
+ 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;
# elif TLS_DTV_AT_TP
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)
- GL(dl_init_static_tls) (map);
+ /* 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_info[DT_PLTRELSZ]->d_un.d_val);
+ 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;
}
}
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index a0aecda2e8..f92cbe26bd 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -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
@@ -22,6 +22,7 @@
#include <alloca.h>
#include <stdlib.h>
#include <unistd.h>
+#include <sys/param.h>
#include <ldsodefs.h>
#include "dynamic-link.h"
@@ -51,15 +52,15 @@
function. */
#ifndef ELF_MACHINE_NO_PLT
-static ElfW(Addr)
-__attribute ((used, noinline)) ARCH_FIXUP_ATTRIBUTE
-fixup (
+DL_FIXUP_VALUE_TYPE
+__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
+_dl_fixup (
# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
- ELF_MACHINE_RUNTIME_FIXUP_ARGS,
+ ELF_MACHINE_RUNTIME_FIXUP_ARGS,
# endif
- /* GKM FIXME: Fix trampoline to pass bounds so we can do
- without the `__unbounded' qualifier. */
- struct link_map *__unbounded l, ElfW(Word) reloc_offset)
+ /* GKM FIXME: Fix trampoline to pass bounds so we can do
+ without the `__unbounded' qualifier. */
+ struct link_map *__unbounded l, ElfW(Word) reloc_offset)
{
const ElfW(Sym) *const symtab
= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
@@ -70,7 +71,7 @@ fixup (
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
lookup_t result;
- ElfW(Addr) value;
+ DL_FIXUP_VALUE_TYPE value;
/* Sanity check that we're really looking at a PLT relocation. */
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
@@ -80,8 +81,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 +90,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,
@@ -102,16 +99,16 @@ 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 = DL_FIXUP_MAKE_VALUE (result,
+ sym ? LOOKUP_VALUE_ADDRESS (result)
+ + sym->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 = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value);
result = l;
-#endif
}
/* And now perhaps the relocation addend. */
@@ -127,45 +124,45 @@ fixup (
#if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
-static ElfW(Addr)
-__attribute ((used, noinline)) ARCH_FIXUP_ATTRIBUTE
-profile_fixup (
+DL_FIXUP_VALUE_TYPE
+__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
+_dl_profile_fixup (
#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
- 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, 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)];
+ DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr;
- value = *resultp;
- if (value == 0)
+ DL_FIXUP_VALUE_TYPE value = *resultp;
+ if (DL_FIXUP_VALUE_CODE_ADDR (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 +172,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,26 +182,188 @@ 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 = DL_FIXUP_MAKE_VALUE (result,
+ 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 = DL_FIXUP_MAKE_VALUE (l, 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 = DL_FIXUP_VALUE_ADDR (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 = DL_FIXUP_ADDR_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;
}
- (*mcount_fct) (retaddr, 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 (DL_FIXUP_VALUE_CODE_ADDR (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 = DL_FIXUP_VALUE_ADDR (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 = DL_FIXUP_ADDR_VALUE (sym.st_value);
+ }
+#endif
+
+ /* Store the frame size information. */
+ *framesizep = framesize;
+
+ (*mcount_fct) (retaddr, DL_FIXUP_VALUE_CODE_ADDR (value));
return value;
}
@@ -214,9 +371,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);
+
+ /* 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);
+ }
-ELF_MACHINE_RUNTIME_TRAMPOLINE
+ afct = afct->next;
+ }
+#endif
+}
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index ba00ef56f4..ca83daf21d 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -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;
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index f9559dc59c..5118144174 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -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)
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index f8504fb95e..70f3a8f402 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
+/* Copyright (C) 1999-2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Andreas Jaeger <aj@suse.de>, 1999.
@@ -279,7 +279,7 @@ print_version (FILE *stream, struct argp_state *state)
Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2004");
+"), "2005");
fprintf (stream, gettext ("Written by %s.\n"),
"Andreas Jaeger");
}
diff --git a/elf/ldd.bash.in b/elf/ldd.bash.in
index 4d7c33c728..4587efd1cb 100644
--- a/elf/ldd.bash.in
+++ b/elf/ldd.bash.in
@@ -1,5 +1,5 @@
#! @BASH@
-# Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+# Copyright (C) 1996-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
@@ -39,7 +39,7 @@ while test $# -gt 0; do
printf $"Copyright (C) %s Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-" "2004"
+" "2005"
printf $"Written by %s and %s.
" "Roland McGrath" "Ulrich Drepper"
exit 0
diff --git a/elf/link.h b/elf/link.h
index 6d5ad9d98c..fdda019cbe 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -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
diff --git a/elf/rtld.c b/elf/rtld.c
index 3835a207ec..9fda5b8122 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -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
@@ -267,6 +263,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
memcpy (GL(dl_rtld_map).l_info, info->l.l_info,
sizeof GL(dl_rtld_map).l_info);
GL(dl_rtld_map).l_mach = info->l.l_mach;
+ GL(dl_rtld_map).l_relocated = 1;
#endif
_dl_setup_hash (&GL(dl_rtld_map));
GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
@@ -348,8 +345,6 @@ _dl_start (void *arg)
#define RTLD_BOOTSTRAP
#define RESOLVE_MAP(sym, version, flags) \
((*(sym))->st_shndx == SHN_UNDEF ? 0 : &bootstrap_map)
-#define RESOLVE(sym, version, flags) \
- ((*(sym))->st_shndx == SHN_UNDEF ? 0 : bootstrap_map.l_addr)
#include "dynamic-link.h"
if (HP_TIMING_INLINE && HP_TIMING_AVAIL)
@@ -472,7 +467,7 @@ _dl_start (void *arg)
while (remaining-- > 0)
*p++ = '\0';
}
-#endif
+# endif
/* Install the pointer to the dtv. */
@@ -514,6 +509,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 +562,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
{
@@ -591,6 +600,28 @@ map_doit (void *a)
}
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)
{
struct version_check_args *args = (struct version_check_args *) a;
@@ -648,6 +679,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 +807,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 +931,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 +993,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,
+ __RTLD_OPENEXEC, 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 +1097,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 +1119,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 +1156,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 +1205,11 @@ 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,
+ LM_ID_BASE);
+ 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. */
@@ -1148,6 +1284,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)
@@ -1158,6 +1295,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. */
@@ -1418,6 +1753,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;
@@ -1533,20 +1871,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
@@ -1554,57 +1878,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)
@@ -1885,8 +2161,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;
@@ -1921,8 +2195,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;
@@ -1945,11 +2217,17 @@ 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);
+
+#ifdef USE_TLS
+ /* Add object to slot information data if necessasy. */
+ if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+ _dl_add_to_slotinfo (l);
+#endif
}
_dl_sysdep_start_cleanup ();
@@ -1965,7 +2243,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;
@@ -1976,7 +2253,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;
@@ -1998,6 +2275,12 @@ cannot allocate TLS data structures for initial thread");
_dl_relocate_object (l, l->l_scope, GLRO(dl_lazy),
consider_profiling);
+#ifdef USE_TLS
+ /* Add object to slot information data if necessasy. */
+ if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+ _dl_add_to_slotinfo (l);
+#endif
+
l = l->l_prev;
}
while (l);
@@ -2025,6 +2308,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);
@@ -2039,6 +2324,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. */
@@ -2046,16 +2334,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. */
- 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);
+ 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);
+ }
}
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, LM_ID_BASE);
+ r->r_state = RT_CONSISTENT;
_dl_debug_state ();
#ifndef MAP_COPY
@@ -2187,6 +2501,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. */
@@ -2229,7 +2569,12 @@ process_envvars (enum mode *modep)
case 5:
/* Debugging of the dynamic linker? */
if (memcmp (envline, "DEBUG", 5) == 0)
- process_dl_debug (&envline[6]);
+ {
+ process_dl_debug (&envline[6]);
+ break;
+ }
+ if (memcmp (envline, "AUDIT", 5) == 0)
+ process_dl_audit (&envline[6]);
break;
case 7:
diff --git a/elf/sprof.c b/elf/sprof.c
index afe3955ad8..9567e4689f 100644
--- a/elf/sprof.c
+++ b/elf/sprof.c
@@ -1,5 +1,5 @@
/* Read and display shared object profiling data.
- Copyright (C) 1997-2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1997-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -357,7 +357,7 @@ Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
"),
- "2004");
+ "2005");
fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
}
diff --git a/elf/tst-align2.c b/elf/tst-align2.c
new file mode 100644
index 0000000000..4fc0330e39
--- /dev/null
+++ b/elf/tst-align2.c
@@ -0,0 +1,157 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
+
+ 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 <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <tst-stack-align.h>
+#include <unistd.h>
+
+static int res, fds[2], result;
+static bool test_destructors;
+
+extern void in_dso (int *, bool *, int *);
+
+static void __attribute__ ((constructor)) con (void)
+{
+ res = TEST_STACK_ALIGN () ? -1 : 1;
+}
+
+static void __attribute__ ((destructor)) des (void)
+{
+ if (!test_destructors)
+ return;
+
+ char c = TEST_STACK_ALIGN () ? 'B' : 'A';
+ write (fds[1], &c, 1);
+}
+
+static int
+do_test (void)
+{
+ if (!res)
+ {
+ puts ("binary's constructor has not been run");
+ result = 1;
+ }
+ else if (res != 1)
+ {
+ puts ("binary's constructor has been run without sufficient alignment");
+ result = 1;
+ }
+
+ if (TEST_STACK_ALIGN ())
+ {
+ puts ("insufficient stack alignment in do_test");
+ result = 1;
+ }
+
+ in_dso (&result, &test_destructors, &fds[1]);
+
+ if (pipe (fds) < 0)
+ {
+ printf ("couldn't create pipe: %m\n");
+ return 1;
+ }
+
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("fork failed: %m\n");
+ return 1;
+ }
+
+ if (!pid)
+ {
+ close (fds[0]);
+ test_destructors = true;
+ exit (0);
+ }
+
+ close (fds[1]);
+
+ unsigned char c;
+ ssize_t len;
+ int des_seen = 0, dso_des_seen = 0;
+ while ((len = TEMP_FAILURE_RETRY (read (fds[0], &c, 1))) > 0)
+ {
+ switch (c)
+ {
+ case 'B':
+ puts ("insufficient alignment in binary's destructor");
+ result = 1;
+ /* FALLTHROUGH */
+ case 'A':
+ des_seen++;
+ break;
+ case 'D':
+ puts ("insufficient alignment in DSO destructor");
+ result = 1;
+ /* FALLTHROUGH */
+ case 'C':
+ dso_des_seen++;
+ break;
+ default:
+ printf ("unexpected character %x read from pipe", c);
+ result = 1;
+ break;
+ }
+ }
+
+ close (fds[0]);
+
+ if (des_seen != 1)
+ {
+ printf ("binary destructor run %d times instead of once\n", des_seen);
+ result = 1;
+ }
+
+ if (dso_des_seen != 1)
+ {
+ printf ("DSO destructor run %d times instead of once\n", dso_des_seen);
+ result = 1;
+ }
+
+ int status;
+ pid_t termpid;
+ termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (termpid == -1)
+ {
+ printf ("waitpid failed: %m\n");
+ result = 1;
+ }
+ else if (termpid != pid)
+ {
+ printf ("waitpid returned %ld != %ld\n",
+ (long int) termpid, (long int) pid);
+ result = 1;
+ }
+ else if (!WIFEXITED (status) || WEXITSTATUS (status))
+ {
+ puts ("child hasn't exited with exit status 0");
+ result = 1;
+ }
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/elf/tst-alignmod2.c b/elf/tst-alignmod2.c
new file mode 100644
index 0000000000..21dcc535c0
--- /dev/null
+++ b/elf/tst-alignmod2.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ 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 <stdbool.h>
+#include <stdio.h>
+#include <tst-stack-align.h>
+#include <unistd.h>
+
+static int res, *fdp;
+static bool *test_destructorsp;
+
+static void __attribute__((constructor))
+con (void)
+{
+ res = TEST_STACK_ALIGN () ? -1 : 1;
+}
+
+void
+in_dso (int *result, bool *test_destructors, int *fd)
+{
+ if (!res)
+ {
+ puts ("constructor has not been run");
+ *result = 1;
+ }
+ else if (res != 1)
+ {
+ puts ("constructor has been run without sufficient alignment");
+ *result = 1;
+ }
+
+ test_destructorsp = test_destructors;
+ fdp = fd;
+}
+
+static void __attribute__((destructor))
+des (void)
+{
+ if (!test_destructorsp || !*test_destructorsp)
+ return;
+
+ char c = TEST_STACK_ALIGN () ? 'D' : 'C';
+ write (*fdp, &c, 1);
+}
diff --git a/elf/tst-audit1.c b/elf/tst-audit1.c
new file mode 100644
index 0000000000..63656b4ee9
--- /dev/null
+++ b/elf/tst-audit1.c
@@ -0,0 +1 @@
+#include "../io/pwd.c"
diff --git a/elf/tst-auditmod1.c b/elf/tst-auditmod1.c
new file mode 100644
index 0000000000..9b07588288
--- /dev/null
+++ b/elf/tst-auditmod1.c
@@ -0,0 +1,190 @@
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <bits/wordsize.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__
+# define pltenter la_i86_gnu_pltenter
+# define pltexit la_i86_gnu_pltexit
+# define La_regs La_i86_regs
+# define La_retval La_i86_retval
+# define int_retval lrv_eax
+#elif defined __x86_64__
+# define pltenter la_x86_64_gnu_pltenter
+# define pltexit la_x86_64_gnu_pltexit
+# define La_regs La_x86_64_regs
+# define La_retval La_x86_64_retval
+# define int_retval lrv_rax
+#elif defined __powerpc__ && __WORDSIZE == 32
+# define pltenter la_ppc32_gnu_pltenter
+# define pltexit la_ppc32_gnu_pltexit
+# define La_regs La_ppc32_regs
+# define La_retval La_ppc32_retval
+# define int_retval lrv_r3
+#elif defined __powerpc__ && __WORDSIZE == 64
+# define pltenter la_ppc64_gnu_pltenter
+# define pltexit la_ppc64_gnu_pltexit
+# define La_regs La_ppc64_regs
+# define La_retval La_ppc64_retval
+# define int_retval lrv_r3
+#elif defined __sh__
+# define pltenter la_sh_gnu_pltenter
+# define pltexit la_sh_gnu_pltexit
+# define La_regs La_sh_regs
+# define La_retval La_sh_retval
+# define int_retval lrv_r0
+#elif defined __mc68000__
+# define pltenter la_m68k_gnu_pltenter
+# define pltexit la_m68k_gnu_pltexit
+# define La_regs La_m68k_regs
+# define La_retval La_m68k_retval
+# define int_retval lrv_d0
+#elif defined __alpha__
+# define pltenter la_alpha_gnu_pltenter
+# define pltexit la_alpha_gnu_pltexit
+# define La_regs La_alpha_regs
+# define La_retval La_alpha_retval
+# define int_retval lrv_r0
+#elif defined __s390__ && __WORDSIZE == 32
+# define pltenter la_s390_32_gnu_pltenter
+# define pltexit la_s390_32_gnu_pltexit
+# define La_regs La_s390_32_regs
+# define La_retval La_s390_32_retval
+# define int_retval lrv_r2
+#elif defined __s390__ && __WORDSIZE == 64
+# define pltenter la_s390_64_gnu_pltenter
+# define pltexit la_s390_64_gnu_pltexit
+# define La_regs La_s390_64_regs
+# define La_retval La_s390_64_retval
+# define int_retval lrv_r2
+#elif defined __ia64__
+# define pltenter la_ia64_gnu_pltenter
+# define pltexit la_ia64_gnu_pltexit
+# define La_regs La_ia64_regs
+# define La_retval La_ia64_retval
+# define int_retval lrv_r8
+#else
+# error "architecture specific code needed"
+#endif
+
+
+ElfW(Addr)
+pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, La_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ printf ("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
+pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const La_regs *inregs, La_retval *outregs,
+ const char *symname)
+{
+ printf ("pltexit: symname=%s, st_value=%#lx, ndx=%u, retval=%tu\n",
+ symname, (long int) sym->st_value, ndx, outregs->int_retval);
+
+ return 0;
+}