diff options
Diffstat (limited to 'elf/dlsym.c')
-rw-r--r-- | elf/dlsym.c | 90 |
1 files changed, 57 insertions, 33 deletions
diff --git a/elf/dlsym.c b/elf/dlsym.c index d05619b..1072f16 100644 --- a/elf/dlsym.c +++ b/elf/dlsym.c @@ -22,47 +22,71 @@ #include <dlfcn.h> #include <setjmp.h> - -void * -dlsym (void *handle, const char *name) +struct dlsym_args { - ElfW(Addr) caller = (ElfW(Addr)) __builtin_return_address (0); + /* The arguments to dlsym_doit. */ + void *handle; + const char *name; + struct r_found_version version; + ElfW(Addr) caller; + /* The return values of dlsym_doit. */ ElfW(Addr) loadbase; - const ElfW(Sym) *ref = NULL; - void doit (void) + const ElfW(Sym) *ref; +}; + + +static void +dlsym_doit (void *a) +{ + struct dlsym_args *args = (struct dlsym_args *) a; + args->ref = NULL; + + if (args->handle == NULL) + /* Search the global scope. */ + args->loadbase = _dl_lookup_symbol (args->name, &args->ref, + &(_dl_global_scope + ?: _dl_default_scope)[2], + NULL, 0); + else if (args->handle == RTLD_NEXT) { - if (handle == NULL) - /* Search the global scope. */ - loadbase = _dl_lookup_symbol - (name, &ref, &(_dl_global_scope ?: _dl_default_scope)[2], NULL, 0); - else if (handle == RTLD_NEXT) - { - struct link_map *l, *match; + struct link_map *l, *match; - /* 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; + /* Find the highest-addressed object that CALLER is not below. */ + match = NULL; + for (l = _dl_loaded; l; l = l->l_next) + if (args->caller >= l->l_addr && (!match || match->l_addr < l->l_addr)) + match = l; - if (! match) - _dl_signal_error (0, NULL, _("\ + if (! match) + _dl_signal_error (0, NULL, _("\ RTLD_NEXT used in code not dynamically loaded")); - l = match; - while (l->l_loader) - l = l->l_loader; + l = match; + while (l->l_loader) + l = l->l_loader; - loadbase = _dl_lookup_symbol_skip (name, &ref, &_dl_loaded, NULL, l); - } - else - { - /* Search the scope of the given object. */ - struct link_map *map = handle; - struct link_map *mapscope[2] = { map, NULL }; - loadbase = _dl_lookup_symbol (name, &ref, mapscope, map->l_name, 0); - } + args->loadbase = _dl_lookup_symbol_skip (args->name, &args->ref, + &_dl_loaded, NULL, l); } + else + { + /* Search the scope of the given object. */ + struct link_map *map = args->handle; + struct link_map *mapscope[2] = { map, NULL }; + args->loadbase = _dl_lookup_symbol (args->name, &args->ref, mapscope, + map->l_name, 0); + } +} + + +void * +dlsym (void *handle, const char *name) +{ + struct dlsym_args args; + args.caller = (ElfW(Addr)) __builtin_return_address (0); + args.handle = handle; + args.name = name; - return _dlerror_run (doit) ? NULL : (void *) (loadbase + ref->st_value); + return (_dlerror_run (dlsym_doit, &args) + ? NULL : (void *) (args.loadbase + args.ref->st_value)); } |