From 2b7238dda8a0675577701d59f655029c55c60bfe Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 26 Aug 2000 23:41:19 +0000 Subject: [PATCH] Update. 2000-08-26 Ulrich Drepper * elf/Makefile (distribute): Add unloadmod.c, reldepmod1.c, reldepmod2.c, reldepmod3.c, and reldepmod4.c. (tests): Add unload, reldep, reldep2, and reldep3. (modules-names): Add unloadmod, reldepmod1, reldepmod2, reldepmod3, and reldepmod4. Add rules to build and run unload, reldep, reldep2, and reldep3. * elf/dl-lookup.c (_dl_lookup_symbol): Add new parameter explicit. Don't create relocation dependency if it is nonzero. (_dl_lookup_symbol_skip): Remove relocation dependency stuff. This can never happen here. (_dl_lookup_versioned_symbol): Add new parameter explicit. Don't create relocation dependency if it is nonzero. (_dl_lookup_versioned_symbol_skip): Remove relocation dependency stuff. This can never happen here. * sysdeps/generic/ldsodefs.h: Change prototypes. * elf/dl-reloc.c (RESOLVE_MAP): Pass 0 in explicit parameter to _dl_lookup_up and _dl_lookup_versioned_symbol. (RESOLV): Likewise. * elf/dl-runtime.c (fixup): Likewise. (profile_fixup): Likewise. * elf/dl-libc.c (do_dlsym): Pass 1 in explicit parameter to _dl_lookup_symbol. * elf/dl-symbol.c (_dl_symbol_value): Likewise. * elf/rtld.c (dl_main): Likewise. * elf/dl-sym.c (_dl_sym): Pass 1 in explicit parameter to _dl_lookup_symbol if handle is not RTLD_DEFAULT. Always compute and pass down the caller map. (_dl_vsym): Likewise. * elf/reldep.c: New file. * elf/reldep2.c: New file. * elf/reldep3.c: New file. * elf/reldepmod1.c: New file. * elf/reldepmod2.c: New file. * elf/reldepmod3.c: New file. * elf/reldepmod4.c: New file. * elf/unload.c: New file. * elf/unloadmod.c: New file. * elf/do-lookup.h: Remove unused undef_name parameter. * elf/dl-lookup.c: Adjust callers. --- ChangeLog | 43 +++++++++++ elf/Makefile | 26 +++++-- elf/dl-libc.c | 2 +- elf/dl-lookup.c | 149 ++++++++++--------------------------- elf/dl-reloc.c | 8 +- elf/dl-runtime.c | 9 ++- elf/dl-sym.c | 48 ++++++------ elf/dl-symbol.c | 2 +- elf/do-lookup.h | 7 +- elf/reldep.c | 111 +++++++++++++++++++++++++++ elf/reldep2.c | 101 +++++++++++++++++++++++++ elf/reldep3.c | 101 +++++++++++++++++++++++++ elf/reldepmod1.c | 7 ++ elf/reldepmod2.c | 7 ++ elf/reldepmod3.c | 17 +++++ elf/reldepmod4.c | 34 +++++++++ elf/rtld.c | 2 +- elf/unload.c | 65 ++++++++++++++++ elf/unloadmod.c | 4 + sysdeps/generic/ldsodefs.h | 4 +- 20 files changed, 590 insertions(+), 157 deletions(-) create mode 100644 elf/reldep.c create mode 100644 elf/reldep2.c create mode 100644 elf/reldep3.c create mode 100644 elf/reldepmod1.c create mode 100644 elf/reldepmod2.c create mode 100644 elf/reldepmod3.c create mode 100644 elf/reldepmod4.c create mode 100644 elf/unload.c create mode 100644 elf/unloadmod.c diff --git a/ChangeLog b/ChangeLog index 9f4e4512e2..6fc74a0fcb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,46 @@ +2000-08-26 Ulrich Drepper + + * elf/Makefile (distribute): Add unloadmod.c, reldepmod1.c, + reldepmod2.c, reldepmod3.c, and reldepmod4.c. + (tests): Add unload, reldep, reldep2, and reldep3. + (modules-names): Add unloadmod, reldepmod1, reldepmod2, reldepmod3, + and reldepmod4. + Add rules to build and run unload, reldep, reldep2, and reldep3. + * elf/dl-lookup.c (_dl_lookup_symbol): Add new parameter explicit. + Don't create relocation dependency if it is nonzero. + (_dl_lookup_symbol_skip): Remove relocation dependency stuff. This + can never happen here. + (_dl_lookup_versioned_symbol): Add new parameter explicit. + Don't create relocation dependency if it is nonzero. + (_dl_lookup_versioned_symbol_skip): Remove relocation dependency + stuff. This can never happen here. + * sysdeps/generic/ldsodefs.h: Change prototypes. + * elf/dl-reloc.c (RESOLVE_MAP): Pass 0 in explicit parameter to + _dl_lookup_up and _dl_lookup_versioned_symbol. + (RESOLV): Likewise. + * elf/dl-runtime.c (fixup): Likewise. + (profile_fixup): Likewise. + * elf/dl-libc.c (do_dlsym): Pass 1 in explicit parameter to + _dl_lookup_symbol. + * elf/dl-symbol.c (_dl_symbol_value): Likewise. + * elf/rtld.c (dl_main): Likewise. + * elf/dl-sym.c (_dl_sym): Pass 1 in explicit parameter to + _dl_lookup_symbol if handle is not RTLD_DEFAULT. Always compute + and pass down the caller map. + (_dl_vsym): Likewise. + * elf/reldep.c: New file. + * elf/reldep2.c: New file. + * elf/reldep3.c: New file. + * elf/reldepmod1.c: New file. + * elf/reldepmod2.c: New file. + * elf/reldepmod3.c: New file. + * elf/reldepmod4.c: New file. + * elf/unload.c: New file. + * elf/unloadmod.c: New file. + + * elf/do-lookup.h: Remove unused undef_name parameter. + * elf/dl-lookup.c: Adjust callers. + 2000-08-25 Ulrich Drepper * iconv/gconv_trans.c (__gconv_transliterate): Pass NULL instead of diff --git a/elf/Makefile b/elf/Makefile index 369aaba693..9f9fef99bc 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -41,13 +41,14 @@ distribute := $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \ dl-librecon.h interp.c sln.c dl-dst.h hp-timing.h \ do-lookup.h dl-lookupcfg.h sprof.c gen-trusted-dirs.awk \ testobj1.c testobj2.c testobj3.c testobj4.c testobj5.c \ - testobj6.c testobj1_1.c failobj.c \ + testobj6.c testobj1_1.c failobj.c unloadmod.c \ ldconfig.h ldconfig.c cache.c readlib.c readelflib.c \ dep1.c dep2.c dep3.c dep4.c dl-dtprocnum.h \ vismain.c vismod1.c vismod2.c vismod3.c \ constload2.c constload3.c filtmod1.c filtmod2.c \ nodlopenmod.c nodelete.c nodelmod1.c nodelmod2.c \ - nodelmod3.c nodelmod4.c nodlopen.c dl-osinfo.h + nodelmod3.c nodelmod4.c nodlopen.c dl-osinfo.h \ + reldepmod1.c reldepmod2.c reldepmod3.c reldepmod4.c include ../Makeconfig @@ -87,18 +88,19 @@ endif ifeq (yes,$(build-shared)) tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ - constload1 order $(tests-vis-$(have-protected)) noload filter \ - $(tests-nodelete-$(have-z-nodelete)) \ + constload1 order $(tests-vis-$(have-protected)) noload filter unload \ + reldep reldep2 reldep3 $(tests-nodelete-$(have-z-nodelete)) \ $(tests-nodlopen-$(have-z-nodlopen)) tests-vis-yes = vismain tests-nodelete-yes = nodelete tests-nodlopen-yes = nodlopen endif modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ - testobj1_1 failobj constload2 constload3 \ + testobj1_1 failobj constload2 constload3 unloadmod \ dep1 dep2 dep3 dep4 $(modules-vis-$(have-protected)) \ $(modules-nodelete-$(have-z-nodelete)) \ - $(modules-nodlopen-$(have-z-nodlopen)) filtmod1 filtmod2 + $(modules-nodlopen-$(have-z-nodlopen)) filtmod1 filtmod2 \ + reldepmod1 reldepmod2 reldepmod3 reldepmod4 modules-vis-yes = vismod1 vismod2 vismod3 modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4 modules-nodlopen-yes = nodlopenmod @@ -319,3 +321,15 @@ $(objpfx)filtmod1.so: $(objpfx)filtmod1.os $(objpfx)filtmod2.so -Wl,-rpath-link=$(rpath-link) \ $< -Wl,-F,$(objpfx)filtmod2.so $(objpfx)filter: $(objpfx)filtmod1.so + +$(objpfx)unload: $(libdl) +$(objpfx)unload.out: $(objpfx)unloadmod.so + +$(objpfx)reldep: $(libdl) +$(objpfx)reldep.out: $(objpfx)reldepmod1.so $(objpfx)reldepmod2.so + +$(objpfx)reldep2: $(libdl) +$(objpfx)reldep2.out: $(objpfx)reldepmod1.so $(objpfx)reldepmod3.so + +$(objpfx)reldep3: $(libdl) +$(objpfx)reldep3.out: $(objpfx)reldepmod1.so $(objpfx)reldepmod4.so diff --git a/elf/dl-libc.c b/elf/dl-libc.c index 8518909b25..7d2b3608b2 100644 --- a/elf/dl-libc.c +++ b/elf/dl-libc.c @@ -84,7 +84,7 @@ do_dlsym (void *ptr) struct do_dlsym_args *args = (struct do_dlsym_args *) ptr; args->ref = NULL; args->loadbase = _dl_lookup_symbol (args->name, args->map, &args->ref, - args->map->l_local_scope, 0); + args->map->l_local_scope, 0, 1); } static void diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index f1ec98e74b..2b58ff32aa 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -190,7 +190,7 @@ lookup_t internal_function _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], - int reloc_type) + int reloc_type, int explicit) { const char *reference_name = undef_map ? undef_map->l_name : NULL; const unsigned long int hash = _dl_elf_hash (undef_name); @@ -204,8 +204,8 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, /* Search the relevant loaded objects for a definition. */ for (scope = symbol_scope; *scope; ++scope) - if (do_lookup (undef_name, undef_map, hash, *ref, ¤t_value, - *scope, 0, NULL, noexec, noplt)) + if (do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, NULL, + noexec, noplt)) { /* We have to check whether this would bind UNDEF_MAP to an object in the global scope which was dynamically loaded. In this case @@ -215,12 +215,15 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, && (__builtin_expect (current_value.m->l_type, lt_library) == lt_loaded) && undef_map != current_value.m + /* Don't do this for explicit lookups as opposed to implicit + runtime lookups. */ + && __builtin_expect (! explicit, 1) /* Add UNDEF_MAP to the dependencies. */ && add_dependency (undef_map, current_value.m) < 0) /* Something went wrong. Perhaps the object we tried to reference was just removed. Try finding another definition. */ return _dl_lookup_symbol (undef_name, undef_map, ref, symbol_scope, - reloc_type); + reloc_type, 0); break; } @@ -262,8 +265,8 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, struct sym_val protected_value = { NULL, NULL }; for (scope = symbol_scope; *scope; ++scope) - if (do_lookup (undef_name, undef_map, hash, *ref, - &protected_value, *scope, 0, NULL, 0, 1)) + if (do_lookup (undef_name, hash, *ref, &protected_value, *scope, 0, + NULL, 0, 1)) break; if (protected_value.s == NULL || protected_value.m == undef_map) @@ -303,47 +306,13 @@ _dl_lookup_symbol_skip (const char *undef_name, for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i) assert (i < (*scope)->r_nduplist); - if (i < (*scope)->r_nlist - && do_lookup (undef_name, undef_map, hash, *ref, ¤t_value, - *scope, i, skip_map, 0, 0)) - { - /* We have to check whether this would bind UNDEF_MAP to an object - in the global scope which was dynamically loaded. In this case - we have to prevent the latter from being unloaded unless the - UNDEF_MAP object is also unloaded. */ - if (current_value.m->l_global - && (__builtin_expect (current_value.m->l_type, lt_library) - == lt_loaded) - && undef_map != current_value.m - /* Add UNDEF_MAP to the dependencies. */ - && add_dependency (undef_map, current_value.m) < 0) - /* Something went wrong. Perhaps the object we tried to reference - was just removed. Try finding another definition. */ - return _dl_lookup_symbol_skip (undef_name, undef_map, ref, - symbol_scope, skip_map); - } - else + while (i >= (*scope)->r_nlist + || ! do_lookup (undef_name, hash, *ref, ¤t_value, *scope, i, + skip_map, 0, 0)) while (*++scope) - if (do_lookup (undef_name, undef_map, hash, *ref, ¤t_value, - *scope, 0, skip_map, 0, 0)) - { - /* We have to check whether this would bind UNDEF_MAP to an object - in the global scope which was dynamically loaded. In this case - we have to prevent the latter from being unloaded unless the - UNDEF_MAP object is also unloaded. */ - if (__builtin_expect (current_value.m->l_global, 0) - && (__builtin_expect (current_value.m->l_type, lt_library) - == lt_loaded) - && undef_map != current_value.m - /* Add UNDEF_MAP to the dependencies. */ - && add_dependency (undef_map, current_value.m) < 0) - /* Something went wrong. Perhaps the object we tried to reference - was just removed. Try finding another definition. */ - return _dl_lookup_symbol_skip (undef_name, undef_map, ref, - symbol_scope, skip_map); - - break; - } + if (do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, + skip_map, 0, 0)) + break; if (__builtin_expect (current_value.s == NULL, 0)) { @@ -370,16 +339,16 @@ _dl_lookup_symbol_skip (const char *undef_name, } else { - /* It is very tricky. We need to figure out what value to - return for the protected symbol */ + /* It is very tricky. We need to figure out what value to + return for the protected symbol. */ struct sym_val protected_value = { NULL, NULL }; if (i >= (*scope)->r_nlist - || !do_lookup (undef_name, undef_map, hash, *ref, &protected_value, - *scope, i, skip_map, 0, 1)) + || !do_lookup (undef_name, hash, *ref, &protected_value, *scope, i, + skip_map, 0, 1)) while (*++scope) - if (do_lookup (undef_name, undef_map, hash, *ref, &protected_value, - *scope, 0, skip_map, 0, 1)) + if (do_lookup (undef_name, hash, *ref, &protected_value, *scope, 0, + skip_map, 0, 1)) break; if (protected_value.s == NULL || protected_value.m == undef_map) @@ -404,7 +373,7 @@ _dl_lookup_versioned_symbol (const char *undef_name, struct link_map *undef_map, const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], const struct r_found_version *version, - int reloc_type) + int reloc_type, int explicit) { const char *reference_name = undef_map ? undef_map->l_name : NULL; const unsigned long int hash = _dl_elf_hash (undef_name); @@ -419,9 +388,8 @@ _dl_lookup_versioned_symbol (const char *undef_name, /* Search the relevant loaded objects for a definition. */ for (scope = symbol_scope; *scope; ++scope) { - int res = do_lookup_versioned (undef_name, undef_map, hash, *ref, - ¤t_value, *scope, 0, version, NULL, - noexec, noplt); + int res = do_lookup_versioned (undef_name, hash, *ref, ¤t_value, + *scope, 0, version, NULL, noexec, noplt); if (res > 0) { /* We have to check whether this would bind UNDEF_MAP to an object @@ -432,13 +400,16 @@ _dl_lookup_versioned_symbol (const char *undef_name, && (__builtin_expect (current_value.m->l_type, lt_library) == lt_loaded) && undef_map != current_value.m + /* Don't do this for explicit lookups as opposed to implicit + runtime lookups. */ + && __builtin_expect (! explicit, 1) /* Add UNDEF_MAP to the dependencies. */ && add_dependency (undef_map, current_value.m) < 0) /* Something went wrong. Perhaps the object we tried to reference was just removed. Try finding another definition. */ return _dl_lookup_versioned_symbol (undef_name, undef_map, ref, symbol_scope, version, - reloc_type); + reloc_type, 0); break; } @@ -502,9 +473,8 @@ _dl_lookup_versioned_symbol (const char *undef_name, struct sym_val protected_value = { NULL, NULL }; for (scope = symbol_scope; *scope; ++scope) - if (do_lookup_versioned (undef_name, undef_map, hash, *ref, - &protected_value, *scope, 0, version, NULL, - 0, 1)) + if (do_lookup_versioned (undef_name, hash, *ref, &protected_value, + *scope, 0, version, NULL, 0, 1)) break; if (protected_value.s == NULL || protected_value.m == undef_map) @@ -543,50 +513,13 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name, for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i) assert (i < (*scope)->r_nduplist); - if (i < (*scope)->r_nlist - && do_lookup_versioned (undef_name, undef_map, hash, *ref, - ¤t_value, *scope, i, version, skip_map, - 0, 0)) - { - /* We have to check whether this would bind UNDEF_MAP to an object - in the global scope which was dynamically loaded. In this case - we have to prevent the latter from being unloaded unless the - UNDEF_MAP object is also unloaded. */ - if (__builtin_expect (current_value.m->l_global, 0) - && (__builtin_expect (current_value.m->l_type, lt_library) - == lt_loaded) - && undef_map != current_value.m - /* Add UNDEF_MAP to the dependencies. */ - && add_dependency (undef_map, current_value.m) < 0) - /* Something went wrong. Perhaps the object we tried to reference - was just removed. Try finding another definition. */ - return _dl_lookup_versioned_symbol_skip (undef_name, undef_map, ref, - symbol_scope, version, - skip_map); - } - else + if (i >= (*scope)->r_nlist + || ! do_lookup_versioned (undef_name, hash, *ref, ¤t_value, + *scope, i, version, skip_map, 0, 0)) while (*++scope) - if (do_lookup_versioned (undef_name, undef_map, hash, *ref, - ¤t_value, *scope, 0, version, skip_map, - 0, 0)) - { - /* We have to check whether this would bind UNDEF_MAP to an object - in the global scope which was dynamically loaded. In this case - we have to prevent the latter from being unloaded unless the - UNDEF_MAP object is also unloaded. */ - if (current_value.m->l_global - && (__builtin_expect (current_value.m->l_type, lt_library) - == lt_loaded) - && undef_map != current_value.m - /* Add UNDEF_MAP to the dependencies. */ - && add_dependency (undef_map, current_value.m) < 0) - /* Something went wrong. Perhaps the object we tried to reference - was just removed. Try finding another definition. */ - return _dl_lookup_versioned_symbol_skip (undef_name, undef_map, - ref, symbol_scope, - version, skip_map); - break; - } + if (do_lookup_versioned (undef_name, hash, *ref, ¤t_value, *scope, + 0, version, skip_map, 0, 0)) + break; if (__builtin_expect (current_value.s == NULL, 0)) { @@ -631,13 +564,11 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name, struct sym_val protected_value = { NULL, NULL }; if (i >= (*scope)->r_nlist - || !do_lookup_versioned (undef_name, undef_map, hash, *ref, - &protected_value, *scope, i, version, - skip_map, 0, 1)) + || !do_lookup_versioned (undef_name, hash, *ref, &protected_value, + *scope, i, version, skip_map, 0, 1)) while (*++scope) - if (do_lookup_versioned (undef_name, undef_map, hash, *ref, - &protected_value, *scope, 0, version, - skip_map, 0, 1)) + if (do_lookup_versioned (undef_name, hash, *ref, &protected_value, + *scope, 0, version, skip_map, 0, 1)) break; if (protected_value.s == NULL || protected_value.m == undef_map) diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index f840f3c802..643885e95b 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -75,17 +75,17 @@ cannot make segment writable for relocation")); (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \ ? ((version) != NULL && (version)->hash != 0 \ ? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, l, (ref), \ - scope, (version), (flags)) \ + scope, (version), (flags), 0) \ : _dl_lookup_symbol (strtab + (*ref)->st_name, l, (ref), scope, \ - (flags))) \ + (flags), 0)) \ : l) #define RESOLVE(ref, version, flags) \ (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \ ? ((version) != NULL && (version)->hash != 0 \ ? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, l, (ref), \ - scope, (version), (flags)) \ + scope, (version), (flags), 0) \ : _dl_lookup_symbol (strtab + (*ref)->st_name, l, (ref), scope, \ - (flags))) \ + (flags), 0)) \ : l->l_addr) #include "dynamic-link.h" diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c index 57746092f1..01beb19633 100644 --- a/elf/dl-runtime.c +++ b/elf/dl-runtime.c @@ -89,13 +89,13 @@ fixup ( result = _dl_lookup_versioned_symbol (strtab + sym->st_name, l, &sym, l->l_scope, version, - ELF_MACHINE_JMP_SLOT); + ELF_MACHINE_JMP_SLOT, 0); break; } } case 0: result = _dl_lookup_symbol (strtab + sym->st_name, l, &sym, - l->l_scope, ELF_MACHINE_JMP_SLOT); + l->l_scope, ELF_MACHINE_JMP_SLOT, 0); } /* Currently result contains the base load address (or link map) @@ -181,13 +181,14 @@ profile_fixup ( result = _dl_lookup_versioned_symbol(strtab + sym->st_name, l, &sym, l->l_scope, version, - ELF_MACHINE_JMP_SLOT); + ELF_MACHINE_JMP_SLOT, + 0); break; } } case 0: result = _dl_lookup_symbol (strtab + sym->st_name, l, &sym, - l->l_scope, ELF_MACHINE_JMP_SLOT); + l->l_scope, ELF_MACHINE_JMP_SLOT, 0); } /* Currently result contains the base load address (or link map) diff --git a/elf/dl-sym.c b/elf/dl-sym.c index e54ed808b2..873865698c 100644 --- a/elf/dl-sym.c +++ b/elf/dl-sym.c @@ -31,22 +31,21 @@ _dl_sym (void *handle, const char *name, void *who) { const ElfW(Sym) *ref = NULL; lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + struct link_map *match; + struct link_map *l; + + /* Find the highest-addressed object that CALLER is not below. */ + match = NULL; + for (l = _dl_loaded; l; l = l->l_next) + if (caller >= l->l_addr && (!match || match->l_addr < l->l_addr)) + match = l; if (handle == RTLD_DEFAULT) /* Search the global scope. */ - result = _dl_lookup_symbol (name, NULL, &ref, _dl_global_scope, 0); + result = _dl_lookup_symbol (name, match, &ref, _dl_global_scope, 0, 0); else { - struct link_map *l; - struct link_map *match; - ElfW(Addr) caller = (ElfW(Addr)) who; - - /* Find the highest-addressed object that CALLER is not below. */ - match = NULL; - for (l = _dl_loaded; l; l = l->l_next) - if (caller >= l->l_addr && (!match || match->l_addr < l->l_addr)) - match = l; - if (handle != RTLD_NEXT) { /* Search the scope of the given object. */ @@ -58,7 +57,7 @@ _dl_sym (void *handle, const char *name, void *who) match = _dl_loaded; result = _dl_lookup_symbol (name, match, &ref, map->l_local_scope, - 0); + 0, 1); } else { @@ -88,6 +87,9 @@ _dl_vsym (void *handle, const char *name, const char *version, void *who) const ElfW(Sym) *ref = NULL; struct r_found_version vers; lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + struct link_map *match; + struct link_map *l; /* Compute hash value to the version string. */ vers.name = version; @@ -96,22 +98,18 @@ _dl_vsym (void *handle, const char *name, const char *version, void *who) /* We don't have a specific file where the symbol can be found. */ vers.filename = NULL; + /* Find the highest-addressed object that CALLER is not below. */ + match = NULL; + for (l = _dl_loaded; l; l = l->l_next) + if (caller >= l->l_addr && (!match || match->l_addr < l->l_addr)) + match = l; + if (handle == RTLD_DEFAULT) /* Search the global scope. */ - result = _dl_lookup_versioned_symbol (name, NULL, &ref, _dl_global_scope, - &vers, 0); + result = _dl_lookup_versioned_symbol (name, match, &ref, _dl_global_scope, + &vers, 0, 0); else if (handle == RTLD_NEXT) { - struct link_map *l; - struct link_map *match; - ElfW(Addr) caller = (ElfW(Addr)) who; - - /* Find the highest-addressed object that CALLER is not below. */ - match = NULL; - for (l = _dl_loaded; l; l = l->l_next) - if (caller >= l->l_addr && (!match || match->l_addr < l->l_addr)) - match = l; - if (! match) _dl_signal_error (0, NULL, N_("\ RTLD_NEXT used in code not dynamically loaded")); @@ -129,7 +127,7 @@ RTLD_NEXT used in code not dynamically loaded")); /* Search the scope of the given object. */ struct link_map *map = handle; result = _dl_lookup_versioned_symbol (name, map, &ref, - map->l_local_scope, &vers, 0); + map->l_local_scope, &vers, 0, 1); } if (ref) diff --git a/elf/dl-symbol.c b/elf/dl-symbol.c index bdd7615e48..5c12df7bff 100644 --- a/elf/dl-symbol.c +++ b/elf/dl-symbol.c @@ -28,6 +28,6 @@ _dl_symbol_value (struct link_map *map, const char *name) { const ElfW(Sym) *ref = NULL; lookup_t result; - result = _dl_lookup_symbol (name, map, &ref, map->l_local_scope, 0); + result = _dl_lookup_symbol (name, map, &ref, map->l_local_scope, 0, 1); return (result ? LOOKUP_VALUE_ADDRESS (result) : 0) + ref->st_value; } diff --git a/elf/do-lookup.h b/elf/do-lookup.h index 4511ef6289..932c385168 100644 --- a/elf/do-lookup.h +++ b/elf/do-lookup.h @@ -29,10 +29,9 @@ found the symbol, the value 0 if nothing is found and < 0 if something bad happened. */ static inline int -FCT (const char *undef_name, struct link_map *undef_map, - unsigned long int hash, const ElfW(Sym) *ref, struct sym_val *result, - struct r_scope_elem *scope, size_t i, ARG struct link_map *skip, - int noexec, int noplt) +FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, + struct sym_val *result, struct r_scope_elem *scope, size_t i, ARG + struct link_map *skip, int noexec, int noplt) { struct link_map **list = scope->r_list; size_t n = scope->r_nlist; diff --git a/elf/reldep.c b/elf/reldep.c new file mode 100644 index 0000000000..44b239b6c7 --- /dev/null +++ b/elf/reldep.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include + +int +main (void) +{ + void *h1; + void *h2; + int (*fp) (void); + int *vp; + + mtrace (); + + /* Open the two objects. */ + h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL); + if (h1 == NULL) + { + printf ("cannot open reldepmod1.so: %s\n", dlerror ()); + exit (1); + } + h2 = dlopen ("reldepmod2.so", RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open reldepmod2.so: %s\n", dlerror ()); + exit (1); + } + + /* Get the address of the variable in reldepmod1.so. */ + vp = dlsym (h1, "some_var"); + if (vp == NULL) + { + printf ("cannot get address of \"some_var\": %s\n", dlerror ()); + exit (1); + } + + *vp = 42; + + /* Get the function `call_me' in the second object. This has a + dependency which is resolved by a definition in reldepmod1.so. */ + fp = dlsym (h2, "call_me"); + if (fp == NULL) + { + printf ("cannot get address of \"call_me\": %s\n", dlerror ()); + exit (1); + } + + /* Call the function. */ + if (fp () != 0) + { + puts ("function \"call_me\" returned wrong result"); + exit (1); + } + + /* Now close the first object. If must still be around since we have + a implicit dependency. */ + if (dlclose (h1) != 0) + { + printf ("closing h1 failed: %s\n", dlerror ()); + exit (1); + } + + /* Try calling the function again. This will fail if the first object + got unloaded. */ + if (fp () != 0) + { + puts ("second call of function \"call_me\" returned wrong result"); + exit (1); + } + + /* Now close the second file as well. */ + if (dlclose (h2) != 0) + { + printf ("closing h2 failed: %s\n", dlerror ()); + exit (1); + } + + /* Finally, open the first object again. */ + h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL); + if (h1 == NULL) + { + printf ("cannot open reldepmod1.so the second time: %s\n", dlerror ()); + exit (1); + } + + /* And get the variable address again. */ + vp = dlsym (h1, "some_var"); + if (vp == NULL) + { + printf ("cannot get address of \"some_var\" the second time: %s\n", + dlerror ()); + exit (1); + } + + /* The variable now must have its originial value. */ + if (*vp != 0) + { + puts ("variable \"some_var\" not reset"); + exit (1); + } + + /* Close the first object again, we are done. */ + if (dlclose (h1) != 0) + { + printf ("closing h1 failed: %s\n", dlerror ()); + exit (1); + } + + return 0; +} diff --git a/elf/reldep2.c b/elf/reldep2.c new file mode 100644 index 0000000000..aadb0cbfdb --- /dev/null +++ b/elf/reldep2.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +int +main (void) +{ + void *h1; + void *h2; + int (*fp) (void); + int *vp; + + mtrace (); + + /* Open the two objects. */ + h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL); + if (h1 == NULL) + { + printf ("cannot open reldepmod1.so: %s\n", dlerror ()); + exit (1); + } + h2 = dlopen ("reldepmod3.so", RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open reldepmod3.so: %s\n", dlerror ()); + exit (1); + } + + /* Get the address of the variable in reldepmod1.so. */ + vp = dlsym (h1, "some_var"); + if (vp == NULL) + { + printf ("cannot get address of \"some_var\": %s\n", dlerror ()); + exit (1); + } + + *vp = 42; + + /* Get the function `call_me' in the second object. This has a + dependency which is resolved by a definition in reldepmod1.so. */ + fp = dlsym (h2, "call_me"); + if (fp == NULL) + { + printf ("cannot get address of \"call_me\": %s\n", dlerror ()); + exit (1); + } + + /* Call the function. */ + if (fp () != 0) + { + puts ("function \"call_me\" returned wrong result"); + exit (1); + } + + /* Now close the first object. If must still be around since we have + a implicit dependency. */ + if (dlclose (h1) != 0) + { + printf ("closing h1 failed: %s\n", dlerror ()); + exit (1); + } + + /* Open the first object again. */ + h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL); + if (h1 == NULL) + { + printf ("cannot open reldepmod1.so the second time: %s\n", dlerror ()); + exit (1); + } + + /* Get the variable address again. */ + vp = dlsym (h1, "some_var"); + if (vp == NULL) + { + printf ("cannot get address of \"some_var\" the second time: %s\n", + dlerror ()); + exit (1); + } + + /* The variable now must have its originial value. */ + if (*vp != 42) + { + puts ("variable \"some_var\" reset"); + exit (1); + } + + /* Close the first object again, we are done. */ + if (dlclose (h1) != 0) + { + printf ("closing h1 failed: %s\n", dlerror ()); + exit (1); + } + if (dlclose (h2) != 0) + { + printf ("closing h2 failed: %s\n", dlerror ()); + exit (1); + } + + return 0; +} diff --git a/elf/reldep3.c b/elf/reldep3.c new file mode 100644 index 0000000000..b051c41dbc --- /dev/null +++ b/elf/reldep3.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +int +main (void) +{ + void *h1; + void *h2; + int (*fp) (void); + int *vp; + + mtrace (); + + /* Open the two objects. */ + h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL); + if (h1 == NULL) + { + printf ("cannot open reldepmod1.so: %s\n", dlerror ()); + exit (1); + } + h2 = dlopen ("reldepmod4.so", RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open reldepmod4.so: %s\n", dlerror ()); + exit (1); + } + + /* Get the address of the variable in reldepmod1.so. */ + vp = dlsym (h1, "some_var"); + if (vp == NULL) + { + printf ("cannot get address of \"some_var\": %s\n", dlerror ()); + exit (1); + } + + *vp = 42; + + /* Get the function `call_me' in the second object. This has a + dependency which is resolved by a definition in reldepmod1.so. */ + fp = dlsym (h2, "call_me"); + if (fp == NULL) + { + printf ("cannot get address of \"call_me\": %s\n", dlerror ()); + exit (1); + } + + /* Call the function. */ + if (fp () != 0) + { + puts ("function \"call_me\" returned wrong result"); + exit (1); + } + + /* Now close the first object. If must still be around since we have + a implicit dependency. */ + if (dlclose (h1) != 0) + { + printf ("closing h1 failed: %s\n", dlerror ()); + exit (1); + } + + /* Open the first object again. */ + h1 = dlopen ("reldepmod1.so", RTLD_LAZY | RTLD_GLOBAL); + if (h1 == NULL) + { + printf ("cannot open reldepmod1.so the second time: %s\n", dlerror ()); + exit (1); + } + + /* Get the variable address again. */ + vp = dlsym (h1, "some_var"); + if (vp == NULL) + { + printf ("cannot get address of \"some_var\" the second time: %s\n", + dlerror ()); + exit (1); + } + + /* The variable now must have its originial value. */ + if (*vp != 0) + { + puts ("variable \"some_var\" not reset"); + exit (1); + } + + /* Close the first object again, we are done. */ + if (dlclose (h1) != 0) + { + printf ("closing h1 failed: %s\n", dlerror ()); + exit (1); + } + if (dlclose (h2) != 0) + { + printf ("closing h2 failed: %s\n", dlerror ()); + exit (1); + } + + return 0; +} diff --git a/elf/reldepmod1.c b/elf/reldepmod1.c new file mode 100644 index 0000000000..26f67b3d0d --- /dev/null +++ b/elf/reldepmod1.c @@ -0,0 +1,7 @@ +int some_var; + +int +foo (void) +{ + return some_var; +} diff --git a/elf/reldepmod2.c b/elf/reldepmod2.c new file mode 100644 index 0000000000..f511755444 --- /dev/null +++ b/elf/reldepmod2.c @@ -0,0 +1,7 @@ +extern int foo (void); + +int +call_me (void) +{ + return foo () - 42; +} diff --git a/elf/reldepmod3.c b/elf/reldepmod3.c new file mode 100644 index 0000000000..e56b19d499 --- /dev/null +++ b/elf/reldepmod3.c @@ -0,0 +1,17 @@ +#include +#include + +int +call_me (void) +{ + int (*fp) (void); + + fp = dlsym (RTLD_DEFAULT, "foo"); + if (fp == NULL) + { + printf ("cannot get address of foo in global scope: %s\n", dlerror ()); + exit (1); + } + + return fp () - 42; +} diff --git a/elf/reldepmod4.c b/elf/reldepmod4.c new file mode 100644 index 0000000000..7036af832e --- /dev/null +++ b/elf/reldepmod4.c @@ -0,0 +1,34 @@ +#include +#include + +int +call_me (void) +{ + void *h; + int (*fp) (void); + int res; + + h = dlopen ("reldepmod1.so", RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open reldepmod1.so in %s: %s\n", __FILE__, dlerror ()); + exit (1); + } + + fp = dlsym (h, "foo"); + if (fp == NULL) + { + printf ("cannot get address of foo in global scope: %s\n", dlerror ()); + exit (1); + } + + res = fp () - 42; + + if (dlclose (h) != 0) + { + printf ("failure when closing h in %s: %s\n", __FILE__, dlerror ()); + exit (1); + } + + return res; +} diff --git a/elf/rtld.c b/elf/rtld.c index 41cf5c36d5..4f92844e54 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -910,7 +910,7 @@ of this helper program; chances are you did not intend to run this program.\n\ result = _dl_lookup_symbol (_dl_argv[i], _dl_loaded, &ref, _dl_loaded->l_scope, - ELF_MACHINE_JMP_SLOT); + ELF_MACHINE_JMP_SLOT, 1); loadbase = LOOKUP_VALUE_ADDRESS (result); diff --git a/elf/unload.c b/elf/unload.c new file mode 100644 index 0000000000..2789abd5bb --- /dev/null +++ b/elf/unload.c @@ -0,0 +1,65 @@ +/* Test for unloading (really unmapping) of objects. By Franz Sirl. + This test does not have to passed in all dlopen() et.al. implementation + since it is not required the unloading actually happens. But we + require it for glibc. */ + +#include +#include +#include +#include + +typedef struct +{ + void *next; +} strct; + +int +main (void) +{ + void *sohandle; + strct *testdat; + int ret; + int result = 0; + + mtrace (); + + sohandle = dlopen ("unloadmod.so", RTLD_NOW | RTLD_GLOBAL); + if (sohandle == NULL) + { + printf ("first dlopen failed: %s\n", dlerror ()); + exit (1); + } + + testdat = dlsym (sohandle, "testdat"); + testdat->next = (void *) -1; + + ret = dlclose (sohandle); + if (ret != 0) + { + puts ("first dlclose failed"); + result = 1; + } + + sohandle = dlopen ("unloadmod.so", RTLD_NOW | RTLD_GLOBAL); + if (sohandle == NULL) + { + printf ("second dlopen failed: %s\n", dlerror ()); + exit (1); + } + + testdat = dlsym (sohandle, "testdat"); + if (testdat->next == (void *) -1) + { + puts ("testdat->next == (void *) -1"); + result = 1; + } + + ret = dlclose (sohandle); + if (ret != 0) + { + puts ("second dlclose failed"); + result = 1; + } + + return result; +} diff --git a/elf/unloadmod.c b/elf/unloadmod.c new file mode 100644 index 0000000000..3aa5403edf --- /dev/null +++ b/elf/unloadmod.c @@ -0,0 +1,4 @@ +struct testdat +{ + void *next; +} testdat; diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index ceb2b87694..4cb4472ca1 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -307,7 +307,7 @@ extern lookup_t _dl_lookup_symbol (const char *undef, struct link_map *undef_map, const ElfW(Sym) **sym, struct r_scope_elem *symbol_scope[], - int reloc_type) + int reloc_type, int explicit) internal_function; /* Lookup versioned symbol. */ @@ -316,7 +316,7 @@ extern lookup_t _dl_lookup_versioned_symbol (const char *undef, const ElfW(Sym) **sym, struct r_scope_elem *symbol_scope[], const struct r_found_version *version, - int reloc_type) + int reloc_type, int explicit) internal_function; /* For handling RTLD_NEXT we must be able to skip shared objects. */