]>
Commit | Line | Data |
---|---|---|
266180eb | 1 | /* Load a shared object at runtime, relocate it, and run its initializer. |
d6b5d570 | 2 | Copyright (C) 1996-2001, 2002 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 | |
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. | |
afd4eb37 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
afd4eb37 | 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. */ | |
266180eb | 19 | |
dc5efe83 | 20 | #include <assert.h> |
266180eb | 21 | #include <dlfcn.h> |
ba79d61b | 22 | #include <errno.h> |
06535ae9 | 23 | #include <libintl.h> |
b209e34a | 24 | #include <stdio.h> |
a853022c | 25 | #include <stdlib.h> |
7a68c94a | 26 | #include <string.h> |
06535ae9 | 27 | #include <unistd.h> |
08cac4ac | 28 | #include <sys/mman.h> /* Check whether MAP_COPY is defined. */ |
dc5efe83 | 29 | #include <sys/param.h> |
9a0a462c | 30 | #include <bits/libc-lock.h> |
a42195db | 31 | #include <ldsodefs.h> |
ebdf53a7 | 32 | #include <bp-sym.h> |
ba79d61b | 33 | |
dc5efe83 UD |
34 | #include <dl-dst.h> |
35 | ||
39778c6c | 36 | |
11336c16 UD |
37 | extern ElfW(Addr) _dl_sysdep_start (void **start_argptr, |
38 | void (*dl_main) (const ElfW(Phdr) *phdr, | |
39 | ElfW(Word) phnum, | |
40 | ElfW(Addr) *user_entry)); | |
ebdf53a7 | 41 | weak_extern (BP_SYM (_dl_sysdep_start)) |
39778c6c UD |
42 | |
43 | extern int __libc_multiple_libcs; /* Defined in init-first.c. */ | |
44 | ||
100351c3 UD |
45 | extern int __libc_argc attribute_hidden; |
46 | extern char **__libc_argv attribute_hidden; | |
dcf0671d | 47 | |
57ba7bb4 | 48 | extern char **__environ; |
dcf0671d | 49 | |
482eec0d UD |
50 | /* Undefine the following for debugging. */ |
51 | /* #define SCOPE_DEBUG 1 */ | |
52 | #ifdef SCOPE_DEBUG | |
53 | static void show_scope (struct link_map *new); | |
54 | #endif | |
26b4d766 | 55 | |
7a68c94a UD |
56 | /* We must be carefull not to leave us in an inconsistent state. Thus we |
57 | catch any error and re-raise it after cleaning up. */ | |
58 | ||
59 | struct dl_open_args | |
266180eb | 60 | { |
7a68c94a UD |
61 | const char *file; |
62 | int mode; | |
dc5efe83 | 63 | const void *caller; |
7a68c94a UD |
64 | struct link_map *map; |
65 | }; | |
66 | ||
d785c366 UD |
67 | |
68 | static int | |
69 | add_to_global (struct link_map *new) | |
70 | { | |
71 | struct link_map **new_global; | |
72 | unsigned int to_add = 0; | |
73 | unsigned int cnt; | |
74 | ||
75 | /* Count the objects we have to put in the global scope. */ | |
76 | for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) | |
77 | if (new->l_searchlist.r_list[cnt]->l_global == 0) | |
78 | ++to_add; | |
79 | ||
80 | /* The symbols of the new objects and its dependencies are to be | |
81 | introduced into the global scope that will be used to resolve | |
82 | references from other dynamically-loaded objects. | |
83 | ||
84 | The global scope is the searchlist in the main link map. We | |
85 | extend this list if necessary. There is one problem though: | |
86 | since this structure was allocated very early (before the libc | |
87 | is loaded) the memory it uses is allocated by the malloc()-stub | |
88 | in the ld.so. When we come here these functions are not used | |
89 | anymore. Instead the malloc() implementation of the libc is | |
90 | used. But this means the block from the main map cannot be used | |
91 | in an realloc() call. Therefore we allocate a completely new | |
92 | array the first time we have to add something to the locale scope. */ | |
93 | ||
d6b5d570 | 94 | if (GL(dl_global_scope_alloc) == 0) |
d785c366 UD |
95 | { |
96 | /* This is the first dynamic object given global scope. */ | |
d6b5d570 | 97 | GL(dl_global_scope_alloc) = GL(dl_main_searchlist)->r_nlist + to_add + 8; |
d785c366 | 98 | new_global = (struct link_map **) |
d6b5d570 | 99 | malloc (GL(dl_global_scope_alloc) * sizeof (struct link_map *)); |
d785c366 UD |
100 | if (new_global == NULL) |
101 | { | |
d6b5d570 | 102 | GL(dl_global_scope_alloc) = 0; |
d785c366 | 103 | nomem: |
407fe3bb | 104 | _dl_signal_error (ENOMEM, new->l_libname->name, NULL, |
d785c366 UD |
105 | N_("cannot extend global scope")); |
106 | return 1; | |
107 | } | |
108 | ||
109 | /* Copy over the old entries. */ | |
d6b5d570 UD |
110 | memcpy (new_global, GL(dl_main_searchlist)->r_list, |
111 | (GL(dl_main_searchlist)->r_nlist * sizeof (struct link_map *))); | |
d785c366 | 112 | |
d6b5d570 | 113 | GL(dl_main_searchlist)->r_list = new_global; |
d785c366 | 114 | } |
d6b5d570 UD |
115 | else if (GL(dl_main_searchlist)->r_nlist + to_add |
116 | > GL(dl_global_scope_alloc)) | |
d785c366 UD |
117 | { |
118 | /* We have to extend the existing array of link maps in the | |
119 | main map. */ | |
120 | new_global = (struct link_map **) | |
d6b5d570 UD |
121 | realloc (GL(dl_main_searchlist)->r_list, |
122 | ((GL(dl_global_scope_alloc) + to_add + 8) | |
d785c366 UD |
123 | * sizeof (struct link_map *))); |
124 | if (new_global == NULL) | |
125 | goto nomem; | |
126 | ||
d6b5d570 UD |
127 | GL(dl_global_scope_alloc) += to_add + 8; |
128 | GL(dl_main_searchlist)->r_list = new_global; | |
d785c366 UD |
129 | } |
130 | ||
131 | /* Now add the new entries. */ | |
132 | for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) | |
133 | { | |
134 | struct link_map *map = new->l_searchlist.r_list[cnt]; | |
135 | ||
136 | if (map->l_global == 0) | |
137 | { | |
138 | map->l_global = 1; | |
d6b5d570 UD |
139 | GL(dl_main_searchlist)->r_list[GL(dl_main_searchlist)->r_nlist] |
140 | = map; | |
141 | ++GL(dl_main_searchlist)->r_nlist; | |
d785c366 UD |
142 | } |
143 | } | |
144 | ||
d785c366 UD |
145 | return 0; |
146 | } | |
147 | ||
148 | ||
7a68c94a UD |
149 | static void |
150 | dl_open_worker (void *a) | |
151 | { | |
152 | struct dl_open_args *args = a; | |
153 | const char *file = args->file; | |
154 | int mode = args->mode; | |
266180eb | 155 | struct link_map *new, *l; |
dc5efe83 | 156 | const char *dst; |
12b5b6b7 | 157 | int lazy; |
752a2a50 | 158 | unsigned int i; |
d552a431 UD |
159 | #ifdef USE_TLS |
160 | bool any_tls; | |
161 | #endif | |
dc5efe83 UD |
162 | |
163 | /* Maybe we have to expand a DST. */ | |
164 | dst = strchr (file, '$'); | |
87837aac | 165 | if (__builtin_expect (dst != NULL, 0)) |
dc5efe83 UD |
166 | { |
167 | const void *caller = args->caller; | |
168 | size_t len = strlen (file); | |
169 | size_t required; | |
170 | struct link_map *call_map; | |
171 | char *new_file; | |
172 | ||
06535ae9 UD |
173 | /* DSTs must not appear in SUID/SGID programs. */ |
174 | if (__libc_enable_secure) | |
175 | /* This is an error. */ | |
407fe3bb | 176 | _dl_signal_error (0, "dlopen", NULL, |
8e17ea58 | 177 | N_("DST not allowed in SUID/SGID programs")); |
06535ae9 | 178 | |
2373b30e | 179 | /* We have to find out from which object the caller is calling. */ |
dc5efe83 | 180 | call_map = NULL; |
d6b5d570 | 181 | for (l = GL(dl_loaded); l; l = l->l_next) |
2373b30e | 182 | if (caller >= (const void *) l->l_map_start |
28760b3d UD |
183 | && caller < (const void *) l->l_map_end) |
184 | { | |
185 | /* There must be exactly one DSO for the range of the virtual | |
186 | memory. Otherwise something is really broken. */ | |
187 | call_map = l; | |
188 | break; | |
189 | } | |
dc5efe83 UD |
190 | |
191 | if (call_map == NULL) | |
192 | /* In this case we assume this is the main application. */ | |
d6b5d570 | 193 | call_map = GL(dl_loaded); |
dc5efe83 UD |
194 | |
195 | /* Determine how much space we need. We have to allocate the | |
196 | memory locally. */ | |
197 | required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0)); | |
198 | ||
199 | /* Get space for the new file name. */ | |
200 | new_file = (char *) alloca (required + 1); | |
201 | ||
202 | /* Generate the new file name. */ | |
7969407a | 203 | _dl_dst_substitute (call_map, file, new_file, 0); |
dc5efe83 UD |
204 | |
205 | /* If the substitution failed don't try to load. */ | |
206 | if (*new_file == '\0') | |
407fe3bb | 207 | _dl_signal_error (0, "dlopen", NULL, |
8e17ea58 | 208 | N_("empty dynamic string token substitution")); |
dc5efe83 UD |
209 | |
210 | /* Now we have a new file name. */ | |
211 | file = new_file; | |
212 | } | |
ba79d61b | 213 | |
266180eb | 214 | /* Load the named object. */ |
87837aac | 215 | args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0, mode); |
bf8b3e74 UD |
216 | |
217 | /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is | |
218 | set and the object is not already loaded. */ | |
219 | if (new == NULL) | |
220 | { | |
221 | assert (mode & RTLD_NOLOAD); | |
222 | return; | |
223 | } | |
224 | ||
9d0881aa UD |
225 | if (__builtin_expect (mode & __RTLD_SPROF, 0)) |
226 | /* This happens only if we load a DSO for 'sprof'. */ | |
227 | return; | |
228 | ||
42c4f32a UD |
229 | /* It was already open. */ |
230 | if (new->l_searchlist.r_list != NULL) | |
b35e21f4 UD |
231 | { |
232 | /* Let the user know about the opencount. */ | |
d6b5d570 | 233 | if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_FILES, 0)) |
35fc382a UD |
234 | _dl_debug_printf ("opening file=%s; opencount == %u\n\n", |
235 | new->l_name, new->l_opencount); | |
d785c366 | 236 | |
e30f2b98 | 237 | /* If the user requested the object to be in the global namespace |
d785c366 UD |
238 | but it is not so far, add it now. */ |
239 | if ((mode & RTLD_GLOBAL) && new->l_global == 0) | |
240 | (void) add_to_global (new); | |
241 | ||
42c4f32a UD |
242 | /* Increment just the reference counter of the object. */ |
243 | ++new->l_opencount; | |
244 | ||
b35e21f4 UD |
245 | return; |
246 | } | |
266180eb RM |
247 | |
248 | /* Load that object's dependencies. */ | |
87837aac | 249 | _dl_map_object_deps (new, NULL, 0, 0, mode & __RTLD_DLOPEN); |
266180eb | 250 | |
c84142e8 | 251 | /* So far, so good. Now check the versions. */ |
752a2a50 UD |
252 | for (i = 0; i < new->l_searchlist.r_nlist; ++i) |
253 | if (new->l_searchlist.r_list[i]->l_versions == NULL) | |
254 | (void) _dl_check_map_versions (new->l_searchlist.r_list[i], 0, 0); | |
ba79d61b | 255 | |
482eec0d UD |
256 | #ifdef SCOPE_DEBUG |
257 | show_scope (new); | |
258 | #endif | |
259 | ||
12b5b6b7 | 260 | /* Only do lazy relocation if `LD_BIND_NOW' is not set. */ |
5688da55 | 261 | lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && GL(dl_lazy); |
12b5b6b7 | 262 | |
ba79d61b RM |
263 | /* Relocate the objects loaded. We do this in reverse order so that copy |
264 | relocs of earlier objects overwrite the data written by later objects. */ | |
265 | ||
266 | l = new; | |
267 | while (l->l_next) | |
268 | l = l->l_next; | |
4d6acc61 | 269 | while (1) |
ba79d61b RM |
270 | { |
271 | if (! l->l_relocated) | |
272 | { | |
b5567b2a | 273 | #ifdef SHARED |
d6b5d570 | 274 | if (GL(dl_profile) != NULL) |
5ad49c07 UD |
275 | { |
276 | /* If this here is the shared object which we want to profile | |
277 | make sure the profile is started. We can find out whether | |
278 | this is necessary or not by observing the `_dl_profile_map' | |
279 | variable. If was NULL but is not NULL afterwars we must | |
280 | start the profiling. */ | |
d6b5d570 | 281 | struct link_map *old_profile_map = GL(dl_profile_map); |
5ad49c07 | 282 | |
be935610 | 283 | _dl_relocate_object (l, l->l_scope, 1, 1); |
5ad49c07 | 284 | |
d6b5d570 | 285 | if (old_profile_map == NULL && GL(dl_profile_map) != NULL) |
5ad49c07 | 286 | /* We must prepare the profiling. */ |
d6b5d570 | 287 | _dl_start_profile (GL(dl_profile_map), GL(dl_profile_output)); |
5ad49c07 UD |
288 | } |
289 | else | |
290 | #endif | |
12b5b6b7 | 291 | _dl_relocate_object (l, l->l_scope, lazy, 0); |
ba79d61b RM |
292 | } |
293 | ||
4d6acc61 RM |
294 | if (l == new) |
295 | break; | |
ba79d61b | 296 | l = l->l_prev; |
4d6acc61 | 297 | } |
ba79d61b | 298 | |
d552a431 UD |
299 | #ifdef USE_TLS |
300 | /* We normally don't bump the TLS generation counter. There must be | |
301 | actually a need to do this. */ | |
302 | any_tls = false; | |
303 | #endif | |
304 | ||
5a21d307 UD |
305 | /* Increment the open count for all dependencies. If the file is |
306 | not loaded as a dependency here add the search list of the newly | |
307 | loaded object to the scope. */ | |
09f5e163 | 308 | for (i = 0; i < new->l_searchlist.r_nlist; ++i) |
5a21d307 UD |
309 | if (++new->l_searchlist.r_list[i]->l_opencount > 1 |
310 | && new->l_searchlist.r_list[i]->l_type == lt_loaded) | |
311 | { | |
312 | struct link_map *imap = new->l_searchlist.r_list[i]; | |
313 | struct r_scope_elem **runp = imap->l_scope; | |
314 | size_t cnt = 0; | |
315 | ||
316 | while (*runp != NULL) | |
317 | { | |
c47e78b1 UD |
318 | /* This can happen if imap was just loaded, but during |
319 | relocation had l_opencount bumped because of relocation | |
320 | dependency. Avoid duplicates in l_scope. */ | |
321 | if (__builtin_expect (*runp == &new->l_searchlist, 0)) | |
322 | break; | |
323 | ||
5a21d307 UD |
324 | ++cnt; |
325 | ++runp; | |
326 | } | |
327 | ||
c47e78b1 UD |
328 | if (*runp != NULL) |
329 | /* Avoid duplicates. */ | |
330 | continue; | |
331 | ||
9596d0dd | 332 | if (__builtin_expect (cnt + 1 >= imap->l_scope_max, 0)) |
5a21d307 UD |
333 | { |
334 | /* The 'r_scope' array is too small. Allocate a new one | |
335 | dynamically. */ | |
336 | struct r_scope_elem **newp; | |
337 | size_t new_size = imap->l_scope_max * 2; | |
338 | ||
339 | if (imap->l_scope == imap->l_scope_mem) | |
340 | { | |
341 | newp = (struct r_scope_elem **) | |
342 | malloc (new_size * sizeof (struct r_scope_elem *)); | |
343 | if (newp == NULL) | |
344 | _dl_signal_error (ENOMEM, "dlopen", NULL, | |
345 | N_("cannot create scope list")); | |
346 | imap->l_scope = memcpy (newp, imap->l_scope, | |
9596d0dd | 347 | cnt * sizeof (imap->l_scope[0])); |
5a21d307 UD |
348 | } |
349 | else | |
350 | { | |
351 | newp = (struct r_scope_elem **) | |
352 | realloc (imap->l_scope, | |
353 | new_size * sizeof (struct r_scope_elem *)); | |
354 | if (newp == NULL) | |
355 | _dl_signal_error (ENOMEM, "dlopen", NULL, | |
356 | N_("cannot create scope list")); | |
357 | imap->l_scope = newp; | |
358 | } | |
61423e13 UD |
359 | |
360 | imap->l_scope_max = new_size; | |
5a21d307 | 361 | } |
9596d0dd UD |
362 | |
363 | imap->l_scope[cnt++] = &new->l_searchlist; | |
364 | imap->l_scope[cnt] = NULL; | |
5a21d307 | 365 | } |
aed283dd UD |
366 | #if USE_TLS |
367 | else if (new->l_searchlist.r_list[i]->l_opencount == 1 | |
368 | /* Only if the module defines thread local data. */ | |
369 | && __builtin_expect (new->l_searchlist.r_list[i]->l_tls_blocksize | |
370 | > 0, 0)) | |
371 | { | |
372 | /* Now that we know the object is loaded successfully add | |
373 | modules containing TLS data to the dtv info table. We | |
374 | might have to increase its size. */ | |
375 | struct dtv_slotinfo_list *listp; | |
376 | struct dtv_slotinfo_list *prevp; | |
377 | size_t idx = new->l_searchlist.r_list[i]->l_tls_modid; | |
378 | ||
379 | assert (new->l_searchlist.r_list[i]->l_type == lt_loaded); | |
380 | ||
381 | /* Find the place in the stv slotinfo list. */ | |
382 | listp = GL(dl_tls_dtv_slotinfo_list); | |
383 | prevp = NULL; /* Needed to shut up gcc. */ | |
384 | do | |
385 | { | |
386 | /* Does it fit in the array of this list element? */ | |
387 | if (idx <= listp->len) | |
388 | break; | |
389 | prevp = listp; | |
390 | } | |
391 | while ((listp = listp->next) != NULL); | |
392 | ||
393 | if (listp == NULL) | |
394 | { | |
395 | /* When we come here it means we have to add a new element | |
396 | to the slotinfo list. And the new module must be in | |
397 | the first slot. */ | |
398 | assert (idx == 0); | |
399 | ||
400 | listp = prevp->next = (struct dtv_slotinfo_list *) | |
401 | malloc (sizeof (struct dtv_slotinfo_list) | |
402 | + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); | |
403 | if (listp == NULL) | |
404 | { | |
405 | /* We ran out of memory. We will simply fail this | |
406 | call but don't undo anything we did so far. The | |
407 | application will crash or be terminated anyway very | |
408 | soon. */ | |
409 | ||
410 | /* We have to do this since some entries in the dtv | |
411 | slotinfo array might already point to this | |
412 | generation. */ | |
413 | ++GL(dl_tls_generation); | |
414 | ||
415 | _dl_signal_error (ENOMEM, "dlopen", NULL, | |
416 | N_("cannot create TLS data structures")); | |
417 | } | |
418 | ||
419 | listp->len = TLS_SLOTINFO_SURPLUS; | |
420 | listp->next = NULL; | |
421 | memset (listp->slotinfo, '\0', | |
422 | TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); | |
423 | } | |
424 | ||
425 | /* Add the information into the slotinfo data structure. */ | |
426 | listp->slotinfo[idx].map = new->l_searchlist.r_list[i]; | |
427 | listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; | |
d552a431 UD |
428 | |
429 | /* We have to bump the generation counter. */ | |
430 | any_tls = true; | |
aed283dd UD |
431 | } |
432 | ||
d552a431 UD |
433 | /* Bump the generation number if necessary. */ |
434 | if (any_tls) | |
b209e34a | 435 | if (__builtin_expect (++GL(dl_tls_generation) == 0, 0)) |
a585ba22 | 436 | __libc_fatal (_("TLS generation counter wrapped! Please send report with the 'glibcbug' script.")); |
aed283dd | 437 | #endif |
09f5e163 | 438 | |
266180eb | 439 | /* Run the initializer functions of new objects. */ |
dacc8ffa | 440 | _dl_init (new, __libc_argc, __libc_argv, __environ); |
266180eb | 441 | |
50b65db1 | 442 | /* Now we can make the new map available in the global scope. */ |
d9cb1a7d | 443 | if (mode & RTLD_GLOBAL) |
d785c366 UD |
444 | /* Move the object in the global namespace. */ |
445 | if (add_to_global (new) != 0) | |
446 | /* It failed. */ | |
447 | return; | |
be935610 | 448 | |
bf8b3e74 UD |
449 | /* Mark the object as not deletable if the RTLD_NODELETE flags was |
450 | passed. */ | |
451 | if (__builtin_expect (mode & RTLD_NODELETE, 0)) | |
452 | new->l_flags_1 |= DF_1_NODELETE; | |
453 | ||
7969407a UD |
454 | #ifndef SHARED |
455 | /* We must be the static _dl_open in libc.a. A static program that | |
456 | has loaded a dynamic object now has competition. */ | |
457 | __libc_multiple_libcs = 1; | |
458 | #endif | |
b35e21f4 UD |
459 | |
460 | /* Let the user know about the opencount. */ | |
d6b5d570 | 461 | if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_FILES, 0)) |
35fc382a UD |
462 | _dl_debug_printf ("opening file=%s; opencount == %u\n\n", |
463 | new->l_name, new->l_opencount); | |
7a68c94a UD |
464 | } |
465 | ||
466 | ||
94e365c6 | 467 | void * |
7a68c94a | 468 | internal_function |
dc5efe83 | 469 | _dl_open (const char *file, int mode, const void *caller) |
7a68c94a UD |
470 | { |
471 | struct dl_open_args args; | |
8e17ea58 UD |
472 | const char *objname; |
473 | const char *errstring; | |
7a68c94a UD |
474 | int errcode; |
475 | ||
e254df14 UD |
476 | if ((mode & RTLD_BINDING_MASK) == 0) |
477 | /* One of the flags must be set. */ | |
407fe3bb | 478 | _dl_signal_error (EINVAL, file, NULL, N_("invalid mode for dlopen()")); |
e254df14 | 479 | |
7a68c94a | 480 | /* Make sure we are alone. */ |
5688da55 | 481 | __libc_lock_lock_recursive (GL(dl_load_lock)); |
7a68c94a UD |
482 | |
483 | args.file = file; | |
484 | args.mode = mode; | |
dc5efe83 | 485 | args.caller = caller; |
7a68c94a | 486 | args.map = NULL; |
8e17ea58 | 487 | errcode = _dl_catch_error (&objname, &errstring, dl_open_worker, &args); |
39778c6c | 488 | |
08cac4ac UD |
489 | #ifndef MAP_COPY |
490 | /* We must munmap() the cache file. */ | |
491 | _dl_unload_cache (); | |
492 | #endif | |
493 | ||
26b4d766 | 494 | /* Release the lock. */ |
5688da55 | 495 | __libc_lock_unlock_recursive (GL(dl_load_lock)); |
26b4d766 | 496 | |
87837aac | 497 | if (__builtin_expect (errstring != NULL, 0)) |
7a68c94a | 498 | { |
49c091e5 | 499 | /* Some error occurred during loading. */ |
7a68c94a | 500 | char *local_errstring; |
7b70fef6 | 501 | size_t len_errstring; |
7a68c94a | 502 | |
7a68c94a UD |
503 | /* Remove the object from memory. It may be in an inconsistent |
504 | state if relocation failed, for example. */ | |
505 | if (args.map) | |
c77a4478 | 506 | { |
2e47aff5 | 507 | unsigned int i; |
c77a4478 | 508 | |
aed283dd UD |
509 | /* Increment open counters for all objects since this |
510 | sometimes has not happened yet. */ | |
511 | if (args.map->l_searchlist.r_list[0]->l_opencount == 0) | |
512 | for (i = 0; i < args.map->l_searchlist.r_nlist; ++i) | |
513 | ++args.map->l_searchlist.r_list[i]->l_opencount; | |
514 | ||
069b7c3e | 515 | #ifdef USE_TLS |
aed283dd UD |
516 | /* Maybe some of the modules which were loaded uses TLS. |
517 | Since it will be removed in the folowing _dl_close call | |
518 | we have to mark the dtv array as having gaps to fill | |
519 | the holes. This is a pessimistic assumption which won't | |
520 | hurt if not true. */ | |
521 | GL(dl_tls_dtv_gaps) = true; | |
069b7c3e | 522 | #endif |
c77a4478 UD |
523 | |
524 | _dl_close (args.map); | |
525 | } | |
7a68c94a UD |
526 | |
527 | /* Make a local copy of the error string so that we can release the | |
528 | memory allocated for it. */ | |
7b70fef6 UD |
529 | len_errstring = strlen (errstring) + 1; |
530 | if (objname == errstring + len_errstring) | |
531 | { | |
7231f6f9 UD |
532 | size_t total_len = len_errstring + strlen (objname) + 1; |
533 | local_errstring = alloca (total_len); | |
534 | memcpy (local_errstring, errstring, total_len); | |
7b70fef6 UD |
535 | objname = local_errstring + len_errstring; |
536 | } | |
537 | else | |
538 | { | |
539 | local_errstring = alloca (len_errstring); | |
540 | memcpy (local_errstring, errstring, len_errstring); | |
541 | } | |
542 | ||
ca3c0135 UD |
543 | if (errstring != _dl_out_of_memory) |
544 | free ((char *) errstring); | |
7a68c94a UD |
545 | |
546 | /* Reraise the error. */ | |
407fe3bb | 547 | _dl_signal_error (errcode, objname, NULL, local_errstring); |
7a68c94a UD |
548 | } |
549 | ||
7e36861e UD |
550 | #ifndef SHARED |
551 | DL_STATIC_INIT (args.map); | |
552 | #endif | |
553 | ||
7a68c94a | 554 | return args.map; |
266180eb | 555 | } |
cc7e7a26 | 556 | libc_hidden_def (_dl_open) |
482eec0d UD |
557 | |
558 | ||
559 | #ifdef SCOPE_DEBUG | |
560 | #include <unistd.h> | |
561 | ||
562 | static void | |
563 | show_scope (struct link_map *new) | |
564 | { | |
565 | int scope_cnt; | |
566 | ||
567 | for (scope_cnt = 0; new->l_scope[scope_cnt] != NULL; ++scope_cnt) | |
568 | { | |
569 | char numbuf[2]; | |
570 | unsigned int cnt; | |
571 | ||
572 | numbuf[0] = '0' + scope_cnt; | |
573 | numbuf[1] = '\0'; | |
35fc382a | 574 | _dl_printf ("scope %s:", numbuf); |
482eec0d UD |
575 | |
576 | for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt) | |
577 | if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name) | |
c47e78b1 | 578 | _dl_printf (" %s", new->l_scope[scope_cnt]->r_list[cnt]->l_name); |
482eec0d | 579 | else |
c47e78b1 | 580 | _dl_printf (" <main>"); |
482eec0d | 581 | |
c47e78b1 | 582 | _dl_printf ("\n"); |
482eec0d UD |
583 | } |
584 | } | |
585 | #endif |