diff options
author | Roland McGrath <roland@gnu.org> | 1996-06-04 23:06:02 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1996-06-04 23:06:02 +0000 |
commit | f68b86cc7bdcee246296d49f3a3318c1b97693f0 (patch) | |
tree | 34a9e7bde9fd4f15d76192869b800ff7ff461874 /elf/dlclose.c | |
parent | 14d898aef6373abaf64a7b17f32e8ce3f655cdf3 (diff) | |
download | glibc-f68b86cc7bdcee246296d49f3a3318c1b97693f0.tar.gz glibc-f68b86cc7bdcee246296d49f3a3318c1b97693f0.tar.xz glibc-f68b86cc7bdcee246296d49f3a3318c1b97693f0.zip |
Tue Jun 4 18:57:57 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
* elf/dladdr.c: Remove #include <setjmp.h>, we don't use it. * shlib-versions: Set libdl=2. * elf/dl-deps.c (_dl_map_object_deps): Use a linked list of alloca'd elements and then scan it to fill the single malloc'd array, instead of using realloc to grow the array in the first pass. _dl_map_object may do some mallocs that break our stream of reallocs, and the minimal realloc can't handle that. * elf/dl-init.c (_dl_init_next): Take argument, link_map whose searchlist describes the piece of the DT_NEEDED graph to be initialized. * elf/link.h: Update prototype. * sysdeps/i386/dl-machine.h (RTLD_START): Pass _dl_loaded as argument to _dl_init_next. * sysdeps/m68k/dl-machine.h: Likewise. * elf/dl-deps.c (_dl_open): Pass new object as arg to _dl_init_next. * elf/link.h (struct link_map): Add `l_reserved' member, soaking up extra bits in last byte. * elf/dl-deps.c (_dl_map_object_deps): Use that for mark bit to avoid putting dup elts in search list. * elf/dlclose.c: Use MAP->l_searchlist to find deps to close. * elf/dlsym.c: Don't tweak linked list. Scope array given to _dl_lookup_symbol does the right thing. Tue Jun 4 02:25:44 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
Diffstat (limited to 'elf/dlclose.c')
-rw-r--r-- | elf/dlclose.c | 100 |
1 files changed, 52 insertions, 48 deletions
diff --git a/elf/dlclose.c b/elf/dlclose.c index 06b2d1bdcd..fbb3ca6fe2 100644 --- a/elf/dlclose.c +++ b/elf/dlclose.c @@ -1,5 +1,5 @@ /* dlclose -- Close a handle opened by `dlopen'. -Copyright (C) 1995 Free Software Foundation, Inc. +Copyright (C) 1995, 1996 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 @@ -32,64 +32,68 @@ dlclose (void *handle) void doit (void) { struct link_map *map = handle; + struct link_map **list; + unsigned int i; if (map->l_opencount == 0) LOSE ("shared object not open"); /* Decrement the reference count. */ - --map->l_opencount; - - if (map->l_opencount == 0 && map->l_type == lt_loaded) + if (--map->l_opencount > 0 || map->l_type != lt_loaded) + /* There are still references to this object. Do nothing more. */ + return; + + list = map->l_searchlist; + + /* The search list contains a counted reference to each object it + points to, the 0th elt being MAP itself. Decrement the reference + counts on all the objects MAP depends on. */ + for (i = 1; i < map->l_nsearchlist; ++i) + --list[i]->l_opencount; + + /* Clear the search list so it doesn't get freed while we are still + using it. We have cached it in LIST and will free it when + finished. */ + map->l_searchlist = NULL; + + /* Check each element of the search list to see if all references to + it are gone. */ + for (i = 0; i < map->l_nsearchlist; ++i) { - /* That was the last reference, and this was a dlopen-loaded - object. We can unmap it. */ - const Elf32_Phdr *ph; - - if (map->l_info[DT_FINI]) - /* Call its termination function. */ - (*(void (*) (void)) ((void *) map->l_addr + - map->l_info[DT_FINI]->d_un.d_ptr)) (); - - if (map->l_info[DT_NEEDED]) + struct link_map *map = list[i]; + if (map->l_opencount == 0 && map->l_type == lt_loaded) { - /* Also close all the dependencies. */ - const char *strtab - = (void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr; - const Elf32_Dyn *d; - for (d = map->l_ld; d->d_tag != DT_NULL; ++d) - if (d->d_tag == DT_NEEDED) + /* That was the last reference, and this was a dlopen-loaded + object. We can unmap it. */ + const Elf32_Phdr *ph; + + if (map->l_info[DT_FINI]) + /* Call its termination function. */ + (*(void (*) (void)) ((void *) map->l_addr + + map->l_info[DT_FINI]->d_un.d_ptr)) (); + + /* Unmap the segments. */ + for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph) + if (ph->p_type == PT_LOAD) { - /* It must already be open, since this one needed it; - so dlopen will just find us its `struct link_map' - and bump its reference count. */ - struct link_map *o, *dep - = dlopen (strtab + d->d_un.d_val, RTLD_LAZY); - --dep->l_opencount; /* Lose the ref from that dlopen. */ - /* Now we have the handle; we can close it for real. */ - o = map; - map = dep; - doit (); - map = o; + Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1); + Elf32_Addr mapend = ((ph->p_vaddr + ph->p_memsz + + ph->p_align - 1) + & ~(ph->p_align - 1)); + munmap ((caddr_t) mapstart, mapend - mapstart); } - } - /* Unmap the segments. */ - for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph) - if (ph->p_type == PT_LOAD) - { - Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1); - Elf32_Addr mapend = ((ph->p_vaddr + ph->p_memsz - + ph->p_align - 1) - & ~(ph->p_align - 1)); - munmap ((caddr_t) mapstart, mapend - mapstart); - } - - /* Finally, unlink the data structure and free it. */ - map->l_prev->l_next = map->l_next; - if (map->l_next) - map->l_next->l_prev = map->l_prev; - free (map); + /* Finally, unlink the data structure and free it. */ + map->l_prev->l_next = map->l_next; + if (map->l_next) + map->l_next->l_prev = map->l_prev; + if (map->l_searchlist) + free (map->l_searchlist); + free (map); + } } + + free (list); } return _dlerror_run (doit) ? -1 : 0; |