Updated.
[glibc.git] / elf / dl-close.c
blob66c88b2641e8fc7885abcd17d7ee80776ff1c1a0
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.
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.
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.
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. */
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>
31 /* Type of the constructor functions. */
32 typedef void (*fini_t) (void);
35 void
36 internal_function
37 _dl_close (void *_map)
39 struct reldep_list
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;
50 /* First see whether we can remove the object at all. */
51 if ((map->l_flags_1 & DF_1_NODELETE) && map->l_init_called)
52 /* Nope. Do nothing. */
53 return;
55 if (__builtin_expect (map->l_opencount, 1) == 0)
56 _dl_signal_error (0, map->l_name, N_("shared object not open"));
58 /* Acquire the lock. */
59 __libc_lock_lock_recursive (_dl_load_lock);
61 /* Decrement the reference count. */
62 if (map->l_opencount > 1 || map->l_type != lt_loaded)
64 /* There are still references to this object. Do nothing more. */
65 if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
67 char buf[20];
69 buf[sizeof buf - 1] = '\0';
71 _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
72 map->l_name, map->l_opencount);
75 /* One decrement the object itself, not the dependencies. */
76 --map->l_opencount;
78 __libc_lock_unlock_recursive (_dl_load_lock);
79 return;
82 list = map->l_initfini;
84 /* Compute the new l_opencount values. */
85 new_opencount = (unsigned int *) alloca (map->l_searchlist.r_nlist
86 * sizeof (unsigned int));
87 for (i = 0; list[i] != NULL; ++i)
89 list[i]->l_idx = i;
90 new_opencount[i] = list[i]->l_opencount;
92 --new_opencount[0];
93 for (i = 1; list[i] != NULL; ++i)
94 if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
95 /* Decrement counter. */
96 && --new_opencount[i] == 0
97 /* Test whether this object was also loaded directly. */
98 && list[i]->l_searchlist.r_list != NULL)
100 /* In this case we have the decrement all the dependencies of
101 this object. They are all in MAP's dependency list. */
102 unsigned int j;
103 struct link_map **dep_list = list[i]->l_searchlist.r_list;
105 for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j)
106 if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)
107 || ! dep_list[j]->l_init_called)
109 assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
110 --new_opencount[dep_list[j]->l_idx];
113 assert (new_opencount[0] == 0);
115 /* Call all termination functions at once. */
116 for (i = 0; list[i] != NULL; ++i)
118 struct link_map *imap = list[i];
119 if (new_opencount[i] == 0 && imap->l_type == lt_loaded
120 && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
121 && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
122 /* Skip any half-cooked objects that were never initialized. */
123 && imap->l_init_called)
125 /* When debugging print a message first. */
126 if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0))
127 _dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name);
129 /* Call its termination function. */
130 if (imap->l_info[DT_FINI_ARRAY] != NULL)
132 ElfW(Addr) *array =
133 (ElfW(Addr) *) (imap->l_addr
134 + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
135 unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
136 / sizeof (ElfW(Addr)));
137 unsigned int cnt;
139 for (cnt = 0; cnt < sz; ++cnt)
140 ((fini_t) (imap->l_addr + array[cnt])) ();
143 /* Next try the old-style destructor. */
144 if (imap->l_info[DT_FINI] != NULL)
145 (*(void (*) (void)) DL_DT_FINI_ADDRESS
146 (imap, (void *) imap->l_addr
147 + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
150 /* Store the new l_opencount value. */
151 imap->l_opencount = new_opencount[i];
152 /* Just a sanity check. */
153 assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
156 /* Notify the debugger we are about to remove some loaded objects. */
157 _r_debug.r_state = RT_DELETE;
158 _dl_debug_state ();
160 /* Check each element of the search list to see if all references to
161 it are gone. */
162 for (i = 0; list[i] != NULL; ++i)
164 struct link_map *imap = list[i];
165 if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
167 struct libname_list *lnp;
169 /* That was the last reference, and this was a dlopen-loaded
170 object. We can unmap it. */
171 if (__builtin_expect (imap->l_global, 0))
173 /* This object is in the global scope list. Remove it. */
174 unsigned int cnt = _dl_main_searchlist->r_nlist;
177 --cnt;
178 while (_dl_main_searchlist->r_list[cnt] != imap);
180 /* The object was already correctly registered. */
181 while (++cnt < _dl_main_searchlist->r_nlist)
182 _dl_main_searchlist->r_list[cnt - 1]
183 = _dl_main_searchlist->r_list[cnt];
185 --_dl_main_searchlist->r_nlist;
188 /* We can unmap all the maps at once. We determined the
189 start address and length when we loaded the object and
190 the `munmap' call does the rest. */
191 DL_UNMAP (imap);
193 /* Finally, unlink the data structure and free it. */
194 #ifdef SHARED
195 /* We will unlink the first object only if this is a statically
196 linked program. */
197 assert (imap->l_prev != NULL);
198 imap->l_prev->l_next = imap->l_next;
199 #else
200 if (imap->l_prev != NULL)
201 imap->l_prev->l_next = imap->l_next;
202 else
203 _dl_loaded = imap->l_next;
204 #endif
205 --_dl_nloaded;
206 if (imap->l_next)
207 imap->l_next->l_prev = imap->l_prev;
209 if (imap->l_versions != NULL)
210 free (imap->l_versions);
211 if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
212 free ((char *) imap->l_origin);
214 /* If the object has relocation dependencies save this
215 information for latter. */
216 if (__builtin_expect (imap->l_reldeps != NULL, 0))
218 struct reldep_list *newrel;
220 newrel = (struct reldep_list *) alloca (sizeof (*reldeps));
221 newrel->rellist = imap->l_reldeps;
222 newrel->nrellist = imap->l_reldepsact;
223 newrel->next = reldeps;
225 reldeps = newrel;
228 /* This name always is allocated. */
229 free (imap->l_name);
230 /* Remove the list with all the names of the shared object. */
231 lnp = imap->l_libname;
234 struct libname_list *this = lnp;
235 lnp = lnp->next;
236 free (this);
238 while (lnp != NULL);
240 /* Remove the searchlists. */
241 if (imap != map)
242 free (imap->l_initfini);
244 if (imap->l_phdr_allocated)
245 free ((void *) imap->l_phdr);
247 if (imap->l_rpath_dirs.dirs != (void *) -1)
248 free (imap->l_rpath_dirs.dirs);
249 if (imap->l_runpath_dirs.dirs != (void *) -1)
250 free (imap->l_runpath_dirs.dirs);
252 free (imap);
256 /* Notify the debugger those objects are finalized and gone. */
257 _r_debug.r_state = RT_CONSISTENT;
258 _dl_debug_state ();
260 /* Now we can perhaps also remove the modules for which we had
261 dependencies because of symbol lookup. */
262 while (__builtin_expect (reldeps != NULL, 0))
264 while (reldeps->nrellist-- > 0)
265 _dl_close (reldeps->rellist[reldeps->nrellist]);
267 free (reldeps->rellist);
269 reldeps = reldeps->next;
272 free (list);
274 /* Release the lock. */
275 __libc_lock_unlock_recursive (_dl_load_lock);
279 static void
280 free_mem (void)
282 if (__builtin_expect (_dl_global_scope_alloc, 0) != 0
283 && _dl_main_searchlist->r_nlist == _dl_initial_searchlist.r_nlist)
285 /* All object dynamically loaded by the program are unloaded. Free
286 the memory allocated for the global scope variable. */
287 struct link_map **old = _dl_main_searchlist->r_list;
289 /* Put the old map in. */
290 _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list;
291 /* Signal that the original map is used. */
292 _dl_global_scope_alloc = 0;
294 /* Now free the old map. */
295 free (old);
298 text_set_element (__libc_subfreeres, free_mem);