From fcf70d4114db9ff7923f5dfeb3fea6e2d623e5c2 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 24 Jul 1999 19:45:13 +0000 Subject: [PATCH] Update. 1999-07-24 Ulrich Drepper * 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. --- ChangeLog | 20 +++++++ elf/dl-fini.c | 42 ++++++++++++-- elf/dl-init.c | 58 +++++++++++++------ elf/dl-load.c | 140 +++++++++++++++++++++++++++++---------------- elf/dl-support.c | 3 +- elf/dynamic-link.h | 21 ++++++- elf/link.h | 11 +++- elf/rtld.c | 3 +- 8 files changed, 218 insertions(+), 80 deletions(-) diff --git a/ChangeLog b/ChangeLog index e2a0dc6694..1a124aab1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +1999-07-24 Ulrich Drepper + + * 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 * elf/rtld.c (dl_main): Adopt to changed _dl_lookup_symbol diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 4b578f8bd7..3f2d625652 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 64aa1ce0bf..c4b1e22152 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)) + /* Account for running next constructor. */ + ++l->l_runcount; + + if (l->l_runcount == 1) { - /* Run this object's initializer. */ - l->l_init_running = 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); - /* 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; + } - 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; } - /* No initializer for this object. - Mark it so we will skip it in the future. */ - l->l_init_called = 1; + if (l->l_runcount > l->l_initcount) + { + /* That were all of the constructors. */ + l->l_runcount = 0; + 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 */ } diff --git a/elf/dl-load.c b/elf/dl-load.c index c1194ce580..e8b42a96e2 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 #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 b3ff0c6857..edf58742be 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 59a6001069..bdd297e24b 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 5e9d7a8868..cda739df99 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 808cc9df96..60293800c5 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;