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