Blame elf/dl-deps.c

Packit 6c4009
/* Load the dependencies of a mapped object.
Packit 6c4009
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <atomic.h>
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <scratch_buffer.h>
Packit 6c4009
Packit 6c4009
#include <dl-dst.h>
Packit 6c4009
Packit 6c4009
/* Whether an shared object references one or more auxiliary objects
Packit 6c4009
   is signaled by the AUXTAG entry in l_info.  */
Packit 6c4009
#define AUXTAG	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
Packit 6c4009
		 + DT_EXTRATAGIDX (DT_AUXILIARY))
Packit 6c4009
/* Whether an shared object references one or more auxiliary objects
Packit 6c4009
   is signaled by the AUXTAG entry in l_info.  */
Packit 6c4009
#define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
Packit 6c4009
		   + DT_EXTRATAGIDX (DT_FILTER))
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* When loading auxiliary objects we must ignore errors.  It's ok if
Packit 6c4009
   an object is missing.  */
Packit 6c4009
struct openaux_args
Packit 6c4009
  {
Packit 6c4009
    /* The arguments to openaux.  */
Packit 6c4009
    struct link_map *map;
Packit 6c4009
    int trace_mode;
Packit 6c4009
    int open_mode;
Packit 6c4009
    const char *strtab;
Packit 6c4009
    const char *name;
Packit 6c4009
Packit 6c4009
    /* The return value of openaux.  */
Packit 6c4009
    struct link_map *aux;
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
openaux (void *a)
Packit 6c4009
{
Packit 6c4009
  struct openaux_args *args = (struct openaux_args *) a;
Packit 6c4009
Packit 6c4009
  args->aux = _dl_map_object (args->map, args->name,
Packit 6c4009
			      (args->map->l_type == lt_executable
Packit 6c4009
			       ? lt_library : args->map->l_type),
Packit 6c4009
			      args->trace_mode, args->open_mode,
Packit 6c4009
			      args->map->l_ns);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static ptrdiff_t
Packit 6c4009
_dl_build_local_scope (struct link_map **list, struct link_map *map)
Packit 6c4009
{
Packit 6c4009
  struct link_map **p = list;
Packit 6c4009
  struct link_map **q;
Packit 6c4009
Packit 6c4009
  *p++ = map;
Packit 6c4009
  map->l_reserved = 1;
Packit 6c4009
  if (map->l_initfini)
Packit 6c4009
    for (q = map->l_initfini + 1; *q; ++q)
Packit 6c4009
      if (! (*q)->l_reserved)
Packit 6c4009
	p += _dl_build_local_scope (p, *q);
Packit 6c4009
  return p - list;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* We use a very special kind of list to track the path
Packit 6c4009
   through the list of loaded shared objects.  We have to
Packit 6c4009
   produce a flat list with unique members of all involved objects.
Packit 6c4009
*/
Packit 6c4009
struct list
Packit 6c4009
  {
Packit 6c4009
    int done;			/* Nonzero if this map was processed.  */
Packit 6c4009
    struct link_map *map;	/* The data.  */
Packit 6c4009
    struct list *next;		/* Elements for normal list.  */
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Macro to expand DST.  It is an macro since we use `alloca'.  */
Packit 6c4009
#define expand_dst(l, str, fatal) \
Packit 6c4009
  ({									      \
Packit 6c4009
    const char *__str = (str);						      \
Packit 6c4009
    const char *__result = __str;					      \
Packit 6c4009
    size_t __dst_cnt = _dl_dst_count (__str);				      \
Packit 6c4009
									      \
Packit 6c4009
    if (__dst_cnt != 0)							      \
Packit 6c4009
      {									      \
Packit 6c4009
	char *__newp;							      \
Packit 6c4009
									      \
Packit 6c4009
	/* DST must not appear in SUID/SGID programs.  */		      \
Packit 6c4009
	if (__libc_enable_secure)					      \
Packit 6c4009
	  _dl_signal_error (0, __str, NULL, N_("\
Packit 6c4009
DST not allowed in SUID/SGID programs"));				      \
Packit 6c4009
									      \
Packit 6c4009
	__newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str),  \
Packit 6c4009
						   __dst_cnt));		      \
Packit 6c4009
									      \
Packit 6c4009
	__result = _dl_dst_substitute (l, __str, __newp);		      \
Packit 6c4009
									      \
Packit 6c4009
	if (*__result == '\0')						      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* The replacement for the DST is not known.  We can't	      \
Packit 6c4009
	       processed.  */						      \
Packit 6c4009
	    if (fatal)							      \
Packit 6c4009
	      _dl_signal_error (0, __str, NULL, N_("\
Packit 6c4009
empty dynamic string token substitution"));				      \
Packit 6c4009
	    else							      \
Packit 6c4009
	      {								      \
Packit 6c4009
		/* This is for DT_AUXILIARY.  */			      \
Packit 6c4009
		if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))   \
Packit 6c4009
		  _dl_debug_printf (N_("\
Packit 6c4009
cannot load auxiliary `%s' because of empty dynamic string token "	      \
Packit 6c4009
					    "substitution\n"), __str);	      \
Packit 6c4009
		continue;						      \
Packit 6c4009
	      }								      \
Packit 6c4009
	  }								      \
