For Google b/8315591, experimental implementation of dlopen_with_offset.

This commit is contained in:
Paul Pluzhnikov 2014-03-10 14:02:07 -07:00
parent 05fc85cb17
commit 17c46147bc
14 changed files with 193 additions and 56 deletions

View File

@ -262,3 +262,19 @@ ports/sysdeps/unix/sysv/linux/tile/bits/local_lim.h
Forward ported from cl/59612021, cl/59817832, and cl/59176280.
(ahh, google-local)
Versions.def
dlfcn/Versions
dlfcn/dlfcn.h
dlfcn/dlmopen.c
dlfcn/dlopen.c
dlfcn/dlopenold.c
elf/dl-deps.c
elf/dl-libc.c
elf/dl-load.c
elf/dl-open.c
elf/rtld.c
include/dlfcn.h
sysdeps/generic/ldsodefs.h
For Google b/8315591, experimental implementation of dlopen_with_offset.
Forward-ported from cl/59286541, cl/59438930
(ppluzhnikov, google-local)

View File

@ -50,6 +50,7 @@ libdl {
GLIBC_2.1
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.15
}
libm {
GLIBC_2.0

View File

@ -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;
}

View File

@ -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,

View File

@ -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,55 @@ dlmopen_doit (void *a)
GLRO(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 (__builtin_expect (_dlfcn_hook != NULL, 0))
return _dlfcn_hook->dlmopen_with_offset (nsid, file, offset,
mode, RETURN_ADDRESS (0));
# endif
struct dlmopen_args args;
args.nsid = nsid;
args.file = file;
args.offset = offset;
args.mode = mode;
args.caller = DL_CALLER;
return __dlmopen_common (&args);
}
# 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 +132,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)

View File

@ -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,51 @@ dlopen_doit (void *a)
| __RTLD_SPROF))
GLRO(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 (__builtin_expect (_dlfcn_hook != NULL, 0))
return _dlfcn_hook->dlopen_with_offset (file, offset, mode, DL_CALLER);
# endif
struct dlopen_args args;
args.file = file;
args.offset = offset;
args.mode = mode;
args.caller = DL_CALLER;
return __dlopen_common (&args);
}
# ifdef SHARED
strong_alias (__dlopen_with_offset, __google_dlopen_with_offset)
# endif
void *
__dlopen (const char *file, int mode DL_CALLER_DECL)
{
@ -82,20 +129,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>

View File

@ -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);

View File

