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