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)
GLIBC_2.1
GLIBC_2.3.3
GLIBC_2.3.4
+ GLIBC_2.15
}
libm {
GLIBC_2.0
GLIBC_2.3.4 {
dlmopen;
}
+ GLIBC_2.15 {
+ __google_dlopen_with_offset; __google_dlmopen_with_offset;
+ }
GLIBC_PRIVATE {
_dlfcn_hook;
}
#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>
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));
/* 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,
{
/* Namespace ID. */
Lmid_t nsid;
+ /* ELF header at offset in file. */
+ off_t offset;
/* The arguments for dlopen_doit. */
const char *file;
int mode;
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 (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
+__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 (nsid, file, mode, RETURN_ADDRESS (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
- 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);
+strong_alias (__dlmopen_with_offset, __google_dlmopen_with_offset)
+# endif
- return args.new;
+void *
+__dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
+{
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
# endif
+
+ struct dlmopen_args args;
+ args.nsid = nsid;
+ args.file = file;
+ args.offset = 0;
+ args.mode = mode;
+ args.caller = DL_CALLER;
+
+ return __dlmopen_common (&args);
}
# ifdef SHARED
strong_alias (__dlmopen, dlmopen)
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;
| __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 (const char *file, int mode DL_CALLER_DECL)
+__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 (file, mode, DL_CALLER);
+ 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)
+{
# ifdef SHARED
- return _dlerror_run (dlopen_doit, &args) ? NULL : args.new;
-# else
- if (_dlerror_run (dlopen_doit, &args))
- return NULL;
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlopen (file, mode, DL_CALLER);
+# endif
- __libc_register_dl_open_hook ((struct link_map *) args.new);
- __libc_register_dlfcn_hook ((struct link_map *) args.new);
+ struct dlopen_args args;
+ args.file = file;
+ args.offset = 0;
+ args.mode = mode;
+ args.caller = DL_CALLER;
- return args.new;
-# endif
+ return __dlopen_common (&args);
}
# ifdef SHARED
# include <shlib-compat.h>
{
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);
{
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,
{
/* Argument to do_dlopen. */
const char *name;
+ off_t offset;
/* Opening mode. */
int mode;
/* This is the caller of the dlopen() function. */
{
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
{
struct do_dlopen_args args;
args.name = name;
+ args.offset = 0;
args.mode = mode;
args.caller_dlopen = RETURN_ADDRESS (0);
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)
{
& ~(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. */
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. */
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);
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)
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)
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;
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);
&& 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);
/* 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);
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);
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))
&& ((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. */
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)
}
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);
}
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;
/* 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
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)
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);
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),
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);
#ifndef _DLFCN_H
#include <dlfcn/dlfcn.h>
+#include <sys/types.h>
#ifndef _ISOMAC
#include <link.h> /* For ElfW. */
#include <stdbool.h>
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,
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];
};
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)
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
/* 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;
/* 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