]> sourceware.org Git - glibc.git/blob - elf/dl-close.c
094db533ddfd9735dea40d3144bcb4ea765f7e88
[glibc.git] / elf / dl-close.c
1 /* Close a shared object opened by `_dl_open'.
2 Copyright (C) 1996-2001, 2002 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 <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <bits/libc-lock.h>
27 #include <ldsodefs.h>
28 #include <sys/types.h>
29 #include <sys/mman.h>
30
31
32 /* Type of the constructor functions. */
33 typedef void (*fini_t) (void);
34
35
36 #ifdef USE_TLS
37 /* Returns true we an non-empty was found. */
38 static bool
39 remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
40 bool should_be_there)
41 {
42 if (idx - disp >= listp->len)
43 {
44 if (listp->next == NULL)
45 {
46 /* The index is not actually valid in the slotinfo list,
47 because this object was closed before it was fully set
48 up due to some error. */
49 assert (! should_be_there);
50 }
51 else
52 {
53 if (remove_slotinfo (idx, listp->next, disp + listp->len,
54 should_be_there))
55 return true;
56
57 /* No non-empty entry. Search from the end of this element's
58 slotinfo array. */
59 idx = disp + listp->len;
60 }
61 }
62 else
63 {
64 struct link_map *old_map = listp->slotinfo[idx - disp].map;
65
66 /* The entry might still be in its unused state if we are closing an
67 object that wasn't fully set up. */
68 if (__builtin_expect (old_map != NULL, 1))
69 {
70 assert (old_map->l_tls_modid == idx);
71
72 /* Mark the entry as unused. */
73 listp->slotinfo[idx - disp].gen = GL(dl_tls_generation) + 1;
74 listp->slotinfo[idx - disp].map = NULL;
75 }
76
77 /* If this is not the last currently used entry no need to look
78 further. */
79 if (idx != GL(dl_tls_max_dtv_idx))
80 return true;
81 }
82
83 while (idx - disp > disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0)
84 {
85 --idx;
86
87 if (listp->slotinfo[idx - disp].map != NULL)
88 {
89 /* Found a new last used index. */
90 GL(dl_tls_max_dtv_idx) = idx;
91 return true;
92 }
93 }
94
95 /* No non-entry in this list element. */
96 return false;
97 }
98 #endif
99
100
101 void
102 internal_function
103 _dl_close (void *_map)
104 {
105 struct reldep_list
106 {
107 struct link_map **rellist;
108 unsigned int nrellist;
109 struct reldep_list *next;
110 } *reldeps = NULL;
111 struct link_map **list;
112 struct link_map *map = _map;
113 unsigned int i;
114 unsigned int *new_opencount;
115 #ifdef USE_TLS
116 bool any_tls = false;
117 #endif
118
119 /* First see whether we can remove the object at all. */
120 if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0)
121 && map->l_init_called)
122 /* Nope. Do nothing. */
123 return;
124
125 if (__builtin_expect (map->l_opencount, 1) == 0)
126 _dl_signal_error (0, map->l_name, NULL, N_("shared object not open"));
127
128 /* Acquire the lock. */
129 __libc_lock_lock_recursive (GL(dl_load_lock));
130
131 /* Decrement the reference count. */
132 if (map->l_opencount > 1 || map->l_type != lt_loaded)
133 {
134 /* There are still references to this object. Do nothing more. */
135 if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_FILES, 0))
136 _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
137 map->l_name, map->l_opencount);
138
139 /* One decrement the object itself, not the dependencies. */
140 --map->l_opencount;
141
142 __libc_lock_unlock_recursive (GL(dl_load_lock));
143 return;
144 }
145
146 list = map->l_initfini;
147
148 /* Compute the new l_opencount values. */
149 i = map->l_searchlist.r_nlist;
150 if (__builtin_expect (i == 0, 0))
151 /* This can happen if we handle relocation dependencies for an
152 object which wasn't loaded directly. */
153 for (i = 1; list[i] != NULL; ++i)
154 ;
155
156 new_opencount = (unsigned int *) alloca (i * sizeof (unsigned int));
157
158 for (i = 0; list[i] != NULL; ++i)
159 {
160 list[i]->l_idx = i;
161 new_opencount[i] = list[i]->l_opencount;
162 }
163 --new_opencount[0];
164 for (i = 1; list[i] != NULL; ++i)
165 if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
166 /* Decrement counter. */
167 && --new_opencount[i] == 0
168 /* Test whether this object was also loaded directly. */
169 && list[i]->l_searchlist.r_list != NULL)
170 {
171 /* In this case we have the decrement all the dependencies of
172 this object. They are all in MAP's dependency list. */
173 unsigned int j;
174 struct link_map **dep_list = list[i]->l_searchlist.r_list;
175
176 for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j)
177 if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)
178 || ! dep_list[j]->l_init_called)
179 {
180 assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
181 --new_opencount[dep_list[j]->l_idx];
182 }
183 }
184 assert (new_opencount[0] == 0);
185
186 /* Call all termination functions at once. */
187 for (i = 0; list[i] != NULL; ++i)
188 {
189 struct link_map *imap = list[i];
190 if (new_opencount[i] == 0 && imap->l_type == lt_loaded
191 && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
192 && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
193 /* Skip any half-cooked objects that were never initialized. */
194 && imap->l_init_called)
195 {
196 /* When debugging print a message first. */
197 if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
198 _dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name);
199
200 /* Call its termination function. */
201 if (imap->l_info[DT_FINI_ARRAY] != NULL)
202 {
203 ElfW(Addr) *array =
204 (ElfW(Addr) *) (imap->l_addr
205 + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
206 unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
207 / sizeof (ElfW(Addr)));
208 unsigned int cnt;
209
210 for (cnt = 0; cnt < sz; ++cnt)
211 ((fini_t) (imap->l_addr + array[cnt])) ();
212 }
213
214 /* Next try the old-style destructor. */
215 if (imap->l_info[DT_FINI] != NULL)
216 (*(void (*) (void)) DL_DT_FINI_ADDRESS
217 (imap, (void *) imap->l_addr
218 + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
219 }
220 else if (new_opencount[i] != 0 && imap->l_type == lt_loaded)
221 {
222 /* The object is still used. But the object we are unloading
223 right now is responsible for loading it and therefore we
224 have the search list of the current object in its scope.
225 Remove it. */
226 struct r_scope_elem **runp = imap->l_scope;
227
228 while (*runp != NULL)
229 if (*runp == &map->l_searchlist)
230 {
231 /* Copy all later elements. */
232 while ((runp[0] = runp[1]) != NULL)
233 ++runp;
234 break;
235 }
236 else
237 ++runp;
238 }
239
240 /* Store the new l_opencount value. */
241 imap->l_opencount = new_opencount[i];
242 /* Just a sanity check. */
243 assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
244 }
245
246 /* Notify the debugger we are about to remove some loaded objects. */
247 _r_debug.r_state = RT_DELETE;
248 _dl_debug_state ();
249
250 /* Check each element of the search list to see if all references to
251 it are gone. */
252 for (i = 0; list[i] != NULL; ++i)
253 {
254 struct link_map *imap = list[i];
255 if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
256 {
257 struct libname_list *lnp;
258
259 /* That was the last reference, and this was a dlopen-loaded
260 object. We can unmap it. */
261 if (__builtin_expect (imap->l_global, 0))
262 {
263 /* This object is in the global scope list. Remove it. */
264 unsigned int cnt = GL(dl_main_searchlist)->r_nlist;
265
266 do
267 --cnt;
268 while (GL(dl_main_searchlist)->r_list[cnt] != imap);
269
270 /* The object was already correctly registered. */
271 while (++cnt < GL(dl_main_searchlist)->r_nlist)
272 GL(dl_main_searchlist)->r_list[cnt - 1]
273 = GL(dl_main_searchlist)->r_list[cnt];
274
275 --GL(dl_main_searchlist)->r_nlist;
276 }
277
278 #ifdef USE_TLS
279 /* Remove the object from the dtv slotinfo array if it uses TLS. */
280 if (__builtin_expect (imap->l_tls_blocksize > 0, 0))
281 {
282 any_tls = true;
283
284 if (! remove_slotinfo (imap->l_tls_modid,
285 GL(dl_tls_dtv_slotinfo_list), 0,
286 imap->l_init_called))
287 /* All dynamically loaded modules with TLS are unloaded. */
288 GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
289 }
290 #endif
291
292 /* We can unmap all the maps at once. We determined the
293 start address and length when we loaded the object and
294 the `munmap' call does the rest. */
295 DL_UNMAP (imap);
296
297 /* Finally, unlink the data structure and free it. */
298 #ifdef SHARED
299 /* We will unlink the first object only if this is a statically
300 linked program. */
301 assert (imap->l_prev != NULL);
302 imap->l_prev->l_next = imap->l_next;
303 #else
304 if (imap->l_prev != NULL)
305 imap->l_prev->l_next = imap->l_next;
306 else
307 GL(dl_loaded) = imap->l_next;
308 #endif
309 --GL(dl_nloaded);
310 if (imap->l_next)
311 imap->l_next->l_prev = imap->l_prev;
312
313 if (imap->l_versions != NULL)
314 free (imap->l_versions);
315 if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
316 free ((char *) imap->l_origin);
317
318 /* If the object has relocation dependencies save this
319 information for latter. */
320 if (__builtin_expect (imap->l_reldeps != NULL, 0))
321 {
322 struct reldep_list *newrel;
323
324 newrel = (struct reldep_list *) alloca (sizeof (*reldeps));
325 newrel->rellist = imap->l_reldeps;
326 newrel->nrellist = imap->l_reldepsact;
327 newrel->next = reldeps;
328
329 reldeps = newrel;
330 }
331
332 /* This name always is allocated. */
333 free (imap->l_name);
334 /* Remove the list with all the names of the shared object. */
335 lnp = imap->l_libname;
336 do
337 {
338 struct libname_list *this = lnp;
339 lnp = lnp->next;
340 if (!this->dont_free)
341 free (this);
342 }
343 while (lnp != NULL);
344
345 /* Remove the searchlists. */
346 if (imap != map)
347 free (imap->l_initfini);
348
349 /* Remove the scope array if we allocated it. */
350 if (imap->l_scope != imap->l_scope_mem)
351 free (imap->l_scope);
352
353 if (imap->l_phdr_allocated)
354 free ((void *) imap->l_phdr);
355
356 if (imap->l_rpath_dirs.dirs != (void *) -1)
357 free (imap->l_rpath_dirs.dirs);
358 if (imap->l_runpath_dirs.dirs != (void *) -1)
359 free (imap->l_runpath_dirs.dirs);
360
361 free (imap);
362 }
363 }
364
365 #ifdef USE_TLS
366 /* If we removed any object which uses TLS bumnp the generation
367 counter. */
368 if (any_tls)
369 if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
370 __libc_fatal (_("TLS generation counter wrapped! Please send report with the 'glibcbug' script."));
371 #endif
372
373 /* Notify the debugger those objects are finalized and gone. */
374 _r_debug.r_state = RT_CONSISTENT;
375 _dl_debug_state ();
376
377 /* Now we can perhaps also remove the modules for which we had
378 dependencies because of symbol lookup. */
379 while (__builtin_expect (reldeps != NULL, 0))
380 {
381 while (reldeps->nrellist-- > 0)
382 _dl_close (reldeps->rellist[reldeps->nrellist]);
383
384 free (reldeps->rellist);
385
386 reldeps = reldeps->next;
387 }
388
389 free (list);
390
391 /* Release the lock. */
392 __libc_lock_unlock_recursive (GL(dl_load_lock));
393 }
394 libc_hidden_def (_dl_close)
395
396
397 #ifdef USE_TLS
398 static bool
399 free_slotinfo (struct dtv_slotinfo_list *elemp)
400 {
401 size_t cnt;
402
403 if (elemp == NULL)
404 /* Nothing here, all is removed (or there never was anything). */
405 return true;
406
407 if (!free_slotinfo (elemp->next))
408 /* We cannot free the entry. */
409 return false;
410
411 /* The least we could do is remove next element (if there was any). */
412 elemp->next = NULL;
413
414 for (cnt = 0; cnt < elemp->len; ++cnt)
415 if (elemp->slotinfo[cnt].map != NULL)
416 /* Still used. */
417 return false;
418
419 /* We can remove the list element. */
420 free (elemp);
421
422 return true;
423 }
424 #endif
425
426
427 static void
428 free_mem (void)
429 {
430 if (__builtin_expect (GL(dl_global_scope_alloc), 0) != 0
431 && GL(dl_main_searchlist)->r_nlist == GL(dl_initial_searchlist).r_nlist)
432 {
433 /* All object dynamically loaded by the program are unloaded. Free
434 the memory allocated for the global scope variable. */
435 struct link_map **old = GL(dl_main_searchlist)->r_list;
436
437 /* Put the old map in. */
438 GL(dl_main_searchlist)->r_list = GL(dl_initial_searchlist).r_list;
439 /* Signal that the original map is used. */
440 GL(dl_global_scope_alloc) = 0;
441
442 /* Now free the old map. */
443 free (old);
444 }
445
446 #ifdef USE_TLS
447 /* Free the memory allocated for the dtv slotinfo array. We can do
448 this only if all modules which used this memory are unloaded.
449 Also, the first element of the list does not have to be
450 deallocated. It was allocated in the dynamic linker (i.e., with
451 a different malloc). */
452 if (free_slotinfo (GL(dl_tls_dtv_slotinfo_list)->next))
453 GL(dl_tls_dtv_slotinfo_list)->next = NULL;
454 #endif
455 }
456 text_set_element (__libc_subfreeres, free_mem);
This page took 0.057288 seconds and 4 git commands to generate.