diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/Makefile | 2 | ||||
-rw-r--r-- | elf/dl-close.c | 23 | ||||
-rw-r--r-- | elf/dl-object.c | 6 | ||||
-rw-r--r-- | elf/dl-open.c | 50 |
4 files changed, 78 insertions, 3 deletions
diff --git a/elf/Makefile b/elf/Makefile index 0831662715..160d901526 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -106,7 +106,7 @@ tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ reldep reldep2 reldep3 reldep4 $(tests-nodelete-$(have-z-nodelete)) \ $(tests-nodlopen-$(have-z-nodlopen)) neededtest neededtest2 \ neededtest3 neededtest4 unload2 lateglobal initfirst global \ - restest2 next #dblload dblunload + restest2 next dblload dblunload test-srcs = tst-pathopt tests-vis-yes = vismain tests-nodelete-yes = nodelete diff --git a/elf/dl-close.c b/elf/dl-close.c index e83865f0a1..dfc204d478 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -146,6 +146,25 @@ _dl_close (void *_map) (imap, (void *) imap->l_addr + imap->l_info[DT_FINI]->d_un.d_ptr)) (); } + else if (new_opencount[i] != 0 && imap->l_type == lt_loaded) + { + /* The object is still used. But the object we are unloading + right now is responsible for loading it and therefore we + have the search list of the current object in its scope. + Remove it. */ + struct r_scope_elem **runp = imap->l_scope; + + while (*runp != NULL) + if (*runp == &map->l_searchlist) + { + /* Copy all later elements. */ + while ((runp[0] = runp[1]) != NULL) + ++runp; + break; + } + else + ++runp; + } /* Store the new l_opencount value. */ imap->l_opencount = new_opencount[i]; @@ -241,6 +260,10 @@ _dl_close (void *_map) if (imap != map) free (imap->l_initfini); + /* Remove the scope array if we allocated it. */ + if (imap->l_scope != imap->l_scope_mem) + free (imap->l_scope); + if (imap->l_phdr_allocated) free ((void *) imap->l_phdr); diff --git a/elf/dl-object.c b/elf/dl-object.c index 07e428e8e6..9c32c08ff2 100644 --- a/elf/dl-object.c +++ b/elf/dl-object.c @@ -50,6 +50,12 @@ _dl_new_object (char *realname, const char *libname, int type, new->l_loader = loader; /* new->l_global = 0; We use calloc therefore not necessary. */ + /* Use the 'l_scope_mem' array by default for the the 'l_scope' + information. If we need more entries we will allocate a large + array dynamically. */ + new->l_scope = new->l_scope_mem; + new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]); + /* Counter for the scopes we have to handle. */ idx = 0; diff --git a/elf/dl-open.c b/elf/dl-open.c index ec88c79a27..f79c317da8 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -295,9 +295,55 @@ dl_open_worker (void *a) l = l->l_prev; } - /* Increment the open count for all dependencies. */ + /* Increment the open count for all dependencies. If the file is + not loaded as a dependency here add the search list of the newly + loaded object to the scope. */ for (i = 0; i < new->l_searchlist.r_nlist; ++i) - ++new->l_searchlist.r_list[i]->l_opencount; + if (++new->l_searchlist.r_list[i]->l_opencount > 1 + && new->l_searchlist.r_list[i]->l_type == lt_loaded) + { + struct link_map *imap = new->l_searchlist.r_list[i]; + struct r_scope_elem **runp = imap->l_scope; + size_t cnt = 0; + + while (*runp != NULL) + { + ++cnt; + ++runp; + } + + if (__builtin_expect (cnt + 1 < imap->l_scope_max, 0)) + { + /* The 'r_scope' array is too small. Allocate a new one + dynamically. */ + struct r_scope_elem **newp; + size_t new_size = imap->l_scope_max * 2; + + if (imap->l_scope == imap->l_scope_mem) + { + newp = (struct r_scope_elem **) + malloc (new_size * sizeof (struct r_scope_elem *)); + if (newp == NULL) + _dl_signal_error (ENOMEM, "dlopen", NULL, + N_("cannot create scope list")); + imap->l_scope = memcpy (newp, imap->l_scope, + cnt * imap->l_scope_max); + } + else + { + newp = (struct r_scope_elem **) + realloc (imap->l_scope, + new_size * sizeof (struct r_scope_elem *)); + if (newp == NULL) + _dl_signal_error (ENOMEM, "dlopen", NULL, + N_("cannot create scope list")); + imap->l_scope = newp; + } + + imap->l_scope[cnt++] = &new->l_searchlist; + imap->l_scope[cnt] = NULL; + } + } /* Run the initializer functions of new objects. */ _dl_init (new, __libc_argc, __libc_argv, __environ); |