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