From patchwork Thu Jul 20 19:15:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Thibault X-Patchwork-Id: 791747 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-82307-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="rMDZX9km"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xD3XM1Xwtz9s4s for ; Fri, 21 Jul 2017 05:16:02 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:mime-version :content-type; q=dns; s=default; b=D5R7hRokc1w1EPAAU1Uq4QkOQ2/fQ Zufc7zajTQZkCNiCOoECdiCu9wPDbTtG3xbEuM84i+fpznsA4BFocXCwpaGkDAzJ IcK0LdCYpjJjHWgD/xaXgOGoB68nWzEhUdVJtsadvoVCGNnpjKkkgNOyjxUWVkDb 9CRFYDkbE2c44k= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:mime-version :content-type; s=default; bh=EMdL3Hz7YfGI0Si3GCgOO8gywWE=; b=rMD ZX9kmzlPrp+J9baChHvK4EMqhoUf1mTyR+34yIH5rf5C1IbRc2FasTiod8SNonzk 0WYrvN8B+80MOlb1/FhUMM+MDFYN5vgDhFVkNL5hScLhOPs8jnMBOM7TIlchtIwS RbsrwqvNdqGRXBJezHgy0JZ6/mtkbSlkSLew5cQc= Received: (qmail 120994 invoked by alias); 20 Jul 2017 19:15:44 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 120816 invoked by uid 89); 20 Jul 2017 19:15:38 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.1 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS, SPF_NEUTRAL autolearn=ham version=3.3.2 spammy=executions, Samuel, thibault, Thibault X-HELO: hera.aquilenet.fr Date: Thu, 20 Jul 2017 14:15:18 -0500 From: Samuel Thibault To: libc-alpha@sourceware.org Subject: [PATCH] Add RTLD_RELOAD to dlopen Message-ID: <20170720191517.xah6rggoaeqgbokf@var.youpi.perso.aquilenet.fr> MIME-Version: 1.0 Content-Disposition: inline User-Agent: NeoMutt/20170113 (1.7.2) Hello, In our parallel programming projects, we would like to load some DSO several times within the same process, because we want to share the addresse space for passing data pointers between parallel executions, and the DSO has global variables and such which we want to see duplicated. Unfortunately, dlopen() does not re-load the DSO when it is already loaded. One workaround is to cp the file under another name, but that's ugly and does not share the memory pages. The patch proposed here simply adds an RTLD_RELOAD flag which disables checking for the DSO being already loaded, thus always loading the DSO again. There is no actual code modification, only the addition of two if()s and reindent. Samuel 2017-07-19 Samuel Thibault * bits/dlfcn.h (RTLD_RELOAD): New macro * sysdeps/mips/bits/dlfcn.h (RTLD_RELOAD): New macro * dlfcn/dlopen.c (dlopen_doit): Let args->mode contain RTLD_RELOAD. * elf/dl-load.c (_dl_map_object_from_fd): Do not match the file id when mode contains RTLD_RELOAD. (_dl_map_object): Do not match the file name when mode contains RTLD_RELOAD. * elf/tst-reload.c: New file. diff --git a/bits/dlfcn.h b/bits/dlfcn.h index 7786d8f939..371e8a0e3c 100644 --- a/bits/dlfcn.h +++ b/bits/dlfcn.h @@ -26,6 +26,7 @@ #define RTLD_BINDING_MASK 0x3 /* Mask of binding time value. */ #define RTLD_NOLOAD 0x00004 /* Do not load the object. */ #define RTLD_DEEPBIND 0x00008 /* Use deep binding. */ +#define RTLD_RELOAD 0x00010 /* Reload the object. */ /* If the following bit is set in the MODE argument to `dlopen', the symbols of the loaded object and its dependencies are made diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c index 22120655d2..d317565b7f 100644 --- a/dlfcn/dlopen.c +++ b/dlfcn/dlopen.c @@ -60,7 +60,7 @@ dlopen_doit (void *a) if (args->mode & ~(RTLD_BINDING_MASK | RTLD_NOLOAD | RTLD_DEEPBIND | RTLD_GLOBAL | RTLD_LOCAL | RTLD_NODELETE - | __RTLD_SPROF)) + | RTLD_RELOAD | __RTLD_SPROF)) _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-load.c b/elf/dl-load.c index c1b6d4ba0f..6cd28dc15e 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -894,20 +894,23 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, } /* Look again to see if the real name matched another already loaded. */ - for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next) - if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id)) - { - /* The object is already loaded. - Just bump its reference count and return it. */ - __close (fd); + if ((mode & RTLD_RELOAD) == 0) + { + for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next) + if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id)) + { + /* The object is already loaded. + Just bump its reference count and return it. */ + __close (fd); - /* If the name is not in the list of names for this object add - it. */ - free (realname); - add_name_to_object (l, name); + /* If the name is not in the list of names for this object add + it. */ + free (realname); + add_name_to_object (l, name); - return l; - } + return l; + } + } #ifdef SHARED /* When loading into a namespace other than the base one we must @@ -1902,33 +1905,36 @@ _dl_map_object (struct link_map *loader, const char *name, assert (nsid < GL(dl_nns)); /* Look for this name among those already loaded. */ - for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next) + if ((mode & RTLD_RELOAD) == 0) { - /* If the requested name matches the soname of a loaded object, - use that object. Elide this check for names that have not - yet been opened. */ - if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0)) - continue; - if (!_dl_name_match_p (name, l)) + for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next) { - const char *soname; - - if (__glibc_likely (l->l_soname_added) - || l->l_info[DT_SONAME] == NULL) + /* If the requested name matches the soname of a loaded object, + use that object. Elide this check for names that have not + yet been opened. */ + if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0)) continue; + if (!_dl_name_match_p (name, l)) + { + const char *soname; - soname = ((const char *) D_PTR (l, l_info[DT_STRTAB]) - + l->l_info[DT_SONAME]->d_un.d_val); - if (strcmp (name, soname) != 0) - continue; + if (__glibc_likely (l->l_soname_added) + || l->l_info[DT_SONAME] == NULL) + continue; - /* We have a match on a new name -- cache it. */ - add_name_to_object (l, soname); - l->l_soname_added = 1; - } + soname = ((const char *) D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_SONAME]->d_un.d_val); + if (strcmp (name, soname) != 0) + continue; - /* We have a match. */ - return l; + /* We have a match on a new name -- cache it. */ + add_name_to_object (l, soname); + l->l_soname_added = 1; + } + + /* We have a match. */ + return l; + } } /* Display information if we are debugging. */ diff --git a/elf/tst-reload.c b/elf/tst-reload.c new file mode 100644 index 0000000000..1fb25e7c97 --- /dev/null +++ b/elf/tst-reload.c @@ -0,0 +1,83 @@ +/* Verify that RTLD_NOLOAD works as expected. + + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +static int +do_test (void) +{ + /* Test that no object is loaded with RTLD_NOLOAD. */ + void *h1 = dlopen (LIBM_SO, RTLD_LAZY | RTLD_NOLOAD); + if (h1 != NULL) + { + printf ("h1: DSO has been loaded while it should have not\n"); + return 1; + } + + /* Test that loading an already loaded object returns the same handle. */ + void *h2 = dlopen (LIBM_SO, RTLD_LAZY); + if (h2 == NULL) + { + printf ("h2: failed to open DSO: %s\n", dlerror ()); + return 1; + } + void *h3 = dlopen (LIBM_SO, RTLD_LAZY); + if (h3 == NULL) + { + printf ("h3: failed to open DSO: %s\n", dlerror ()); + return 1; + } + if (h3 != h2) + { + printf ("h3: should return the same object\n"); + return 1; + } + + /* Test that reloading an already loaded object returns a different handle. */ + void *h4 = dlopen (LIBM_SO, RTLD_LAZY | RTLD_RELOAD); + if (h4 == NULL) + { + printf ("h4: failed to open DSO: %s\n", dlerror ()); + return 1; + } + if (h4 == h2) + { + printf ("h4: should not return the same object\n"); + return 1; + } + + /* Cleanup */ + if (dlclose (h4) != 0) + { + printf ("h4: dlclose failed: %s\n", dlerror ()); + return 1; + } + if (dlclose (h2) != 0) + { + printf ("h2: dlclose failed: %s\n", dlerror ()); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/mips/bits/dlfcn.h b/sysdeps/mips/bits/dlfcn.h index 95b2fa0973..c4bf5e149b 100644 --- a/sysdeps/mips/bits/dlfcn.h +++ b/sysdeps/mips/bits/dlfcn.h @@ -26,6 +26,7 @@ #define RTLD_BINDING_MASK 0x3 /* Mask of binding time value. */ #define RTLD_NOLOAD 0x00008 /* Do not load the object. */ #define RTLD_DEEPBIND 0x00010 /* Use deep binding. */ +#define RTLD_RELOAD 0x00020 /* Reload the object. */ /* If the following bit is set in the MODE argument to `dlopen', the symbols of the loaded object and its dependencies are made