diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/dl-deps.c | 45 | ||||
-rw-r--r-- | elf/dl-error.c | 18 | ||||
-rw-r--r-- | elf/dlclose.c | 13 | ||||
-rw-r--r-- | elf/dlerror.c | 4 | ||||
-rw-r--r-- | elf/dlopen.c | 30 | ||||
-rw-r--r-- | elf/dlsym.c | 90 | ||||
-rw-r--r-- | elf/dlvsym.c | 109 | ||||
-rw-r--r-- | elf/link.h | 17 | ||||
-rw-r--r-- | elf/rtld.c | 80 |
9 files changed, 272 insertions, 134 deletions
diff --git a/elf/dl-deps.c b/elf/dl-deps.c index 7a67729..e2fd340 100644 --- a/elf/dl-deps.c +++ b/elf/dl-deps.c @@ -22,6 +22,29 @@ #include <dlfcn.h> #include <stdlib.h> +struct openaux_args +{ + /* The arguments to openaux. */ + struct link_map *map; + int trace_mode; + const char *strtab; + ElfW(Dyn) *d; + + /* The return value of openaux. */ + struct link_map *aux; +}; + +static void +openaux (void *a) +{ + struct openaux_args *args = (struct openaux_args *) a; + + args->aux = _dl_map_object (args->map, args->strtab + args->d->d_un.d_val, + (args->map->l_type == lt_executable + ? lt_library : args->map->l_type), + args->trace_mode); +} + void _dl_map_object_deps (struct link_map *map, struct link_map **preloads, unsigned int npreloads, @@ -75,27 +98,21 @@ _dl_map_object_deps (struct link_map *map, /* There is at least one auxiliary library specified. We try to load it, and if we can, use its symbols in preference to our own. But if we can't load it, we just silently ignore it. */ - const char *strtab + struct openaux_args args; + args.strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr); - ElfW(Dyn) *d; + args.map = map; + args.trace_mode = trace_mode; - for (d = map->l_ld; d->d_tag != DT_NULL; ++d) - if (d->d_tag == DT_AUXILIARY) + for (args.d = map->l_ld; args.d->d_tag != DT_NULL; ++args.d) + if (args.d->d_tag == DT_AUXILIARY) { - struct link_map *aux; - void openaux (void) - { - aux = _dl_map_object (map, strtab + d->d_un.d_val, - (map->l_type == lt_executable - ? lt_library : map->l_type), - trace_mode); - } char *errstring; const char *objname; - if (! _dl_catch_error (&errstring, &objname, openaux)) + if (! _dl_catch_error (&errstring, &objname, openaux, &args)) /* The auxiliary object is actually there. Use it as the first search element, even before MAP itself. */ - preload (aux); + preload (args.aux); } } diff --git a/elf/dl-error.c b/elf/dl-error.c index 263bd65..e2565bb 100644 --- a/elf/dl-error.c +++ b/elf/dl-error.c @@ -85,19 +85,25 @@ _dl_signal_error (int errcode, int _dl_catch_error (char **errstring, const char **objname, - void (*operate) (void)) + void (*operate) (void *), + void *args) { int errcode; - struct catch *old, c = { errstring: NULL, objname: NULL }; - /* We need not handle `receiver' since setting a `catch' is handle + struct catch *old, c; + /* We need not handle `receiver' since setting a `catch' is handled before it. */ + /* Some systems (.e.g, SPARC) handle constructors to local variables + inefficient. So we initialize `c' by hand. */ + c.errstring = NULL; + c.objname = NULL; + old = catch; errcode = setjmp (c.env); if (errcode == 0) { catch = &c; - (*operate) (); + (*operate) (args); catch = old; *errstring = NULL; *objname = NULL; @@ -112,7 +118,7 @@ _dl_catch_error (char **errstring, } void -_dl_receive_error (receiver_fct fct, void (*operate) (void)) +_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) { struct catch *old_catch; receiver_fct old_receiver; @@ -124,7 +130,7 @@ _dl_receive_error (receiver_fct fct, void (*operate) (void)) catch = NULL; receiver = fct; - (*operate) (); + (*operate) (args); catch = old_catch; receiver = old_receiver; diff --git a/elf/dlclose.c b/elf/dlclose.c index 6a14211..d96ffc9 100644 --- a/elf/dlclose.c +++ b/elf/dlclose.c @@ -20,13 +20,14 @@ #include <link.h> #include <dlfcn.h> +static void +dlclose_doit (void *handle) +{ + _dl_close (handle); +} + int dlclose (void *handle) { - void doit (void) - { - _dl_close (handle); - } - - return _dlerror_run (doit) ? -1 : 0; + return _dlerror_run (dlclose_doit, handle) ? -1 : 0; } diff --git a/elf/dlerror.c b/elf/dlerror.c index 9e55bc7..e2b1ac9 100644 --- a/elf/dlerror.c +++ b/elf/dlerror.c @@ -64,7 +64,7 @@ dlerror (void) } int -_dlerror_run (void (*operate) (void)) +_dlerror_run (void (*operate) (void *), void *args) { if (last_errstring != NULL) /* Free the error string from the last failed command. This can @@ -72,6 +72,6 @@ _dlerror_run (void (*operate) (void)) free (last_errstring); last_errcode = _dl_catch_error (&last_errstring, &last_object_name, - operate); + operate, args); return last_errstring != NULL; } diff --git a/elf/dlopen.c b/elf/dlopen.c index c2cf8cd..4963e99 100644 --- a/elf/dlopen.c +++ b/elf/dlopen.c @@ -21,15 +21,31 @@ #include <link.h> #include <dlfcn.h> -void * -dlopen (const char *file, int mode) +struct dlopen_args { + /* The arguments for dlopen_doit. */ + const char *file; + int mode; + /* The return value of dlopen_doit. */ struct link_map *new; +}; + - void doit (void) - { - new = _dl_open (file ?: "", mode); - } +static void +dlopen_doit (void *a) +{ + struct dlopen_args *args = (struct dlopen_args *) a; + + args->new = _dl_open (args->file ?: "", args->mode); +} + + +void * +dlopen (const char *file, int mode) +{ + struct dlopen_args args; + args.file = file; + args.mode = mode; - return _dlerror_run (doit) ? NULL : new; + return _dlerror_run (dlopen_doit, &args) ? NULL : args.new; } 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)); } diff --git a/elf/dlvsym.c b/elf/dlvsym.c index b3d4c1a..ca8e25d 100644 --- a/elf/dlvsym.c +++ b/elf/dlvsym.c @@ -24,57 +24,82 @@ #include <dl-hash.h> -void * -__dlvsym (void *handle, const char *name, const char *version_str) +struct dlvsym_args { - ElfW(Addr) caller = (ElfW(Addr)) __builtin_return_address (0); - ElfW(Addr) loadbase; + /* The arguments to dlvsym_doit. */ + void *handle; + const char *name; struct r_found_version version; - const ElfW(Sym) *ref = NULL; - void doit (void) + ElfW(Addr) caller; + /* The return values of dlvsym_doit. */ + ElfW(Addr) loadbase; + const ElfW(Sym) *ref; +}; + + +static void +dlvsym_doit (void *a) +{ + struct dlvsym_args *args = (struct dlvsym_args *)a; + args->ref = NULL; + + if (args->handle == NULL) + /* Search the global scope. */ + args->loadbase = _dl_lookup_versioned_symbol (args->name, &args->ref, + &(_dl_global_scope + ?: _dl_default_scope)[2], + NULL, &args->version, 0); + else if (args->handle == RTLD_NEXT) { - if (handle == NULL) - /* Search the global scope. */ - loadbase = _dl_lookup_versioned_symbol - (name, &ref, &(_dl_global_scope ?: _dl_default_scope)[2], NULL, - &version, 0); - else if (handle == RTLD_NEXT) - { - 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; - - if (! match) - _dl_signal_error (0, NULL, _("\ + 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 (args->caller >= l->l_addr && (!match || match->l_addr < l->l_addr)) + match = l; + + 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; - - loadbase = _dl_lookup_versioned_symbol_skip - (name, &ref, &_dl_loaded, NULL, &version, l); - } - else - { - /* Search the scope of the given object. */ - struct link_map *map = handle; - struct link_map *mapscope[2] = { map, NULL }; - loadbase = _dl_lookup_versioned_symbol - (name, &ref, mapscope, map->l_name, &version, 0); - } + l = match; + while (l->l_loader) + l = l->l_loader; + + args->loadbase = _dl_lookup_versioned_symbol_skip (args->name, + &args->ref, + &_dl_loaded, + NULL, &args->version, + 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_versioned_symbol (args->name, &args->ref, + mapscope, map->l_name, + &args->version, 0); } +} + +void * +__dlvsym (void *handle, const char *name, const char *version_str) +{ + struct dlvsym_args args; + + args.handle = handle; + args.name = name; + args.caller = (ElfW(Addr)) __builtin_return_address (0); /* Compute hash value to the version string. */ - version.name = version_str; - version.hash = _dl_elf_hash (version_str); + args.version.name = version_str; + args.version.hash = _dl_elf_hash (version_str); /* We don't have a specific file where the symbol can be found. */ - version.filename = NULL; + args.version.filename = NULL; - return _dlerror_run (doit) ? NULL : (void *) (loadbase + ref->st_value); + return (_dlerror_run (dlvsym_doit, &args) + ? NULL : (void *) (args.loadbase + args.ref->st_value)); } weak_alias (__dlvsym, dlvsym) @@ -238,21 +238,26 @@ extern void _dl_signal_error (int errcode, error, *ERRSTRING is set to null. If there is an error, *ERRSTRING and *OBJECT are set to the strings passed to _dl_signal_error, and the error code passed is the return value. ERRSTRING if nonzero points to a - malloc'ed string which the caller has to free after use. */ + malloc'ed string which the caller has to free after use. + ARGS is passed as argument to OPERATE. */ extern int _dl_catch_error (char **errstring, const char **object, - void (*operate) (void)); + void (*operate) (void *), + void *args); /* Call OPERATE, receiving errors from `dl_signal_error'. Unlike `_dl_catch_error' the operation is resumed after the OPERATE - function returns. */ -extern void _dl_receive_error (receiver_fct fct, void (*operate) (void)); + function returns. + ARGS is passed as argument to OPERATE. */ +extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *), + void *args); /* Helper function for <dlfcn.h> functions. Runs the OPERATE function via _dl_catch_error. Returns zero for success, nonzero for failure; and - arranges for `dlerror' to return the error details. */ -extern int _dlerror_run (void (*operate) (void)); + arranges for `dlerror' to return the error details. + ARGS is passed as argument to OPERATE. */ +extern int _dlerror_run (void (*operate) (void *), void *args); /* Open the shared object NAME and map in its segments. @@ -140,6 +140,55 @@ _dl_start (void *arg) void _start (void); +/* Some helper functions. */ + +/* Arguments to relocate_doit. */ +struct relocate_args +{ + struct link_map *l; + int lazy; +}; + +struct map_args +{ + /* Argument to map_doit. */ + char *str; + /* Return value of map_doit. */ + struct link_map *main_map; +}; + +/* Arguments to version_check_doit. */ +struct version_check_args +{ + struct link_map *main_map; + int doexit; +}; + +static void +relocate_doit (void *a) +{ + struct relocate_args *args = (struct relocate_args *) a; + + _dl_relocate_object (args->l, _dl_object_relocation_scope (args->l), + args->lazy); +} + +static void +map_doit (void *a) +{ + struct map_args *args = (struct map_args *)a; + args->main_map = _dl_map_object (NULL, args->str, lt_library, 0); +} + +static void +version_check_doit (void *a) +{ + struct version_check_args *args = (struct version_check_args *)a; + if (_dl_check_all_versions (args->main_map, 1) && args->doexit) + /* We cannot start the application. Abort now. */ + _exit (1); +} + unsigned int _dl_skip_args; /* Nonzero if we were run directly. */ static void @@ -234,14 +283,13 @@ of this helper program; chances are you did not intend to run this program.\n", if (mode == verify) { - void doit (void) - { - main_map = _dl_map_object (NULL, _dl_argv[0], lt_library, 0); - } char *err_str = NULL; const char *obj_name __attribute__ ((unused)); + struct map_args args; - (void) _dl_catch_error (&err_str, &obj_name, doit); + args.str = _dl_argv[0]; + (void) _dl_catch_error (&err_str, &obj_name, map_doit, &args); + main_map = args.main_map; if (err_str != NULL) { free (err_str); @@ -469,14 +517,10 @@ of this helper program; chances are you did not intend to run this program.\n", /* Now let us see whether all libraries are available in the versions we need. */ { - void doit (void) - { - if (_dl_check_all_versions (main_map, 1) && mode == normal) - /* We cannot start the application. Abort now. */ - _exit (1); - } - - _dl_receive_error (print_missing_version, doit); + struct version_check_args args; + args.doexit = mode == normal; + args.main_map = main_map; + _dl_receive_error (print_missing_version, version_check_doit, &args); } if (mode != normal) @@ -535,11 +579,10 @@ of this helper program; chances are you did not intend to run this program.\n", else if (lazy >= 0) { /* We have to do symbol dependency testing. */ + struct relocate_args args; struct link_map *l; - void doit (void) - { - _dl_relocate_object (l, _dl_object_relocation_scope (l), lazy); - } + + args.lazy = lazy; l = _dl_loaded; while (l->l_next) @@ -548,7 +591,8 @@ of this helper program; chances are you did not intend to run this program.\n", { if (l != &_dl_rtld_map && l->l_opencount > 0) { - _dl_receive_error (print_unresolved, doit); + args.l = l; + _dl_receive_error (print_unresolved, relocate_doit, &args); *_dl_global_scope_end = NULL; } l = l->l_prev; |