]>
Commit | Line | Data |
---|---|---|
26b4d766 | 1 | /* Close a shared object opened by `_dl_open'. |
482eec0d | 2 | Copyright (C) 1996, 1997, 1998, 1999 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 | 19 | |
7afab53d | 20 | #include <assert.h> |
ba79d61b RM |
21 | #include <dlfcn.h> |
22 | #include <stdlib.h> | |
8d6468d0 | 23 | #include <string.h> |
a853022c UD |
24 | #include <bits/libc-lock.h> |
25 | #include <elf/ldsodefs.h> | |
ba79d61b RM |
26 | #include <sys/types.h> |
27 | #include <sys/mman.h> | |
28 | ||
29 | ||
26b4d766 UD |
30 | /* During the program run we must not modify the global data of |
31 | loaded shared object simultanously in two threads. Therefore we | |
32 | protect `dlopen' and `dlclose' in dlclose.c. */ | |
33 | __libc_lock_define (extern, _dl_load_lock) | |
34 | ||
ba79d61b RM |
35 | #define LOSE(s) _dl_signal_error (0, map->l_name, s) |
36 | ||
37 | void | |
d0fc4041 | 38 | internal_function |
ba79d61b RM |
39 | _dl_close (struct link_map *map) |
40 | { | |
41 | struct link_map **list; | |
6075607b | 42 | unsigned nsearchlist; |
ba79d61b RM |
43 | unsigned int i; |
44 | ||
45 | if (map->l_opencount == 0) | |
46 | LOSE ("shared object not open"); | |
47 | ||
26b4d766 UD |
48 | /* Acquire the lock. */ |
49 | __libc_lock_lock (_dl_load_lock); | |
50 | ||
ba79d61b | 51 | /* Decrement the reference count. */ |
a709dd43 | 52 | if (map->l_opencount > 1 || map->l_type != lt_loaded) |
26b4d766 UD |
53 | { |
54 | /* There are still references to this object. Do nothing more. */ | |
a709dd43 | 55 | --map->l_opencount; |
26b4d766 UD |
56 | __libc_lock_unlock (_dl_load_lock); |
57 | return; | |
58 | } | |
ba79d61b | 59 | |
be935610 UD |
60 | list = map->l_searchlist.r_list; |
61 | nsearchlist = map->l_searchlist.r_nlist; | |
a709dd43 UD |
62 | |
63 | /* Call all termination functions at once. */ | |
6075607b | 64 | for (i = 0; i < nsearchlist; ++i) |
a709dd43 UD |
65 | { |
66 | struct link_map *imap = list[i]; | |
b48abe3c | 67 | if (imap->l_opencount == 1 && imap->l_type == lt_loaded |
7a68c94a UD |
68 | && imap->l_info[DT_FINI] |
69 | /* Skip any half-cooked objects that were never initialized. */ | |
70 | && imap->l_init_called) | |
a709dd43 | 71 | { |
b48abe3c UD |
72 | /* When debugging print a message first. */ |
73 | if (_dl_debug_impcalls) | |
74 | _dl_debug_message (1, "\ncalling fini: ", imap->l_name, | |
75 | "\n\n", NULL); | |
76 | /* Call its termination function. */ | |
77 | (*(void (*) (void)) ((void *) imap->l_addr | |
78 | + imap->l_info[DT_FINI]->d_un.d_ptr)) (); | |
a709dd43 UD |
79 | } |
80 | } | |
81 | ||
4d6acc61 RM |
82 | /* Notify the debugger we are about to remove some loaded objects. */ |
83 | _r_debug.r_state = RT_DELETE; | |
84 | _dl_debug_state (); | |
85 | ||
ba79d61b RM |
86 | /* The search list contains a counted reference to each object it |
87 | points to, the 0th elt being MAP itself. Decrement the reference | |
88 | counts on all the objects MAP depends on. */ | |
6075607b | 89 | for (i = 0; i < nsearchlist; ++i) |
ba79d61b RM |
90 | --list[i]->l_opencount; |
91 | ||
ba79d61b RM |
92 | /* Check each element of the search list to see if all references to |
93 | it are gone. */ | |
6075607b | 94 | for (i = 0; i < nsearchlist; ++i) |
ba79d61b | 95 | { |
af69217f UD |
96 | struct link_map *imap = list[i]; |
97 | if (imap->l_opencount == 0 && imap->l_type == lt_loaded) | |
ba79d61b | 98 | { |
a8a1269d UD |
99 | struct libname_list *lnp; |
100 | ||
ba79d61b RM |
101 | /* That was the last reference, and this was a dlopen-loaded |
102 | object. We can unmap it. */ | |
af69217f | 103 | if (imap->l_global) |
ba79d61b RM |
104 | { |
105 | /* This object is in the global scope list. Remove it. */ | |
82df2969 | 106 | int cnt = _dl_main_searchlist->r_nlist; |
be935610 | 107 | |
ba79d61b | 108 | do |
82df2969 | 109 | if (--cnt < 0) |
d3556ac9 | 110 | break; |
be935610 | 111 | while (_dl_main_searchlist->r_list[cnt] != imap); |
482eec0d | 112 | |
d3556ac9 UD |
113 | if (cnt >= 0) |
114 | { | |
115 | /* The object was already correctly registered. */ | |
116 | while (++cnt < _dl_main_searchlist->r_nlist) | |
117 | _dl_main_searchlist->r_list[cnt - 1] | |
118 | = _dl_main_searchlist->r_list[cnt]; | |
482eec0d | 119 | |
d3556ac9 UD |
120 | --_dl_main_searchlist->r_nlist; |
121 | } | |
122 | else | |
604510f7 | 123 | { |
d3556ac9 UD |
124 | /* This can happen if loading was interrupted by something |
125 | like a missing symbol in the newly loaded objects. In | |
126 | this case the object is already marked as global but | |
127 | `r_nlist' does not count it in. The pointer is in the | |
128 | `r_list' array so we keep searching in the other | |
129 | direction. */ | |
130 | cnt = _dl_main_searchlist->r_nlist; | |
131 | while (_dl_main_searchlist->r_list[cnt] != imap) | |
132 | { | |
133 | ++cnt; | |
134 | /* Note that if _dl_global_scope_alloc is zero we | |
135 | should never come here in the first place. */ | |
136 | assert (cnt < _dl_global_scope_alloc); | |
137 | } | |
604510f7 | 138 | } |
ba79d61b RM |
139 | } |
140 | ||
a8a1269d | 141 | /* We can unmap all the maps at once. We determined the |
4ce636da UD |
142 | start address and length when we loaded the object and |
143 | the `munmap' call does the rest. */ | |
a8a1269d UD |
144 | __munmap ((void *) imap->l_map_start, |
145 | imap->l_map_end - imap->l_map_start); | |
22bc7978 | 146 | |
ba79d61b | 147 | /* Finally, unlink the data structure and free it. */ |
7afab53d UD |
148 | #ifdef PIC |
149 | /* We will unlink the first object only if this is a statically | |
150 | linked program. */ | |
151 | assert (imap->l_prev != NULL); | |
6a805a0b | 152 | imap->l_prev->l_next = imap->l_next; |
7afab53d UD |
153 | #else |
154 | if (imap->l_prev != NULL) | |
af69217f | 155 | imap->l_prev->l_next = imap->l_next; |
7afab53d UD |
156 | else |
157 | _dl_loaded = imap->l_next; | |
158 | #endif | |
af69217f UD |
159 | if (imap->l_next) |
160 | imap->l_next->l_prev = imap->l_prev; | |
a8a1269d UD |
161 | |
162 | if (imap->l_versions != NULL) | |
163 | free (imap->l_versions); | |
1c3a6f19 | 164 | if (imap->l_origin != NULL && imap->l_origin != (char *) -1) |
a8a1269d UD |
165 | free ((char *) imap->l_origin); |
166 | ||
4ce636da | 167 | /* This name always is allocated. */ |
a8a1269d | 168 | free (imap->l_name); |
4ce636da | 169 | /* Remove the list with all the names of the shared object. */ |
a8a1269d UD |
170 | lnp = imap->l_libname; |
171 | do | |
172 | { | |
76156ea1 | 173 | struct libname_list *this = lnp; |
a8a1269d | 174 | lnp = lnp->next; |
76156ea1 | 175 | free (this); |
a8a1269d UD |
176 | } |
177 | while (lnp != NULL); | |
a8a1269d | 178 | |
4ce636da | 179 | /* Remove the searchlists. */ |
be935610 | 180 | if (imap->l_searchlist.r_duplist != imap->l_searchlist.r_list) |
4ce636da | 181 | { |
be935610 UD |
182 | /* If a r_list exists there always also is a r_duplist. */ |
183 | assert (imap->l_searchlist.r_list != NULL); | |
184 | free (imap->l_searchlist.r_duplist); | |
4ce636da | 185 | } |
be935610 UD |
186 | if (imap != map && imap->l_searchlist.r_list != NULL) |
187 | free (imap->l_searchlist.r_list); | |
4ce636da | 188 | |
af69217f | 189 | free (imap); |
ba79d61b RM |
190 | } |
191 | } | |
192 | ||
193 | free (list); | |
4d6acc61 | 194 | |
d3556ac9 UD |
195 | if (_dl_global_scope_alloc != 0 |
196 | && _dl_main_searchlist->r_nlist == _dl_initial_searchlist.r_nlist) | |
197 | { | |
198 | /* All object dynamically loaded by the program are unloaded. Free | |
199 | the memory allocated for the global scope variable. */ | |
200 | struct link_map **old = _dl_main_searchlist->r_list; | |
201 | ||
202 | /* Put the old map in. */ | |
203 | _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list; | |
204 | /* Signal that the original map is used. */ | |
205 | _dl_global_scope_alloc = 0; | |
206 | ||
207 | /* Now free the old map. */ | |
208 | free (old); | |
209 | } | |
210 | ||
4d6acc61 RM |
211 | /* Notify the debugger those objects are finalized and gone. */ |
212 | _r_debug.r_state = RT_CONSISTENT; | |
213 | _dl_debug_state (); | |
26b4d766 UD |
214 | |
215 | /* Release the lock. */ | |
216 | __libc_lock_unlock (_dl_load_lock); | |
ba79d61b | 217 | } |