@ -60,7 +60,7 @@ openaux (void *a)
{
struct openaux_args *args = (struct openaux_args *) a;
args->aux = _dl_map_object (args->map, args->name,
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->open_mode,

View File

@ -59,6 +59,7 @@ struct do_dlopen_args
{
/* Argument to do_dlopen. */
const char *name;
off_t offset;
/* Opening mode. */
int mode;
/* This is the caller of the dlopen() function. */
@ -84,9 +85,9 @@ do_dlopen (void *ptr)
{
struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
/* Open and relocate the shared object. */
args->map = GLRO(dl_open) (args->name, args->mode, args->caller_dlopen,
__LM_ID_CALLER, __libc_argc, __libc_argv,
__environ);
args->map = GLRO(dl_open) (args->name, args->offset, args->mode,
args->caller_dlopen, __LM_ID_CALLER,
__libc_argc, __libc_argv, __environ);
}
static void
@ -154,6 +155,7 @@ __libc_dlopen_mode (const char *name, int mode)
{
struct do_dlopen_args args;
args.name = name;
args.offset = 0;
args.mode = mode;
args.caller_dlopen = RETURN_ADDRESS (0);

View File

@ -925,7 +925,8 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
static
#endif
struct link_map *
_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
_dl_map_object_from_fd (const char *name, int fd, off_t offset,
struct filebuf *fbp,
char *realname, struct link_map *loader, int l_type,
int mode, void **stack_endp, Lmid_t nsid)
{
@ -1152,7 +1153,12 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
& ~(GLRO(dl_pagesize) - 1));
c->dataend = ph->p_vaddr + ph->p_filesz;
c->allocend = ph->p_vaddr + ph->p_memsz;
c->mapoff = ph->p_offset & ~(GLRO(dl_pagesize) - 1);
if (offset & (GLRO(dl_pagesize) - 1))
{
errstring = N_("invalid offset");
goto call_lose;
}
c->mapoff = offset + ph->p_offset & ~(GLRO(dl_pagesize) - 1);
/* Determine whether there is a gap between the last segment
and this one. */
@ -1674,7 +1680,8 @@ print_search_path (struct r_search_path_elem **list,
this could mean there is something wrong in the installation and the
user might want to know about this. */
static int
open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
open_verify (const char *name, off_t offset,
struct filebuf *fbp, struct link_map *loader,
int whatcode, bool *found_other_class, bool free_name)
{
/* This is the expected ELF header. */
@ -1742,6 +1749,9 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
unsigned int osversion;
size_t maplength;
if (__lseek (fd, offset, SEEK_SET) == -1)
goto close_and_out;
/* We successfully opened the file. Now verify it is a file
we can use. */
__set_errno (0);
@ -1936,7 +1946,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
if MAY_FREE_DIRS is true. */
static int
open_path (const char *name, size_t namelen, int secure,
open_path (const char *name, size_t namelen, off_t offset, int secure,
struct r_search_path_struct *sps, char **realname,
struct filebuf *fbp, struct link_map *loader, int whatcode,
bool *found_other_class)
@ -1988,8 +1998,8 @@ open_path (const char *name, size_t namelen, int secure,
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
_dl_debug_printf (" trying file=%s\n", buf);
fd = open_verify (buf, fbp, loader, whatcode, found_other_class,
false);
fd = open_verify (buf, offset, fbp, loader, whatcode,
found_other_class, false);
if (this_dir->status[cnt] == unknown)
{
if (fd != -1)
@ -2118,7 +2128,7 @@ match_one (const char *name, struct link_map *l)
struct link_map *
internal_function
_dl_map_object (struct link_map *loader, const char *name,
_dl_map_object (struct link_map *loader, const char *name, off_t offset,
int type, int trace_mode, int mode, Lmid_t nsid)
{
int fd;
@ -2210,7 +2220,7 @@ _dl_map_object (struct link_map *loader, const char *name,
for (l = loader; l; l = l->l_loader)
if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
{
fd = open_path (name, namelen, mode & __RTLD_SECURE,
fd = open_path (name, namelen, offset, mode & __RTLD_SECURE,
&l->l_rpath_dirs,
&realname, &fb, loader, LA_SER_RUNPATH,
&found_other_class);
@ -2226,7 +2236,7 @@ _dl_map_object (struct link_map *loader, const char *name,
&& main_map != NULL && main_map->l_type != lt_loaded
&& cache_rpath (main_map, &main_map->l_rpath_dirs, DT_RPATH,
"RPATH"))
fd = open_path (name, namelen, mode & __RTLD_SECURE,
fd = open_path (name, namelen, offset, mode & __RTLD_SECURE,
&main_map->l_rpath_dirs,
&realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
&found_other_class);
@ -2234,7 +2244,8 @@ _dl_map_object (struct link_map *loader, const char *name,
/* Try the LD_LIBRARY_PATH environment variable. */
if (fd == -1 && env_path_list.dirs != (void *) -1)
fd = open_path (name, namelen, mode & __RTLD_SECURE, &env_path_list,
fd = open_path (name, namelen, offset,
mode & __RTLD_SECURE, &env_path_list,
&realname, &fb,
loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
LA_SER_LIBPATH, &found_other_class);
@ -2243,7 +2254,7 @@ _dl_map_object (struct link_map *loader, const char *name,
if (fd == -1 && loader != NULL
&& cache_rpath (loader, &loader->l_runpath_dirs,
DT_RUNPATH, "RUNPATH"))
fd = open_path (name, namelen, mode & __RTLD_SECURE,
fd = open_path (name, namelen, offset, mode & __RTLD_SECURE,
&loader->l_runpath_dirs, &realname, &fb, loader,
LA_SER_RUNPATH, &found_other_class);
@ -2291,7 +2302,7 @@ _dl_map_object (struct link_map *loader, const char *name,
if (cached != NULL)
{
fd = open_verify (cached,
fd = open_verify (cached, 0,
&fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
LA_SER_CONFIG, &found_other_class, false);
if (__builtin_expect (fd != -1, 1))
@ -2313,7 +2324,8 @@ _dl_map_object (struct link_map *loader, const char *name,
&& ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
|| __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
&& rtld_search_dirs.dirs != (void *) -1)
fd = open_path (name, namelen, mode & __RTLD_SECURE, &rtld_search_dirs,
fd = open_path (name, namelen, offset, mode & __RTLD_SECURE,
&rtld_search_dirs,
&realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
/* Add another newline when we are tracing the library loading. */
@ -2330,7 +2342,7 @@ _dl_map_object (struct link_map *loader, const char *name,
fd = -1;
else
{
fd = open_verify (realname, &fb,
fd = open_verify (realname, offset, &fb,
loader ?: GL(dl_ns)[nsid]._ns_loaded, 0,
&found_other_class, true);
if (__builtin_expect (fd, 0) == -1)
@ -2392,8 +2404,8 @@ _dl_map_object (struct link_map *loader, const char *name,
}
void *stack_end = __libc_stack_end;
return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode,
&stack_end, nsid);
return _dl_map_object_from_fd (name, fd, offset, &fb, realname, loader, type,
mode, &stack_end, nsid);
}

View File

@ -45,6 +45,8 @@ extern int __libc_multiple_libcs; /* Defined in init-first.c. */
struct dl_open_args
{
const char *file;
/* ELF header at offset in file. */
off_t offset;
int mode;
/* This is the caller of the dlopen() function. */
const void *caller_dlopen;
@ -221,7 +223,7 @@ dl_open_worker (void *a)
/* Load the named object. */
struct link_map *new;
args->map = new = _dl_map_object (call_map, file, lt_loaded, 0,
args->map = new = _dl_map_object (call_map, file, args->offset, lt_loaded, 0,
mode | __RTLD_CALLMAP, args->nsid);
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
@ -592,9 +594,9 @@ cannot load any more object with static TLS"));
new->l_name, new->l_ns, new->l_direct_opencount);
}
void *
_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
_dl_open (const char *file, off_t offset, int mode,
const void *caller_dlopen, Lmid_t nsid,
int argc, char *argv[], char *env[])
{
if ((mode & RTLD_BINDING_MASK) == 0)
@ -638,6 +640,7 @@ no more namespaces available for dlmopen()"));
struct dl_open_args args;
args.file = file;
args.offset = offset;
args.mode = mode;
args.caller_dlopen = caller_dlopen;
args.caller_dl_open = RETURN_ADDRESS (0);

View File

@ -634,15 +634,15 @@ static void
map_doit (void *a)
{
struct map_args *args = (struct map_args *) a;
args->map = _dl_map_object (args->loader, args->str, lt_library, 0,
args->mode, LM_ID_BASE);
args->map = _dl_map_object (args->loader, args->str, 0, lt_library,
0, args->mode, LM_ID_BASE);
}
static void
dlmopen_doit (void *a)
{
struct dlmopen_args *args = (struct dlmopen_args *) a;
args->map = _dl_open (args->fname,
args->map = _dl_open (args->fname, 0,
(RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT
| __RTLD_SECURE),
dl_main, LM_ID_NEWLM, _dl_argc, INTUSE(_dl_argv),
@ -1088,7 +1088,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, rtld_progname, lt_library, 0,
_dl_map_object (NULL, rtld_progname, 0, lt_library, 0,
__RTLD_OPENEXEC, LM_ID_BASE);
HP_TIMING_NOW (stop);

View File

@ -1,5 +1,6 @@
#ifndef _DLFCN_H
#include <dlfcn/dlfcn.h>
#include <sys/types.h>
#ifndef _ISOMAC
#include <link.h> /* For ElfW. */
#include <stdbool.h>
@ -106,6 +107,8 @@ extern int _dlerror_run (void (*operate) (void *), void *args)
struct dlfcn_hook
{
void *(*dlopen) (const char *file, int mode, void *dl_caller);
void *(*dlopen_with_offset) (const char *file, off_t offset,
int mode, void *dl_caller);
int (*dlclose) (void *handle);
void *(*dlsym) (void *handle, const char *name, void *dl_caller);
void *(*dlvsym) (void *handle, const char *name, const char *version,
@ -116,6 +119,8 @@ struct dlfcn_hook
void **extra_info, int flags);
int (*dlinfo) (void *handle, int request, void *arg, void *dl_caller);
void *(*dlmopen) (Lmid_t nsid, const char *file, int mode, void *dl_caller);
void *(*dlmopen_with_offset) (Lmid_t nsid, const char *file, off_t offset,
int mode, void *dl_caller);
void *pad[4];
};
@ -124,8 +129,14 @@ libdl_hidden_proto (_dlfcn_hook)
extern void *__dlopen (const char *file, int mode DL_CALLER_DECL)
attribute_hidden;
extern void *__dlopen_with_offset (const char *file, off_t offset,
int mode DL_CALLER_DECL)
attribute_hidden;
extern void *__dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
attribute_hidden;
extern void *__dlmopen_with_offset (Lmid_t nsid, const char *file, off_t offset,
int mode DL_CALLER_DECL)
attribute_hidden;
extern int __dlclose (void *handle)
attribute_hidden;
extern void *__dlsym (void *handle, const char *name DL_CALLER_DECL)

View File

@ -624,8 +624,9 @@ struct rtld_global_ro
int, int,
struct link_map *);
int (*_dl_check_caller) (const void *, enum allowmask);
void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen,
Lmid_t nsid, int argc, char *argv[], char *env[]);
void *(*_dl_open) (const char *file, off_t offset, int mode,
const void *caller_dlopen, Lmid_t nsid,
int argc, char *argv[], char *env[]);
void (*_dl_close) (void *map);
void *(*_dl_tls_get_addr_soft) (struct link_map *);
#ifdef HAVE_DL_DISCOVER_OSVERSION
@ -797,10 +798,12 @@ extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *),
/* Open the shared object NAME and map in its segments.
ELF header is at OFFSET into the file.
LOADER's DT_RPATH is used in searching for NAME.
If the object is already opened, returns its existing map. */
extern struct link_map *_dl_map_object (struct link_map *loader,
const char *name,
off_t offset,
int type, int trace_mode, int mode,
Lmid_t nsid)
internal_function attribute_hidden;
@ -1068,8 +1071,9 @@ extern int _dl_check_caller (const void *caller, enum allowmask mask)
/* Open the shared object NAME, relocate it, and run its initializer if it
hasn't already been run. MODE is as for `dlopen' (see <dlfcn.h>). If
the object is already opened, returns its existing map. */
extern void *_dl_open (const char *name, int mode, const void *caller,
Lmid_t nsid, int argc, char *argv[], char *env[])
extern void *_dl_open (const char *name, off_t offset, int mode,
const void *caller, Lmid_t nsid,
int argc, char *argv[], char *env[])
attribute_hidden;
/* Free or queue for freeing scope OLD. If other threads might be