]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-deps.c
Fix testing with nss-crypt.
[thirdparty/glibc.git] / elf / dl-deps.c
CommitLineData
efec1d0c 1/* Load the dependencies of a mapped object.
bfff8b1b 2 Copyright (C) 1996-2017 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 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/>. */
efec1d0c 18
385b4cf4 19#include <atomic.h>
dc5efe83 20#include <assert.h>
efec1d0c 21#include <dlfcn.h>
a853022c 22#include <errno.h>
8e17ea58 23#include <libintl.h>
32e6df36 24#include <stddef.h>
efec1d0c 25#include <stdlib.h>
ca34d7a7 26#include <string.h>
06535ae9 27#include <unistd.h>
dc5efe83 28#include <sys/param.h>
a42195db 29#include <ldsodefs.h>
a853022c 30
dc5efe83 31#include <dl-dst.h>
1522c368
UD
32
33/* Whether an shared object references one or more auxiliary objects
34 is signaled by the AUXTAG entry in l_info. */
b0982c4a 35#define AUXTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
1522c368 36 + DT_EXTRATAGIDX (DT_AUXILIARY))
f41c8091
UD
37/* Whether an shared object references one or more auxiliary objects
38 is signaled by the AUXTAG entry in l_info. */
b0982c4a 39#define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
f41c8091 40 + DT_EXTRATAGIDX (DT_FILTER))
1522c368
UD
41
42
43/* When loading auxiliary objects we must ignore errors. It's ok if
44 an object is missing. */
993b3242 45struct openaux_args
1522c368
UD
46 {
47 /* The arguments to openaux. */
48 struct link_map *map;
49 int trace_mode;
87837aac 50 int open_mode;
1522c368 51 const char *strtab;
dc5efe83 52 const char *name;
993b3242 53
1522c368
UD
54 /* The return value of openaux. */
55 struct link_map *aux;
56 };
993b3242
UD
57
58static void
59openaux (void *a)
60{
61 struct openaux_args *args = (struct openaux_args *) a;
62
8e9f92e9 63 args->aux = _dl_map_object (args->map, args->name,
154d10bd
UD
64 (args->map->l_type == lt_executable
65 ? lt_library : args->map->l_type),
c0f62c56
UD
66 args->trace_mode, args->open_mode,
67 args->map->l_ns);
993b3242
UD
68}
69
32e6df36 70static ptrdiff_t
32e6df36
UD
71_dl_build_local_scope (struct link_map **list, struct link_map *map)
72{
73 struct link_map **p = list;
74 struct link_map **q;
75
76 *p++ = map;
77 map->l_reserved = 1;
78 if (map->l_initfini)
79 for (q = map->l_initfini + 1; *q; ++q)
80 if (! (*q)->l_reserved)
81 p += _dl_build_local_scope (p, *q);
82 return p - list;
83}
1522c368
UD
84
85
80d9c5f0 86/* We use a very special kind of list to track the path
1522c368 87 through the list of loaded shared objects. We have to
80d9c5f0 88 produce a flat list with unique members of all involved objects.
1522c368
UD
89*/
90struct list
91 {
92 int done; /* Nonzero if this map was processed. */
93 struct link_map *map; /* The data. */
ac55a25b 94 struct list *next; /* Elements for normal list. */
1522c368
UD
95 };
96
97
dc5efe83
UD
98/* Macro to expand DST. It is an macro since we use `alloca'. */
99#define expand_dst(l, str, fatal) \
100 ({ \
101 const char *__str = (str); \
102 const char *__result = __str; \
ac55a25b 103 size_t __dst_cnt = DL_DST_COUNT (__str, 0); \
dc5efe83 104 \
ac55a25b 105 if (__dst_cnt != 0) \
dc5efe83 106 { \
06535ae9
UD
107 char *__newp; \
108 \
109 /* DST must not appear in SUID/SGID programs. */ \
6bc6bd3b 110 if (__libc_enable_secure) \
154d10bd 111 _dl_signal_error (0, __str, NULL, N_("\
87837aac 112DST not allowed in SUID/SGID programs")); \
06535ae9
UD
113 \
114 __newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str), \
ac55a25b 115 __dst_cnt)); \
dc5efe83 116 \
ac55a25b 117 __result = _dl_dst_substitute (l, __str, __newp, 0); \
dc5efe83
UD
118 \
119 if (*__result == '\0') \
120 { \
121 /* The replacement for the DST is not known. We can't \
122 processed. */ \
123 if (fatal) \
154d10bd 124 _dl_signal_error (0, __str, NULL, N_("\
11bf311e 125empty dynamic string token substitution")); \
dc5efe83
UD
126 else \
127 { \
128 /* This is for DT_AUXILIARY. */ \
a1ffb40e 129 if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) \
154d10bd 130 _dl_debug_printf (N_("\
7969407a
UD
131cannot load auxiliary `%s' because of empty dynamic string token " \
132 "substitution\n"), __str); \
dc5efe83
UD
133 continue; \
134 } \
135 } \
136 } \
137 \
138 __result; })
139
06210a44
KS
140static void
141preload (struct list *known, unsigned int *nlist, struct link_map *map)
142{
143 known[*nlist].done = 0;
144 known[*nlist].map = map;
145 known[*nlist].next = &known[*nlist + 1];
146
147 ++*nlist;
148 /* We use `l_reserved' as a mark bit to detect objects we have
149 already put in the search list and avoid adding duplicate
150 elements later in the list. */
151 map->l_reserved = 1;
152}
dc5efe83 153
d9cb1a7d 154void
2064087b 155_dl_map_object_deps (struct link_map *map,
46ec036d 156 struct link_map **preloads, unsigned int npreloads,
87837aac 157 int trace_mode, int open_mode)
efec1d0c 158{
db2f05ba 159 struct list *known = __alloca (sizeof *known * (1 + npreloads + 1));
80d9c5f0
UD
160 struct list *runp, *tail;
161 unsigned int nlist, i;
c77a4478
UD
162 /* Object name. */
163 const char *name;
164 int errno_saved;
165 int errno_reason;
2449ae7b 166 struct dl_exception exception;
1522c368 167
1522c368
UD
168 /* No loaded object so far. */
169 nlist = 0;
2064087b 170
1522c368 171 /* First load MAP itself. */
06210a44 172 preload (known, &nlist, map);
df4ef2ab
UD
173
174 /* Add the preloaded items after MAP but before any of its dependencies. */
175 for (i = 0; i < npreloads; ++i)
06210a44 176 preload (known, &nlist, preloads[i]);
df4ef2ab 177
8a523922 178 /* Terminate the lists. */
80d9c5f0 179 known[nlist - 1].next = NULL;
1522c368 180
1522c368 181 /* Pointer to last unique object. */
80d9c5f0 182 tail = &known[nlist - 1];
efec1d0c 183
02f9c6cf
PP
184 /* No alloca'd space yet. */
185 struct link_map **needed_space = NULL;
186 size_t needed_space_bytes = 0;
187
1522c368
UD
188 /* Process each element of the search list, loading each of its
189 auxiliary objects and immediate dependencies. Auxiliary objects
190 will be added in the list before the object itself and
191 dependencies will be appended to the list as we step through it.
192 This produces a flat, ordered list that represents a
193 breadth-first search of the dependency tree.
194
195 The whole process is complicated by the fact that we better
196 should use alloca for the temporary list elements. But using
197 alloca means we cannot use recursive function calls. */
c77a4478
UD
198 errno_saved = errno;
199 errno_reason = 0;
200 errno = 0;
201 name = NULL;
1522c368 202 for (runp = known; runp; )
efec1d0c 203 {
1522c368 204 struct link_map *l = runp->map;
dacc8ffa
UD
205 struct link_map **needed = NULL;
206 unsigned int nneeded = 0;
207
208 /* Unless otherwise stated, this object is handled. */
209 runp->done = 1;
210
211 /* Allocate a temporary record to contain the references to the
212 dependencies of this object. */
07a3d63e
UD
213 if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
214 && l != map && l->l_ldnum > 0)
02f9c6cf 215 {
647776f6 216 size_t new_size = l->l_ldnum * sizeof (struct link_map *);
02f9c6cf
PP
217
218 if (new_size > needed_space_bytes)
219 needed_space
647776f6 220 = extend_alloca (needed_space, needed_space_bytes, new_size);
02f9c6cf
PP
221
222 needed = needed_space;
223 }
f68b86cc 224
8193034b 225 if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
efec1d0c 226 {
a42195db 227 const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
1522c368
UD
228 struct openaux_args args;
229 struct list *orig;
266180eb 230 const ElfW(Dyn) *d;
1522c368 231
1522c368
UD
232 args.strtab = strtab;
233 args.map = l;
234 args.trace_mode = trace_mode;
87837aac 235 args.open_mode = open_mode;
1522c368
UD
236 orig = runp;
237
efec1d0c 238 for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
e3e35cfc 239 if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
efec1d0c 240 {
f68b86cc 241 /* Map in the needed object. */
dc5efe83 242 struct link_map *dep;
dc5efe83
UD
243
244 /* Recognize DSTs. */
245 name = expand_dst (l, strtab + d->d_un.d_val, 0);
c77a4478
UD
246 /* Store the tag in the argument structure. */
247 args.name = name;
dc5efe83 248
2449ae7b
FW
249 int err = _dl_catch_exception (&exception, openaux, &args);
250 if (__glibc_unlikely (exception.errstring != NULL))
c77a4478 251 {
505d4b24
UD
252 if (err)
253 errno_reason = err;
c77a4478
UD
254 else
255 errno_reason = -1;
256 goto out;
257 }
258 else
259 dep = args.aux;
1522c368 260
42c4f32a 261 if (! dep->l_reserved)
efec1d0c 262 {
80d9c5f0
UD
263 /* Allocate new entry. */
264 struct list *newp;
265
266 newp = alloca (sizeof (struct list));
267
268 /* Append DEP to the list. */
269 newp->map = dep;
1522c368 270 newp->done = 0;
80d9c5f0
UD
271 newp->next = NULL;
272 tail->next = newp;
273 tail = newp;
f68b86cc 274 ++nlist;
f9496a7b
RM
275 /* Set the mark bit that says it's already in the list. */
276 dep->l_reserved = 1;
efec1d0c 277 }
dacc8ffa
UD
278
279 /* Remember this dependency. */
280 if (needed != NULL)
281 needed[nneeded++] = dep;
1522c368 282 }
f41c8091 283 else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
1522c368 284 {
f41c8091 285 struct list *newp;
dc5efe83
UD
286
287 /* Recognize DSTs. */
288 name = expand_dst (l, strtab + d->d_un.d_val,
289 d->d_tag == DT_AUXILIARY);
c77a4478
UD
290 /* Store the tag in the argument structure. */
291 args.name = name;
84384f5b 292
3dfb9a5c
OB
293 /* Say that we are about to load an auxiliary library. */
294 if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
295 0))
296 _dl_debug_printf ("load auxiliary object=%s"
297 " requested by file=%s\n",
298 name,
299 DSO_FILENAME (l->l_name));
300
301 /* We must be prepared that the addressed shared
302 object is not available. For filter objects the dependency
303 must be available. */
2449ae7b
FW
304 int err = _dl_catch_exception (&exception, openaux, &args);
305 if (__glibc_unlikely (exception.errstring != NULL))
1522c368 306 {
3dfb9a5c 307 if (d->d_tag == DT_AUXILIARY)
f41c8091
UD
308 {
309 /* We are not interested in the error message. */
2449ae7b 310 _dl_exception_free (&exception);
f41c8091
UD
311 /* Simply ignore this error and continue the work. */
312 continue;
313 }
3dfb9a5c 314 else
c77a4478 315 {
505d4b24
UD
316 if (err)
317 errno_reason = err;
c77a4478
UD
318 else
319 errno_reason = -1;
320 goto out;
321 }
8d9618b7 322 }
f41c8091
UD
323
324 /* The auxiliary object is actually available.
325 Incorporate the map in all the lists. */
326
327 /* Allocate new entry. This always has to be done. */
328 newp = alloca (sizeof (struct list));
329
ee0f7bd6
UD
330 /* We want to insert the new map before the current one,
331 but we have no back links. So we copy the contents of
332 the current entry over. Note that ORIG and NEWP now
333 have switched their meanings. */
80d9c5f0 334 memcpy (newp, orig, sizeof (*newp));
f41c8091
UD
335
336 /* Initialize new entry. */
337 orig->done = 0;
338 orig->map = args.aux;
f41c8091 339
dacc8ffa
UD
340 /* Remember this dependency. */
341 if (needed != NULL)
342 needed[nneeded++] = args.aux;
343
f41c8091
UD
344 /* We must handle two situations here: the map is new,
345 so we must add it in all three lists. If the map
346 is already known, we have two further possibilities:
347 - if the object is before the current map in the
348 search list, we do nothing. It is already found
349 early
350 - if the object is after the current one, we must
351 move it just before the current map to make sure
352 the symbols are found early enough
353 */
354 if (args.aux->l_reserved)
1522c368 355 {
f41c8091
UD
356 /* The object is already somewhere in the list.
357 Locate it first. */
358 struct list *late;
359
360 /* This object is already in the search list we
361 are building. Don't add a duplicate pointer.
42c4f32a 362 Just added by _dl_map_object. */
23382b36 363 for (late = newp; late->next != NULL; late = late->next)
80d9c5f0 364 if (late->next->map == args.aux)
f41c8091
UD
365 break;
366
23382b36 367 if (late->next != NULL)
1522c368 368 {
f41c8091
UD
369 /* The object is somewhere behind the current
370 position in the search path. We have to
371 move it to this earlier position. */
80d9c5f0 372 orig->next = newp;
f41c8091 373
80d9c5f0 374 /* Now remove the later entry from the list
ee0f7bd6 375 and adjust the tail pointer. */
80d9c5f0
UD
376 if (tail == late->next)
377 tail = late;
378 late->next = late->next->next;
f41c8091 379
ee0f7bd6 380 /* We must move the object earlier in the chain. */
23382b36 381 if (args.aux->l_prev != NULL)
1522c368 382 args.aux->l_prev->l_next = args.aux->l_next;
23382b36 383 if (args.aux->l_next != NULL)
1522c368
UD
384 args.aux->l_next->l_prev = args.aux->l_prev;
385
386 args.aux->l_prev = newp->map->l_prev;
387 newp->map->l_prev = args.aux;
388 if (args.aux->l_prev != NULL)
389 args.aux->l_prev->l_next = args.aux;
390 args.aux->l_next = newp->map;
391 }
f41c8091
UD
392 else
393 {
394 /* The object must be somewhere earlier in the
23382b36
UD
395 list. Undo to the current list element what
396 we did above. */
397 memcpy (orig, newp, sizeof (*newp));
398 continue;
f41c8091
UD
399 }
400 }
401 else
402 {
403 /* This is easy. We just add the symbol right here. */
80d9c5f0 404 orig->next = newp;
f41c8091
UD
405 ++nlist;
406 /* Set the mark bit that says it's already in the list. */
407 args.aux->l_reserved = 1;
408
409 /* The only problem is that in the double linked
410 list of all objects we don't have this new
411 object at the correct place. Correct this here. */
412 if (args.aux->l_prev)
413 args.aux->l_prev->l_next = args.aux->l_next;
414 if (args.aux->l_next)
415 args.aux->l_next->l_prev = args.aux->l_prev;
416
417 args.aux->l_prev = newp->map->l_prev;
418 newp->map->l_prev = args.aux;
419 if (args.aux->l_prev != NULL)
420 args.aux->l_prev->l_next = args.aux;
421 args.aux->l_next = newp->map;
422 }
1522c368 423
80d9c5f0
UD
424 /* Move the tail pointer if necessary. */
425 if (orig == tail)
426 tail = newp;
1522c368 427
f41c8091
UD
428 /* Move on the insert point. */
429 orig = newp;
efec1d0c
RM
430 }
431 }
dacc8ffa
UD
432
433 /* Terminate the list of dependencies and store the array address. */
434 if (needed != NULL)
435 {
436 needed[nneeded++] = NULL;
437
385b4cf4 438 struct link_map **l_initfini = (struct link_map **)
aff4519d 439 malloc ((2 * nneeded + 1) * sizeof needed[0]);
385b4cf4 440 if (l_initfini == NULL)
154d10bd
UD
441 _dl_signal_error (ENOMEM, map->l_name, NULL,
442 N_("cannot allocate dependency list"));
385b4cf4
UD
443 l_initfini[0] = l;
444 memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
445 memcpy (&l_initfini[nneeded + 1], l_initfini,
aff4519d 446 nneeded * sizeof needed[0]);
385b4cf4
UD
447 atomic_write_barrier ();
448 l->l_initfini = l_initfini;
0479b305 449 l->l_free_initfini = 1;
dacc8ffa 450 }
1522c368
UD
451
452 /* If we have no auxiliary objects just go on to the next map. */
453 if (runp->done)
454 do
80d9c5f0 455 runp = runp->next;
8193034b 456 while (runp != NULL && runp->done);
efec1d0c
RM
457 }
458
c4bb124a 459 out:
c77a4478
UD
460 if (errno == 0 && errno_saved != 0)
461 __set_errno (errno_saved);
462
385b4cf4 463 struct link_map **old_l_initfini = NULL;
752a2a50
UD
464 if (map->l_initfini != NULL && map->l_type == lt_loaded)
465 {
466 /* This object was previously loaded as a dependency and we have
467 a separate l_initfini list. We don't need it anymore. */
468 assert (map->l_searchlist.r_list == NULL);
385b4cf4 469 old_l_initfini = map->l_initfini;
752a2a50
UD
470 }
471
f68b86cc
RM
472 /* Store the search list we built in the object. It will be used for
473 searches in the scope of this object. */
385b4cf4 474 struct link_map **l_initfini =
80d9c5f0 475 (struct link_map **) malloc ((2 * nlist + 1)
2e93b4a4 476 * sizeof (struct link_map *));
385b4cf4 477 if (l_initfini == NULL)
154d10bd
UD
478 _dl_signal_error (ENOMEM, map->l_name, NULL,
479 N_("cannot allocate symbol search list"));
2e93b4a4
UD
480
481
385b4cf4 482 map->l_searchlist.r_list = &l_initfini[nlist + 1];
be935610 483 map->l_searchlist.r_nlist = nlist;
f68b86cc 484
80d9c5f0 485 for (nlist = 0, runp = known; runp; runp = runp->next)
f68b86cc 486 {
c4bb124a 487 if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
ad9570d7
UD
488 /* This can happen when we trace the loading. */
489 --map->l_searchlist.r_nlist;
490 else
491 map->l_searchlist.r_list[nlist++] = runp->map;
f68b86cc
RM
492
493 /* Now clear all the mark bits we set in the objects on the search list
494 to avoid duplicates, so the next call starts fresh. */
1522c368 495 runp->map->l_reserved = 0;
f68b86cc 496 }
84384f5b 497
1fc07491 498 if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
c0f62c56 499 && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
32e6df36
UD
500 {
501 /* If we are to compute conflicts, we have to build local scope
502 for each library, not just the ultimate loader. */
503 for (i = 0; i < nlist; ++i)
504 {
505 struct link_map *l = map->l_searchlist.r_list[i];
506 unsigned int j, cnt;
507
508 /* The local scope has been already computed. */
509 if (l == map
510 || (l->l_local_scope[0]
511 && l->l_local_scope[0]->r_nlist) != 0)
512 continue;
513
514 if (l->l_info[AUXTAG] || l->l_info[FILTERTAG])
515 {
516 /* As current DT_AUXILIARY/DT_FILTER implementation needs to be
517 rewritten, no need to bother with prelinking the old
518 implementation. */
154d10bd 519 _dl_signal_error (EINVAL, l->l_name, NULL, N_("\
32e6df36
UD
520Filters not supported with LD_TRACE_PRELINKING"));
521 }
522
385b4cf4 523 cnt = _dl_build_local_scope (l_initfini, l);
32e6df36
UD
524 assert (cnt <= nlist);
525 for (j = 0; j < cnt; j++)
4ad43b62
UD
526 {
527 l_initfini[j]->l_reserved = 0;
528 if (j && __builtin_expect (l_initfini[j]->l_info[DT_SYMBOLIC]
529 != NULL, 0))
530 l->l_symbolic_in_local_scope = true;
531 }
32e6df36
UD
532
533 l->l_local_scope[0] =
534 (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
535 + (cnt
536 * sizeof (struct link_map *)));
537 if (l->l_local_scope[0] == NULL)
154d10bd
UD
538 _dl_signal_error (ENOMEM, map->l_name, NULL,
539 N_("cannot allocate symbol search list"));
32e6df36
UD
540 l->l_local_scope[0]->r_nlist = cnt;
541 l->l_local_scope[0]->r_list =
542 (struct link_map **) (l->l_local_scope[0] + 1);
385b4cf4 543 memcpy (l->l_local_scope[0]->r_list, l_initfini,
32e6df36
UD
544 cnt * sizeof (struct link_map *));
545 }
546 }
547
c4bb124a
UD
548 /* Maybe we can remove some relocation dependencies now. */
549 assert (map->l_searchlist.r_list[0] == map);
385b4cf4
UD
550 struct link_map_reldeps *l_reldeps = NULL;
551 if (map->l_reldeps != NULL)
c4bb124a 552 {
385b4cf4
UD
553 for (i = 1; i < nlist; ++i)
554 map->l_searchlist.r_list[i]->l_reserved = 1;
c4bb124a 555
385b4cf4
UD
556 struct link_map **list = &map->l_reldeps->list[0];
557 for (i = 0; i < map->l_reldeps->act; ++i)
558 if (list[i]->l_reserved)
c4bb124a 559 {
385b4cf4 560 /* Need to allocate new array of relocation dependencies. */
385b4cf4 561 l_reldeps = malloc (sizeof (*l_reldeps)
968dad0a 562 + map->l_reldepsmax
385b4cf4
UD
563 * sizeof (struct link_map *));
564 if (l_reldeps == NULL)
565 /* Bad luck, keep the reldeps duplicated between
566 map->l_reldeps->list and map->l_initfini lists. */
567 ;
568 else
569 {
570 unsigned int j = i;
571 memcpy (&l_reldeps->list[0], &list[0],
572 i * sizeof (struct link_map *));
573 for (i = i + 1; i < map->l_reldeps->act; ++i)
574 if (!list[i]->l_reserved)
575 l_reldeps->list[j++] = list[i];
576 l_reldeps->act = j;
577 }
c4bb124a 578 }
385b4cf4
UD
579
580 for (i = 1; i < nlist; ++i)
581 map->l_searchlist.r_list[i]->l_reserved = 0;
c4bb124a
UD
582 }
583
6b1e7d19
UD
584 /* Sort the initializer list to take dependencies into account. The binary
585 itself will always be initialize last. */
385b4cf4 586 memcpy (l_initfini, map->l_searchlist.r_list,
2e93b4a4 587 nlist * sizeof (struct link_map *));
c2c299fd
AS
588 /* We can skip looking for the binary itself which is at the front of
589 the search list. */
590 _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false);
968dad0a 591
a8571d37 592 /* Terminate the list of dependencies. */
385b4cf4
UD
593 l_initfini[nlist] = NULL;
594 atomic_write_barrier ();
595 map->l_initfini = l_initfini;
0479b305 596 map->l_free_initfini = 1;
385b4cf4
UD
597 if (l_reldeps != NULL)
598 {
599 atomic_write_barrier ();
600 void *old_l_reldeps = map->l_reldeps;
601 map->l_reldeps = l_reldeps;
602 _dl_scope_free (old_l_reldeps);
603 }
604 if (old_l_initfini != NULL)
0479b305 605 _dl_scope_free (old_l_initfini);
f55ffe58
AS
606
607 if (errno_reason)
2449ae7b
FW
608 _dl_signal_exception (errno_reason == -1 ? 0 : errno_reason,
609 &exception, NULL);
efec1d0c 610}