]>
Commit | Line | Data |
---|---|---|
efec1d0c | 1 | /* Load the dependencies of a mapped object. |
df4ef2ab | 2 | Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
afd4eb37 UD |
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 not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
efec1d0c RM |
19 | |
20 | #include <link.h> | |
21 | #include <errno.h> | |
22 | #include <dlfcn.h> | |
23 | #include <stdlib.h> | |
24 | ||
25 | void | |
2064087b | 26 | _dl_map_object_deps (struct link_map *map, |
46ec036d UD |
27 | struct link_map **preloads, unsigned int npreloads, |
28 | int trace_mode) | |
efec1d0c | 29 | { |
f68b86cc RM |
30 | struct list |
31 | { | |
32 | struct link_map *map; | |
33 | struct list *next; | |
34 | }; | |
1228ed5c | 35 | struct list *head, *tailp, *scanp; |
84384f5b | 36 | struct list duphead, *duptailp; |
84384f5b | 37 | unsigned int nduplist; |
df4ef2ab UD |
38 | unsigned int nlist, naux, i; |
39 | inline void preload (struct link_map *map) | |
40 | { | |
41 | head[nlist].next = &head[nlist + 1]; | |
42 | head[nlist++].map = map; | |
efec1d0c | 43 | |
df4ef2ab UD |
44 | /* We use `l_reserved' as a mark bit to detect objects we have |
45 | already put in the search list and avoid adding duplicate | |
46 | elements later in the list. */ | |
47 | map->l_reserved = 1; | |
48 | } | |
2064087b | 49 | |
df4ef2ab | 50 | naux = nlist = 0; |
84384f5b | 51 | |
1228ed5c UD |
52 | /* XXX The AUXILIARY implementation isn't correct in the moment. XXX |
53 | XXX The problem is that we currently do not handle auxiliary XXX | |
54 | XXX entries in the loaded objects. XXX */ | |
df4ef2ab | 55 | |
1228ed5c UD |
56 | #define AUXTAG (DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM \ |
57 | + DT_EXTRATAGIDX (DT_AUXILIARY)) | |
58 | ||
59 | /* First determine the number of auxiliary objects we have to load. */ | |
df4ef2ab | 60 | if (map->l_info[AUXTAG]) |
2064087b | 61 | { |
1228ed5c UD |
62 | ElfW(Dyn) *d; |
63 | for (d = map->l_ld; d->d_tag != DT_NULL; ++d) | |
64 | if (d->d_tag == DT_AUXILIARY) | |
65 | ++naux; | |
66 | } | |
67 | ||
68 | /* Now we can allocate the array for the linker maps. */ | |
69 | head = (struct list *) alloca (sizeof (struct list) | |
70 | * (naux + npreloads + 2)); | |
71 | ||
72 | /* Load the auxiliary objects, even before the object itself. */ | |
73 | if (map->l_info[AUXTAG]) | |
74 | { | |
75 | /* There is at least one auxiliary library specified. We try to | |
76 | load it, and if we can, use its symbols in preference to our | |
77 | own. But if we can't load it, we just silently ignore it. */ | |
78 | const char *strtab | |
79 | = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr); | |
80 | ElfW(Dyn) *d; | |
81 | ||
82 | for (d = map->l_ld; d->d_tag != DT_NULL; ++d) | |
83 | if (d->d_tag == DT_AUXILIARY) | |
84 | { | |
85 | struct link_map *aux; | |
86 | void openaux (void) | |
87 | { | |
88 | aux = _dl_map_object (map, strtab + d->d_un.d_val, | |
89 | (map->l_type == lt_executable | |
90 | ? lt_library : map->l_type), | |
91 | trace_mode); | |
92 | } | |
93 | char *errstring; | |
94 | const char *objname; | |
95 | if (! _dl_catch_error (&errstring, &objname, openaux)) | |
96 | /* The auxiliary object is actually there. Use it as | |
97 | the first search element, even before MAP itself. */ | |
98 | preload (aux); | |
99 | } | |
2064087b RM |
100 | } |
101 | ||
1228ed5c | 102 | /* Next load MAP itself. */ |
df4ef2ab UD |
103 | preload (map); |
104 | ||
105 | /* Add the preloaded items after MAP but before any of its dependencies. */ | |
106 | for (i = 0; i < npreloads; ++i) | |
107 | preload (preloads[i]); | |
108 | ||
8a523922 | 109 | /* Terminate the lists. */ |
df4ef2ab | 110 | head[nlist - 1].next = NULL; |
8a523922 | 111 | duphead.next = NULL; |
c928de79 RM |
112 | |
113 | /* Start here for adding dependencies to the list. */ | |
df4ef2ab | 114 | tailp = &head[nlist - 1]; |
f68b86cc | 115 | |
84384f5b UD |
116 | /* Until now we have the same number of libraries in the normal and |
117 | the list with duplicates. */ | |
118 | nduplist = nlist; | |
119 | duptailp = &duphead; | |
efec1d0c RM |
120 | |
121 | /* Process each element of the search list, loading each of its immediate | |
122 | dependencies and appending them to the list as we step through it. | |
123 | This produces a flat, ordered list that represents a breadth-first | |
124 | search of the dependency tree. */ | |
c928de79 | 125 | for (scanp = head; scanp; scanp = scanp->next) |
efec1d0c | 126 | { |
f68b86cc RM |
127 | struct link_map *l = scanp->map; |
128 | ||
efec1d0c RM |
129 | if (l->l_info[DT_NEEDED]) |
130 | { | |
131 | const char *strtab | |
132 | = ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr); | |
266180eb | 133 | const ElfW(Dyn) *d; |
efec1d0c RM |
134 | for (d = l->l_ld; d->d_tag != DT_NULL; ++d) |
135 | if (d->d_tag == DT_NEEDED) | |
136 | { | |
f68b86cc RM |
137 | /* Map in the needed object. */ |
138 | struct link_map *dep | |
ba79d61b RM |
139 | = _dl_map_object (l, strtab + d->d_un.d_val, |
140 | l->l_type == lt_executable ? lt_library : | |
46ec036d | 141 | l->l_type, trace_mode); |
f68b86cc RM |
142 | |
143 | if (dep->l_reserved) | |
144 | /* This object is already in the search list we are | |
145 | building. Don't add a duplicate pointer. Release the | |
146 | reference just added by _dl_map_object. */ | |
147 | --dep->l_opencount; | |
efec1d0c RM |
148 | else |
149 | { | |
f68b86cc RM |
150 | /* Append DEP to the search list. */ |
151 | tailp->next = alloca (sizeof *tailp); | |
152 | tailp = tailp->next; | |
153 | tailp->map = dep; | |
154 | tailp->next = NULL; | |
155 | ++nlist; | |
f9496a7b RM |
156 | /* Set the mark bit that says it's already in the list. */ |
157 | dep->l_reserved = 1; | |
efec1d0c | 158 | } |
84384f5b | 159 | |
df4ef2ab | 160 | /* In any case append DEP to the duplicates search list. */ |
84384f5b UD |
161 | duptailp->next = alloca (sizeof *duptailp); |
162 | duptailp = duptailp->next; | |
163 | duptailp->map = dep; | |
164 | duptailp->next = NULL; | |
165 | ++nduplist; | |
efec1d0c RM |
166 | } |
167 | } | |
168 | } | |
169 | ||
f68b86cc RM |
170 | /* Store the search list we built in the object. It will be used for |
171 | searches in the scope of this object. */ | |
172 | map->l_searchlist = malloc (nlist * sizeof (struct link_map *)); | |
df4ef2ab UD |
173 | if (map->l_searchlist == NULL) |
174 | _dl_signal_error (ENOMEM, map->l_name, | |
175 | "cannot allocate symbol search list"); | |
efec1d0c | 176 | map->l_nsearchlist = nlist; |
f68b86cc RM |
177 | |
178 | nlist = 0; | |
2064087b | 179 | for (scanp = head; scanp; scanp = scanp->next) |
f68b86cc RM |
180 | { |
181 | map->l_searchlist[nlist++] = scanp->map; | |
182 | ||
183 | /* Now clear all the mark bits we set in the objects on the search list | |
184 | to avoid duplicates, so the next call starts fresh. */ | |
185 | scanp->map->l_reserved = 0; | |
186 | } | |
84384f5b UD |
187 | |
188 | map->l_dupsearchlist = malloc (nduplist * sizeof (struct link_map *)); | |
df4ef2ab UD |
189 | if (map->l_dupsearchlist == NULL) |
190 | _dl_signal_error (ENOMEM, map->l_name, | |
191 | "cannot allocate symbol search list"); | |
84384f5b UD |
192 | map->l_ndupsearchlist = nduplist; |
193 | ||
df4ef2ab | 194 | for (nlist = 0; nlist < naux + 1 + npreloads; ++nlist) |
84384f5b UD |
195 | map->l_dupsearchlist[nlist] = head[nlist].map; |
196 | for (scanp = duphead.next; scanp; scanp = scanp->next) | |
197 | map->l_dupsearchlist[nlist++] = scanp->map; | |
efec1d0c | 198 | } |