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.
This commit is contained in:
Ulrich Drepper 1999-07-24 19:45:13 +00:00
parent 3f38221989
commit fcf70d4114
8 changed files with 218 additions and 80 deletions

View File

@ -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> 1999-07-24 Andreas Jaeger <aj@arthur.rhein-neckar.de>
* elf/rtld.c (dl_main): Adopt to changed _dl_lookup_symbol * elf/rtld.c (dl_main): Adopt to changed _dl_lookup_symbol

View File

@ -1,5 +1,5 @@
/* Call the termination functions of loaded shared objects. /* 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or 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) for (l = _dl_loaded; l; l = l->l_next)
if (l->l_init_called) if (l->l_init_called)
{ {
if (l->l_info[DT_FINI] && int first = 1;
!(l->l_name[0] == '\0' && l->l_type == lt_executable))
/* 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. */ /* 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);
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 && first)
_dl_debug_message (1, "\ncalling fini: ", _dl_debug_message (1, "\ncalling fini: ",
l->l_name[0] ? l->l_name : _dl_argv[0], l->l_name[0] ? l->l_name : _dl_argv[0],
"\n\n", NULL); "\n\n", NULL);
(*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); (*(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;
} }
} }

View File

@ -1,5 +1,5 @@
/* Return the next shared object initializer function not yet run. /* 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -38,27 +38,28 @@ _dl_init_next (struct r_scope_elem *searchlist)
while (i-- > 0) while (i-- > 0)
{ {
struct link_map *l = searchlist->r_list[i]; struct link_map *l = searchlist->r_list[i];
ElfW(Addr) *array;
if (l->l_init_called) if (l->l_init_called)
/* This object is all done. */ /* This object is all done. */
continue; 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; l->l_init_called = 1;
continue; continue;
} }
if (l->l_info[DT_INIT] /* Account for running next constructor. */
&& (l->l_name[0] != '\0' || l->l_type != lt_executable)) ++l->l_runcount;
{
/* Run this object's initializer. */
l->l_init_running = 1;
if (l->l_runcount == 1)
{
/* Try running the DT_INIT constructor. */
if (l->l_info[DT_INIT])
{
/* Print a debug message if wanted. */ /* Print a debug message if wanted. */
if (_dl_debug_impcalls) if (_dl_debug_impcalls)
_dl_debug_message (1, "\ncalling init: ", _dl_debug_message (1, "\ncalling init: ",
@ -68,9 +69,28 @@ _dl_init_next (struct r_scope_elem *searchlist)
return l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr; return l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr;
} }
/* No initializer for this object. /* No DT_INIT, so go on with the array. */
Mark it so we will skip it in the future. */ ++l->l_runcount;
}
if (l->l_runcount > l->l_initcount)
{
/* That were all of the constructors. */
l->l_runcount = 0;
l->l_init_called = 1; l->l_init_called = 1;
continue;
}
/* 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 */
} }

View File

