about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Pluzhnikov <ppluzhnikov@google.com>2014-03-10 14:02:07 -0700
committerPaul Pluzhnikov <ppluzhnikov@google.com>2014-03-10 14:02:07 -0700
commit9590be99606bd4903f8527affccc7c0957a9515d (patch)
tree129dbe46c6bfd6004804fad25c153f8cd6fd2b50
parent8eb1716c9108c987004e886e37d33296032d8663 (diff)
downloadglibc-9590be99606bd4903f8527affccc7c0957a9515d.tar.gz
glibc-9590be99606bd4903f8527affccc7c0957a9515d.tar.xz
glibc-9590be99606bd4903f8527affccc7c0957a9515d.zip
For Google b/8315591, experimental implementation of dlopen_with_offset.
-rw-r--r--dlfcn/Versions3
-rw-r--r--dlfcn/dlfcn.h12
-rw-r--r--dlfcn/dlmopen.c56
-rw-r--r--dlfcn/dlopen.c60
-rw-r--r--dlfcn/dlopenold.c2
-rw-r--r--elf/dl-deps.c2
-rw-r--r--elf/dl-libc.c4
-rw-r--r--elf/dl-load.c38
-rw-r--r--elf/dl-open.c7
-rw-r--r--elf/rtld.c6
-rw-r--r--include/dlfcn.h11
-rw-r--r--sysdeps/generic/ldsodefs.h12
12 files changed, 162 insertions, 51 deletions
diff --git a/dlfcn/Versions b/dlfcn/Versions
index 97902f0dfd..77b0cf01c4 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 0921fd724c..caa92e6785 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 2be13195fe..fb665ed084 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 c62ca2305a..319ae6ef2e 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 d3b6a6cff5..d9ca12d9d8 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);
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index c975fcffd7..30830ff014 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -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,
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index fc01f5514d..41dccf0d04 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -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.  */
@@ -93,7 +94,7 @@ 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,
+  args->map = GLRO(dl_open) (args->name, args->offset, args->mode, args->caller_dlopen,
 			     __LM_ID_CALLER, __libc_argc, __libc_argv,
 			     __environ);
 }
@@ -186,6 +187,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);
 
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 4d8af1db41..e49d0862f9 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -809,7 +809,7 @@ 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, const char *origname, int fd,
+_dl_map_object_from_fd (const char *name, const char *origname, 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)
@@ -1035,7 +1035,12 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 	  c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize));
 	  c->dataend = ph->p_vaddr + ph->p_filesz;
 	  c->allocend = ph->p_vaddr + ph->p_memsz;
-	  c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize));
+	  if (offset & (GLRO(dl_pagesize) - 1))
+	    {
+	      errstring = N_("invalid offset");
+	      goto call_lose;
+	    }
+	  c->mapoff = ALIGN_DOWN(offset + ph->p_offset, GLRO(dl_pagesize));
 
 	  /* Determine whether there is a gap between the last segment
 	     and this one.  */
