aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--elf/dl-fini.c42
-rw-r--r--elf/dl-init.c60
-rw-r--r--elf/dl-load.c140
-rw-r--r--elf/dl-support.c3
-rw-r--r--elf/dynamic-link.h21
-rw-r--r--elf/link.h11
-rw-r--r--elf/rtld.c3
8 files changed, 219 insertions, 81 deletions
diff --git a/ChangeLog b/ChangeLog
index e2a0dc6..1a124aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+1999-07-24 Ulrich Drepper <drepper@cygnus.com>
+
+ * elf/dl-fini.c: Handle DT_FINI_ARRAY.
+ * elf/link.h (struct link_map): Remove l_init_running. Add l_runcount
+ and l_initcount.
+ * elf/dl-init.c: Handle DT_INIT_ARRAY.
+ * elf/dynamic-link.h: Change parameters. Now only get link_map
+ pointer. Calculate l_initcount.
+
+ * elf/link.h (struct link_map): Add l_runpath_dirs.
+ * elf/dynamic-link.h: If RUNPATH is given, set RPATH to NULL.
+ * elf/dl-load.c: Pretty print.
+ (decompose_rpath): Take new parameter with info from where the path
+ comes. Pass it the fillin_rpath.
+ (_dl_init_paths): Initialize l_runpath_dirs.
+ (_dl_map_object): Don't search using RPATHs if object has RUNPATH.
+ Search using RUNPATH after LD_LIBRARY_PATH.
+ * elf/dl-support.c: Adjust comment.
+ * elf/rtld.c: Adjust help message.
+
1999-07-24 Andreas Jaeger <aj@arthur.rhein-neckar.de>
* elf/rtld.c (dl_main): Adopt to changed _dl_lookup_symbol
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index 4b578f8..3f2d625 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, 1996, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1998, 1999 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
@@ -28,18 +28,48 @@ _dl_fini (void)
for (l = _dl_loaded; l; l = l->l_next)
if (l->l_init_called)
{
- if (l->l_info[DT_FINI] &&
- !(l->l_name[0] == '\0' && l->l_type == lt_executable))
+ int first = 1;
+
+ /* 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;
+
+ /* 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 sz = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
+ / sizeof (ElfW(Addr)));
+ unsigned int cnt;
+
+ for (cnt = 0; cnt < sz; ++cnt)
+ {
+ /* When debugging print a message first. */
+ if (_dl_debug_impcalls && first)
+ _dl_debug_message (1, "\ncalling fini: ",
+ l->l_name[0] ? l->l_name : _dl_argv[0],
+ "\n\n", NULL);
+ first = 0;
+
+ (*(void (*) (void)) (l->l_addr + array[cnt])) ();
+ }
+ }
+
+ /* Next try the old-style destructor. */
+ if (l->l_info[DT_FINI])
{
/* When debugging print a message first. */
- if (_dl_debug_impcalls)
+ if (_dl_debug_impcalls && first)
_dl_debug_message (1, "\ncalling fini: ",
l->l_name[0] ? l->l_name : _dl_argv[0],
"\n\n", NULL);
(*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
}
- /* Make sure nothing happens if we are called twice. */
- l->l_init_called = 0;
}
}
diff --git a/elf/dl-init.c b/elf/dl-init.c
index 64aa1ce..c4b1e22 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -1,5 +1,5 @@
/* Return the next shared object initializer function not yet run.
- Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1998, 1999 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
@@ -38,39 +38,59 @@ _dl_init_next (struct r_scope_elem *searchlist)
while (i-- > 0)
{
struct link_map *l = searchlist->r_list[i];
+ ElfW(Addr) *array;
if (l->l_init_called)
/* This object is all done. */
continue;
- if (l->l_init_running)
+ /* Check for object which constructors we do not run here.
+ XXX Maybe this should be pre-computed, but where? */
+ if (l->l_name[0] == '\0' && l->l_type == lt_executable)
{
- /* This object's initializer was just running.
- Now mark it as having run, so this object
- will be skipped in the future. */
- l->l_init_running = 0;
l->l_init_called = 1;
continue;
}
- if (l->l_info[DT_INIT]
- && (l->l_name[0] != '\0' || l->l_type != lt_executable))
- {
- /* Run this object's initializer. */
- l->l_init_running = 1;
+ /* Account for running next constructor. */
+ ++l->l_runcount;
- /* Print a debug message if wanted. */
- if (_dl_debug_impcalls)
- _dl_debug_message (1, "\ncalling init: ",
- l->l_name[0] ? l->l_name : _dl_argv[0],
- "\n\n", NULL);
+ if (l->l_runcount == 1)
+ {
+ /* Try running the DT_INIT constructor. */
+ if (l->l_info[DT_INIT])
+ {
+ /* Print a debug message if wanted. */
+ if (_dl_debug_impcalls)
+ _dl_debug_message (1, "\ncalling init: ",
+ l->l_name[0] ? l->l_name : _dl_argv[0],
+ "\n\n", NULL);
+
+ return l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr;
+ }
+
+ /* No DT_INIT, so go on with the array. */
+ ++l->l_runcount;
+ }
- return l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr;
+ if (l->l_runcount > l->l_initcount)
+ {
+ /* That were all of the constructors. */
+ l->l_runcount = 0;
+ l->l_init_called = 1;
+ continue;
}
- /* No initializer for this object.
- Mark it so we will skip it in the future. */
- l->l_init_called = 1;
+ /* Print a debug message if wanted. */
+ if (_dl_debug_impcalls && l->l_info[DT_INIT] == NULL
+ && l->l_runcount == 2)
+ _dl_debug_message (1, "\ncalling init: ",
+ l->l_name[0] ? l->l_name : _dl_argv[0],
+ "\n\n", NULL);
+
+ array = (ElfW(Addr) *) l->l_info[DT_INIT_ARRAY]->d_un.d_ptr;
+ return l->l_addr + array[l->l_runcount - 2];
+ /* NOTREACHED */
}
diff --git a/elf/dl-load.c b/elf/dl-load.c
index c1194ce..e8b42a9 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -35,7 +35,7 @@
/* On some systems, no flag bits are given to specify file mapping. */
#ifndef MAP_FILE
-#define MAP_FILE 0
+# define MAP_FILE 0
#endif
/* The right way to map in the shared library files is MAP_COPY, which
@@ -46,7 +46,7 @@
means if the file is overwritten, we may at some point get some pages
from the new version after starting with pages from the old version. */
#ifndef MAP_COPY
-#define MAP_COPY MAP_PRIVATE
+# define MAP_COPY MAP_PRIVATE
#endif
/* Some systems link their relocatable objects for another base address
@@ -55,30 +55,30 @@
This results in a more efficient address space usage. Defaults to
zero for almost all systems. */
#ifndef MAP_BASE_ADDR
-#define MAP_BASE_ADDR(l) 0
+# define MAP_BASE_ADDR(l) 0
#endif
#include <endian.h>
#if BYTE_ORDER == BIG_ENDIAN
-#define byteorder ELFDATA2MSB
-#define byteorder_name "big-endian"
+# define byteorder ELFDATA2MSB
+# define byteorder_name "big-endian"
#elif BYTE_ORDER == LITTLE_ENDIAN
-#define byteorder ELFDATA2LSB
-#define byteorder_name "little-endian"
+# define byteorder ELFDATA2LSB
+# define byteorder_name "little-endian"
#else
-#error "Unknown BYTE_ORDER " BYTE_ORDER
-#define byteorder ELFDATANONE
+# error "Unknown BYTE_ORDER " BYTE_ORDER
+# define byteorder ELFDATANONE
#endif
#define STRING(x) __STRING (x)
#ifdef MAP_ANON
/* The fd is not examined when using MAP_ANON. */
-#define ANONFD -1
+# define ANONFD -1
#else
int _dl_zerofd = -1;
-#define ANONFD _dl_zerofd
+# define ANONFD _dl_zerofd
#endif
/* Handle situations where we have a preferred location in memory for
@@ -87,10 +87,10 @@ int _dl_zerofd = -1;
ELF_PREFERRED_ADDRESS_DATA;
#endif
#ifndef ELF_PREFERRED_ADDRESS
-#define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref)
+# define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref)
#endif
#ifndef ELF_FIXED_ADDRESS
-#define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
+# define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
#endif
size_t _dl_pagesize;
@@ -436,7 +436,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
static struct r_search_path_elem **
internal_function
-decompose_rpath (const char *rpath, struct link_map *l)
+decompose_rpath (const char *rpath, struct link_map *l, const char *what)
{
/* Make a copy we can work with. */
const char *where = l->l_name;
@@ -445,7 +445,8 @@ decompose_rpath (const char *rpath, struct link_map *l)
struct r_search_path_elem **result;
size_t nelems;
- /* First see whether we must forget the RPATH from this object. */
+ /* First see whether we must forget the RUNPATH and RPATH from this
+ object. */
if (_dl_inhibit_rpath != NULL && !__libc_enable_secure)
{
const char *found = strstr (_dl_inhibit_rpath, where);
@@ -455,8 +456,8 @@ decompose_rpath (const char *rpath, struct link_map *l)
if ((found == _dl_inhibit_rpath || found[-1] == ':')
&& (found[len] == '\0' || found[len] == ':'))
{
- /* This object is on the list of objects for which the RPATH
- must not be used. */
+ /* This object is on the list of objects for which the
+ RUNPATH and RPATH must not be used. */
result = (struct r_search_path_elem **)
malloc (sizeof (*result));
if (result == NULL)
@@ -473,7 +474,7 @@ decompose_rpath (const char *rpath, struct link_map *l)
string tokens. */
copy = expand_dynamic_string_token (l, rpath);
if (copy == NULL)
- _dl_signal_error (ENOMEM, NULL, "cannot create RPATH copy");
+ _dl_signal_error (ENOMEM, NULL, "cannot create RUNPATH/RPATH copy");
/* Count the number of necessary elements in the result array. */
nelems = 0;
@@ -488,7 +489,7 @@ decompose_rpath (const char *rpath, struct link_map *l)
if (result == NULL)
_dl_signal_error (ENOMEM, NULL, "cannot create cache for search path");
- return fillin_rpath (copy, result, ":", 0, "RPATH", where);
+ return fillin_rpath (copy, result, ":", 0, what, where);
}
@@ -570,15 +571,32 @@ _dl_init_paths (const char *llp)
{
assert (l->l_type != lt_loaded);
- if (l->l_info[DT_RPATH])
- /* Allocate room for the search path and fill in information
- from RPATH. */
- l->l_rpath_dirs =
- decompose_rpath ((const void *) (l->l_info[DT_STRTAB]->d_un.d_ptr
- + l->l_info[DT_RPATH]->d_un.d_val),
- l);
+ if (l->l_info[DT_RUNPATH])
+ {
+ /* Allocate room for the search path and fill in information
+ from RUNPATH. */
+ l->l_runpath_dirs =
+ decompose_rpath ((const void *) (l->l_info[DT_STRTAB]->d_un.d_ptr
+ + l->l_info[DT_RUNPATH]->d_un.d_val),
+ l, "RUNPATH");
+
+ /* The RPATH is ignored. */
+ l->l_rpath_dirs = NULL;
+ }
else
- l->l_rpath_dirs = NULL;
+ {
+ l->l_runpath_dirs = NULL;
+
+ if (l->l_info[DT_RPATH])
+ /* Allocate room for the search path and fill in information
+ from RPATH. */
+ l->l_rpath_dirs =
+ decompose_rpath ((const void *) (l->l_info[DT_STRTAB]->d_un.d_ptr
+ + l->l_info[DT_RPATH]->d_un.d_val),
+ l, "RPATH");
+ else
+ l->l_rpath_dirs = NULL;
+ }
}
#endif /* PIC */
@@ -1036,7 +1054,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
" phnum: ", buf3, "\n\n", NULL);
}
- elf_get_dynamic_info (l->l_ld, l->l_addr, l->l_info);
+ elf_get_dynamic_info (l);
if (l->l_info[DT_HASH])
_dl_setup_hash (l);
@@ -1292,35 +1310,59 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
fd = -1;
- /* First try the DT_RPATH of the dependent object that caused NAME
- to be loaded. Then that object's dependent, and on up. */
- for (l = loader; fd == -1 && l; l = l->l_loader)
- if (l->l_info[DT_RPATH])
- {
- /* Make sure the cache information is available. */
- if (l->l_rpath_dirs == NULL)
+ /* When the object has the RUNPATH information we don't use any
+ RPATHs. */
+ if (loader != NULL && loader->l_info[DT_RUNPATH] == NULL)
+ {
+ /* First try the DT_RPATH of the dependent object that caused NAME
+ to be loaded. Then that object's dependent, and on up. */
+ for (l = loader; fd == -1 && l; l = l->l_loader)
+ if (l->l_info[DT_RPATH])
{
- size_t ptrval = (l->l_info[DT_STRTAB]->d_un.d_ptr
- + l->l_info[DT_RPATH]->d_un.d_val);
- l->l_rpath_dirs =
- decompose_rpath ((const char *) ptrval, l);
- }
+ /* Make sure the cache information is available. */
+ if (l->l_rpath_dirs == NULL)
+ {
+ size_t ptrval = (l->l_info[DT_STRTAB]->d_un.d_ptr
+ + l->l_info[DT_RPATH]->d_un.d_val);
+ l->l_rpath_dirs =
+ decompose_rpath ((const char *) ptrval, l, "RPATH");
+ }
- if (l->l_rpath_dirs != NULL)
- fd = open_path (name, namelen, preloaded, l->l_rpath_dirs,
- &realname);
- }
+ if (l->l_rpath_dirs != NULL)
+ fd = open_path (name, namelen, preloaded, l->l_rpath_dirs,
+ &realname);
+ }
- /* If dynamically linked, try the DT_RPATH of the executable itself. */
- l = _dl_loaded;
- if (fd == -1 && l && l->l_type != lt_loaded && l != loader
- && l->l_rpath_dirs != NULL)
- fd = open_path (name, namelen, preloaded, l->l_rpath_dirs, &realname);
+ /* If dynamically linked, try the DT_RPATH of the executable
+ itself. */
+ l = _dl_loaded;
+ if (fd == -1 && l && l->l_type != lt_loaded && l != loader
+ && l->l_rpath_dirs != NULL)
+ fd = open_path (name, namelen, preloaded, l->l_rpath_dirs,
+ &realname);
+ }
/* Try the LD_LIBRARY_PATH environment variable. */
if (fd == -1 && env_path_list != NULL)
fd = open_path (name, namelen, preloaded, env_path_list, &realname);
+ /* Look at the RUNPATH informaiton for this binary. */
+ if (loader != NULL && loader->l_info[DT_RUNPATH])
+ {
+ /* Make sure the cache information is available. */
+ if (loader->l_runpath_dirs == NULL)
+ {
+ size_t ptrval = (loader->l_info[DT_STRTAB]->d_un.d_ptr
+ + loader->l_info[DT_RUNPATH]->d_un.d_val);
+ loader->l_runpath_dirs =
+ decompose_rpath ((const char *) ptrval, loader, "RUNPATH");
+ }
+
+ if (loader->l_runpath_dirs != NULL)
+ fd = open_path (name, namelen, preloaded, loader->l_runpath_dirs,
+ &realname);
+ }
+
if (fd == -1)
{
/* Check the list of libraries in the file /etc/ld.so.cache,
diff --git a/elf/dl-support.c b/elf/dl-support.c
index b3ff0c6..edf5874 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -51,7 +51,8 @@ struct r_search_path *_dl_search_paths;
/* We never do profiling. */
const char *_dl_profile;
-/* Names of shared object for which the RPATHs should be ignored. */
+/* Names of shared object for which the RUNPATHs and RPATHs should be
+ ignored. */
const char *_dl_inhibit_rpath;
/* The map for the object we will profile. */
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index 59a6001..bdd297e 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -34,13 +34,18 @@ extern int _dl_verbose __attribute__ ((unused));
/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
static inline void __attribute__ ((unused))
-elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Addr) l_addr,
- ElfW(Dyn) *info[DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM
- + DT_EXTRANUM])
+elf_get_dynamic_info (struct link_map *l)
{
+ ElfW(Dyn) *dyn = l->l_ld;
+ ElfW(Addr) l_addr;
+ ElfW(Dyn) **info;
+
if (! dyn)
return;
+ l_addr = l->l_addr;
+ info = l->l_info;
+
while (dyn->d_tag != DT_NULL)
{
if (dyn->d_tag < DT_NUM)
@@ -106,6 +111,16 @@ elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Addr) l_addr,
if (flags & DF_BIND_NOW)
info[DT_BIND_NOW] = info[DT_FLAGS];
}
+ /* Determine how many constructors there are. */
+ if (info[DT_INIT_ARRAY] != NULL)
+ info[DT_INIT_ARRAY]->d_un.d_ptr += l_addr;
+ l->l_initcount = 1 + (info[DT_INIT_ARRAY]
+ ? (info[DT_INIT_ARRAYSZ]->d_un.d_val
+ / sizeof (ElfW(Addr)))
+ : 0);
+ if (info[DT_RUNPATH] != NULL)
+ /* If both RUNPATH and RPATH are given, the latter is ignored. */
+ info[DT_RPATH] = NULL;
}
#ifdef RESOLVE
diff --git a/elf/link.h b/elf/link.h
index 5e9d7a8..cda739d 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -163,7 +163,6 @@ struct link_map
} l_type:2;
unsigned int l_relocated:1; /* Nonzero if object's relocations done. */
unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */
- unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs. */
unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */
unsigned int l_reserved:2; /* Reserved for internal use. */
@@ -202,6 +201,16 @@ struct link_map
/* Nonzero if the data structure pointed to by `l_phdr' is allocated. */
int l_phdr_allocated;
+
+ /* Counter for running constructors and destructors. */
+ unsigned int l_runcount;
+
+ /* Number of constructors. We compute this during loading to avoid
+ duplication of this during the possibly many calls to _dl_init_next. */
+ unsigned int l_initcount;
+
+ /* Collected information about own RUNPATH directories. */
+ struct r_search_path_elem **l_runpath_dirs;
};
#endif /* link.h */
diff --git a/elf/rtld.c b/elf/rtld.c
index 808cc9d..6029380 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -448,7 +448,8 @@ of this helper program; chances are you did not intend to run this program.\n\
object we get handle\n\
--library-path PATH use given PATH instead of content of the environment\n\
variable LD_LIBRARY_PATH\n\
- --inhibit-rpath LIST ignore RPATH information in object names in LIST\n",
+ --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\
+ in LIST\n",
NULL);
++_dl_skip_args;