Packit 6c4009
      }									      \
Packit 6c4009
									      \
Packit 6c4009
    __result; })
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
preload (struct list *known, unsigned int *nlist, struct link_map *map)
Packit 6c4009
{
Packit 6c4009
  known[*nlist].done = 0;
Packit 6c4009
  known[*nlist].map = map;
Packit 6c4009
  known[*nlist].next = &known[*nlist + 1];
Packit 6c4009
Packit 6c4009
  ++*nlist;
Packit 6c4009
  /* We use `l_reserved' as a mark bit to detect objects we have
Packit 6c4009
     already put in the search list and avoid adding duplicate
Packit 6c4009
     elements later in the list.  */
Packit 6c4009
  map->l_reserved = 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_dl_map_object_deps (struct link_map *map,
Packit 6c4009
		     struct link_map **preloads, unsigned int npreloads,
Packit 6c4009
		     int trace_mode, int open_mode)
Packit 6c4009
{
Packit 6c4009
  struct list *known = __alloca (sizeof *known * (1 + npreloads + 1));
Packit 6c4009
  struct list *runp, *tail;
Packit 6c4009
  unsigned int nlist, i;
Packit 6c4009
  /* Object name.  */
Packit 6c4009
  const char *name;
Packit 6c4009
  int errno_saved;
Packit 6c4009
  int errno_reason;
Packit 6c4009
  struct dl_exception exception;
Packit 6c4009
Packit 6c4009
  /* No loaded object so far.  */
Packit 6c4009
  nlist = 0;
Packit 6c4009
Packit 6c4009
  /* First load MAP itself.  */
Packit 6c4009
  preload (known, &nlist, map);
Packit 6c4009
Packit 6c4009
  /* Add the preloaded items after MAP but before any of its dependencies.  */
Packit 6c4009
  for (i = 0; i < npreloads; ++i)
Packit 6c4009
    preload (known, &nlist, preloads[i]);
Packit 6c4009
Packit 6c4009
  /* Terminate the lists.  */
Packit 6c4009
  known[nlist - 1].next = NULL;
Packit 6c4009
Packit 6c4009
  /* Pointer to last unique object.  */
Packit 6c4009
  tail = &known[nlist - 1];
Packit 6c4009
Packit 6c4009
  struct scratch_buffer needed_space;
Packit 6c4009
  scratch_buffer_init (&needed_space);
Packit 6c4009
Packit 6c4009
  /* Process each element of the search list, loading each of its
Packit 6c4009
     auxiliary objects and immediate dependencies.  Auxiliary objects
Packit 6c4009
     will be added in the list before the object itself and
Packit 6c4009
     dependencies will be appended to the list as we step through it.
Packit 6c4009
     This produces a flat, ordered list that represents a
Packit 6c4009
     breadth-first search of the dependency tree.
Packit 6c4009
Packit 6c4009
     The whole process is complicated by the fact that we better
Packit 6c4009
     should use alloca for the temporary list elements.  But using
Packit 6c4009
     alloca means we cannot use recursive function calls.  */
Packit 6c4009
  errno_saved = errno;
Packit 6c4009
  errno_reason = 0;
Packit 6c4009
  errno = 0;
Packit 6c4009
  name = NULL;
Packit 6c4009
  for (runp = known; runp; )
Packit 6c4009
    {
Packit 6c4009
      struct link_map *l = runp->map;
Packit 6c4009
      struct link_map **needed = NULL;
Packit 6c4009
      unsigned int nneeded = 0;
Packit 6c4009
Packit 6c4009
      /* Unless otherwise stated, this object is handled.  */
Packit 6c4009
      runp->done = 1;
Packit 6c4009
Packit 6c4009
      /* Allocate a temporary record to contain the references to the
Packit 6c4009
	 dependencies of this object.  */
Packit 6c4009
      if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
Packit 6c4009
	  && l != map && l->l_ldnum > 0)
Packit 6c4009
	{
Packit 6c4009
	  /* l->l_ldnum includes space for the terminating NULL.  */
Packit 6c4009
	  if (!scratch_buffer_set_array_size
Packit 6c4009
	      (&needed_space, l->l_ldnum, sizeof (struct link_map *)))
Packit 6c4009
	    _dl_signal_error (ENOMEM, map->l_name, NULL,
Packit 6c4009
			      N_("cannot allocate dependency buffer"));
Packit 6c4009
	  needed = needed_space.data;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
Packit 6c4009
	{
Packit 6c4009
	  const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
Packit 6c4009
	  struct openaux_args args;
Packit 6c4009
	  struct list *orig;
Packit 6c4009
	  const ElfW(Dyn) *d;
Packit 6c4009
Packit 6c4009
	  args.strtab = strtab;
Packit 6c4009
	  args.map = l;
Packit 6c4009
	  args.trace_mode = trace_mode;
Packit 6c4009
	  args.open_mode = open_mode;
Packit 6c4009
	  orig = runp;
Packit 6c4009
Packit 6c4009
	  for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
Packit 6c4009
	    if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
Packit 6c4009
	      {
Packit 6c4009
		/* Map in the needed object.  */
Packit 6c4009
		struct link_map *dep;
Packit 6c4009
Packit 6c4009
		/* Recognize DSTs.  */
Packit 6c4009
		name = expand_dst (l, strtab + d->d_un.d_val, 0);
Packit 6c4009
		/* Store the tag in the argument structure.  */
Packit 6c4009
		args.name = name;
Packit 6c4009
Packit 6c4009
		int err = _dl_catch_exception (&exception, openaux, &args);
Packit 6c4009
		if (__glibc_unlikely (exception.errstring != NULL))
Packit 6c4009
		  {
Packit 6c4009
		    if (err)
Packit 6c4009
		      errno_reason = err;
Packit 6c4009
		    else
Packit 6c4009
		      errno_reason = -1;
Packit 6c4009
		    goto out;
Packit 6c4009
		  }
Packit 6c4009
		else
Packit 6c4009
		  dep = args.aux;
Packit 6c4009
Packit 6c4009
		if (! dep->l_reserved)
Packit 6c4009
		  {
Packit 6c4009
		    /* Allocate new entry.  */
Packit 6c4009
		    struct list *newp;
Packit 6c4009
Packit 6c4009
		    newp = alloca (sizeof (struct list));
Packit 6c4009
Packit 6c4009
		    /* Append DEP to the list.  */
Packit 6c4009
		    newp->map = dep;
Packit 6c4009
		    newp->done = 0;
Packit 6c4009
		    newp->next = NULL;
Packit 6c4009
		    tail->next = newp;
Packit 6c4009
		    tail = newp;
Packit 6c4009
		    ++nlist;
Packit 6c4009
		    /* Set the mark bit that says it's already in the list.  */
Packit 6c4009
		    dep->l_reserved = 1;
Packit 6c4009
		  }
Packit 6c4009
Packit 6c4009
		/* Remember this dependency.  */
Packit 6c4009
		if (needed != NULL)
Packit 6c4009
		  needed[nneeded++] = dep;
Packit 6c4009
	      }
Packit 6c4009
	    else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
Packit 6c4009
	      {
Packit 6c4009
		struct list *newp;
Packit 6c4009
Packit 6c4009
		/* Recognize DSTs.  */
Packit 6c4009
		name = expand_dst (l, strtab + d->d_un.d_val,
Packit 6c4009
				   d->d_tag == DT_AUXILIARY);
Packit 6c4009
		/* Store the tag in the argument structure.  */
Packit 6c4009
		args.name = name;
Packit 6c4009
Packit 6c4009
		/* Say that we are about to load an auxiliary library.  */
Packit 6c4009
		if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
Packit 6c4009
				      0))
Packit 6c4009
		  _dl_debug_printf ("load auxiliary object=%s"
Packit 6c4009
				    " requested by file=%s\n",
Packit 6c4009
				    name,
Packit 6c4009
				    DSO_FILENAME (l->l_name));
Packit 6c4009
Packit 6c4009
		/* We must be prepared that the addressed shared
Packit 6c4009
		   object is not available.  For filter objects the dependency
Packit 6c4009
		   must be available.  */
Packit 6c4009
		int err = _dl_catch_exception (&exception, openaux, &args);
Packit 6c4009
		if (__glibc_unlikely (exception.errstring != NULL))
Packit 6c4009
		  {
Packit 6c4009
		    if (d->d_tag == DT_AUXILIARY)
Packit 6c4009
		      {
Packit 6c4009
			/* We are not interested in the error message.  */
Packit 6c4009
			_dl_exception_free (&exception);
Packit 6c4009
			/* Simply ignore this error and continue the work.  */
Packit 6c4009
			continue;
Packit 6c4009
		      }
Packit 6c4009
		    else
Packit 6c4009
		      {
Packit 6c4009
			if (err)
Packit 6c4009
			  errno_reason = err;
Packit 6c4009
			else
Packit 6c4009
			  errno_reason = -1;
Packit 6c4009
			goto out;
Packit 6c4009
		      }
Packit 6c4009
		  }
Packit 6c4009
Packit 6c4009
		/* The auxiliary object is actually available.
Packit 6c4009
		   Incorporate the map in all the lists.  */
Packit 6c4009
Packit 6c4009
		/* Allocate new entry.  This always has to be done.  */
Packit 6c4009
		newp = alloca (sizeof (struct list));
Packit 6c4009
Packit 6c4009
		/* We want to insert the new map before the current one,
Packit 6c4009
		   but we have no back links.  So we copy the contents of
Packit 6c4009
		   the current entry over.  Note that ORIG and NEWP now
Packit 6c4009
		   have switched their meanings.  */
Packit 6c4009
		memcpy (newp, orig, sizeof (*newp));
Packit 6c4009
Packit 6c4009
		/* Initialize new entry.  */
Packit 6c4009
		orig->done = 0;
Packit 6c4009
		orig->map = args.aux;
Packit 6c4009
Packit 6c4009
		/* Remember this dependency.  */
Packit 6c4009
		if (needed != NULL)
Packit 6c4009
		  needed[nneeded++] = args.aux;
Packit 6c4009
Packit 6c4009
		/* We must handle two situations here: the map is new,
Packit 6c4009
		   so we must add it in all three lists.  If the map
Packit 6c4009
		   is already known, we have two further possibilities:
Packit 6c4009
		   - if the object is before the current map in the
Packit 6c4009
		   search list, we do nothing.  It is already found
Packit 6c4009
		   early
Packit 6c4009
		   - if the object is after the current one, we must
Packit 6c4009
		   move it just before the current map to make sure
Packit 6c4009
		   the symbols are found early enough
Packit 6c4009
		*/
Packit 6c4009
		if (args.aux->l_reserved)
Packit 6c4009
		  {
Packit 6c4009
		    /* The object is already somewhere in the list.
Packit 6c4009
		       Locate it first.  */
Packit 6c4009
		    struct list *late;
Packit 6c4009
Packit 6c4009
		    /* This object is already in the search list we
Packit 6c4009
		       are building.  Don't add a duplicate pointer.
Packit 6c4009
		       Just added by _dl_map_object.  */
Packit 6c4009
		    for (late = newp; late->next != NULL; late = late->next)
Packit 6c4009
		      if (late->next->map == args.aux)
Packit 6c4009
			break;
Packit 6c4009
Packit 6c4009
		    if (late->next != NULL)
Packit 6c4009
		      {
Packit 6c4009
			/* The object is somewhere behind the current
Packit 6c4009
			   position in the search path.  We have to
Packit 6c4009
			   move it to this earlier position.  */
Packit 6c4009
			orig->next = newp;
Packit 6c4009
Packit 6c4009
			/* Now remove the later entry from the list
Packit 6c4009
			   and adjust the tail pointer.  */
Packit 6c4009
			if (tail == late->next)
Packit 6c4009
			  tail = late;
Packit 6c4009
			late->next = late->next->next;
Packit 6c4009
Packit 6c4009
			/* We must move the object earlier in the chain.  */
Packit 6c4009
			if (args.aux->l_prev != NULL)
Packit 6c4009
			  args.aux->l_prev->l_next = args.aux->l_next;
Packit 6c4009
			if (args.aux->l_next != NULL)
Packit 6c4009
			  args.aux->l_next->l_prev = args.aux->l_prev;
Packit 6c4009
Packit 6c4009
			args.aux->l_prev = newp->map->l_prev;
Packit 6c4009
			newp->map->l_prev = args.aux;
Packit 6c4009
			if (args.aux->l_prev != NULL)
Packit 6c4009
			  args.aux->l_prev->l_next = args.aux;
Packit 6c4009
			args.aux->l_next = newp->map;
Packit 6c4009
		      }
Packit 6c4009
		    else
Packit 6c4009
		      {
Packit 6c4009
			/* The object must be somewhere earlier in the
Packit 6c4009
			   list.  Undo to the current list element what
Packit 6c4009
			   we did above.  */
Packit 6c4009
			memcpy (orig, newp, sizeof (*newp));
Packit 6c4009
			continue;
Packit 6c4009
		      }
Packit 6c4009
		  }
Packit 6c4009
		else
Packit 6c4009
		  {
Packit 6c4009
		    /* This is easy.  We just add the symbol right here.  */
Packit 6c4009
		    orig->next = newp;
Packit 6c4009
		    ++nlist;
Packit 6c4009
		    /* Set the mark bit that says it's already in the list.  */
Packit 6c4009
		    args.aux->l_reserved = 1;
Packit 6c4009
Packit 6c4009
		    /* The only problem is that in the double linked
Packit 6c4009
		       list of all objects we don't have this new
Packit 6c4009
		       object at the correct place.  Correct this here.  */
Packit 6c4009
		    if (args.aux->l_prev)
Packit 6c4009
		      args.aux->l_prev->l_next = args.aux->l_next;
Packit 6c4009
		    if (args.aux->l_next)
Packit 6c4009
		      args.aux->l_next->l_prev = args.aux->l_prev;
Packit 6c4009
Packit 6c4009
		    args.aux->l_prev = newp->map->l_prev;
Packit 6c4009
		    newp->map->l_prev = args.aux;
Packit 6c4009
		    if (args.aux->l_prev != NULL)
Packit 6c4009
		      args.aux->l_prev->l_next = args.aux;
Packit 6c4009
		    args.aux->l_next = newp->map;
Packit 6c4009
		  }
Packit 6c4009
Packit 6c4009
		/* Move the tail pointer if necessary.  */
Packit 6c4009
		if (orig == tail)
Packit 6c4009
		  tail = newp;
Packit 6c4009
Packit 6c4009
		/* Move on the insert point.  */
Packit 6c4009
		orig = newp;
Packit 6c4009
	      }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Terminate the list of dependencies and store the array address.  */
Packit 6c4009
      if (needed != NULL)
Packit 6c4009
	{
Packit 6c4009
	  needed[nneeded++] = NULL;
Packit 6c4009
Packit 6c4009
	  struct link_map **l_initfini = (struct link_map **)
Packit 6c4009
	    malloc ((2 * nneeded + 1) * sizeof needed[0]);
Packit 6c4009
	  if (l_initfini == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      scratch_buffer_free (&needed_space);
Packit 6c4009
	      _dl_signal_error (ENOMEM, map->l_name, NULL,
Packit 6c4009
				N_("cannot allocate dependency list"));
Packit 6c4009
	    }
Packit 6c4009
	  l_initfini[0] = l;
Packit 6c4009
	  memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
Packit 6c4009
	  memcpy (&l_initfini[nneeded + 1], l_initfini,
Packit 6c4009
		  nneeded * sizeof needed[0]);
Packit 6c4009
	  atomic_write_barrier ();
Packit 6c4009
	  l->l_initfini = l_initfini;
Packit 6c4009
	  l->l_free_initfini = 1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* If we have no auxiliary objects just go on to the next map.  */
Packit 6c4009
      if (runp->done)
Packit 6c4009
	do
Packit 6c4009
	  runp = runp->next;
Packit 6c4009
	while (runp != NULL && runp->done);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
 out:
Packit 6c4009
  scratch_buffer_free (&needed_space);
Packit 6c4009
Packit 6c4009
  if (errno == 0 && errno_saved != 0)
Packit 6c4009
    __set_errno (errno_saved);
Packit 6c4009
Packit 6c4009
  struct link_map **old_l_initfini = NULL;
Packit 6c4009
  if (map->l_initfini != NULL && map->l_type == lt_loaded)
Packit 6c4009
    {
Packit 6c4009
      /* This object was previously loaded as a dependency and we have
Packit 6c4009
	 a separate l_initfini list.  We don't need it anymore.  */
Packit 6c4009
      assert (map->l_searchlist.r_list == NULL);
Packit 6c4009
      old_l_initfini = map->l_initfini;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Store the search list we built in the object.  It will be used for
Packit 6c4009
     searches in the scope of this object.  */
Packit 6c4009
  struct link_map **l_initfini =
Packit 6c4009
    (struct link_map **) malloc ((2 * nlist + 1)
Packit 6c4009
				 * sizeof (struct link_map *));
Packit 6c4009
  if (l_initfini == NULL)
Packit 6c4009
    _dl_signal_error (ENOMEM, map->l_name, NULL,
Packit 6c4009
		      N_("cannot allocate symbol search list"));
Packit 6c4009
Packit 6c4009
Packit 6c4009
  map->l_searchlist.r_list = &l_initfini[nlist + 1];
Packit 6c4009
  map->l_searchlist.r_nlist = nlist;
Packit 6c4009
Packit 6c4009
  for (nlist = 0, runp = known; runp; runp = runp->next)
Packit 6c4009
    {
Packit 6c4009
      if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
Packit 6c4009
	/* This can happen when we trace the loading.  */
Packit 6c4009
	--map->l_searchlist.r_nlist;
Packit Service 562438
      else
Packit 6c4009
	map->l_searchlist.r_list[nlist++] = runp->map;
Packit 6c4009
Packit 6c4009
      /* Now clear all the mark bits we set in the objects on the search list
Packit 6c4009
	 to avoid duplicates, so the next call starts fresh.  */
Packit 6c4009
      runp->map->l_reserved = 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
Packit 6c4009
      && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
Packit 6c4009
    {
Packit 6c4009
      /* If we are to compute conflicts, we have to build local scope
Packit 6c4009
	 for each library, not just the ultimate loader.  */
Packit 6c4009
      for (i = 0; i < nlist; ++i)
Packit 6c4009
	{
Packit 6c4009
	  struct link_map *l = map->l_searchlist.r_list[i];
Packit 6c4009
	  unsigned int j, cnt;
Packit 6c4009
Packit 6c4009
	  /* The local scope has been already computed.  */
Packit 6c4009
	  if (l == map
Packit 6c4009
	      || (l->l_local_scope[0]
Packit 6c4009
		  && l->l_local_scope[0]->r_nlist) != 0)
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  if (l->l_info[AUXTAG] || l->l_info[FILTERTAG])
Packit 6c4009
	    {
Packit 6c4009
	      /* As current DT_AUXILIARY/DT_FILTER implementation needs to be
Packit 6c4009
		 rewritten, no need to bother with prelinking the old
Packit 6c4009
		 implementation.  */
Packit 6c4009
	      _dl_signal_error (EINVAL, l->l_name, NULL, N_("\
Packit 6c4009
Filters not supported with LD_TRACE_PRELINKING"));
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  cnt = _dl_build_local_scope (l_initfini, l);
Packit 6c4009
	  assert (cnt <= nlist);
Packit 6c4009
	  for (j = 0; j < cnt; j++)
Packit 6c4009
	    {
Packit 6c4009
	      l_initfini[j]->l_reserved = 0;
Packit 6c4009
	      if (j && __builtin_expect (l_initfini[j]->l_info[DT_SYMBOLIC]
Packit 6c4009
					 != NULL, 0))
Packit 6c4009
		l->l_symbolic_in_local_scope = true;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  l->l_local_scope[0] =
Packit 6c4009
	    (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
Packit 6c4009
					    + (cnt
Packit 6c4009
					       * sizeof (struct link_map *)));
Packit 6c4009
	  if (l->l_local_scope[0] == NULL)
Packit 6c4009
	    _dl_signal_error (ENOMEM, map->l_name, NULL,
Packit 6c4009
			      N_("cannot allocate symbol search list"));
Packit 6c4009
	  l->l_local_scope[0]->r_nlist = cnt;
Packit 6c4009
	  l->l_local_scope[0]->r_list =
Packit 6c4009
	    (struct link_map **) (l->l_local_scope[0] + 1);
Packit 6c4009
	  memcpy (l->l_local_scope[0]->r_list, l_initfini,
Packit 6c4009
		  cnt * sizeof (struct link_map *));
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Maybe we can remove some relocation dependencies now.  */
Packit Service 562438
  assert (map->l_searchlist.r_list[0] == map);
Packit 6c4009
  struct link_map_reldeps *l_reldeps = NULL;
Packit 6c4009
  if (map->l_reldeps != NULL)
Packit 6c4009
    {
Packit Service 562438
      for (i = 1; i < nlist; ++i)
Packit 6c4009
	map->l_searchlist.r_list[i]->l_reserved = 1;
Packit 6c4009
Packit 6c4009
      struct link_map **list = &map->l_reldeps->list[0];
Packit 6c4009
      for (i = 0; i < map->l_reldeps->act; ++i)
Packit 6c4009
	if (list[i]->l_reserved)
Packit 6c4009
	  {
Packit 6c4009
	    /* Need to allocate new array of relocation dependencies.  */
Packit 6c4009
	    l_reldeps = malloc (sizeof (*l_reldeps)
Packit 6c4009
				+ map->l_reldepsmax
Packit 6c4009
				  * sizeof (struct link_map *));
Packit 6c4009
	    if (l_reldeps == NULL)
Packit 6c4009
	      /* Bad luck, keep the reldeps duplicated between
Packit 6c4009
		 map->l_reldeps->list and map->l_initfini lists.  */
Packit 6c4009
	      ;
Packit 6c4009
	    else
Packit 6c4009
	      {
Packit 6c4009
		unsigned int j = i;
Packit 6c4009
		memcpy (&l_reldeps->list[0], &list[0],
Packit 6c4009
			i * sizeof (struct link_map *));
Packit 6c4009
		for (i = i + 1; i < map->l_reldeps->act; ++i)
Packit 6c4009
		  if (!list[i]->l_reserved)
Packit 6c4009
		    l_reldeps->list[j++] = list[i];
Packit 6c4009
		l_reldeps->act = j;
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
Packit Service 562438
      for (i = 1; i < nlist; ++i)
Packit 6c4009
	map->l_searchlist.r_list[i]->l_reserved = 0;
Packit 6c4009
    }
Packit 6c4009
Packit Service 562438
  /* Sort the initializer list to take dependencies into account.  The binary
Packit Service 562438
     itself will always be initialize last.  */
Packit Service 562438
  memcpy (l_initfini, map->l_searchlist.r_list,
Packit Service 562438
	  nlist * sizeof (struct link_map *));
Packit Service 562438
  /* We can skip looking for the binary itself which is at the front of
Packit Service 562438
     the search list.  */
Packit Service 562438
  _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false);
Packit 6c4009
Packit 6c4009
  /* Terminate the list of dependencies.  */
Packit 6c4009
  l_initfini[nlist] = NULL;
Packit 6c4009
  atomic_write_barrier ();
Packit 6c4009
  map->l_initfini = l_initfini;
Packit 6c4009
  map->l_free_initfini = 1;
Packit 6c4009
  if (l_reldeps != NULL)
Packit 6c4009
    {
Packit 6c4009
      atomic_write_barrier ();
Packit 6c4009
      void *old_l_reldeps = map->l_reldeps;
Packit 6c4009
      map->l_reldeps = l_reldeps;
Packit 6c4009
      _dl_scope_free (old_l_reldeps);
Packit 6c4009
    }
Packit 6c4009
  if (old_l_initfini != NULL)
Packit 6c4009
    _dl_scope_free (old_l_initfini);
Packit 6c4009
Packit 6c4009
  if (errno_reason)
Packit 6c4009
    _dl_signal_exception (errno_reason == -1 ? 0 : errno_reason,
Packit 6c4009
			  &exception, NULL);
Packit 6c4009
}