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.
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
25 #include <bits/libc-lock.h>
27 #include <sys/types.h>
31 /* Type of the constructor functions. */
32 typedef void (*fini_t
) (void);
37 _dl_close (void *_map
)
41 struct link_map
**rellist
;
42 unsigned int nrellist
;
43 struct reldep_list
*next
;
45 struct link_map
**list
;
46 struct link_map
*map
= _map
;
48 unsigned int *new_opencount
;
53 /* First see whether we can remove the object at all. */
54 if (__builtin_expect (map
->l_flags_1
& DF_1_NODELETE
, 0)
55 && map
->l_init_called
)
56 /* Nope. Do nothing. */
59 if (__builtin_expect (map
->l_opencount
, 1) == 0)
60 _dl_signal_error (0, map
->l_name
, NULL
, N_("shared object not open"));
62 /* Acquire the lock. */
63 __libc_lock_lock_recursive (GL(dl_load_lock
));
65 /* Decrement the reference count. */
66 if (map
->l_opencount
> 1 || map
->l_type
!= lt_loaded
)
68 /* There are still references to this object. Do nothing more. */
69 if (__builtin_expect (GL(dl_debug_mask
) & DL_DEBUG_FILES
, 0))
70 _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
71 map
->l_name
, map
->l_opencount
);
73 /* One decrement the object itself, not the dependencies. */
76 __libc_lock_unlock_recursive (GL(dl_load_lock
));
80 list
= map
->l_initfini
;
82 /* Compute the new l_opencount values. */
83 i
= map
->l_searchlist
.r_nlist
;
84 if (__builtin_expect (i
== 0, 0))
85 /* This can happen if we handle relocation dependencies for an
86 object which wasn't loaded directly. */
87 for (i
= 1; list
[i
] != NULL
; ++i
)
90 new_opencount
= (unsigned int *) alloca (i
* sizeof (unsigned int));
92 for (i
= 0; list
[i
] != NULL
; ++i
)
95 new_opencount
[i
] = list
[i
]->l_opencount
;
98 for (i
= 1; list
[i
] != NULL
; ++i
)
99 if ((! (list
[i
]->l_flags_1
& DF_1_NODELETE
) || ! list
[i
]->l_init_called
)
100 /* Decrement counter. */
101 && --new_opencount
[i
] == 0
102 /* Test whether this object was also loaded directly. */
103 && list
[i
]->l_searchlist
.r_list
!= NULL
)
105 /* In this case we have the decrement all the dependencies of
106 this object. They are all in MAP's dependency list. */
108 struct link_map
**dep_list
= list
[i
]->l_searchlist
.r_list
;
110 for (j
= 1; j
< list
[i
]->l_searchlist
.r_nlist
; ++j
)
111 if (! (dep_list
[j
]->l_flags_1
& DF_1_NODELETE
)
112 || ! dep_list
[j
]->l_init_called
)
114 assert (dep_list
[j
]->l_idx
< map
->l_searchlist
.r_nlist
);
115 --new_opencount
[dep_list
[j
]->l_idx
];
118 assert (new_opencount
[0] == 0);
120 /* Call all termination functions at once. */
121 for (i
= 0; list
[i
] != NULL
; ++i
)
123 struct link_map
*imap
= list
[i
];
124 if (new_opencount
[i
] == 0 && imap
->l_type
== lt_loaded
125 && (imap
->l_info
[DT_FINI
] || imap
->l_info
[DT_FINI_ARRAY
])
126 && (! (imap
->l_flags_1
& DF_1_NODELETE
) || ! imap
->l_init_called
)
127 /* Skip any half-cooked objects that were never initialized. */
128 && imap
->l_init_called
)
130 /* When debugging print a message first. */
131 if (__builtin_expect (GL(dl_debug_mask
) & DL_DEBUG_IMPCALLS
, 0))
132 _dl_debug_printf ("\ncalling fini: %s\n\n", imap
->l_name
);
134 /* Call its termination function. */
135 if (imap
->l_info
[DT_FINI_ARRAY
] != NULL
)
138 (ElfW(Addr
) *) (imap
->l_addr
139 + imap
->l_info
[DT_FINI_ARRAY
]->d_un
.d_ptr
);
140 unsigned int sz
= (imap
->l_info
[DT_FINI_ARRAYSZ
]->d_un
.d_val
141 / sizeof (ElfW(Addr
)));
144 for (cnt
= 0; cnt
< sz
; ++cnt
)
145 ((fini_t
) (imap
->l_addr
+ array
[cnt
])) ();
148 /* Next try the old-style destructor. */
149 if (imap
->l_info
[DT_FINI
] != NULL
)
150 (*(void (*) (void)) DL_DT_FINI_ADDRESS
151 (imap
, (void *) imap
->l_addr
152 + imap
->l_info
[DT_FINI
]->d_un
.d_ptr
)) ();
154 else if (new_opencount
[i
] != 0 && imap
->l_type
== lt_loaded
)
156 /* The object is still used. But the object we are unloading
157 right now is responsible for loading it and therefore we
158 have the search list of the current object in its scope.
160 struct r_scope_elem
**runp
= imap
->l_scope
;
162 while (*runp
!= NULL
)
163 if (*runp
== &map
->l_searchlist
)
165 /* Copy all later elements. */
166 while ((runp
[0] = runp
[1]) != NULL
)
174 /* Store the new l_opencount value. */
175 imap
->l_opencount
= new_opencount
[i
];
176 /* Just a sanity check. */
177 assert (imap
->l_type
== lt_loaded
|| imap
->l_opencount
> 0);
180 /* Notify the debugger we are about to remove some loaded objects. */
181 _r_debug
.r_state
= RT_DELETE
;
184 /* Check each element of the search list to see if all references to
186 for (i
= 0; list
[i
] != NULL
; ++i
)
188 struct link_map
*imap
= list
[i
];
189 if (imap
->l_opencount
== 0 && imap
->l_type
== lt_loaded
)
191 struct libname_list
*lnp
;
193 /* That was the last reference, and this was a dlopen-loaded
194 object. We can unmap it. */
195 if (__builtin_expect (imap
->l_global
, 0))
197 /* This object is in the global scope list. Remove it. */
198 unsigned int cnt
= GL(dl_main_searchlist
)->r_nlist
;
202 while (GL(dl_main_searchlist
)->r_list
[cnt
] != imap
);
204 /* The object was already correctly registered. */
205 while (++cnt
< GL(dl_main_searchlist
)->r_nlist
)
206 GL(dl_main_searchlist
)->r_list
[cnt
- 1]
207 = GL(dl_main_searchlist
)->r_list
[cnt
];
209 --GL(dl_main_searchlist
)->r_nlist
;
213 /* Remove the object from the dtv slotinfo array if it uses
215 if (__builtin_expect (imap
->l_tls_blocksize
> 0, 0))
217 /* Locate the entry in the slotinfo array. */
218 size_t idx
= imap
->l_tls_modid
;
219 struct dtv_slotinfo_list
*listp
= GL(dl_tls_dtv_slotinfo_list
);
221 while (idx
>= listp
->len
)
227 listp
->slotinfo
[idx
].gen
= GL(dl_tls_generation
) + 1;
228 listp
->slotinfo
[idx
].map
= NULL
;
232 if (imap
->l_tls_modid
== GL(dl_tls_max_dtv_idx
))
233 --GL(dl_tls_max_dtv_idx
);
235 GL(dl_tls_dtv_gaps
) = true;
239 /* We can unmap all the maps at once. We determined the
240 start address and length when we loaded the object and
241 the `munmap' call does the rest. */
244 /* Finally, unlink the data structure and free it. */
246 /* We will unlink the first object only if this is a statically
248 assert (imap
->l_prev
!= NULL
);
249 imap
->l_prev
->l_next
= imap
->l_next
;
251 if (imap
->l_prev
!= NULL
)
252 imap
->l_prev
->l_next
= imap
->l_next
;
254 GL(dl_loaded
) = imap
->l_next
;
258 imap
->l_next
->l_prev
= imap
->l_prev
;
260 if (imap
->l_versions
!= NULL
)
261 free (imap
->l_versions
);
262 if (imap
->l_origin
!= NULL
&& imap
->l_origin
!= (char *) -1)
263 free ((char *) imap
->l_origin
);
265 /* If the object has relocation dependencies save this
266 information for latter. */
267 if (__builtin_expect (imap
->l_reldeps
!= NULL
, 0))
269 struct reldep_list
*newrel
;
271 newrel
= (struct reldep_list
*) alloca (sizeof (*reldeps
));
272 newrel
->rellist
= imap
->l_reldeps
;
273 newrel
->nrellist
= imap
->l_reldepsact
;
274 newrel
->next
= reldeps
;
279 /* This name always is allocated. */
281 /* Remove the list with all the names of the shared object. */
282 lnp
= imap
->l_libname
;
285 struct libname_list
*this = lnp
;
287 if (!this->dont_free
)
292 /* Remove the searchlists. */
294 free (imap
->l_initfini
);
296 /* Remove the scope array if we allocated it. */
297 if (imap
->l_scope
!= imap
->l_scope_mem
)
298 free (imap
->l_scope
);
300 if (imap
->l_phdr_allocated
)
301 free ((void *) imap
->l_phdr
);
303 if (imap
->l_rpath_dirs
.dirs
!= (void *) -1)
304 free (imap
->l_rpath_dirs
.dirs
);
305 if (imap
->l_runpath_dirs
.dirs
!= (void *) -1)
306 free (imap
->l_runpath_dirs
.dirs
);
313 /* If we removed any object which uses TLS bumnp the generation
316 ++GL(dl_tls_generation
);
319 /* Notify the debugger those objects are finalized and gone. */
320 _r_debug
.r_state
= RT_CONSISTENT
;
323 /* Now we can perhaps also remove the modules for which we had
324 dependencies because of symbol lookup. */
325 while (__builtin_expect (reldeps
!= NULL
, 0))
327 while (reldeps
->nrellist
-- > 0)
328 _dl_close (reldeps
->rellist
[reldeps
->nrellist
]);
330 free (reldeps
->rellist
);
332 reldeps
= reldeps
->next
;
337 /* Release the lock. */
338 __libc_lock_unlock_recursive (GL(dl_load_lock
));
344 free_slotinfo (struct dtv_slotinfo_list
*elemp
)
348 if (elemp
->next
!= NULL
&& !free_slotinfo (elemp
->next
))
349 /* We cannot free the entry. */
352 /* The least we could do is remove next element (if there was any). */
355 for (cnt
= 0; cnt
< elemp
->len
; ++cnt
)
356 if (elemp
->slotinfo
[cnt
].map
!= NULL
)
360 /* We can remove the list element. */
371 if (__builtin_expect (GL(dl_global_scope_alloc
), 0) != 0
372 && GL(dl_main_searchlist
)->r_nlist
== GL(dl_initial_searchlist
).r_nlist
)
374 /* All object dynamically loaded by the program are unloaded. Free
375 the memory allocated for the global scope variable. */
376 struct link_map
**old
= GL(dl_main_searchlist
)->r_list
;
378 /* Put the old map in. */
379 GL(dl_main_searchlist
)->r_list
= GL(dl_initial_searchlist
).r_list
;
380 /* Signal that the original map is used. */
381 GL(dl_global_scope_alloc
) = 0;
383 /* Now free the old map. */
388 /* Free the memory allocated for the dtv slotinfo array. We can do
389 this only if all modules which used this memory are unloaded.
390 Also, the first element of the list does not have to be
391 deallocated. It was allocated in the dynamic linker (i.e., with
392 a different malloc). */
393 if (free_slotinfo (GL(dl_tls_dtv_slotinfo_list
)->next
))
394 GL(dl_tls_dtv_slotinfo_list
)->next
= NULL
;
397 text_set_element (__libc_subfreeres
, free_mem
);