@@ -41,6 +41,9 @@
#define RTLD_NODELETE 0x01000
#ifdef __USE_GNU
+/* Do not relocte object on dlopen(). */
+#define RTLD_NORELOCATE 0x02000
+
/* To support profiling of shared objects it is a good idea to call
the function found using `dlsym' using the following macro since
these calls do not use the PLT. But this would mean the dynamic
@@ -50,7 +50,7 @@ dlopen_doit (void *a)
if (args->mode & ~(RTLD_BINDING_MASK | RTLD_NOLOAD | RTLD_DEEPBIND
| RTLD_GLOBAL | RTLD_LOCAL | RTLD_NODELETE
- | __RTLD_SPROF))
+ | __RTLD_SPROF | RTLD_NORELOCATE))
_dl_signal_error (0, NULL, NULL, _("invalid mode parameter"));
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
@@ -31,7 +31,7 @@
#include <tls.h>
#include <atomic.h>
#include <elf_machine_sym_no_match.h>
-
+#include <dl-main.h>
#include <assert.h>
#define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
@@ -759,6 +759,10 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope = symbol_scope;
+ if (undef_map && !undef_map->l_relocated && undef_map->l_reloc_deferred
+ && undef_map->l_type == lt_loaded)
+ _dl_object_reloc (undef_map);
+
bump_num_relocations ();
/* DL_LOOKUP_RETURN_NEWEST does not make sense for versioned
@@ -127,4 +127,6 @@ _Noreturn void _dl_help (const char *argv0, struct dl_main_state *state)
/* Print a diagnostics dump. */
_Noreturn void _dl_print_diagnostics (char **environ) attribute_hidden;
+extern void _dl_object_reloc (struct link_map *l) attribute_hidden;
+
#endif /* _DL_MAIN */
@@ -223,6 +223,8 @@ _dl_find_dso_for_object (const ElfW(Addr) addr)
|| _dl_addr_inside_object (l, (ElfW(Addr)) addr)))
{
assert (ns == l->l_ns);
+ if (!l->l_relocated)
+ return NULL;
return l;
}
return NULL;
@@ -681,7 +683,7 @@ dl_reloc_worker_begin (void *a)
do_reloc_1 (args->map, args->mode, args->nsid, !args->libc_already_loaded);
}
-static void
+void
_dl_object_reloc (struct link_map *l)
{
struct dl_exception ex;
@@ -689,6 +691,8 @@ _dl_object_reloc (struct link_map *l)
struct dl_open_args *args = l->l_dlopen_args;
int mode = args->mode;
+ l->l_reloc_deferred = 0;
+
/* Protects global and module specific TLS state. */
__rtld_lock_lock_recursive (GL(dl_load_tls_lock));
err = _dl_catch_exception (&ex, dl_reloc_worker_begin, args);
@@ -760,6 +764,10 @@ dl_open_worker_begin (void *a)
/* This happens only if we load a DSO for 'sprof'. */
return;
+ if (__glibc_unlikely ((mode & RTLD_NORELOCATE) && new->l_relocated))
+ _dl_signal_error (EINVAL, new->l_name, NULL,
+ N_("RTLD_NORELOCATE used with already relocated object"));
+
/* This object is directly loaded. */
++new->l_direct_opencount;
@@ -821,7 +829,12 @@ dl_open_worker_begin (void *a)
memcpy (new->l_dlopen_args, args, sizeof (*args));
}
else
- new->l_dlopen_args = args;
+ {
+ assert (new->l_relocated);
+ /* If relocated, this flag is filtered above. */
+ assert (!(mode & RTLD_NORELOCATE));
+ new->l_dlopen_args = args;
+ }
}
else
{
@@ -873,7 +886,10 @@ dl_open_worker (void *a)
struct link_map *new = args->map;
- _dl_object_reloc (new);
+ if (__glibc_likely (!(args->mode & RTLD_NORELOCATE)))
+ _dl_object_reloc (new);
+ else
+ new->l_reloc_deferred = 1;
/* For !lt_loaded we do not malloc(), so needs to null out here. */
if (new->l_type != lt_loaded)
new->l_dlopen_args = NULL;
@@ -180,6 +180,7 @@ struct link_map
unsigned int l_dt_relr_ref:1; /* Nonzero if GLIBC_ABI_DT_RELR is
referenced. */
unsigned int l_map_completed:1; /* Nonzero if object fully mapped. */
+ unsigned int l_reloc_deferred:1; /* Nonzero if relocation deferred. */
unsigned int l_relocated:1; /* Nonzero if object's relocations done. */
unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */
unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */
This flag allows to delay the relocation of the dlopen()ed object. If this flag is used, then the relocation is called from _dl_lookup_symbol_x(), which is called by dlsym() among other places. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev <stsp2@yandex.ru> --- bits/dlfcn.h | 3 +++ dlfcn/dlopen.c | 2 +- elf/dl-lookup.c | 6 +++++- elf/dl-main.h | 2 ++ elf/dl-open.c | 22 +++++++++++++++++++--- include/link.h | 1 + 6 files changed, 31 insertions(+), 5 deletions(-)