@ -35,7 +35,7 @@
/* On some systems, no flag bits are given to specify file mapping. */ /* On some systems, no flag bits are given to specify file mapping. */
#ifndef MAP_FILE #ifndef MAP_FILE
#define MAP_FILE 0 # define MAP_FILE 0
#endif #endif
/* The right way to map in the shared library files is MAP_COPY, which /* 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 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. */ from the new version after starting with pages from the old version. */
#ifndef MAP_COPY #ifndef MAP_COPY
#define MAP_COPY MAP_PRIVATE # define MAP_COPY MAP_PRIVATE
#endif #endif
/* Some systems link their relocatable objects for another base address /* 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 This results in a more efficient address space usage. Defaults to
zero for almost all systems. */ zero for almost all systems. */
#ifndef MAP_BASE_ADDR #ifndef MAP_BASE_ADDR
#define MAP_BASE_ADDR(l) 0 # define MAP_BASE_ADDR(l) 0
#endif #endif
#include <endian.h> #include <endian.h>
#if BYTE_ORDER == BIG_ENDIAN #if BYTE_ORDER == BIG_ENDIAN
#define byteorder ELFDATA2MSB # define byteorder ELFDATA2MSB
#define byteorder_name "big-endian" # define byteorder_name "big-endian"
#elif BYTE_ORDER == LITTLE_ENDIAN #elif BYTE_ORDER == LITTLE_ENDIAN
#define byteorder ELFDATA2LSB # define byteorder ELFDATA2LSB
#define byteorder_name "little-endian" # define byteorder_name "little-endian"
#else #else
#error "Unknown BYTE_ORDER " BYTE_ORDER # error "Unknown BYTE_ORDER " BYTE_ORDER
#define byteorder ELFDATANONE # define byteorder ELFDATANONE
#endif #endif
#define STRING(x) __STRING (x) #define STRING(x) __STRING (x)
#ifdef MAP_ANON #ifdef MAP_ANON
/* The fd is not examined when using MAP_ANON. */ /* The fd is not examined when using MAP_ANON. */
#define ANONFD -1 # define ANONFD -1
#else #else
int _dl_zerofd = -1; int _dl_zerofd = -1;
#define ANONFD _dl_zerofd # define ANONFD _dl_zerofd
#endif #endif
/* Handle situations where we have a preferred location in memory for /* Handle situations where we have a preferred location in memory for
@ -87,10 +87,10 @@ int _dl_zerofd = -1;
ELF_PREFERRED_ADDRESS_DATA; ELF_PREFERRED_ADDRESS_DATA;
#endif #endif
#ifndef ELF_PREFERRED_ADDRESS #ifndef ELF_PREFERRED_ADDRESS
#define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref) # define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref)
#endif #endif
#ifndef ELF_FIXED_ADDRESS #ifndef ELF_FIXED_ADDRESS
#define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0) # define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
#endif #endif
size_t _dl_pagesize; 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 ** static struct r_search_path_elem **
internal_function 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. */ /* Make a copy we can work with. */
const char *where = l->l_name; 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; struct r_search_path_elem **result;
size_t nelems; 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) if (_dl_inhibit_rpath != NULL && !__libc_enable_secure)
{ {
const char *found = strstr (_dl_inhibit_rpath, where); 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] == ':') if ((found == _dl_inhibit_rpath || found[-1] == ':')
&& (found[len] == '\0' || found[len] == ':')) && (found[len] == '\0' || found[len] == ':'))
{ {
/* This object is on the list of objects for which the RPATH /* This object is on the list of objects for which the
must not be used. */ RUNPATH and RPATH must not be used. */
result = (struct r_search_path_elem **) result = (struct r_search_path_elem **)
malloc (sizeof (*result)); malloc (sizeof (*result));
if (result == NULL) if (result == NULL)
@ -473,7 +474,7 @@ decompose_rpath (const char *rpath, struct link_map *l)
string tokens. */ string tokens. */
copy = expand_dynamic_string_token (l, rpath); copy = expand_dynamic_string_token (l, rpath);
if (copy == NULL) 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. */ /* Count the number of necessary elements in the result array. */
nelems = 0; nelems = 0;
@ -488,7 +489,7 @@ decompose_rpath (const char *rpath, struct link_map *l)
if (result == NULL) if (result == NULL)
_dl_signal_error (ENOMEM, NULL, "cannot create cache for search path"); _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,16 +571,33 @@ _dl_init_paths (const char *llp)
{ {
assert (l->l_type != lt_loaded); assert (l->l_type != lt_loaded);
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_runpath_dirs = NULL;
if (l->l_info[DT_RPATH]) if (l->l_info[DT_RPATH])
/* Allocate room for the search path and fill in information /* Allocate room for the search path and fill in information
from RPATH. */ from RPATH. */
l->l_rpath_dirs = l->l_rpath_dirs =
decompose_rpath ((const void *) (l->l_info[DT_STRTAB]->d_un.d_ptr decompose_rpath ((const void *) (l->l_info[DT_STRTAB]->d_un.d_ptr
+ l->l_info[DT_RPATH]->d_un.d_val), + l->l_info[DT_RPATH]->d_un.d_val),
l); l, "RPATH");
else else
l->l_rpath_dirs = NULL; l->l_rpath_dirs = NULL;
} }
}
#endif /* PIC */ #endif /* PIC */
if (llp != NULL && *llp != '\0') if (llp != NULL && *llp != '\0')
@ -1036,7 +1054,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
" phnum: ", buf3, "\n\n", NULL); " 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]) if (l->l_info[DT_HASH])
_dl_setup_hash (l); _dl_setup_hash (l);
@ -1292,6 +1310,10 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
fd = -1; fd = -1;
/* 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 /* First try the DT_RPATH of the dependent object that caused NAME
to be loaded. Then that object's dependent, and on up. */ to be loaded. Then that object's dependent, and on up. */
for (l = loader; fd == -1 && l; l = l->l_loader) for (l = loader; fd == -1 && l; l = l->l_loader)
@ -1303,7 +1325,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
size_t ptrval = (l->l_info[DT_STRTAB]->d_un.d_ptr size_t ptrval = (l->l_info[DT_STRTAB]->d_un.d_ptr
+ l->l_info[DT_RPATH]->d_un.d_val); + l->l_info[DT_RPATH]->d_un.d_val);
l->l_rpath_dirs = l->l_rpath_dirs =
decompose_rpath ((const char *) ptrval, l); decompose_rpath ((const char *) ptrval, l, "RPATH");
} }
if (l->l_rpath_dirs != NULL) if (l->l_rpath_dirs != NULL)
@ -1311,16 +1333,36 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
&realname); &realname);
} }
/* If dynamically linked, try the DT_RPATH of the executable itself. */ /* If dynamically linked, try the DT_RPATH of the executable
itself. */
l = _dl_loaded; l = _dl_loaded;
if (fd == -1 && l && l->l_type != lt_loaded && l != loader if (fd == -1 && l && l->l_type != lt_loaded && l != loader
&& l->l_rpath_dirs != NULL) && l->l_rpath_dirs != NULL)
fd = open_path (name, namelen, preloaded, l->l_rpath_dirs, &realname); fd = open_path (name, namelen, preloaded, l->l_rpath_dirs,
&realname);
}
/* Try the LD_LIBRARY_PATH environment variable. */ /* Try the LD_LIBRARY_PATH environment variable. */
if (fd == -1 && env_path_list != NULL) if (fd == -1 && env_path_list != NULL)
fd = open_path (name, namelen, preloaded, env_path_list, &realname); 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) if (fd == -1)
{ {
/* Check the list of libraries in the file /etc/ld.so.cache, /* Check the list of libraries in the file /etc/ld.so.cache,

View File

@ -51,7 +51,8 @@ struct r_search_path *_dl_search_paths;
/* We never do profiling. */ /* We never do profiling. */
const char *_dl_profile; 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; const char *_dl_inhibit_rpath;
/* The map for the object we will profile. */ /* The map for the object we will profile. */

View File

@ -34,13 +34,18 @@ extern int _dl_verbose __attribute__ ((unused));
/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */ /* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
static inline void __attribute__ ((unused)) static inline void __attribute__ ((unused))
elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Addr) l_addr, elf_get_dynamic_info (struct link_map *l)
ElfW(Dyn) *info[DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM
+ DT_EXTRANUM])
{ {
ElfW(Dyn) *dyn = l->l_ld;
ElfW(Addr) l_addr;
ElfW(Dyn) **info;
if (! dyn) if (! dyn)
return; return;
l_addr = l->l_addr;
info = l->l_info;
while (dyn->d_tag != DT_NULL) while (dyn->d_tag != DT_NULL)
{ {
if (dyn->d_tag < DT_NUM) 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) if (flags & DF_BIND_NOW)
info[DT_BIND_NOW] = info[DT_FLAGS]; 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 #ifdef RESOLVE

View File

@ -163,7 +163,6 @@ struct link_map
} l_type:2; } l_type:2;
unsigned int l_relocated:1; /* Nonzero if object's relocations done. */ 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_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_global:1; /* Nonzero if object in _dl_global_scope. */
unsigned int l_reserved:2; /* Reserved for internal use. */ 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. */ /* Nonzero if the data structure pointed to by `l_phdr' is allocated. */
int l_phdr_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 */ #endif /* link.h */

View File

@ -448,7 +448,8 @@ of this helper program; chances are you did not intend to run this program.\n\
object we get handle\n\ object we get handle\n\
--library-path PATH use given PATH instead of content of the environment\n\ --library-path PATH use given PATH instead of content of the environment\n\
variable LD_LIBRARY_PATH\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); NULL);
++_dl_skip_args; ++_dl_skip_args;