Tue Jun 4 18:57:57 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / elf / dl-deps.c
1 /* Load the dependencies of a mapped object.
2 Copyright (C) 1996 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
20 #include <link.h>
21 #include <errno.h>
22 #include <dlfcn.h>
23 #include <stdlib.h>
24
25 void
26 _dl_map_object_deps (struct link_map *map)
27 {
28   struct list
29     {
30       struct link_map *map;
31       struct list *next;
32     };
33   struct list head, *tailp, *scanp;
34   unsigned int nlist;
35
36   /* Start the search list with one element: MAP itself.  */
37   head.map = map;
38   head.next = NULL;
39   nlist = 1;
40
41
42   /* Process each element of the search list, loading each of its immediate
43      dependencies and appending them to the list as we step through it.
44      This produces a flat, ordered list that represents a breadth-first
45      search of the dependency tree.  */
46   for (scanp = tailp = &head; scanp; scanp = scanp->next)
47     {
48       struct link_map *l = scanp->map;
49
50       /* We use `l_reserved' as a mark bit to detect objects we have
51          already put in the search list and avoid adding duplicate elements
52          later in the list.  */
53       l->l_reserved = 1;
54
55       if (l->l_info[DT_NEEDED])
56         {
57           const char *strtab
58             = ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
59           const Elf32_Dyn *d;
60           for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
61             if (d->d_tag == DT_NEEDED)
62               {
63                 /* Map in the needed object.  */
64                 struct link_map *dep
65                   = _dl_map_object (l, strtab + d->d_un.d_val);
66
67                 if (dep->l_reserved)
68                   /* This object is already in the search list we are
69                      building.  Don't add a duplicate pointer.  Release the
70                      reference just added by _dl_map_object.  */
71                   --dep->l_opencount;
72                 else
73                   {
74                     /* Append DEP to the search list.  */
75                     tailp->next = alloca (sizeof *tailp);
76                     tailp = tailp->next;
77                     tailp->map = dep;
78                     tailp->next = NULL;
79                     ++nlist;
80                   }
81               }
82         }
83     }
84
85   /* Store the search list we built in the object.  It will be used for
86      searches in the scope of this object.  */
87   map->l_searchlist = malloc (nlist * sizeof (struct link_map *));
88   map->l_nsearchlist = nlist;
89
90   nlist = 0;
91   for (scanp = &head; scanp; scanp = scanp->next)
92     {
93       map->l_searchlist[nlist++] = scanp->map;
94
95       /* Now clear all the mark bits we set in the objects on the search list
96          to avoid duplicates, so the next call starts fresh.  */
97       scanp->map->l_reserved = 0;
98     }
99 }
100
101
102 struct link_map *
103 _dl_open (struct link_map *parent, const char *file, int mode)
104 {
105   struct link_map *new, *l;
106   Elf32_Addr init;
107
108   /* Load the named object.  */
109   new = _dl_map_object (parent, file);
110
111   /* Load that object's dependencies.  */
112   _dl_map_object_deps (new);
113
114   /* Relocate the objects loaded.  */
115   for (l = new; l; l = l->l_next)
116     if (! l->l_relocated)
117       _dl_relocate_object (l, (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
118
119   /* Run the initializer functions of new objects.  */
120   while (init = _dl_init_next (new))
121     (*(void (*) (void)) init) ();
122
123   return new;
124 }