From patchwork Thu May 18 08:28:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 69580 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2412D388207B for ; Thu, 18 May 2023 08:33:58 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward100c.mail.yandex.net (forward100c.mail.yandex.net [178.154.239.211]) by sourceware.org (Postfix) with ESMTPS id 9BA28385354A for ; Thu, 18 May 2023 08:29:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9BA28385354A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=yandex.ru Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=yandex.ru Received: from mail-nwsmtp-smtp-production-main-91.iva.yp-c.yandex.net (mail-nwsmtp-smtp-production-main-91.iva.yp-c.yandex.net [IPv6:2a02:6b8:c0c:1186:0:640:38cb:0]) by forward100c.mail.yandex.net (Yandex) with ESMTP id CA047600B3 for ; Thu, 18 May 2023 11:29:43 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-91.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id XTYe39MDZ0U0-pHjssSzy; Thu, 18 May 2023 11:29:43 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.ru; s=mail; t=1684398583; bh=2gXTDrBcZEL/pAFT/w8FxjMaa1Y7Js1rb2/nPhhJOac=; h=Message-Id:Date:In-Reply-To:Cc:Subject:References:To:From; b=iYcPmeG+RPIIdsVi/k90VXaJSFPNliFQSwlgm73XaOiKAFwmUzdw9ybRk2b4UQolu gpqBl5m9dDeiP/g7nvJtUg2Xol3C40jwkdidDrX+1vgh7v4HzC5KTutWaL41aUURfZ OicwwjJ01GXFOxZPLlAst3SRp+jjAD+/umDnN/FQ= Authentication-Results: mail-nwsmtp-smtp-production-main-91.iva.yp-c.yandex.net; dkim=pass header.i=@yandex.ru From: Stas Sergeev To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 09/14] implement RTLD_NORELOCATE dlopen() flag Date: Thu, 18 May 2023 13:28:49 +0500 Message-Id: <20230518082854.3903342-10-stsp2@yandex.ru> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230518082854.3903342-1-stsp2@yandex.ru> References: <20230518082854.3903342-1-stsp2@yandex.ru> MIME-Version: 1.0 X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, GIT_PATCH_0, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" 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 --- 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(-) diff --git a/bits/dlfcn.h b/bits/dlfcn.h index d1e31cf4e0..9cf2d5fb80 100644 --- a/bits/dlfcn.h +++ b/bits/dlfcn.h @@ -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 diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c index 21ed2c964d..866ccf7a4a 100644 --- a/dlfcn/dlopen.c +++ b/dlfcn/dlopen.c @@ -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, diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index 05f36a2507..d60481676d 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -31,7 +31,7 @@ #include #include #include - +#include #include #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 diff --git a/elf/dl-main.h b/elf/dl-main.h index 92766d06b4..54d139f2c4 100644 --- a/elf/dl-main.h +++ b/elf/dl-main.h @@ -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 */ diff --git a/elf/dl-open.c b/elf/dl-open.c index f1f2e8d3a4..5106c9d029 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -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; diff --git a/include/link.h b/include/link.h index fa16dfa337..6c11c33417 100644 --- a/include/link.h +++ b/include/link.h @@ -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. */