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