diff options
-rw-r--r-- | ChangeLog | 21 | ||||
-rw-r--r-- | bits/dlfcn.h | 12 | ||||
-rw-r--r-- | elf/dl-close.c | 8 | ||||
-rw-r--r-- | elf/dl-deps.c | 6 | ||||
-rw-r--r-- | elf/dl-load.c | 11 | ||||
-rw-r--r-- | elf/dl-open.c | 17 | ||||
-rw-r--r-- | elf/dynamic-link.h | 2 | ||||
-rw-r--r-- | elf/elf.h | 19 | ||||
-rw-r--r-- | elf/noload.c | 70 | ||||
-rw-r--r-- | elf/rtld.c | 10 | ||||
-rw-r--r-- | include/link.h | 4 | ||||
-rw-r--r-- | sysdeps/generic/bits/dlfcn.h | 12 | ||||
-rw-r--r-- | sysdeps/generic/ldsodefs.h | 2 | ||||
-rw-r--r-- | sysdeps/mips/bits/dlfcn.h | 12 |
14 files changed, 179 insertions, 27 deletions
@@ -1,5 +1,26 @@ 2000-07-20 Ulrich Drepper <drepper@redhat.com> + * elf/elf.h: Add various DF_1_*, DTF_1_*, and DF_P1_* entries. + * elf/dl-close.c (_dl_close): Don't close an object if it is marked + with nodelete. + * elf/dl-open.c (dl_open_worker): Pass RTLD_NOLOAD as new parameter + to _dl_map_object. Return immediately if no object loaded. + Set DF_1_NODELETE bit in l_flags_1 if RTLD_NODELETE was passed. + * elf/dynamic-link.h (elf_get_dynamic_info): Copy DT_FLAGS_1 entry + if it exists into l_flags_1 word. + * elf/dl-load.c (_dl_map_object_from_fd): Take no parameter and use + it to determine whether loading is wanted or not. + (_dl_map_object): Likewise. + Call _dl_map_object_from_fd with new parameter. + * sysdeps/generic/ldsodefs.h: Update prototype. + * elf/dl-deps.c: Add new parameter to _dl_map_object calls. + * elf/rtld.c: Likewise. + * elf/Makefile (tests): Add noload. Add rules to generate noload. + * elf/noload.c: New file. + * include/link.h (struct link_map): Add l_feature_1 and l_flags_1. + * sysdeps/generic/bits/dlfcn.h: Define RTLD_NOLOAD and RTLD_NODELETE. + * sysdeps/mips/bits/dlfcn.h: Likewise. + * libio/Makefile (tests): Add tst_wprintf2. (tst_wprintf2-ARGS): Define. * libio/tst_wprintf2.c: New file. diff --git a/bits/dlfcn.h b/bits/dlfcn.h index 99d5448..0039eda 100644 --- a/bits/dlfcn.h +++ b/bits/dlfcn.h @@ -22,20 +22,24 @@ #endif /* The MODE argument to `dlopen' contains one of the following: */ -#define RTLD_LAZY 0x001 /* Lazy function call binding. */ -#define RTLD_NOW 0x002 /* Immediate function call binding. */ -#define RTLD_BINDING_MASK 0x3 /* Mask of binding time value. */ +#define RTLD_LAZY 0x00001 /* Lazy function call binding. */ +#define RTLD_NOW 0x00002 /* Immediate function call binding. */ +#define RTLD_BINDING_MASK 0x3 /* Mask of binding time value. */ +#define RTLD_NOLOAD 0x00004 /* Do not load the object. */ /* If the following bit is set in the MODE argument to `dlopen', the symbols of the loaded object and its dependencies are made visible as if the object were linked directly into the program. */ -#define RTLD_GLOBAL 0x100 +#define RTLD_GLOBAL 0x00100 /* Unix98 demands the following flag which is the inverse to RTLD_GLOBAL. The implementation does this by default and so we can define the value to zero. */ #define RTLD_LOCAL 0 +/* Do not delete object when closed. */ +#define RTLD_NODELETE 0x01000 + #ifdef __USE_GNU /* To support profiling of shared objects it is a good idea to call the function found using `dlsym' using the following macro since diff --git a/elf/dl-close.c b/elf/dl-close.c index ec563ed..99d52d0 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -48,6 +48,11 @@ _dl_close (void *_map) unsigned int nrellist; unsigned int i; + /* First see whether we can remove the object at all. */ + if (map->l_flags_1 & DF_1_NODELETE) + /* Nope. Do nothing. */ + return; + if (map->l_opencount == 0) _dl_signal_error (0, map->l_name, N_("shared object not open")); @@ -112,7 +117,8 @@ _dl_close (void *_map) points to, the 0th elt being MAP itself. Decrement the reference counts on all the objects MAP depends on. */ for (i = 0; i < nsearchlist; ++i) - --list[i]->l_opencount; + if (! (list[i]->l_flags_1 & DF_1_NODELETE)) + --list[i]->l_opencount; /* Check each element of the search list to see if all references to it are gone. */ diff --git a/elf/dl-deps.c b/elf/dl-deps.c index 1d3779f..5bc048e 100644 --- a/elf/dl-deps.c +++ b/elf/dl-deps.c @@ -67,7 +67,7 @@ openaux (void *a) args->aux = _dl_map_object (args->map, args->name, 0, (args->map->l_type == lt_executable ? lt_library : args->map->l_type), - args->trace_mode); + args->trace_mode, 0); } @@ -232,7 +232,7 @@ _dl_map_object_deps (struct link_map *map, dep = _dl_map_object (l, name, 0, l->l_type == lt_executable ? lt_library : - l->l_type, trace_mode); + l->l_type, trace_mode, 0); /* Add it in any case to the duplicate list. */ newp = alloca (sizeof (struct list)); @@ -316,7 +316,7 @@ _dl_map_object_deps (struct link_map *map, args.aux = _dl_map_object (l, name, 0, (l->l_type == lt_executable ? lt_library : l->l_type), - trace_mode); + trace_mode, 0); } /* The auxiliary object is actually available. diff --git a/elf/dl-load.c b/elf/dl-load.c index 2c506b5..fbf82e2 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -688,7 +688,7 @@ static #endif struct link_map * _dl_map_object_from_fd (const char *name, int fd, char *realname, - struct link_map *loader, int l_type) + struct link_map *loader, int l_type, int noload) { /* This is the expected ELF header. */ #define ELF32_CLASS ELFCLASS32 @@ -752,6 +752,11 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname, return l; } + if (noload) + /* We are not supposed to load the object unless it is already + loaded. So return now. */ + return NULL; + /* Print debugging message. */ if (__builtin_expect (_dl_debug_files, 0)) _dl_debug_message (1, "file=", name, "; generating link map\n", NULL); @@ -1301,7 +1306,7 @@ open_path (const char *name, size_t namelen, int preloaded, struct link_map * internal_function _dl_map_object (struct link_map *loader, const char *name, int preloaded, - int type, int trace_mode) + int type, int trace_mode, int noload) { int fd; char *realname; @@ -1501,5 +1506,5 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded, _dl_signal_error (errno, name, N_("cannot open shared object file")); } - return _dl_map_object_from_fd (name, fd, realname, loader, type); + return _dl_map_object_from_fd (name, fd, realname, loader, type, noload); } diff --git a/elf/dl-open.c b/elf/dl-open.c index 680377b..477ecdf 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -144,7 +144,17 @@ dl_open_worker (void *a) } /* Load the named object. */ - args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0); + args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0, + mode & RTLD_NOLOAD); + + /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is + set and the object is not already loaded. */ + if (new == NULL) + { + assert (mode & RTLD_NOLOAD); + return; + } + if (new->l_searchlist.r_list) /* It was already open. */ return; @@ -279,6 +289,11 @@ dl_open_worker (void *a) /* XXX Do we have to add something to r_dupsearchlist??? --drepper */ } + /* Mark the object as not deletable if the RTLD_NODELETE flags was + passed. */ + if (__builtin_expect (mode & RTLD_NODELETE, 0)) + new->l_flags_1 |= DF_1_NODELETE; + if (_dl_sysdep_start == NULL) /* We must be the static _dl_open in libc.a. A static program that has loaded a dynamic object now has competition. */ diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h index 79e17ed..c6fa3e1 100644 --- a/elf/dynamic-link.h +++ b/elf/dynamic-link.h @@ -114,6 +114,8 @@ elf_get_dynamic_info (struct link_map *l) if (flags & DF_BIND_NOW) info[DT_BIND_NOW] = info[DT_FLAGS]; } + if (info[VERSYMIDX (DT_FLAGS_1)] != NULL) + l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; if (info[DT_RUNPATH] != NULL) /* If both RUNPATH and RPATH are given, the latter is ignored. */ info[DT_RPATH] = NULL; @@ -622,7 +622,7 @@ typedef struct #define DT_PLTPADSZ 0x6ffffdf9 #define DT_MOVEENT 0x6ffffdfa #define DT_MOVESZ 0x6ffffdfb -#define DT_FEATURE_1 0x6ffffdfc +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ #define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting the following DT_* entry. */ #define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ @@ -678,6 +678,23 @@ typedef struct #define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ #define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ #define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 +#define DF_1_CONFALT 0x00002000 +#define DF_1_ENDFILTEE 0x00004000 + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not + generally available. */ /* Version definition sections. */ diff --git a/elf/noload.c b/elf/noload.c new file mode 100644 index 0000000..826427f --- /dev/null +++ b/elf/noload.c @@ -0,0 +1,70 @@ +#include <dlfcn.h> +#include <stdio.h> + +int +main (void) +{ + int result = 0; + + /* First try to load an object which is a dependency. This should + succeed. */ + if (dlopen ("testobj1.so", RTLD_LAZY | RTLD_NOLOAD) == NULL) + { + printf ("cannot open \"testobj1.so\": %s\n", dlerror ()); + result = 1; + } + else + puts ("loading \"testobj1.so\" succeeded, OK"); + + /* Now try loading an object which is not already loaded. */ + if (dlopen ("testobj5.so", RTLD_LAZY | RTLD_NOLOAD) != NULL) + { + puts ("succeeded in loading \"testobj5.so\""); + result = 1; + } + else + { + /* Load the object and run the same test again. */ + void *p; + + puts ("\"testobj5.so\" wasn't loaded and RTLD_NOLOAD prevented it, OK"); + + p = dlopen ("testobj5.so", RTLD_LAZY); + + if (p == NULL) + { + printf ("cannot open \"testobj5.so\" without RTLD_NOLOAD: %s\n", + dlerror ()); + result = 1; + } + else + { + puts ("loading \"testobj5.so\" succeeded, OK"); + + if (dlopen ("testobj5.so", RTLD_LAZY | RTLD_NOLOAD) == NULL) + { + printf ("cannot open \"testobj5.so\": %s\n", dlerror ()); + result = 1; + } + else + puts ("loading \"testobj5.so\" with RTLD_NOLOAD succeeded, OK"); + + if (dlclose (p) != 0) + { + printf ("cannot close \"testobj5.so\": %s\n", dlerror ()); + result = 1; + } + else + puts ("closing \"testobj5.so\" succeeded, OK"); + } + } + + return result; +} + + +int +foo (int a) +{ + return 42 + a; +} @@ -313,7 +313,7 @@ static void map_doit (void *a) { struct map_args *args = (struct map_args *) a; - args->main_map = _dl_map_object (NULL, args->str, 0, lt_library, 0); + args->main_map = _dl_map_object (NULL, args->str, 0, lt_library, 0, 0); } static void @@ -514,7 +514,7 @@ of this helper program; chances are you did not intend to run this program.\n\ else { HP_TIMING_NOW (start); - _dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0); + _dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0, 0); HP_TIMING_NOW (stop); HP_TIMING_DIFF (load_time, start, stop); @@ -694,7 +694,7 @@ of this helper program; chances are you did not intend to run this program.\n\ || strchr (p, '/') == NULL)) { struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1, - lt_library, 0); + lt_library, 0, 0); if (new_map->l_opencount == 1) /* It is no duplicate. */ ++npreloads; @@ -762,7 +762,7 @@ of this helper program; chances are you did not intend to run this program.\n\ if (p[0] != '\0') { struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1, - lt_library, 0); + lt_library, 0, 0); if (new_map->l_opencount == 1) /* It is no duplicate. */ ++npreloads; @@ -773,7 +773,7 @@ of this helper program; chances are you did not intend to run this program.\n\ { char *p = strndupa (problem, file_size - (problem - file)); struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1, - lt_library, 0); + lt_library, 0, 0); if (new_map->l_opencount == 1) /* It is no duplicate. */ ++npreloads; diff --git a/include/link.h b/include/link.h index 38652ca..375d5d1 100644 --- a/include/link.h +++ b/include/link.h @@ -214,6 +214,10 @@ struct link_map unsigned int l_reldepsmax; unsigned int l_reldepsact; struct link_map **l_reldeps; + + /* Various flag words. */ + ElfW(Word) l_feature_1; + ElfW(Word) l_flags_1; }; #endif /* link.h */ diff --git a/sysdeps/generic/bits/dlfcn.h b/sysdeps/generic/bits/dlfcn.h index 99d5448..0039eda 100644 --- a/sysdeps/generic/bits/dlfcn.h +++ b/sysdeps/generic/bits/dlfcn.h @@ -22,20 +22,24 @@ #endif /* The MODE argument to `dlopen' contains one of the following: */ -#define RTLD_LAZY 0x001 /* Lazy function call binding. */ -#define RTLD_NOW 0x002 /* Immediate function call binding. */ -#define RTLD_BINDING_MASK 0x3 /* Mask of binding time value. */ +#define RTLD_LAZY 0x00001 /* Lazy function call binding. */ +#define RTLD_NOW 0x00002 /* Immediate function call binding. */ +#define RTLD_BINDING_MASK 0x3 /* Mask of binding time value. */ +#define RTLD_NOLOAD 0x00004 /* Do not load the object. */ /* If the following bit is set in the MODE argument to `dlopen', the symbols of the loaded object and its dependencies are made visible as if the object were linked directly into the program. */ -#define RTLD_GLOBAL 0x100 +#define RTLD_GLOBAL 0x00100 /* Unix98 demands the following flag which is the inverse to RTLD_GLOBAL. The implementation does this by default and so we can define the value to zero. */ #define RTLD_LOCAL 0 +/* Do not delete object when closed. */ +#define RTLD_NODELETE 0x01000 + #ifdef __USE_GNU /* To support profiling of shared objects it is a good idea to call the function found using `dlsym' using the following macro since diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index fc9a9d1..a850107 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -271,7 +271,7 @@ extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *), value to allow additional security checks. */ extern struct link_map *_dl_map_object (struct link_map *loader, const char *name, int preloaded, - int type, int trace_mode) + int type, int trace_mode, int noload) internal_function; /* Call _dl_map_object on the dependencies of MAP, and set up diff --git a/sysdeps/mips/bits/dlfcn.h b/sysdeps/mips/bits/dlfcn.h index 0da3a67..006eeb6 100644 --- a/sysdeps/mips/bits/dlfcn.h +++ b/sysdeps/mips/bits/dlfcn.h @@ -22,20 +22,24 @@ #endif /* The MODE argument to `dlopen' contains one of the following: */ -#define RTLD_LAZY 0x001 /* Lazy function call binding. */ -#define RTLD_NOW 0x002 /* Immediate function call binding. */ -#define RTLD_BINDING_MASK 0x3 /* Mask of binding time value. */ +#define RTLD_LAZY 0x0001 /* Lazy function call binding. */ +#define RTLD_NOW 0x0002 /* Immediate function call binding. */ +#define RTLD_BINDING_MASK 0x3 /* Mask of binding time value. */ +#define RTLD_NOLOAD 0x00008 /* Do not load the object. */ /* If the following bit is set in the MODE argument to `dlopen', the symbols of the loaded object and its dependencies are made visible as if the object were linked directly into the program. */ -#define RTLD_GLOBAL 0x004 +#define RTLD_GLOBAL 0x0004 /* Unix98 demands the following flag which is the inverse to RTLD_GLOBAL. The implementation does this by default and so we can define the value to zero. */ #define RTLD_LOCAL 0 +/* Do not delete object when closed. */ +#define RTLD_NODELETE 0x01000 + #ifdef __USE_GNU /* To support profiling of shared objects it is a good idea to call the function found using `dlsym' using the following macro since |