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