Tue Jun 4 18:57:57 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / elf / dlclose.c
1 /* dlclose -- Close a handle opened by `dlopen'.
2 Copyright (C) 1995, 1996 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
20 #include <link.h>
21 #include <dlfcn.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/mman.h>
25
26
27 #define LOSE(s) _dl_signal_error (0, map->l_name, s)
28
29 int
30 dlclose (void *handle)
31 {
32   void doit (void)
33     {
34       struct link_map *map = handle;
35       struct link_map **list;
36       unsigned int i;
37
38       if (map->l_opencount == 0)
39         LOSE ("shared object not open");
40
41       /* Decrement the reference count.  */
42       if (--map->l_opencount > 0 || map->l_type != lt_loaded)
43         /* There are still references to this object.  Do nothing more.  */
44         return;
45
46       list = map->l_searchlist;
47
48       /* The search list contains a counted reference to each object it
49          points to, the 0th elt being MAP itself.  Decrement the reference
50          counts on all the objects MAP depends on.  */
51       for (i = 1; i < map->l_nsearchlist; ++i)
52         --list[i]->l_opencount;
53
54       /* Clear the search list so it doesn't get freed while we are still
55          using it.  We have cached it in LIST and will free it when
56          finished.  */
57       map->l_searchlist = NULL;
58
59       /* Check each element of the search list to see if all references to
60          it are gone.  */
61       for (i = 0; i < map->l_nsearchlist; ++i)
62         {
63           struct link_map *map = list[i];
64           if (map->l_opencount == 0 && map->l_type == lt_loaded)
65             {
66               /* That was the last reference, and this was a dlopen-loaded
67                  object.  We can unmap it.  */
68               const Elf32_Phdr *ph;
69
70               if (map->l_info[DT_FINI])
71                 /* Call its termination function.  */
72                 (*(void (*) (void)) ((void *) map->l_addr +
73                                      map->l_info[DT_FINI]->d_un.d_ptr)) ();
74
75               /* Unmap the segments.  */
76               for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
77                 if (ph->p_type == PT_LOAD)
78                   {
79                     Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
80                     Elf32_Addr mapend = ((ph->p_vaddr + ph->p_memsz
81                                           + ph->p_align - 1)
82                                          & ~(ph->p_align - 1));
83                     munmap ((caddr_t) mapstart, mapend - mapstart);
84                   }
85
86               /* Finally, unlink the data structure and free it.  */
87               map->l_prev->l_next = map->l_next;
88               if (map->l_next)
89                 map->l_next->l_prev = map->l_prev;
90               if (map->l_searchlist)
91                 free (map->l_searchlist);
92               free (map);
93             }
94         }
95
96       free (list);
97     }
98
99   return _dlerror_run (doit) ? -1 : 0;
100 }
101