@@ -884,6 +884,8 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned int rflags,
#endif
(*rpnt)->dyn = tpnt;
tpnt->usage_count++;
+ if (tpnt->rtld_flags & RTLD_NODELETE)
+ tpnt->usage_count++;
#ifdef __LDSO_STANDALONE_SUPPORT__
tpnt->libtype = (epnt->e_type == ET_DYN) ? elf_lib : elf_executable;
#else
@@ -818,7 +818,7 @@ static int do_dlclose(void *vhandle, int need_fini)
_dl_handles = rpnt->next_handle;
_dl_if_debug_print("%s: usage count: %d\n",
handle->dyn->libname, handle->dyn->usage_count);
- if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
+ if (handle->dyn->usage_count != 1) {
handle->dyn->usage_count--;
free(handle);
return 0;
@@ -840,7 +840,7 @@ static int do_dlclose(void *vhandle, int need_fini)
for (j = 0; j < handle->init_fini.nlist; ++j) {
tpnt = handle->init_fini.init_fini[j];
tpnt->usage_count--;
- if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
+ if (tpnt->usage_count == 0) {
if ((tpnt->dynamic_info[DT_FINI]
|| tpnt->dynamic_info[DT_FINI_ARRAY])
&& need_fini
@@ -5,7 +5,7 @@
export UCLIBC_ONLY := 1
TESTS := dltest dltest2 dlstatic test1 test2 test3 dlundef dlafk dladdr \
- testscope nodelete tst-origin
+ testscope nodelete nodelete1 tst-origin
ifneq ($(HAVE_SHARED),y)
TESTS_DISABLED := test3
@@ -80,3 +80,5 @@ LDFLAGS_nodelete := -rdynamic -ldl
LDFLAGS_nodelmod1.so := -Wl,-z,nodelete
LDFLAGS_nodelmod3.so := ./nodelmod4.so
LDFLAGS_nodelmod4.so := -Wl,-z,nodelete
+nodelete1: nodelmod1.so nodelmod2.so
+LDFLAGS_nodelete1 := -rdynamic -ldl
new file mode 100644
@@ -0,0 +1,59 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int fini_ran;
+
+#define LIBNAME1 "nodelmod1.so"
+
+static int
+do_test (void)
+{
+ /* Verify ability to reload RTLD_NODELETE libraries.
+ */
+ void *p;
+
+ p = dlopen (LIBNAME1, RTLD_NOW);
+ if (p == NULL)
+ {
+ printf ("failed to load "LIBNAME1": %s\n", dlerror ());
+ exit (1);
+ }
+
+ if (dlclose (p) != 0)
+ {
+ puts ("failed to close "LIBNAME1"");
+ exit (1);
+ }
+
+ p = dlopen (LIBNAME1, RTLD_LAZY);
+ if (p == NULL)
+ {
+ printf ("failed to load "LIBNAME1": %s\n", dlerror ());
+ exit (1);
+ }
+
+ if (dlclose (p) != 0)
+ {
+ puts ("failed to close "LIBNAME1"");
+ exit (1);
+ }
+
+ p = dlopen ("nodelmod2.so", RTLD_LAZY);
+ if (p == NULL)
+ {
+ printf ("failed to load \"nodelmod2.so\": %s\n", dlerror ());
+ exit (1);
+ }
+ if (dlclose (p) != 0)
+ {
+ puts ("failed to close \"nodelmod2.so\"");
+ exit (1);
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
It can happen under certain cases that the DSO had refcount 0, but was already loaded. (NODELETE flag is set, or it is pulled in via both NEEDED dependency and explicit dlopen()). Add extra reference count for NODELETE objects, this will ensure that the reference count never drops below one. It is improved version of http://lists.busybox.net/pipermail/uclibc/2013-June/047826.html Signed-off-by: Leonid Lisovskiy <lly.dev@gmail.com> --- ldso/ldso/dl-elf.c | 2 ++ ldso/libdl/libdl.c | 4 ++-- test/dlopen/Makefile.in | 4 +++- test/dlopen/nodelete1.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 test/dlopen/nodelete1.c