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