Back to index

glibc  2.9
dl-deps.c
Go to the documentation of this file.
00001 /* Load the dependencies of a mapped object.
00002    Copyright (C) 1996-2003, 2004, 2005, 2006, 2007
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <atomic.h>
00022 #include <assert.h>
00023 #include <dlfcn.h>
00024 #include <errno.h>
00025 #include <libintl.h>
00026 #include <stddef.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 #include <sys/param.h>
00031 #include <ldsodefs.h>
00032 
00033 #include <dl-dst.h>
00034 
00035 /* Whether an shared object references one or more auxiliary objects
00036    is signaled by the AUXTAG entry in l_info.  */
00037 #define AUXTAG       (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
00038                + DT_EXTRATAGIDX (DT_AUXILIARY))
00039 /* Whether an shared object references one or more auxiliary objects
00040    is signaled by the AUXTAG entry in l_info.  */
00041 #define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
00042                  + DT_EXTRATAGIDX (DT_FILTER))
00043 
00044 
00045 /* When loading auxiliary objects we must ignore errors.  It's ok if
00046    an object is missing.  */
00047 struct openaux_args
00048   {
00049     /* The arguments to openaux.  */
00050     struct link_map *map;
00051     int trace_mode;
00052     int open_mode;
00053     const char *strtab;
00054     const char *name;
00055 
00056     /* The return value of openaux.  */
00057     struct link_map *aux;
00058   };
00059 
00060 static void
00061 openaux (void *a)
00062 {
00063   struct openaux_args *args = (struct openaux_args *) a;
00064 
00065   args->aux = _dl_map_object (args->map, args->name, 0,
00066                            (args->map->l_type == lt_executable
00067                             ? lt_library : args->map->l_type),
00068                            args->trace_mode, args->open_mode,
00069                            args->map->l_ns);
00070 }
00071 
00072 static ptrdiff_t
00073 internal_function
00074 _dl_build_local_scope (struct link_map **list, struct link_map *map)
00075 {
00076   struct link_map **p = list;
00077   struct link_map **q;
00078 
00079   *p++ = map;
00080   map->l_reserved = 1;
00081   if (map->l_initfini)
00082     for (q = map->l_initfini + 1; *q; ++q)
00083       if (! (*q)->l_reserved)
00084        p += _dl_build_local_scope (p, *q);
00085   return p - list;
00086 }
00087 
00088 
00089 /* We use a very special kind of list to track the path
00090    through the list of loaded shared objects.  We have to
00091    produce a flat list with unique members of all involved objects.
00092 */
00093 struct list
00094   {
00095     int done;               /* Nonzero if this map was processed.  */
00096     struct link_map *map;   /* The data.  */
00097     struct list *next;             /* Elements for normal list.  */
00098   };
00099 
00100 
00101 /* Macro to expand DST.  It is an macro since we use `alloca'.  */
00102 #define expand_dst(l, str, fatal) \
00103   ({                                                                 \
00104     const char *__str = (str);                                              \
00105     const char *__result = __str;                                    \
00106     size_t __dst_cnt = DL_DST_COUNT (__str, 0);                             \
00107                                                                      \
00108     if (__dst_cnt != 0)                                                     \
00109       {                                                                     \
00110        char *__newp;                                                 \
00111                                                                      \
00112        /* DST must not appear in SUID/SGID programs.  */                    \
00113        if (INTUSE(__libc_enable_secure))                             \
00114          _dl_signal_error (0, __str, NULL, N_("\
00115 DST not allowed in SUID/SGID programs"));                            \
00116                                                                      \
00117        __newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str),  \
00118                                              __dst_cnt));                   \
00119                                                                      \
00120        __result = _dl_dst_substitute (l, __str, __newp, 0);                 \
00121                                                                      \
00122        if (*__result == '\0')                                               \
00123          {                                                           \
00124            /* The replacement for the DST is not known.  We can't           \
00125               processed.  */                                                \
00126            if (fatal)                                                       \
00127              _dl_signal_error (0, __str, NULL, N_("\
00128 empty dynamic string token substitution"));                                 \
00129            else                                                      \
00130              {                                                              \
00131               /* This is for DT_AUXILIARY.  */                       \
00132               if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))\
00133                 _dl_debug_printf (N_("\
00134 cannot load auxiliary `%s' because of empty dynamic string token "          \
00135                                        "substitution\n"), __str);           \
00136               continue;                                              \
00137              }                                                              \
00138          }                                                           \
00139       }                                                                     \
00140                                                                      \
00141     __result; })
00142 
00143 
00144 void
00145 internal_function
00146 _dl_map_object_deps (struct link_map *map,
00147                    struct link_map **preloads, unsigned int npreloads,
00148                    int trace_mode, int open_mode)
00149 {
00150   struct list *known = __alloca (sizeof *known * (1 + npreloads + 1));
00151   struct list *runp, *tail;
00152   unsigned int nlist, i;
00153   /* Object name.  */
00154   const char *name;
00155   int errno_saved;
00156   int errno_reason;
00157   const char *errstring;
00158   const char *objname;
00159 
00160   auto inline void preload (struct link_map *map);
00161 
00162   inline void preload (struct link_map *map)
00163     {
00164       known[nlist].done = 0;
00165       known[nlist].map = map;
00166       known[nlist].next = &known[nlist + 1];
00167 
00168       ++nlist;
00169       /* We use `l_reserved' as a mark bit to detect objects we have
00170         already put in the search list and avoid adding duplicate
00171         elements later in the list.  */
00172       map->l_reserved = 1;
00173     }
00174 
00175   /* No loaded object so far.  */
00176   nlist = 0;
00177 
00178   /* First load MAP itself.  */
00179   preload (map);
00180 
00181   /* Add the preloaded items after MAP but before any of its dependencies.  */
00182   for (i = 0; i < npreloads; ++i)
00183     preload (preloads[i]);
00184 
00185   /* Terminate the lists.  */
00186   known[nlist - 1].next = NULL;
00187 
00188   /* Pointer to last unique object.  */
00189   tail = &known[nlist - 1];
00190 
00191   /* Process each element of the search list, loading each of its
00192      auxiliary objects and immediate dependencies.  Auxiliary objects
00193      will be added in the list before the object itself and
00194      dependencies will be appended to the list as we step through it.
00195      This produces a flat, ordered list that represents a
00196      breadth-first search of the dependency tree.
00197 
00198      The whole process is complicated by the fact that we better
00199      should use alloca for the temporary list elements.  But using
00200      alloca means we cannot use recursive function calls.  */
00201   errno_saved = errno;
00202   errno_reason = 0;
00203   errstring = NULL;
00204   errno = 0;
00205   name = NULL;
00206   for (runp = known; runp; )
00207     {
00208       struct link_map *l = runp->map;
00209       struct link_map **needed = NULL;
00210       unsigned int nneeded = 0;
00211 
00212       /* Unless otherwise stated, this object is handled.  */
00213       runp->done = 1;
00214 
00215       /* Allocate a temporary record to contain the references to the
00216         dependencies of this object.  */
00217       if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
00218          && l != map && l->l_ldnum > 0)
00219        needed = (struct link_map **) alloca (l->l_ldnum
00220                                          * sizeof (struct link_map *));
00221 
00222       if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
00223        {
00224          const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
00225          struct openaux_args args;
00226          struct list *orig;
00227          const ElfW(Dyn) *d;
00228 
00229          args.strtab = strtab;
00230          args.map = l;
00231          args.trace_mode = trace_mode;
00232          args.open_mode = open_mode;
00233          orig = runp;
00234 
00235          for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
00236            if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
00237              {
00238               /* Map in the needed object.  */
00239               struct link_map *dep;
00240 
00241               /* Recognize DSTs.  */
00242               name = expand_dst (l, strtab + d->d_un.d_val, 0);
00243               /* Store the tag in the argument structure.  */
00244               args.name = name;
00245 
00246               bool malloced;
00247               int err = _dl_catch_error (&objname, &errstring, &malloced,
00248                                       openaux, &args);
00249               if (__builtin_expect (errstring != NULL, 0))
00250                 {
00251                   char *new_errstring = strdupa (errstring);
00252                   objname = strdupa (objname);
00253                   if (malloced)
00254                     free ((char *) errstring);
00255                   errstring = new_errstring;
00256 
00257                   if (err)
00258                     errno_reason = err;
00259                   else
00260                     errno_reason = -1;
00261                   goto out;
00262                 }
00263               else
00264                 dep = args.aux;
00265 
00266               if (! dep->l_reserved)
00267                 {
00268                   /* Allocate new entry.  */
00269                   struct list *newp;
00270 
00271                   newp = alloca (sizeof (struct list));
00272 
00273                   /* Append DEP to the list.  */
00274                   newp->map = dep;
00275                   newp->done = 0;
00276                   newp->next = NULL;
00277                   tail->next = newp;
00278                   tail = newp;
00279                   ++nlist;
00280                   /* Set the mark bit that says it's already in the list.  */
00281                   dep->l_reserved = 1;
00282                 }
00283 
00284               /* Remember this dependency.  */
00285               if (needed != NULL)
00286                 needed[nneeded++] = dep;
00287              }
00288            else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
00289              {
00290               struct list *newp;
00291 
00292               /* Recognize DSTs.  */
00293               name = expand_dst (l, strtab + d->d_un.d_val,
00294                                d->d_tag == DT_AUXILIARY);
00295               /* Store the tag in the argument structure.  */
00296               args.name = name;
00297 
00298               if (d->d_tag == DT_AUXILIARY)
00299                 {
00300                   /* Say that we are about to load an auxiliary library.  */
00301                   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
00302                                      0))
00303                     _dl_debug_printf ("load auxiliary object=%s"
00304                                    " requested by file=%s\n",
00305                                    name,
00306                                    l->l_name[0]
00307                                    ? l->l_name : rtld_progname);
00308 
00309                   /* We must be prepared that the addressed shared
00310                      object is not available.  */
00311                   bool malloced;
00312                   (void) _dl_catch_error (&objname, &errstring, &malloced,
00313                                        openaux, &args);
00314                   if (__builtin_expect (errstring != NULL, 0))
00315                     {
00316                      /* We are not interested in the error message.  */
00317                      assert (errstring != NULL);
00318                      if (malloced)
00319                        free ((char *) errstring);
00320 
00321                      /* Simply ignore this error and continue the work.  */
00322                      continue;
00323                     }
00324                 }
00325               else
00326                 {
00327                   /* Say that we are about to load an auxiliary library.  */
00328                   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
00329                                      0))
00330                     _dl_debug_printf ("load filtered object=%s"
00331                                    " requested by file=%s\n",
00332                                    name,
00333                                    l->l_name[0]
00334                                    ? l->l_name : rtld_progname);
00335 
00336                   /* For filter objects the dependency must be available.  */
00337                   bool malloced;
00338                   int err = _dl_catch_error (&objname, &errstring, &malloced,
00339                                           openaux, &args);
00340                   if (__builtin_expect (errstring != NULL, 0))
00341                     {
00342                      char *new_errstring = strdupa (errstring);
00343                      objname = strdupa (objname);
00344                      if (malloced)
00345                        free ((char *) errstring);
00346                      errstring = new_errstring;
00347 
00348                      if (err)
00349                        errno_reason = err;
00350                      else
00351                        errno_reason = -1;
00352                      goto out;
00353                     }
00354                 }
00355 
00356               /* The auxiliary object is actually available.
00357                  Incorporate the map in all the lists.  */
00358 
00359               /* Allocate new entry.  This always has to be done.  */
00360               newp = alloca (sizeof (struct list));
00361 
00362               /* We want to insert the new map before the current one,
00363                  but we have no back links.  So we copy the contents of
00364                  the current entry over.  Note that ORIG and NEWP now
00365                  have switched their meanings.  */
00366               memcpy (newp, orig, sizeof (*newp));
00367 
00368               /* Initialize new entry.  */
00369               orig->done = 0;
00370               orig->map = args.aux;
00371 
00372               /* Remember this dependency.  */
00373               if (needed != NULL)
00374                 needed[nneeded++] = args.aux;
00375 
00376               /* We must handle two situations here: the map is new,
00377                  so we must add it in all three lists.  If the map
00378                  is already known, we have two further possibilities:
00379                  - if the object is before the current map in the
00380                  search list, we do nothing.  It is already found
00381                  early
00382                  - if the object is after the current one, we must
00383                  move it just before the current map to make sure
00384                  the symbols are found early enough
00385               */
00386               if (args.aux->l_reserved)
00387                 {
00388                   /* The object is already somewhere in the list.
00389                      Locate it first.  */
00390                   struct list *late;
00391 
00392                   /* This object is already in the search list we
00393                      are building.  Don't add a duplicate pointer.
00394                      Just added by _dl_map_object.  */
00395                   for (late = newp; late->next != NULL; late = late->next)
00396                     if (late->next->map == args.aux)
00397                      break;
00398 
00399                   if (late->next != NULL)
00400                     {
00401                      /* The object is somewhere behind the current
00402                         position in the search path.  We have to
00403                         move it to this earlier position.  */
00404                      orig->next = newp;
00405 
00406                      /* Now remove the later entry from the list
00407                         and adjust the tail pointer.  */
00408                      if (tail == late->next)
00409                        tail = late;
00410                      late->next = late->next->next;
00411 
00412                      /* We must move the object earlier in the chain.  */
00413                      if (args.aux->l_prev != NULL)
00414                        args.aux->l_prev->l_next = args.aux->l_next;
00415                      if (args.aux->l_next != NULL)
00416                        args.aux->l_next->l_prev = args.aux->l_prev;
00417 
00418                      args.aux->l_prev = newp->map->l_prev;
00419                      newp->map->l_prev = args.aux;
00420                      if (args.aux->l_prev != NULL)
00421                        args.aux->l_prev->l_next = args.aux;
00422                      args.aux->l_next = newp->map;
00423                     }
00424                   else
00425                     {
00426                      /* The object must be somewhere earlier in the
00427                         list.  Undo to the current list element what
00428                         we did above.  */
00429                      memcpy (orig, newp, sizeof (*newp));
00430                      continue;
00431                     }
00432                 }
00433               else
00434                 {
00435                   /* This is easy.  We just add the symbol right here.  */
00436                   orig->next = newp;
00437                   ++nlist;
00438                   /* Set the mark bit that says it's already in the list.  */
00439                   args.aux->l_reserved = 1;
00440 
00441                   /* The only problem is that in the double linked
00442                      list of all objects we don't have this new
00443                      object at the correct place.  Correct this here.  */
00444                   if (args.aux->l_prev)
00445                     args.aux->l_prev->l_next = args.aux->l_next;
00446                   if (args.aux->l_next)
00447                     args.aux->l_next->l_prev = args.aux->l_prev;
00448 
00449                   args.aux->l_prev = newp->map->l_prev;
00450                   newp->map->l_prev = args.aux;
00451                   if (args.aux->l_prev != NULL)
00452                     args.aux->l_prev->l_next = args.aux;
00453                   args.aux->l_next = newp->map;
00454                 }
00455 
00456               /* Move the tail pointer if necessary.  */
00457               if (orig == tail)
00458                 tail = newp;
00459 
00460               /* Move on the insert point.  */
00461               orig = newp;
00462              }
00463        }
00464 
00465       /* Terminate the list of dependencies and store the array address.  */
00466       if (needed != NULL)
00467        {
00468          needed[nneeded++] = NULL;
00469 
00470          struct link_map **l_initfini = (struct link_map **)
00471            malloc ((2 * nneeded + 1) * sizeof needed[0]);
00472          if (l_initfini == NULL)
00473            _dl_signal_error (ENOMEM, map->l_name, NULL,
00474                            N_("cannot allocate dependency list"));
00475          l_initfini[0] = l;
00476          memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
00477          memcpy (&l_initfini[nneeded + 1], l_initfini,
00478                 nneeded * sizeof needed[0]);
00479          atomic_write_barrier ();
00480          l->l_initfini = l_initfini;
00481        }
00482 
00483       /* If we have no auxiliary objects just go on to the next map.  */
00484       if (runp->done)
00485        do
00486          runp = runp->next;
00487        while (runp != NULL && runp->done);
00488     }
00489 
00490  out:
00491   if (errno == 0 && errno_saved != 0)
00492     __set_errno (errno_saved);
00493 
00494   struct link_map **old_l_initfini = NULL;
00495   if (map->l_initfini != NULL && map->l_type == lt_loaded)
00496     {
00497       /* This object was previously loaded as a dependency and we have
00498         a separate l_initfini list.  We don't need it anymore.  */
00499       assert (map->l_searchlist.r_list == NULL);
00500       old_l_initfini = map->l_initfini;
00501     }
00502 
00503   /* Store the search list we built in the object.  It will be used for
00504      searches in the scope of this object.  */
00505   struct link_map **l_initfini =
00506     (struct link_map **) malloc ((2 * nlist + 1)
00507                              * sizeof (struct link_map *));
00508   if (l_initfini == NULL)
00509     _dl_signal_error (ENOMEM, map->l_name, NULL,
00510                     N_("cannot allocate symbol search list"));
00511 
00512 
00513   map->l_searchlist.r_list = &l_initfini[nlist + 1];
00514   map->l_searchlist.r_nlist = nlist;
00515 
00516   for (nlist = 0, runp = known; runp; runp = runp->next)
00517     {
00518       if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
00519        /* This can happen when we trace the loading.  */
00520        --map->l_searchlist.r_nlist;
00521       else
00522        map->l_searchlist.r_list[nlist++] = runp->map;
00523 
00524       /* Now clear all the mark bits we set in the objects on the search list
00525         to avoid duplicates, so the next call starts fresh.  */
00526       runp->map->l_reserved = 0;
00527     }
00528 
00529   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
00530       && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
00531     {
00532       /* If we are to compute conflicts, we have to build local scope
00533         for each library, not just the ultimate loader.  */
00534       for (i = 0; i < nlist; ++i)
00535        {
00536          struct link_map *l = map->l_searchlist.r_list[i];
00537          unsigned int j, cnt;
00538 
00539          /* The local scope has been already computed.  */
00540          if (l == map
00541              || (l->l_local_scope[0]
00542                 && l->l_local_scope[0]->r_nlist) != 0)
00543            continue;
00544 
00545          if (l->l_info[AUXTAG] || l->l_info[FILTERTAG])
00546            {
00547              /* As current DT_AUXILIARY/DT_FILTER implementation needs to be
00548                rewritten, no need to bother with prelinking the old
00549                implementation.  */
00550              _dl_signal_error (EINVAL, l->l_name, NULL, N_("\
00551 Filters not supported with LD_TRACE_PRELINKING"));
00552            }
00553 
00554          cnt = _dl_build_local_scope (l_initfini, l);
00555          assert (cnt <= nlist);
00556          for (j = 0; j < cnt; j++)
00557            l_initfini[j]->l_reserved = 0;
00558 
00559          l->l_local_scope[0] =
00560            (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
00561                                        + (cnt
00562                                           * sizeof (struct link_map *)));
00563          if (l->l_local_scope[0] == NULL)
00564            _dl_signal_error (ENOMEM, map->l_name, NULL,
00565                            N_("cannot allocate symbol search list"));
00566          l->l_local_scope[0]->r_nlist = cnt;
00567          l->l_local_scope[0]->r_list =
00568            (struct link_map **) (l->l_local_scope[0] + 1);
00569          memcpy (l->l_local_scope[0]->r_list, l_initfini,
00570                 cnt * sizeof (struct link_map *));
00571        }
00572     }
00573 
00574   /* Maybe we can remove some relocation dependencies now.  */
00575   assert (map->l_searchlist.r_list[0] == map);
00576   struct link_map_reldeps *l_reldeps = NULL;
00577   if (map->l_reldeps != NULL)
00578     {
00579       for (i = 1; i < nlist; ++i)
00580        map->l_searchlist.r_list[i]->l_reserved = 1;
00581 
00582       struct link_map **list = &map->l_reldeps->list[0];
00583       for (i = 0; i < map->l_reldeps->act; ++i)
00584        if (list[i]->l_reserved)
00585          {
00586            /* Need to allocate new array of relocation dependencies.  */
00587            struct link_map_reldeps *l_reldeps;
00588            l_reldeps = malloc (sizeof (*l_reldeps)
00589                             + map->l_reldepsmax
00590                               * sizeof (struct link_map *));
00591            if (l_reldeps == NULL)
00592              /* Bad luck, keep the reldeps duplicated between
00593                map->l_reldeps->list and map->l_initfini lists.  */
00594              ;
00595            else
00596              {
00597               unsigned int j = i;
00598               memcpy (&l_reldeps->list[0], &list[0],
00599                      i * sizeof (struct link_map *));
00600               for (i = i + 1; i < map->l_reldeps->act; ++i)
00601                 if (!list[i]->l_reserved)
00602                   l_reldeps->list[j++] = list[i];
00603               l_reldeps->act = j;
00604              }
00605          }
00606 
00607       for (i = 1; i < nlist; ++i)
00608        map->l_searchlist.r_list[i]->l_reserved = 0;
00609     }
00610 
00611   /* Now determine the order in which the initialization has to happen.  */
00612   memcpy (l_initfini, map->l_searchlist.r_list,
00613          nlist * sizeof (struct link_map *));
00614   /* We can skip looking for the binary itself which is at the front
00615      of the search list.  Look through the list backward so that circular
00616      dependencies are not changing the order.  */
00617   for (i = 1; i < nlist; ++i)
00618     {
00619       struct link_map *l = map->l_searchlist.r_list[i];
00620       unsigned int j;
00621       unsigned int k;
00622 
00623       /* Find the place in the initfini list where the map is currently
00624         located.  */
00625       for (j = 1; l_initfini[j] != l; ++j)
00626        ;
00627 
00628       /* Find all object for which the current one is a dependency and
00629         move the found object (if necessary) in front.  */
00630       for (k = j + 1; k < nlist; ++k)
00631        {
00632          struct link_map **runp;
00633 
00634          runp = l_initfini[k]->l_initfini;
00635          if (runp != NULL)
00636            {
00637              while (*runp != NULL)
00638               if (__builtin_expect (*runp++ == l, 0))
00639                 {
00640                   struct link_map *here = l_initfini[k];
00641 
00642                   /* Move it now.  */
00643                   memmove (&l_initfini[j] + 1, &l_initfini[j],
00644                           (k - j) * sizeof (struct link_map *));
00645                   l_initfini[j] = here;
00646 
00647                   /* Don't insert further matches before the last
00648                      entry moved to the front.  */
00649                   ++j;
00650 
00651                   break;
00652                 }
00653            }
00654        }
00655     }
00656   /* Terminate the list of dependencies.  */
00657   l_initfini[nlist] = NULL;
00658   atomic_write_barrier ();
00659   map->l_initfini = l_initfini;
00660   if (l_reldeps != NULL)
00661     {
00662       atomic_write_barrier ();
00663       void *old_l_reldeps = map->l_reldeps;
00664       map->l_reldeps = l_reldeps;
00665       _dl_scope_free (old_l_reldeps);
00666     }
00667   if (old_l_initfini != NULL)
00668     _dl_scope_free (old_l_initfini);
00669 
00670   if (errno_reason)
00671     _dl_signal_error (errno_reason == -1 ? 0 : errno_reason, objname,
00672                     NULL, errstring);
00673 }