]>
Commit | Line | Data |
---|---|---|
26b4d766 UD |
1 | /* Close a shared object opened by `_dl_open'. |
2 | Copyright (C) 1996, 1997 Free Software Foundation, Inc. | |
afd4eb37 UD |
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 not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
ba79d61b RM |
19 | |
20 | #include <link.h> | |
21 | #include <dlfcn.h> | |
22 | #include <stdlib.h> | |
8d6468d0 | 23 | #include <string.h> |
ba79d61b RM |
24 | #include <sys/types.h> |
25 | #include <sys/mman.h> | |
9a0a462c | 26 | #include <bits/libc-lock.h> |
ba79d61b RM |
27 | |
28 | ||
26b4d766 UD |
29 | /* During the program run we must not modify the global data of |
30 | loaded shared object simultanously in two threads. Therefore we | |
31 | protect `dlopen' and `dlclose' in dlclose.c. */ | |
32 | __libc_lock_define (extern, _dl_load_lock) | |
33 | ||
ba79d61b RM |
34 | #define LOSE(s) _dl_signal_error (0, map->l_name, s) |
35 | ||
36 | void | |
37 | _dl_close (struct link_map *map) | |
38 | { | |
39 | struct link_map **list; | |
40 | unsigned int i; | |
41 | ||
42 | if (map->l_opencount == 0) | |
43 | LOSE ("shared object not open"); | |
44 | ||
26b4d766 UD |
45 | /* Acquire the lock. */ |
46 | __libc_lock_lock (_dl_load_lock); | |
47 | ||
ba79d61b RM |
48 | /* Decrement the reference count. */ |
49 | if (--map->l_opencount > 0 || map->l_type != lt_loaded) | |
26b4d766 UD |
50 | { |
51 | /* There are still references to this object. Do nothing more. */ | |
52 | __libc_lock_unlock (_dl_load_lock); | |
53 | return; | |
54 | } | |
ba79d61b | 55 | |
4d6acc61 RM |
56 | /* Notify the debugger we are about to remove some loaded objects. */ |
57 | _r_debug.r_state = RT_DELETE; | |
58 | _dl_debug_state (); | |
59 | ||
ba79d61b RM |
60 | list = map->l_searchlist; |
61 | ||
62 | /* The search list contains a counted reference to each object it | |
63 | points to, the 0th elt being MAP itself. Decrement the reference | |
64 | counts on all the objects MAP depends on. */ | |
65 | for (i = 1; i < map->l_nsearchlist; ++i) | |
66 | --list[i]->l_opencount; | |
67 | ||
68 | /* Clear the search list so it doesn't get freed while we are still | |
69 | using it. We have cached it in LIST and will free it when | |
70 | finished. */ | |
71 | map->l_searchlist = NULL; | |
72 | ||
73 | /* Check each element of the search list to see if all references to | |
74 | it are gone. */ | |
75 | for (i = 0; i < map->l_nsearchlist; ++i) | |
76 | { | |
77 | struct link_map *map = list[i]; | |
78 | if (map->l_opencount == 0 && map->l_type == lt_loaded) | |
79 | { | |
80 | /* That was the last reference, and this was a dlopen-loaded | |
81 | object. We can unmap it. */ | |
82 | const ElfW(Phdr) *ph; | |
83 | ||
84 | if (map->l_info[DT_FINI]) | |
85 | /* Call its termination function. */ | |
86 | (*(void (*) (void)) ((void *) map->l_addr + | |
87 | map->l_info[DT_FINI]->d_un.d_ptr)) (); | |
88 | ||
89 | if (map->l_global) | |
90 | { | |
91 | /* This object is in the global scope list. Remove it. */ | |
92 | struct link_map **tail = _dl_global_scope_end; | |
93 | do | |
94 | --tail; | |
95 | while (*tail != map); | |
96 | --_dl_global_scope_end; | |
97 | memcpy (tail, tail + 1, _dl_global_scope_end - tail); | |
98 | _dl_global_scope_end[0] = NULL; | |
99 | _dl_global_scope_end[1] = NULL; | |
100 | } | |
101 | ||
102 | /* Unmap the segments. */ | |
103 | for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph) | |
104 | if (ph->p_type == PT_LOAD) | |
105 | { | |
106 | ElfW(Addr) mapstart = ph->p_vaddr & ~(ph->p_align - 1); | |
107 | ElfW(Addr) mapend = ((ph->p_vaddr + ph->p_memsz | |
108 | + ph->p_align - 1) | |
109 | & ~(ph->p_align - 1)); | |
110 | __munmap ((caddr_t) mapstart, mapend - mapstart); | |
111 | } | |
112 | ||
113 | /* Finally, unlink the data structure and free it. */ | |
57ba7bb4 UD |
114 | if (map->l_prev) |
115 | map->l_prev->l_next = map->l_next; | |
ba79d61b RM |
116 | if (map->l_next) |
117 | map->l_next->l_prev = map->l_prev; | |
118 | if (map->l_searchlist) | |
119 | free (map->l_searchlist); | |
120 | free (map); | |
121 | } | |
122 | } | |
123 | ||
124 | free (list); | |
4d6acc61 RM |
125 | |
126 | /* Notify the debugger those objects are finalized and gone. */ | |
127 | _r_debug.r_state = RT_CONSISTENT; | |
128 | _dl_debug_state (); | |
26b4d766 UD |
129 | |
130 | /* Release the lock. */ | |
131 | __libc_lock_unlock (_dl_load_lock); | |
ba79d61b | 132 | } |