]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-close.c
* sysdeps/posix/system.c (do_system): New function, guts broken out of
[thirdparty/glibc.git] / elf / dl-close.c
CommitLineData
26b4d766 1/* Close a shared object opened by `_dl_open'.
d6b5d570 2 Copyright (C) 1996-2001, 2002 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
41bdb6e2
AJ
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.
afd4eb37
UD
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
41bdb6e2 13 Lesser General Public License for more details.
afd4eb37 14
41bdb6e2
AJ
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. */
ba79d61b 19
7afab53d 20#include <assert.h>
ba79d61b 21#include <dlfcn.h>
8e17ea58 22#include <libintl.h>
b209e34a 23#include <stdio.h>
ba79d61b 24#include <stdlib.h>
8d6468d0 25#include <string.h>
a853022c 26#include <bits/libc-lock.h>
b8445829 27#include <ldsodefs.h>
ba79d61b
RM
28#include <sys/types.h>
29#include <sys/mman.h>
30
31
dacc8ffa
UD
32/* Type of the constructor functions. */
33typedef void (*fini_t) (void);
34
35
fc093be1
UD
36#ifdef USE_TLS
37/* Returns true we an non-empty was found. */
38static bool
39remove_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
ba79d61b 88void
d0fc4041 89internal_function
94e365c6 90_dl_close (void *_map)
ba79d61b 91{
4b4fcf99
UD
92 struct reldep_list
93 {
94 struct link_map **rellist;
95 unsigned int nrellist;
96 struct reldep_list *next;
97 } *reldeps = NULL;
ba79d61b 98 struct link_map **list;
94e365c6 99 struct link_map *map = _map;
ba79d61b 100 unsigned int i;
42c4f32a 101 unsigned int *new_opencount;
a04586d8
UD
102#ifdef USE_TLS
103 bool any_tls = false;
104#endif
ba79d61b 105
bf8b3e74 106 /* First see whether we can remove the object at all. */
c4bb124a
UD
107 if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0)
108 && map->l_init_called)
bf8b3e74
UD
109 /* Nope. Do nothing. */
110 return;
111
c41c89d3 112 if (__builtin_expect (map->l_opencount, 1) == 0)
407fe3bb 113 _dl_signal_error (0, map->l_name, NULL, N_("shared object not open"));
ba79d61b 114
26b4d766 115 /* Acquire the lock. */
5688da55 116 __libc_lock_lock_recursive (GL(dl_load_lock));
26b4d766 117
ba79d61b 118 /* Decrement the reference count. */
a709dd43 119 if (map->l_opencount > 1 || map->l_type != lt_loaded)
26b4d766
UD
120 {
121 /* There are still references to this object. Do nothing more. */
d6b5d570 122 if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_FILES, 0))
c4bb124a
UD
123 _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
124 map->l_name, map->l_opencount);
b35e21f4 125
42c4f32a
UD
126 /* One decrement the object itself, not the dependencies. */
127 --map->l_opencount;
8699e7b1 128
5688da55 129 __libc_lock_unlock_recursive (GL(dl_load_lock));
26b4d766
UD
130 return;
131 }
ba79d61b 132
2e93b4a4 133 list = map->l_initfini;
42c4f32a
UD
134
135 /* Compute the new l_opencount values. */
c4bb124a
UD
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
7e036a01 145 for (i = 0; list[i] != NULL; ++i)
42c4f32a 146 {
2e93b4a4
UD
147 list[i]->l_idx = i;
148 new_opencount[i] = list[i]->l_opencount;
42c4f32a
UD
149 }
150 --new_opencount[0];
7e036a01 151 for (i = 1; list[i] != NULL; ++i)
c77a4478 152 if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
42c4f32a
UD
153 /* Decrement counter. */
154 && --new_opencount[i] == 0
155 /* Test whether this object was also loaded directly. */
2e93b4a4 156 && list[i]->l_searchlist.r_list != NULL)
42c4f32a
UD
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;
2e93b4a4 161 struct link_map **dep_list = list[i]->l_searchlist.r_list;
42c4f32a 162
2e93b4a4 163 for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j)
c77a4478
UD
164 if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)
165 || ! dep_list[j]->l_init_called)
42c4f32a 166 {
7e036a01 167 assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
42c4f32a
UD
168 --new_opencount[dep_list[j]->l_idx];
169 }
170 }
171 assert (new_opencount[0] == 0);
172
a709dd43 173 /* Call all termination functions at once. */
7e036a01 174 for (i = 0; list[i] != NULL; ++i)
a709dd43 175 {
2e93b4a4 176 struct link_map *imap = list[i];
42c4f32a 177 if (new_opencount[i] == 0 && imap->l_type == lt_loaded
dacc8ffa 178 && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
c77a4478 179 && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
7a68c94a
UD
180 /* Skip any half-cooked objects that were never initialized. */
181 && imap->l_init_called)
a709dd43 182 {
b48abe3c 183 /* When debugging print a message first. */
d6b5d570 184 if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
35fc382a 185 _dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name);
dacc8ffa 186
b48abe3c 187 /* Call its termination function. */
dacc8ffa
UD
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)
40306912
UD
203 (*(void (*) (void)) DL_DT_FINI_ADDRESS
204 (imap, (void *) imap->l_addr
205 + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
a709dd43 206 }
5a21d307
UD
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 }
42c4f32a
UD
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);
a709dd43
UD
231 }
232
4d6acc61
RM
233 /* Notify the debugger we are about to remove some loaded objects. */
234 _r_debug.r_state = RT_DELETE;
235 _dl_debug_state ();
236
ba79d61b
RM
237 /* Check each element of the search list to see if all references to
238 it are gone. */
7e036a01 239 for (i = 0; list[i] != NULL; ++i)
ba79d61b 240 {
af69217f
UD
241 struct link_map *imap = list[i];
242 if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
ba79d61b 243 {
a8a1269d
UD
244 struct libname_list *lnp;
245
ba79d61b
RM
246 /* That was the last reference, and this was a dlopen-loaded
247 object. We can unmap it. */
c41c89d3 248 if (__builtin_expect (imap->l_global, 0))
ba79d61b
RM
249 {
250 /* This object is in the global scope list. Remove it. */
d6b5d570 251 unsigned int cnt = GL(dl_main_searchlist)->r_nlist;
be935610 252
ba79d61b 253 do
50b65db1 254 --cnt;
d6b5d570 255 while (GL(dl_main_searchlist)->r_list[cnt] != imap);
482eec0d 256
50b65db1 257 /* The object was already correctly registered. */
d6b5d570
UD
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];
50b65db1 261
d6b5d570 262 --GL(dl_main_searchlist)->r_nlist;
ba79d61b
RM
263 }
264
a04586d8
UD
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 {
a04586d8 270 any_tls = true;
bb4cb252 271
fc093be1
UD
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);
a04586d8
UD
276 }
277#endif
278
a8a1269d 279 /* We can unmap all the maps at once. We determined the
4ce636da
UD
280 start address and length when we loaded the object and
281 the `munmap' call does the rest. */
09bf6406 282 DL_UNMAP (imap);
22bc7978 283
ba79d61b 284 /* Finally, unlink the data structure and free it. */
b5567b2a 285#ifdef SHARED
7afab53d
UD
286 /* We will unlink the first object only if this is a statically
287 linked program. */
288 assert (imap->l_prev != NULL);
6a805a0b 289 imap->l_prev->l_next = imap->l_next;
7afab53d
UD
290#else
291 if (imap->l_prev != NULL)
af69217f 292 imap->l_prev->l_next = imap->l_next;
7afab53d 293 else
d6b5d570 294 GL(dl_loaded) = imap->l_next;
7afab53d 295#endif
d6b5d570 296 --GL(dl_nloaded);
af69217f
UD
297 if (imap->l_next)
298 imap->l_next->l_prev = imap->l_prev;
a8a1269d
UD
299
300 if (imap->l_versions != NULL)
301 free (imap->l_versions);
1c3a6f19 302 if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
a8a1269d
UD
303 free ((char *) imap->l_origin);
304
4b4fcf99
UD
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));
1826d793
UD
312 newrel->rellist = imap->l_reldeps;
313 newrel->nrellist = imap->l_reldepsact;
4b4fcf99
UD
314 newrel->next = reldeps;
315
316 reldeps = newrel;
317 }
318
4ce636da 319 /* This name always is allocated. */
a8a1269d 320 free (imap->l_name);
4ce636da 321 /* Remove the list with all the names of the shared object. */
a8a1269d
UD
322 lnp = imap->l_libname;
323 do
324 {
76156ea1 325 struct libname_list *this = lnp;
a8a1269d 326 lnp = lnp->next;
11810621
UD
327 if (!this->dont_free)
328 free (this);
a8a1269d
UD
329 }
330 while (lnp != NULL);
a8a1269d 331
4ce636da 332 /* Remove the searchlists. */
dacc8ffa 333 if (imap != map)
2e93b4a4 334 free (imap->l_initfini);
4ce636da 335
5a21d307
UD
336 /* Remove the scope array if we allocated it. */
337 if (imap->l_scope != imap->l_scope_mem)
338 free (imap->l_scope);
339
7bcaca43 340 if (imap->l_phdr_allocated)
15925412 341 free ((void *) imap->l_phdr);
7bcaca43 342
f55727ca
UD
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
af69217f 348 free (imap);
ba79d61b
RM
349 }
350 }
351
a04586d8
UD
352#ifdef USE_TLS
353 /* If we removed any object which uses TLS bumnp the generation
354 counter. */
bb4cb252 355 if (any_tls)
b209e34a 356 if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
a585ba22 357 __libc_fatal (_("TLS generation counter wrapped! Please send report with the 'glibcbug' script."));
a04586d8
UD
358#endif
359
e3e5f672
UD
360 /* Notify the debugger those objects are finalized and gone. */
361 _r_debug.r_state = RT_CONSISTENT;
362 _dl_debug_state ();
363
cf197e41
UD
364 /* Now we can perhaps also remove the modules for which we had
365 dependencies because of symbol lookup. */
4b4fcf99 366 while (__builtin_expect (reldeps != NULL, 0))
cf197e41 367 {
4b4fcf99
UD
368 while (reldeps->nrellist-- > 0)
369 _dl_close (reldeps->rellist[reldeps->nrellist]);
370
371 free (reldeps->rellist);
cf197e41 372
4b4fcf99 373 reldeps = reldeps->next;
cf197e41
UD
374 }
375
ba79d61b 376 free (list);
4d6acc61 377
e3e5f672 378 /* Release the lock. */
5688da55 379 __libc_lock_unlock_recursive (GL(dl_load_lock));
e3e5f672 380}
cc7e7a26 381libc_hidden_def (_dl_close)
e3e5f672
UD
382
383
100e184f 384#ifdef USE_TLS
a04586d8
UD
385static bool
386free_slotinfo (struct dtv_slotinfo_list *elemp)
387{
388 size_t cnt;
389
69f0c4d8
UD
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))
a04586d8
UD
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}
100e184f 411#endif
a04586d8
UD
412
413
e3e5f672
UD
414static void
415free_mem (void)
416{
d6b5d570
UD
417 if (__builtin_expect (GL(dl_global_scope_alloc), 0) != 0
418 && GL(dl_main_searchlist)->r_nlist == GL(dl_initial_searchlist).r_nlist)
d3556ac9
UD
419 {
420 /* All object dynamically loaded by the program are unloaded. Free
421 the memory allocated for the global scope variable. */
d6b5d570 422 struct link_map **old = GL(dl_main_searchlist)->r_list;
d3556ac9
UD
423
424 /* Put the old map in. */
d6b5d570 425 GL(dl_main_searchlist)->r_list = GL(dl_initial_searchlist).r_list;
d3556ac9 426 /* Signal that the original map is used. */
d6b5d570 427 GL(dl_global_scope_alloc) = 0;
d3556ac9
UD
428
429 /* Now free the old map. */
430 free (old);
431 }
a04586d8
UD
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
ba79d61b 442}
e3e5f672 443text_set_element (__libc_subfreeres, free_mem);