]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-fini.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / elf / dl-fini.c
CommitLineData
d66e34cd 1/* Call the termination functions of loaded shared objects.
bfff8b1b 2 Copyright (C) 1995-2017 Free Software Foundation, Inc.
afd4eb37 3 This file is part of the GNU C Library.
d66e34cd 4
afd4eb37 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.
d66e34cd 9
afd4eb37
UD
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.
d66e34cd 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
d66e34cd 18
dacc8ffa
UD
19#include <assert.h>
20#include <string.h>
a42195db 21#include <ldsodefs.h>
d66e34cd 22
dacc8ffa
UD
23
24/* Type of the constructor functions. */
25typedef void (*fini_t) (void);
26
27
c3381f3e
UD
28void
29internal_function
c8835729 30_dl_sort_fini (struct link_map **maps, size_t nmaps, char *used, Lmid_t ns)
c3381f3e 31{
6b1e7d19
UD
32 /* A list of one element need not be sorted. */
33 if (nmaps == 1)
34 return;
35
968dad0a
UD
36 /* We can skip looking for the binary itself which is at the front
37 of the search list for the main namespace. */
968dad0a 38 unsigned int i = ns == LM_ID_BASE;
28363bbf 39 uint16_t seen[nmaps];
e888bcbe 40 memset (seen, 0, nmaps * sizeof (seen[0]));
968dad0a
UD
41 while (1)
42 {
43 /* Keep track of which object we looked at this round. */
16437fec 44 ++seen[i];
968dad0a
UD
45 struct link_map *thisp = maps[i];
46
47 /* Do not handle ld.so in secondary namespaces and object which
48 are not removed. */
49 if (thisp != thisp->l_real || thisp->l_idx == -1)
50 goto skip;
51
52 /* Find the last object in the list for which the current one is
53 a dependency and move the current object behind the object
54 with the dependency. */
55 unsigned int k = nmaps - 1;
56 while (k > i)
57 {
58 struct link_map **runp = maps[k]->l_initfini;
59 if (runp != NULL)
60 /* Look through the dependencies of the object. */
61 while (*runp != NULL)
a1ffb40e 62 if (__glibc_unlikely (*runp++ == thisp))
968dad0a
UD
63 {
64 move:
65 /* Move the current object to the back past the last
66 object with it as the dependency. */
67 memmove (&maps[i], &maps[i + 1],
68 (k - i) * sizeof (maps[0]));
69 maps[k] = thisp;
70
71 if (used != NULL)
c3381f3e 72 {
968dad0a
UD
73 char here_used = used[i];
74 memmove (&used[i], &used[i + 1],
75 (k - i) * sizeof (used[0]));
76 used[k] = here_used;
77 }
78
28363bbf 79 if (seen[i + 1] > nmaps - i)
968dad0a
UD
80 {
81 ++i;
82 goto next_clear;
83 }
c3381f3e 84
28363bbf 85 uint16_t this_seen = seen[i];
968dad0a 86 memmove (&seen[i], &seen[i + 1], (k - i) * sizeof (seen[0]));
e888bcbe 87 seen[k] = this_seen;
c3381f3e 88
968dad0a
UD
89 goto next;
90 }
c3381f3e 91
a1ffb40e 92 if (__glibc_unlikely (maps[k]->l_reldeps != NULL))
968dad0a
UD
93 {
94 unsigned int m = maps[k]->l_reldeps->act;
95 struct link_map **relmaps = &maps[k]->l_reldeps->list[0];
c3381f3e 96
e888bcbe 97 /* Look through the relocation dependencies of the object. */
968dad0a 98 while (m-- > 0)
a1ffb40e 99 if (__glibc_unlikely (relmaps[m] == thisp))
d45c60c2
AS
100 {
101 /* If a cycle exists with a link time dependency,
102 preserve the latter. */
103 struct link_map **runp = thisp->l_initfini;
104 if (runp != NULL)
105 while (*runp != NULL)
a1ffb40e 106 if (__glibc_unlikely (*runp++ == maps[k]))
d45c60c2
AS
107 goto ignore;
108 goto move;
109 }
110 ignore:;
968dad0a 111 }
c3381f3e 112
968dad0a
UD
113 --k;
114 }
115
116 skip:
117 if (++i == nmaps)
118 break;
119 next_clear:
e888bcbe 120 memset (&seen[i], 0, (nmaps - i) * sizeof (seen[0]));
968dad0a
UD
121
122 next:;
123 }
c3381f3e
UD
124}
125
126
d66e34cd 127void
d0fc4041 128internal_function
d66e34cd
RM
129_dl_fini (void)
130{
dacc8ffa 131 /* Lots of fun ahead. We have to call the destructors for all still
c0f62c56
UD
132 loaded objects, in all namespaces. The problem is that the ELF
133 specification now demands that dependencies between the modules
134 are taken into account. I.e., the destructor for a module is
135 called before the ones for any of its dependencies.
dacc8ffa
UD
136
137 To make things more complicated, we cannot simply use the reverse
138 order of the constructors. Since the user might have loaded objects
139 using `dlopen' there are possibly several other modules with its
140 dependencies to be taken into account. Therefore we have to start
141 determining the order of the modules once again from the beginning. */
c0f62c56 142
b1f68750
UD
143 /* We run the destructors of the main namespaces last. As for the
144 other namespaces, we pick run the destructors in them in reverse
145 order of the namespace ID. */
e145f1cc
UD
146#ifdef SHARED
147 int do_audit = 0;
148 again:
149#endif
22c83193 150 for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
3b3938c9 151 {
c0f62c56
UD
152 /* Protect against concurrent loads and unloads. */
153 __rtld_lock_lock_recursive (GL(dl_load_lock));
1ebba33e 154
c3381f3e 155 unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
9dcafc55
UD
156 /* No need to do anything for empty namespaces or those used for
157 auditing DSOs. */
e145f1cc
UD
158 if (nloaded == 0
159#ifdef SHARED
c3381f3e 160 || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
e145f1cc
UD
161#endif
162 )
58acfe6f
FW
163 __rtld_lock_unlock_recursive (GL(dl_load_lock));
164 else
c0f62c56 165 {
58acfe6f
FW
166 /* Now we can allocate an array to hold all the pointers and
167 copy the pointers in. */
168 struct link_map *maps[nloaded];
169
170 unsigned int i;
171 struct link_map *l;
172 assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
173 for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
174 /* Do not handle ld.so in secondary namespaces. */
175 if (l == l->l_real)
176 {
177 assert (i < nloaded);
178
179 maps[i] = l;
180 l->l_idx = i;
181 ++i;
182
183 /* Bump l_direct_opencount of all objects so that they
184 are not dlclose()ed from underneath us. */
185 ++l->l_direct_opencount;
186 }
187 assert (ns != LM_ID_BASE || i == nloaded);
188 assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
189 unsigned int nmaps = i;
190
191 /* Now we have to do the sorting. */
192 _dl_sort_fini (maps, nmaps, NULL, ns);
193
194 /* We do not rely on the linked list of loaded object anymore
195 from this point on. We have our own list here (maps). The
196 various members of this list cannot vanish since the open
197 count is too high and will be decremented in this loop. So
198 we release the lock so that some code which might be called
199 from a destructor can directly or indirectly access the
200 lock. */
201 __rtld_lock_unlock_recursive (GL(dl_load_lock));
202
203 /* 'maps' now contains the objects in the right order. Now
204 call the destructors. We have to process this array from
205 the front. */
206 for (i = 0; i < nmaps; ++i)
c0f62c56 207 {
58acfe6f 208 struct link_map *l = maps[i];
dacc8ffa 209
58acfe6f 210 if (l->l_init_called)
c0f62c56 211 {
58acfe6f
FW
212 /* Make sure nothing happens if we are called twice. */
213 l->l_init_called = 0;
214
215 /* Is there a destructor function? */
216 if (l->l_info[DT_FINI_ARRAY] != NULL
217 || l->l_info[DT_FINI] != NULL)
9dcafc55 218 {
58acfe6f
FW
219 /* When debugging print a message first. */
220 if (__builtin_expect (GLRO(dl_debug_mask)
221 & DL_DEBUG_IMPCALLS, 0))
222 _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
223 DSO_FILENAME (l->l_name),
224 ns);
225
226 /* First see whether an array is given. */
227 if (l->l_info[DT_FINI_ARRAY] != NULL)
228 {
229 ElfW(Addr) *array =
230 (ElfW(Addr) *) (l->l_addr
231 + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
232 unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
233 / sizeof (ElfW(Addr)));
234 while (i-- > 0)
235 ((fini_t) array[i]) ();
236 }
237
238 /* Next try the old-style destructor. */
239 if (l->l_info[DT_FINI] != NULL)
240 DL_CALL_DT_FINI
241 (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);
9dcafc55
UD
242 }
243
9dcafc55 244#ifdef SHARED
58acfe6f
FW
245 /* Auditing checkpoint: another object closed. */
246 if (!do_audit && __builtin_expect (GLRO(dl_naudit) > 0, 0))
9dcafc55 247 {
58acfe6f
FW
248 struct audit_ifaces *afct = GLRO(dl_audit);
249 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
250 {
251 if (afct->objclose != NULL)
252 /* Return value is ignored. */
253 (void) afct->objclose (&l->l_audit[cnt].cookie);
254
255 afct = afct->next;
256 }
9dcafc55 257 }
9dcafc55 258#endif
58acfe6f 259 }
d66e34cd 260
58acfe6f
FW
261 /* Correct the previous increment. */
262 --l->l_direct_opencount;
263 }
dacc8ffa
UD
264 }
265 }
9836cfe7 266
e145f1cc
UD
267#ifdef SHARED
268 if (! do_audit && GLRO(dl_naudit) > 0)
269 {
270 do_audit = 1;
271 goto again;
272 }
e145f1cc 273
a1ffb40e 274 if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
42af49f8
UD
275 _dl_debug_printf ("\nruntime linker statistics:\n"
276 " final number of relocations: %lu\n"
277 "final number of relocations from cache: %lu\n",
278 GL(dl_num_relocations),
279 GL(dl_num_cache_relocations));
c3381f3e 280#endif
d66e34cd 281}