diff options
author | Paul Pluzhnikov <ppluzhnikov@google.com> | 2014-03-10 14:02:07 -0700 |
---|---|---|
committer | Paul Pluzhnikov <ppluzhnikov@google.com> | 2014-03-10 14:02:07 -0700 |
commit | 9590be99606bd4903f8527affccc7c0957a9515d (patch) | |
tree | 129dbe46c6bfd6004804fad25c153f8cd6fd2b50 /dlfcn | |
parent | 8eb1716c9108c987004e886e37d33296032d8663 (diff) | |
download | glibc-9590be99606bd4903f8527affccc7c0957a9515d.zip glibc-9590be99606bd4903f8527affccc7c0957a9515d.tar.gz glibc-9590be99606bd4903f8527affccc7c0957a9515d.tar.bz2 |
For Google b/8315591, experimental implementation of dlopen_with_offset.
Diffstat (limited to 'dlfcn')
-rw-r--r-- | dlfcn/Versions | 3 | ||||
-rw-r--r-- | dlfcn/dlfcn.h | 12 | ||||
-rw-r--r-- | dlfcn/dlmopen.c | 56 | ||||
-rw-r--r-- | dlfcn/dlopen.c | 60 | ||||
-rw-r--r-- | dlfcn/dlopenold.c | 2 |
5 files changed, 108 insertions, 25 deletions
diff --git a/dlfcn/Versions b/dlfcn/Versions index 97902f0..77b0cf0 100644 --- a/dlfcn/Versions +++ b/dlfcn/Versions @@ -11,6 +11,9 @@ libdl { GLIBC_2.3.4 { dlmopen; } + GLIBC_2.15 { + __google_dlopen_with_offset; __google_dlmopen_with_offset; + } GLIBC_PRIVATE { _dlfcn_hook; } diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h index 0921fd7..caa92e6 100644 --- a/dlfcn/dlfcn.h +++ b/dlfcn/dlfcn.h @@ -22,6 +22,7 @@ #include <features.h> #define __need_size_t #include <stddef.h> +#include <sys/types.h> /* Collect various system dependent definitions and declarations. */ #include <bits/dlfcn.h> @@ -55,6 +56,11 @@ __BEGIN_DECLS passed to `dlsym' to get symbol values from it. */ extern void *dlopen (const char *__file, int __mode) __THROWNL; +/* Same as above, but ELF header is at OFF from the start of file. */ +extern void *__google_dlopen_with_offset (__const char *__file, + off_t offset, + int __mode) __THROW; + /* Unmap and close a shared object opened by `dlopen'. The handle cannot be used again after calling `dlclose'. */ extern int dlclose (void *__handle) __THROWNL __nonnull ((1)); @@ -68,6 +74,12 @@ extern void *dlsym (void *__restrict __handle, /* Like `dlopen', but request object to be allocated in a new namespace. */ extern void *dlmopen (Lmid_t __nsid, const char *__file, int __mode) __THROWNL; +/* Same as above, but ELF header is at OFF from the start of file. */ +extern void *__google_dlmopen_with_offset (Lmid_t __nsid, + __const char *__file, + off_t offset, + int __mode) __THROW; + /* Find the run-time address in the shared object HANDLE refers to of the symbol called NAME with VERSION. */ extern void *dlvsym (void *__restrict __handle, diff --git a/dlfcn/dlmopen.c b/dlfcn/dlmopen.c index 2be1319..fb665ed 100644 --- a/dlfcn/dlmopen.c +++ b/dlfcn/dlmopen.c @@ -40,6 +40,8 @@ struct dlmopen_args { /* Namespace ID. */ Lmid_t nsid; + /* ELF header at offset in file. */ + off_t offset; /* The arguments for dlopen_doit. */ const char *file; int mode; @@ -70,13 +72,52 @@ dlmopen_doit (void *a) _dl_signal_error (EINVAL, NULL, NULL, N_("invalid mode")); } - args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN, + args->new = GLRO(dl_open) (args->file ?: "", args->offset, args->mode | __RTLD_DLOPEN, args->caller, args->nsid, __dlfcn_argc, __dlfcn_argv, __environ); } +static void * +__dlmopen_common (struct dlmopen_args *args) +{ + +# ifdef SHARED + return _dlerror_run (dlmopen_doit, args) ? NULL : args->new; +# else + if (_dlerror_run (dlmopen_doit, args)) + return NULL; + + __libc_register_dl_open_hook ((struct link_map *) args->new); + __libc_register_dlfcn_hook ((struct link_map *) args->new); + + return args->new; +# endif +} + +void * +__dlmopen_with_offset (Lmid_t nsid, const char *file, off_t offset, + int mode DL_CALLER_DECL) +{ +# ifdef SHARED + if (!rtld_active ()) + return _dlfcn_hook->dlmopen_with_offset (nsid, file, offset, mode, RETURN_ADDRESS (0)); +# endif + + struct dlmopen_args oargs; + oargs.nsid = nsid; + oargs.file = file; + oargs.offset = offset; + oargs.mode = mode; + oargs.caller = DL_CALLER; + + return __dlmopen_common (&oargs); +} +# ifdef SHARED +strong_alias (__dlmopen_with_offset, __google_dlmopen_with_offset) +# endif + void * __dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL) { @@ -88,20 +129,11 @@ __dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL) struct dlmopen_args args; args.nsid = nsid; args.file = file; + args.offset = 0; args.mode = mode; args.caller = DL_CALLER; -# ifdef SHARED - return _dlerror_run (dlmopen_doit, &args) ? NULL : args.new; -# else - if (_dlerror_run (dlmopen_doit, &args)) - return NULL; - - __libc_register_dl_open_hook ((struct link_map *) args.new); - __libc_register_dlfcn_hook ((struct link_map *) args.new); - - return args.new; -# endif + return __dlmopen_common (&args); } # ifdef SHARED strong_alias (__dlmopen, dlmopen) diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c index c62ca23..319ae6e 100644 --- a/dlfcn/dlopen.c +++ b/dlfcn/dlopen.c @@ -33,12 +33,21 @@ dlopen (const char *file, int mode) static_link_warning (dlopen) #endif +void * +dlopen_with_offset (const char *file, off_t offset, int mode) +{ + return __dlopen_with_offset (file, offset, mode, RETURN_ADDRESS (0)); +} +static_link_warning (dlopen_with_offset) + #else struct dlopen_args { /* The arguments for dlopen_doit. */ const char *file; + /* ELF header at offset in file. */ + off_t offset; int mode; /* The return value of dlopen_doit. */ void *new; @@ -65,13 +74,49 @@ dlopen_doit (void *a) | __RTLD_SPROF)) _dl_signal_error (0, NULL, NULL, _("invalid mode parameter")); - args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN, + args->new = GLRO(dl_open) (args->file ?: "", args->offset, args->mode | __RTLD_DLOPEN, args->caller, args->file == NULL ? LM_ID_BASE : NS, __dlfcn_argc, __dlfcn_argv, __environ); } +static void * +__dlopen_common (struct dlopen_args *args) +{ +# ifdef SHARED + return _dlerror_run (dlopen_doit, args) ? NULL : args->new; +# else + if (_dlerror_run (dlopen_doit, args)) + return NULL; + + __libc_register_dl_open_hook ((struct link_map *) args->new); + __libc_register_dlfcn_hook ((struct link_map *) args->new); + + return args->new; +# endif +} + +void * +__dlopen_with_offset (const char *file, off_t offset, int mode DL_CALLER_DECL) +{ +# ifdef SHARED + if (!rtld_active ()) + return _dlfcn_hook->dlopen_with_offset (file, offset, mode, DL_CALLER); +# endif + + struct dlopen_args oargs; + oargs.file = file; + oargs.offset = offset; + oargs.mode = mode; + oargs.caller = DL_CALLER; + + return __dlopen_common (&oargs); +} +# ifdef SHARED +strong_alias (__dlopen_with_offset, __google_dlopen_with_offset) +# endif + void * __dlopen (const char *file, int mode DL_CALLER_DECL) { @@ -82,20 +127,11 @@ __dlopen (const char *file, int mode DL_CALLER_DECL) struct dlopen_args args; args.file = file; + args.offset = 0; args.mode = mode; args.caller = DL_CALLER; -# ifdef SHARED - return _dlerror_run (dlopen_doit, &args) ? NULL : args.new; -# else - if (_dlerror_run (dlopen_doit, &args)) - return NULL; - - __libc_register_dl_open_hook ((struct link_map *) args.new); - __libc_register_dlfcn_hook ((struct link_map *) args.new); - - return args.new; -# endif + return __dlopen_common (&args); } # ifdef SHARED # include <shlib-compat.h> diff --git a/dlfcn/dlopenold.c b/dlfcn/dlopenold.c index d3b6a6c..d9ca12d 100644 --- a/dlfcn/dlopenold.c +++ b/dlfcn/dlopenold.c @@ -51,7 +51,7 @@ dlopen_doit (void *a) { struct dlopen_args *args = (struct dlopen_args *) a; - args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN, + args->new = GLRO(dl_open) (args->file ?: "", 0, args->mode | __RTLD_DLOPEN, args->caller, args->file == NULL ? LM_ID_BASE : NS, __dlfcn_argc, __dlfcn_argv, __environ); |