]>
Commit | Line | Data |
---|---|---|
26b4d766 | 1 | /* Close a shared object opened by `_dl_open'. |
af69217f | 2 | Copyright (C) 1996, 1997, 1998 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 | |
6 | modify it under the terms of the GNU Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | 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 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
ba79d61b | 19 | |
7afab53d | 20 | #include <assert.h> |
ba79d61b RM |
21 | #include <dlfcn.h> |
22 | #include <stdlib.h> | |
8d6468d0 | 23 | #include <string.h> |
a853022c UD |
24 | #include <bits/libc-lock.h> |
25 | #include <elf/ldsodefs.h> | |
ba79d61b RM |
26 | #include <sys/types.h> |
27 | #include <sys/mman.h> | |
28 | ||
29 | ||
26b4d766 UD |
30 | /* During the program run we must not modify the global data of |
31 | loaded shared object simultanously in two threads. Therefore we | |
32 | protect `dlopen' and `dlclose' in dlclose.c. */ | |
33 | __libc_lock_define (extern, _dl_load_lock) | |
34 | ||
ba79d61b RM |
35 | #define LOSE(s) _dl_signal_error (0, map->l_name, s) |
36 | ||
37 | void | |
d0fc4041 | 38 | internal_function |
ba79d61b RM |
39 | _dl_close (struct link_map *map) |
40 | { | |
41 | struct link_map **list; | |
6075607b | 42 | unsigned nsearchlist; |
ba79d61b RM |
43 | unsigned int i; |
44 | ||
45 | if (map->l_opencount == 0) | |
46 | LOSE ("shared object not open"); | |
47 | ||
26b4d766 UD |
48 | /* Acquire the lock. */ |
49 | __libc_lock_lock (_dl_load_lock); | |
50 | ||
ba79d61b | 51 | /* Decrement the reference count. */ |
a709dd43 | 52 | if (map->l_opencount > 1 || map->l_type != lt_loaded) |
26b4d766 UD |
53 | { |
54 | /* There are still references to this object. Do nothing more. */ | |
a709dd43 | 55 | --map->l_opencount; |
26b4d766 UD |
56 | __libc_lock_unlock (_dl_load_lock); |
57 | return; | |
58 | } | |
ba79d61b | 59 | |
a709dd43 | 60 | list = map->l_searchlist; |
6075607b | 61 | nsearchlist = map->l_nsearchlist; |
a709dd43 UD |
62 | |
63 | /* Call all termination functions at once. */ | |
6075607b | 64 | for (i = 0; i < nsearchlist; ++i) |
a709dd43 UD |
65 | { |
66 | struct link_map *imap = list[i]; | |
b48abe3c | 67 | if (imap->l_opencount == 1 && imap->l_type == lt_loaded |
7a68c94a UD |
68 | && imap->l_info[DT_FINI] |
69 | /* Skip any half-cooked objects that were never initialized. */ | |
70 | && imap->l_init_called) | |
a709dd43 | 71 | { |
b48abe3c UD |
72 | /* When debugging print a message first. */ |
73 | if (_dl_debug_impcalls) | |
74 | _dl_debug_message (1, "\ncalling fini: ", imap->l_name, | |
75 | "\n\n", NULL); | |
76 | /* Call its termination function. */ | |
77 | (*(void (*) (void)) ((void *) imap->l_addr | |
78 | + imap->l_info[DT_FINI]->d_un.d_ptr)) (); | |
a709dd43 UD |
79 | } |
80 | } | |
81 | ||
4d6acc61 RM |
82 | /* Notify the debugger we are about to remove some loaded objects. */ |
83 | _r_debug.r_state = RT_DELETE; | |
84 | _dl_debug_state (); | |
85 | ||
ba79d61b RM |
86 | /* The search list contains a counted reference to each object it |
87 | points to, the 0th elt being MAP itself. Decrement the reference | |
88 | counts on all the objects MAP depends on. */ | |
6075607b | 89 | for (i = 0; i < nsearchlist; ++i) |
ba79d61b RM |
90 | --list[i]->l_opencount; |
91 | ||
f787edde UD |
92 | if (map->l_origin != NULL) |
93 | free ((char *) map->l_origin); | |
94 | /* The name always is allocated. */ | |
95 | free (map->l_name); | |
96 | ||
ba79d61b RM |
97 | /* Check each element of the search list to see if all references to |
98 | it are gone. */ | |
6075607b | 99 | for (i = 0; i < nsearchlist; ++i) |
ba79d61b | 100 | { |
af69217f UD |
101 | struct link_map *imap = list[i]; |
102 | if (imap->l_opencount == 0 && imap->l_type == lt_loaded) | |
ba79d61b RM |
103 | { |
104 | /* That was the last reference, and this was a dlopen-loaded | |
105 | object. We can unmap it. */ | |
106 | const ElfW(Phdr) *ph; | |
22bc7978 UD |
107 | const ElfW(Phdr) *first, *last; |
108 | ElfW(Addr) mapstart, mapend; | |
ba79d61b | 109 | |
af69217f | 110 | if (imap->l_global) |
ba79d61b RM |
111 | { |
112 | /* This object is in the global scope list. Remove it. */ | |
113 | struct link_map **tail = _dl_global_scope_end; | |
114 | do | |
115 | --tail; | |
af69217f | 116 | while (*tail != imap); |
e9fc7bbb | 117 | while (tail < _dl_global_scope_end) |
3dd90163 UD |
118 | { |
119 | tail[0] = tail[1]; | |
120 | ++tail; | |
121 | } | |
ba79d61b | 122 | --_dl_global_scope_end; |
ba79d61b RM |
123 | } |
124 | ||
22bc7978 UD |
125 | /* We can unmap all the maps at once. We just have to determine |
126 | the length and the `munmap' call does the rest. */ | |
127 | first = last = NULL; | |
128 | for (ph = imap->l_phdr; ph < imap->l_phdr + imap->l_phnum; ++ph) | |
ba79d61b RM |
129 | if (ph->p_type == PT_LOAD) |
130 | { | |
22bc7978 UD |
131 | if (first == NULL) |
132 | first = ph; | |
133 | last = ph; | |
ba79d61b RM |
134 | } |
135 | ||
22bc7978 UD |
136 | /* Now we have all the information we need for the unmapping. |
137 | See the method used in `_dl_map_object_from_fd'. */ | |
138 | mapstart = first->p_vaddr & ~(first->p_align - 1); | |
139 | mapend = last->p_vaddr + last->p_memsz; | |
140 | __munmap ((caddr_t) (imap->l_addr + mapstart), mapend - mapstart); | |
141 | ||
ba79d61b | 142 | /* Finally, unlink the data structure and free it. */ |
7afab53d UD |
143 | #ifdef PIC |
144 | /* We will unlink the first object only if this is a statically | |
145 | linked program. */ | |
146 | assert (imap->l_prev != NULL); | |
6a805a0b | 147 | imap->l_prev->l_next = imap->l_next; |
7afab53d UD |
148 | #else |
149 | if (imap->l_prev != NULL) | |
af69217f | 150 | imap->l_prev->l_next = imap->l_next; |
7afab53d UD |
151 | else |
152 | _dl_loaded = imap->l_next; | |
153 | #endif | |
af69217f UD |
154 | if (imap->l_next) |
155 | imap->l_next->l_prev = imap->l_prev; | |
a709dd43 | 156 | if (imap->l_searchlist && imap->l_searchlist != list) |
af69217f UD |
157 | free (imap->l_searchlist); |
158 | free (imap); | |
ba79d61b RM |
159 | } |
160 | } | |
161 | ||
162 | free (list); | |
4d6acc61 RM |
163 | |
164 | /* Notify the debugger those objects are finalized and gone. */ | |
165 | _r_debug.r_state = RT_CONSISTENT; | |
166 | _dl_debug_state (); | |
26b4d766 UD |
167 | |
168 | /* Release the lock. */ | |
169 | __libc_lock_unlock (_dl_load_lock); | |
ba79d61b | 170 | } |