summary refs log tree commit diff
path: root/elf/dl-deps.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-deps.c')
-rw-r--r--elf/dl-deps.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index ec61326614..af39de1023 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -21,6 +21,7 @@
 #include <dlfcn.h>
 #include <errno.h>
 #include <libintl.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -70,6 +71,21 @@ openaux (void *a)
 			      args->trace_mode, 0);
 }
 
+static ptrdiff_t
+internal_function
+_dl_build_local_scope (struct link_map **list, struct link_map *map)
+{
+  struct link_map **p = list;
+  struct link_map **q;
+
+  *p++ = map;
+  map->l_reserved = 1;
+  if (map->l_initfini)
+    for (q = map->l_initfini + 1; *q; ++q)
+      if (! (*q)->l_reserved)
+	p += _dl_build_local_scope (p, *q);
+  return p - list;
+}
 
 
 /* We use a very special kind of list to track the path
@@ -491,6 +507,51 @@ _dl_map_object_deps (struct link_map *map,
       runp->map->l_reserved = 0;
     }
 
+  if (__builtin_expect(_dl_debug_mask & DL_DEBUG_PRELINK, 0) != 0
+      && map == _dl_loaded)
+    {
+      /* If we are to compute conflicts, we have to build local scope
+	 for each library, not just the ultimate loader.  */
+      for (i = 0; i < nlist; ++i)
+	{
+	  struct link_map *l = map->l_searchlist.r_list[i];
+	  unsigned int j, cnt;
+
+	  /* The local scope has been already computed.  */
+	  if (l == map
+	      || (l->l_local_scope[0]
+		  && l->l_local_scope[0]->r_nlist) != 0)
+	    continue;
+
+	  if (l->l_info[AUXTAG] || l->l_info[FILTERTAG])
+	    {
+	      /* As current DT_AUXILIARY/DT_FILTER implementation needs to be
+		 rewritten, no need to bother with prelinking the old
+		 implementation.  */
+	      _dl_signal_error (EINVAL, l->l_name, NULL, N_("\
+Filters not supported with LD_TRACE_PRELINKING"));
+	    }
+
+	  cnt = _dl_build_local_scope (map->l_initfini, l);
+	  assert (cnt <= nlist);
+	  for (j = 0; j < cnt; j++)
+	    map->l_initfini[j]->l_reserved = 0;
+
+	  l->l_local_scope[0] =
+	    (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
+					    + (cnt
+					       * sizeof (struct link_map *)));
+	  if (l->l_local_scope[0] == NULL)
+	    _dl_signal_error (ENOMEM, map->l_name, NULL,
+			      N_("cannot allocate symbol search list"));
+	  l->l_local_scope[0]->r_nlist = cnt;
+	  l->l_local_scope[0]->r_list =
+	    (struct link_map **) (l->l_local_scope[0] + 1);
+	  memcpy (l->l_local_scope[0]->r_list, map->l_initfini,
+		  cnt * sizeof (struct link_map *));
+	}
+    }
+
   /* Maybe we can remove some relocation dependencies now.  */
   assert (map->l_searchlist.r_list[0] == map);
   for (i = 0; i < map->l_reldepsact; ++i)