@@ -1400,7 +1405,7 @@ print_search_path (struct r_search_path_elem **list,
    If FD is not -1, then the file is already open and FD refers to it.
    In that case, FD is consumed for both successful and error returns.  */
 static int
-open_verify (const char *name, int fd,
+open_verify (const char *name, int fd, off_t offset,
              struct filebuf *fbp, struct link_map *loader,
 	     int whatcode, int mode, bool *found_other_class, bool free_name)
 {
@@ -1480,6 +1485,9 @@ open_verify (const char *name, int fd,
       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);
@@ -1699,7 +1707,7 @@ open_verify (const char *name, int fd,
    if MAY_FREE_DIRS is true.  */
 
 static int
-open_path (const char *name, size_t namelen, int mode,
+open_path (const char *name, size_t namelen, off_t offset, int mode,
 	   struct r_search_path_struct *sps, char **realname,
 	   struct filebuf *fbp, struct link_map *loader, int whatcode,
 	   bool *found_other_class)
@@ -1751,7 +1759,7 @@ open_path (const char *name, size_t namelen, int mode,
 	  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
 	    _dl_debug_printf ("  trying file=%s\n", buf);
 
-	  fd = open_verify (buf, -1, fbp, loader, whatcode, mode,
+	  fd = open_verify (buf, -1, offset, fbp, loader, whatcode, mode,
 			    found_other_class, false);
 	  if (this_dir->status[cnt] == unknown)
 	    {
@@ -1849,7 +1857,7 @@ open_path (const char *name, size_t namelen, int mode,
 /* Map in the shared object file NAME.  */
 
 struct link_map *
-_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;
@@ -1964,7 +1972,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,
+		fd = open_path (name, namelen, offset, mode,
 				&l->l_rpath_dirs,
 				&realname, &fb, loader, LA_SER_RUNPATH,
 				&found_other_class);
@@ -1980,7 +1988,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,
+	    fd = open_path (name, namelen, mode, offset,
 			    &main_map->l_rpath_dirs,
 			    &realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
 			    &found_other_class);
@@ -1988,7 +1996,7 @@ _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, &env_path_list,
+	fd = open_path (name, namelen, offset, mode, &env_path_list,
 			&realname, &fb,
 			loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
 			LA_SER_LIBPATH, &found_other_class);
@@ -1997,7 +2005,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,
+	fd = open_path (name, namelen, offset, mode,
 			&loader->l_runpath_dirs, &realname, &fb, loader,
 			LA_SER_RUNPATH, &found_other_class);
 
@@ -2006,7 +2014,7 @@ _dl_map_object (struct link_map *loader, const char *name,
           realname = _dl_sysdep_open_object (name, namelen, &fd);
           if (realname != NULL)
             {
-              fd = open_verify (realname, fd,
+              fd = open_verify (realname, fd, offset,
                                 &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
                                 LA_SER_CONFIG, mode, &found_other_class,
                                 false);
@@ -2060,7 +2068,7 @@ _dl_map_object (struct link_map *loader, const char *name,
 
 	      if (cached != NULL)
 		{
-		  fd = open_verify (cached, -1,
+		  fd = open_verify (cached, -1, 0,
 				    &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
 				    LA_SER_CONFIG, mode, &found_other_class,
 				    false);
@@ -2078,7 +2086,7 @@ _dl_map_object (struct link_map *loader, const char *name,
 	  && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
 	      || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB)))
 	  && rtld_search_dirs.dirs != (void *) -1)
-	fd = open_path (name, namelen, mode, &rtld_search_dirs,
+	fd = open_path (name, namelen, offset, mode, &rtld_search_dirs,
 			&realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
 
       /* Add another newline when we are tracing the library loading.  */
@@ -2095,7 +2103,7 @@ _dl_map_object (struct link_map *loader, const char *name,
 	fd = -1;
       else
 	{
-	  fd = open_verify (realname, -1, &fb,
+	  fd = open_verify (realname, -1, offset, &fb,
 			    loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode,
 			    &found_other_class, true);
 	  if (__glibc_unlikely (fd == -1))
@@ -2157,7 +2165,7 @@ _dl_map_object (struct link_map *loader, const char *name,
     }
 
   void *stack_end = __libc_stack_end;
-  return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
+  return _dl_map_object_from_fd (name, origname, fd, offset, &fb, realname, loader,
 				 type, mode, &stack_end, nsid);
 }
 
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 0e37dd74b6..0cf786b546 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -44,6 +44,8 @@
 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
@@ -531,7 +533,7 @@ TLS generation counter wrapped!  Please report this."));
 
 
 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)
@@ -581,6 +583,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);
diff --git a/elf/rtld.c b/elf/rtld.c
index 90f7eebdcf..9250cf4f94 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -622,7 +622,7 @@ map_doit (void *a)
 {
   struct map_args *args = (struct map_args *) a;
   int type = (args->mode == __RTLD_OPENEXEC) ? lt_executable : lt_library;
-  args->map = _dl_map_object (args->loader, args->str, type, 0,
+  args->map = _dl_map_object (args->loader, args->str, 0, type, 0,
 			      args->mode, LM_ID_BASE);
 }
 
@@ -630,7 +630,7 @@ 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, _dl_argv,
@@ -1086,7 +1086,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_executable, 0,
+	  _dl_map_object (NULL, rtld_progname, 0, lt_executable, 0,
 			  __RTLD_OPENEXEC, LM_ID_BASE);
 	  HP_TIMING_NOW (stop);
 
diff --git a/include/dlfcn.h b/include/dlfcn.h
index 12ef913e19..f3f6eb3811 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -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>
@@ -88,6 +89,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,
@@ -98,6 +101,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];
 };
 
@@ -106,8 +111,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)
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index caa5f1da4c..5e7224bb49 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -600,8 +600,9 @@ struct rtld_global_ro
 				   const struct r_found_version *, 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
@@ -856,10 +857,12 @@ int _dl_catch_exception (struct dl_exception *exception,
 libc_hidden_proto (_dl_catch_exception)
 
 /* 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) attribute_hidden;
 
@@ -1116,8 +1119,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