1 /* Close a shared object opened by `_dl_open'.
2 Copyright (C) 1996,1997,1998,1999,2000,2001 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 Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20 #include <assert.h>
21 #include <dlfcn.h>
22 #include <libintl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <bits/libc-lock.h>
26 #include <ldsodefs.h>
27 #include <sys/types.h>
28 #include <sys/mman.h>
29
30
31 /* Type of the constructor functions. */
32 typedef void (*fini_t) (void);
33
34
35 void
36 internal_function
_dl_close(void * _map)37 _dl_close (void *_map)
38 {
39 struct reldep_list
40 {
41 struct link_map **rellist;
42 unsigned int nrellist;
43 struct reldep_list *next;
44 } *reldeps = NULL;
45 struct link_map **list;
46 struct link_map *map = _map;
47 unsigned int i;
48 unsigned int *new_opencount;
49
50 /* First see whether we can remove the object at all. */
51 if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0)
52 && map->l_init_called)
53 /* Nope. Do nothing. */
54 return;
55
56 if (__builtin_expect (map->l_opencount, 1) == 0)
57 _dl_signal_error (0, map->l_name, NULL, N_("shared object not open"));
58
59 /* Acquire the lock. */
60 #ifdef HAVE_DD_LOCK
61 __lock_acquire(_dl_load_lock);
62 #endif
63
64
65 /* Decrement the reference count. */
66 if (map->l_opencount > 1 || map->l_type != lt_loaded)
67 {
68 /* There are still references to this object. Do nothing more. */
69 if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
70 _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
71 map->l_name, map->l_opencount);
72
73 /* One decrement the object itself, not the dependencies. */
74 --map->l_opencount;
75
76 #ifdef HAVE_DD_LOCK
77 __lock_release(_dl_load_lock);
78 #endif
79
80 return;
81 }
82
83 list = map->l_initfini;
84
85 /* Compute the new l_opencount values. */
86 i = map->l_searchlist.r_nlist;
87 if (__builtin_expect (i == 0, 0))
88 /* This can happen if we handle relocation dependencies for an
89 object which wasn't loaded directly. */
90 for (i = 1; list[i] != NULL; ++i)
91 ;
92
93 new_opencount = (unsigned int *) alloca (i * sizeof (unsigned int));
94
95 for (i = 0; list[i] != NULL; ++i)
96 {
97 list[i]->l_idx = i;
98 new_opencount[i] = list[i]->l_opencount;
99 }
100 --new_opencount[0];
101 for (i = 1; list[i] != NULL; ++i)
102 if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
103 /* Decrement counter. */
104 && --new_opencount[i] == 0
105 /* Test whether this object was also loaded directly. */
106 && list[i]->l_searchlist.r_list != NULL)
107 {
108 /* In this case we have the decrement all the dependencies of
109 this object. They are all in MAP's dependency list. */
110 unsigned int j;
111 struct link_map **dep_list = list[i]->l_searchlist.r_list;
112
113 for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j)
114 if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)
115 || ! dep_list[j]->l_init_called)
116 {
117 assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
118 --new_opencount[dep_list[j]->l_idx];
119 }
120 }
121 assert (new_opencount[0] == 0);
122
123 /* Call all termination functions at once. */
124 for (i = 0; list[i] != NULL; ++i)
125 {
126 struct link_map *imap = list[i];
127 if (new_opencount[i] == 0 && imap->l_type == lt_loaded
128 && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
129 && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
130 /* Skip any half-cooked objects that were never initialized. */
131 && imap->l_init_called)
132 {
133 /* When debugging print a message first. */
134 if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0))
135 _dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name);
136
137 /* Call its termination function. */
138 if (imap->l_info[DT_FINI_ARRAY] != NULL)
139 {
140 ElfW(Addr) *array =
141 (ElfW(Addr) *) (imap->l_addr
142 + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
143 unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
144 / sizeof (ElfW(Addr)));
145 unsigned int cnt;
146
147 for (cnt = 0; cnt < sz; ++cnt)
148 ((fini_t) (imap->l_addr + array[cnt])) ();
149 }
150
151 /* Next try the old-style destructor. */
152 if (imap->l_info[DT_FINI] != NULL)
153 (*(void (*) (void)) DL_DT_FINI_ADDRESS
154 (imap, (void *) imap->l_addr
155 + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
156 }
157 else if (new_opencount[i] != 0 && imap->l_type == lt_loaded)
158 {
159 /* The object is still used. But the object we are unloading
160 right now is responsible for loading it and therefore we
161 have the search list of the current object in its scope.
162 Remove it. */
163 struct r_scope_elem **runp = imap->l_scope;
164
165 while (*runp != NULL)
166 if (*runp == &map->l_searchlist)
167 {
168 /* Copy all later elements. */
169 while ((runp[0] = runp[1]) != NULL)
170 ++runp;
171 break;
172 }
173 else
174 ++runp;
175 }
176
177 /* Store the new l_opencount value. */
178 imap->l_opencount = new_opencount[i];
179 /* Just a sanity check. */
180 assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
181 }
182
183 /* Notify the debugger we are about to remove some loaded objects. */
184 _r_debug.r_state = RT_DELETE;
185 _dl_debug_state ();
186
187 /* Check each element of the search list to see if all references to
188 it are gone. */
189 for (i = 0; list[i] != NULL; ++i)
190 {
191 struct link_map *imap = list[i];
192 if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
193 {
194 struct libname_list *lnp;
195
196 /* That was the last reference, and this was a dlopen-loaded
197 object. We can unmap it. */
198 if (__builtin_expect (imap->l_global, 0))
199 {
200 /* This object is in the global scope list. Remove it. */
201 unsigned int cnt = _dl_main_searchlist->r_nlist;
202
203 do
204 --cnt;
205 while (_dl_main_searchlist->r_list[cnt] != imap);
206
207 /* The object was already correctly registered. */
208 while (++cnt < _dl_main_searchlist->r_nlist)
209 _dl_main_searchlist->r_list[cnt - 1]
210 = _dl_main_searchlist->r_list[cnt];
211
212 --_dl_main_searchlist->r_nlist;
213 }
214
215 /* We can unmap all the maps at once. We determined the
216 start address and length when we loaded the object and
217 the `munmap' call does the rest. */
218 DL_UNMAP (imap);
219
220 /* Finally, unlink the data structure and free it. */
221 #ifdef SHARED
222 /* We will unlink the first object only if this is a statically
223 linked program. */
224 assert (imap->l_prev != NULL);
225 imap->l_prev->l_next = imap->l_next;
226 #else
227 if (imap->l_prev != NULL)
228 imap->l_prev->l_next = imap->l_next;
229 else
230 _dl_loaded = imap->l_next;
231 #endif
232 --_dl_nloaded;
233 if (imap->l_next)
234 imap->l_next->l_prev = imap->l_prev;
235
236 if (imap->l_versions != NULL)
237 free (imap->l_versions);
238 if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
239 free ((char *) imap->l_origin);
240
241 /* If the object has relocation dependencies save this
242 information for latter. */
243 if (__builtin_expect (imap->l_reldeps != NULL, 0))
244 {
245 struct reldep_list *newrel;
246
247 newrel = (struct reldep_list *) alloca (sizeof (*reldeps));
248 newrel->rellist = imap->l_reldeps;
249 newrel->nrellist = imap->l_reldepsact;
250 newrel->next = reldeps;
251
252 reldeps = newrel;
253 }
254
255 /* This name always is allocated. */
256 free (imap->l_name);
257 /* Remove the list with all the names of the shared object. */
258 lnp = imap->l_libname;
259 do
260 {
261 struct libname_list *this = lnp;
262 lnp = lnp->next;
263 if (!this->dont_free)
264 free (this);
265 }
266 while (lnp != NULL);
267
268 /* Remove the searchlists. */
269 if (imap != map)
270 free (imap->l_initfini);
271
272 /* Remove the scope array if we allocated it. */
273 if (imap->l_scope != imap->l_scope_mem)
274 free (imap->l_scope);
275
276 if (imap->l_phdr_allocated)
277 free ((void *) imap->l_phdr);
278
279 if (imap->l_rpath_dirs.dirs != (void *) -1)
280 free (imap->l_rpath_dirs.dirs);
281 if (imap->l_runpath_dirs.dirs != (void *) -1)
282 free (imap->l_runpath_dirs.dirs);
283
284 free (imap);
285 }
286 }
287
288 /* Notify the debugger those objects are finalized and gone. */
289 _r_debug.r_state = RT_CONSISTENT;
290 _dl_debug_state ();
291
292 /* Now we can perhaps also remove the modules for which we had
293 dependencies because of symbol lookup. */
294 while (__builtin_expect (reldeps != NULL, 0))
295 {
296 while (reldeps->nrellist-- > 0)
297 _dl_close (reldeps->rellist[reldeps->nrellist]);
298
299 free (reldeps->rellist);
300
301 reldeps = reldeps->next;
302 }
303
304 free (list);
305
306 /* Release the lock. */
307 #ifdef HAVE_DD_LOCK
308 __lock_release(_dl_load_lock);
309 #endif
310
311
312 }
313
314
315 static void
free_mem(void)316 free_mem (void)
317 {
318 if (__builtin_expect (_dl_global_scope_alloc, 0) != 0
319 && _dl_main_searchlist->r_nlist == _dl_initial_searchlist.r_nlist)
320 {
321 /* All object dynamically loaded by the program are unloaded. Free
322 the memory allocated for the global scope variable. */
323 struct link_map **old = _dl_main_searchlist->r_list;
324
325 /* Put the old map in. */
326 _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list;
327 /* Signal that the original map is used. */
328 _dl_global_scope_alloc = 0;
329
330 /* Now free the old map. */
331 free (old);
332 }
333 }
334 text_set_element (__libc_subfreeres, free_mem);
335