From patchwork Thu May 18 08:28:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 69576 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 45B633836E92 for ; Thu, 18 May 2023 08:32:22 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward102c.mail.yandex.net (forward102c.mail.yandex.net [IPv6:2a02:6b8:c03:500:1:45:d181:d102]) by sourceware.org (Postfix) with ESMTPS id 9CF463857704 for ; Thu, 18 May 2023 08:29:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9CF463857704 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 forward102c.mail.yandex.net (Yandex) with ESMTP id 2CADD60029 for ; Thu, 18 May 2023 11:29:39 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-91.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id XTYe39MDZ0U0-PrLdeW2K; Thu, 18 May 2023 11:29:38 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.ru; s=mail; t=1684398578; bh=y/x5+YLzl0TZEURcrnlWIsTdddbJ+HMMqlig+tZ5PVI=; h=Message-Id:Date:In-Reply-To:Cc:Subject:References:To:From; b=D7qhJhY4D28UiYJozPOmIZUmpmbLl7jNo44nYHH/6enaZ/AmE/sW9MfK5alutY3f7 4+03c8Mkb3rduD9LzGHD2+hEdwmOvEl8SIdtYw9tRwUAMTPJdUWNz0euxi5aAUzG8U N3QFOxqsGrzpanr5Cab8Slg8znREglBRCPMLpTGQ= 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 04/14] split do_reloc_1() from dl_open_worker_begin() Date: Thu, 18 May 2023 13:28:44 +0500 Message-Id: <20230518082854.3903342-5-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=-10.2 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, URIBL_BLACK 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 is a mostly mechanical code split with no functional changes intended. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-open.c | 259 +++++++++++++++++++++++++------------------------- 1 file changed, 132 insertions(+), 127 deletions(-) diff --git a/elf/dl-open.c b/elf/dl-open.c index 2d985e21d8..a77a6143e2 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -486,114 +486,8 @@ call_dl_init (void *closure) } static void -dl_open_worker_begin (void *a) +do_reloc_1 (struct link_map *new, int mode, Lmid_t nsid, bool call_ctors) { - struct dl_open_args *args = a; - const char *file = args->file; - int mode = args->mode; - struct link_map *call_map = NULL; - - /* Determine the caller's map if necessary. This is needed in case - we have a DST, when we don't know the namespace ID we have to put - the new object in, or when the file name has no path in which - case we need to look along the RUNPATH/RPATH of the caller. */ - const char *dst = strchr (file, '$'); - if (dst != NULL || args->nsid == __LM_ID_CALLER - || strchr (file, '/') == NULL) - { - const void *caller_dlopen = args->caller_dlopen; - - /* We have to find out from which object the caller is calling. - By default we assume this is the main application. */ - call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; - - struct link_map *l = _dl_find_dso_for_object ((ElfW(Addr)) caller_dlopen); - - if (l) - call_map = l; - - if (args->nsid == __LM_ID_CALLER) - args->nsid = call_map->l_ns; - } - - /* The namespace ID is now known. Keep track of whether libc.so was - already loaded, to determine whether it is necessary to call the - early initialization routine (or clear libc_map on error). */ - args->libc_already_loaded = GL(dl_ns)[args->nsid].libc_map != NULL; - - /* Retain the old value, so that it can be restored. */ - args->original_global_scope_pending_adds - = GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds; - - /* One might be tempted to assert that we are RT_CONSISTENT at this point, but that - may not be true if this is a recursive call to dlopen. */ - _dl_debug_initialize (0, args->nsid); - - /* Load the named object. */ - struct link_map *new; - args->map = new = _dl_map_object (call_map, file, lt_loaded, 0, - mode | __RTLD_CALLMAP, args->nsid); - - /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is - set and the object is not already loaded. */ - if (new == NULL) - { - assert (mode & RTLD_NOLOAD); - return; - } - - if (__glibc_unlikely (mode & __RTLD_SPROF)) - /* This happens only if we load a DSO for 'sprof'. */ - return; - - /* This object is directly loaded. */ - ++new->l_direct_opencount; - - /* It was already open. */ - if (__glibc_unlikely (new->l_searchlist.r_list != NULL)) - { - /* Let the user know about the opencount. */ - if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) - _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n", - new->l_name, new->l_ns, new->l_direct_opencount); - - /* If the user requested the object to be in the global - namespace but it is not so far, prepare to add it now. This - can raise an exception to do a malloc failure. */ - if ((mode & RTLD_GLOBAL) && new->l_global == 0) - add_to_global_resize (new); - - /* Mark the object as not deletable if the RTLD_NODELETE flags - was passed. */ - if (__glibc_unlikely (mode & RTLD_NODELETE)) - { - if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES) - && !new->l_nodelete_active) - _dl_debug_printf ("marking %s [%lu] as NODELETE\n", - new->l_name, new->l_ns); - new->l_nodelete_active = true; - } - - /* Finalize the addition to the global scope. */ - if ((mode & RTLD_GLOBAL) && new->l_global == 0) - add_to_global_update (new); - - const int r_state __attribute__ ((unused)) - = _dl_debug_update (args->nsid)->r_state; - assert (r_state == RT_CONSISTENT); - - return; - } - - /* Schedule NODELETE marking for the directly loaded object if - requested. */ - if (__glibc_unlikely (mode & RTLD_NODELETE)) - new->l_nodelete_pending = true; - - /* Load that object's dependencies. */ - _dl_map_object_deps (new, NULL, 0, 0, - mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT)); - /* So far, so good. Now check the versions. */ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) if (new->l_searchlist.r_list[i]->l_real->l_versions == NULL) @@ -612,23 +506,6 @@ dl_open_worker_begin (void *a) #endif } -#ifdef SHARED - /* Auditing checkpoint: we have added all objects. */ - _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT); -#endif - - /* Notify the debugger all new objects are now ready to go. */ - struct r_debug *r = _dl_debug_update (args->nsid); - r->r_state = RT_CONSISTENT; - _dl_debug_state (); - LIBC_PROBE (map_complete, 3, args->nsid, r, new); - - _dl_open_check (new); - - /* Print scope information. */ - if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) - _dl_show_scope (new, 0); - /* Only do lazy relocation if `LD_BIND_NOW' is not set. */ int reloc_mode = mode & __RTLD_AUDIT; if (GLRO(dl_lazy)) @@ -753,20 +630,148 @@ dl_open_worker_begin (void *a) /* Notify the debugger all new objects have been relocated. */ if (relocation_in_progress) - LIBC_PROBE (reloc_complete, 3, args->nsid, r, new); + LIBC_PROBE (reloc_complete, 3, nsid, r, new); /* If libc.so was not there before, attempt to call its early initialization routine. Indicate to the initialization routine whether the libc being initialized is the one in the base namespace. */ - if (!args->libc_already_loaded) + if (call_ctors) { /* dlopen cannot be used to load an initial libc by design. */ - struct link_map *libc_map = GL(dl_ns)[args->nsid].libc_map; + struct link_map *libc_map = GL(dl_ns)[nsid].libc_map; _dl_call_libc_early_init (libc_map, false); } +} + +static void +dl_open_worker_begin (void *a) +{ + struct dl_open_args *args = a; + const char *file = args->file; + int mode = args->mode; + struct link_map *call_map = NULL; + + /* Determine the caller's map if necessary. This is needed in case + we have a DST, when we don't know the namespace ID we have to put + the new object in, or when the file name has no path in which + case we need to look along the RUNPATH/RPATH of the caller. */ + const char *dst = strchr (file, '$'); + if (dst != NULL || args->nsid == __LM_ID_CALLER + || strchr (file, '/') == NULL) + { + const void *caller_dlopen = args->caller_dlopen; + + /* We have to find out from which object the caller is calling. + By default we assume this is the main application. */ + call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + + struct link_map *l = _dl_find_dso_for_object ((ElfW(Addr)) caller_dlopen); + + if (l) + call_map = l; + + if (args->nsid == __LM_ID_CALLER) + args->nsid = call_map->l_ns; + } + + /* The namespace ID is now known. Keep track of whether libc.so was + already loaded, to determine whether it is necessary to call the + early initialization routine (or clear libc_map on error). */ + args->libc_already_loaded = GL(dl_ns)[args->nsid].libc_map != NULL; + + /* Retain the old value, so that it can be restored. */ + args->original_global_scope_pending_adds + = GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds; + + /* One might be tempted to assert that we are RT_CONSISTENT at this point, but that + may not be true if this is a recursive call to dlopen. */ + _dl_debug_initialize (0, args->nsid); + + /* Load the named object. */ + struct link_map *new; + args->map = new = _dl_map_object (call_map, file, lt_loaded, 0, + mode | __RTLD_CALLMAP, args->nsid); + + /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is + set and the object is not already loaded. */ + if (new == NULL) + { + assert (mode & RTLD_NOLOAD); + return; + } + + if (__glibc_unlikely (mode & __RTLD_SPROF)) + /* This happens only if we load a DSO for 'sprof'. */ + return; + + /* This object is directly loaded. */ + ++new->l_direct_opencount; + + /* It was already open. */ + if (__glibc_unlikely (new->l_searchlist.r_list != NULL)) + { + /* Let the user know about the opencount. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) + _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n", + new->l_name, new->l_ns, new->l_direct_opencount); + + /* If the user requested the object to be in the global + namespace but it is not so far, prepare to add it now. This + can raise an exception to do a malloc failure. */ + if ((mode & RTLD_GLOBAL) && new->l_global == 0) + add_to_global_resize (new); + + /* Mark the object as not deletable if the RTLD_NODELETE flags + was passed. */ + if (__glibc_unlikely (mode & RTLD_NODELETE)) + { + if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES) + && !new->l_nodelete_active) + _dl_debug_printf ("marking %s [%lu] as NODELETE\n", + new->l_name, new->l_ns); + new->l_nodelete_active = true; + } + + /* Finalize the addition to the global scope. */ + if ((mode & RTLD_GLOBAL) && new->l_global == 0) + add_to_global_update (new); + + const int r_state __attribute__ ((unused)) + = _dl_debug_update (args->nsid)->r_state; + assert (r_state == RT_CONSISTENT); + + return; + } + + /* Schedule NODELETE marking for the directly loaded object if + requested. */ + if (__glibc_unlikely (mode & RTLD_NODELETE)) + new->l_nodelete_pending = true; + + /* Load that object's dependencies. */ + _dl_map_object_deps (new, NULL, 0, 0, + mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT)); + +#ifdef SHARED + /* Auditing checkpoint: we have added all objects. */ + _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT); +#endif + + /* Notify the debugger all new objects are now ready to go. */ + struct r_debug *r = _dl_debug_update (args->nsid); + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + LIBC_PROBE (map_complete, 3, args->nsid, r, new); + + _dl_open_check (new); + + /* Print scope information. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) + _dl_show_scope (new, 0); args->worker_continue = true; + do_reloc_1 (new, mode, args->nsid, !args->libc_already_loaded); } static void