1 /* $NetBSD: load.c,v 1.35 2007/12/07 20:34:04 ad Exp $ */
4 * Copyright 1996 John D. Polstra.
5 * Copyright 1996 Matt Thomas <matt@3am-software.com>
6 * Copyright 2002 Charles M. Hannum <root@ihack.net>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by John Polstra.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * Dynamic linker for ELF.
38 * John Polstra <jdp@polstra.com>.
41 #include <sys/cdefs.h>
43 __RCSID("$NetBSD: load.c,v 1.35 2007/12/07 20:34:04 ad Exp $");
54 #include <sys/types.h>
55 #include <sys/param.h>
57 #include <sys/sysctl.h>
63 static bool _rtld_load_by_name(const char *, Obj_Entry
*, Needed_Entry
**,
67 Objlist _rtld_list_main
= /* Objects loaded at program startup */
68 SIMPLEQ_HEAD_INITIALIZER(_rtld_list_main
);
69 Objlist _rtld_list_global
= /* Objects dlopened with RTLD_GLOBAL */
70 SIMPLEQ_HEAD_INITIALIZER(_rtld_list_global
);
73 _rtld_objlist_push_head(Objlist
*list
, Obj_Entry
*obj
)
77 elm
= NEW(Objlist_Entry
);
79 SIMPLEQ_INSERT_HEAD(list
, elm
, link
);
83 _rtld_objlist_push_tail(Objlist
*list
, Obj_Entry
*obj
)
87 elm
= NEW(Objlist_Entry
);
89 SIMPLEQ_INSERT_TAIL(list
, elm
, link
);
93 _rtld_objlist_find(Objlist
*list
, const Obj_Entry
*obj
)
97 SIMPLEQ_FOREACH(elm
, list
, link
) {
106 * Load a shared object into memory, if it is not already loaded.
108 * Returns a pointer to the Obj_Entry for the object. Returns NULL
112 _rtld_load_object(const char *filepath
, int mode
)
117 size_t pathlen
= strlen(filepath
);
119 for (obj
= _rtld_objlist
->next
; obj
!= NULL
; obj
= obj
->next
)
120 if (pathlen
== obj
->pathlen
&& !strcmp(obj
->path
, filepath
))
124 * If we didn't find a match by pathname, open the file and check
125 * again by device and inode. This avoids false mismatches caused
126 * by multiple links or ".." in pathnames.
128 * To avoid a race, we open the file and use fstat() rather than
132 if ((fd
= open(filepath
, O_RDONLY
)) == -1) {
133 _rtld_error("Cannot open \"%s\"", filepath
);
136 if (fstat(fd
, &sb
) == -1) {
137 _rtld_error("Cannot fstat \"%s\"", filepath
);
141 for (obj
= _rtld_objlist
->next
; obj
!= NULL
; obj
= obj
->next
) {
142 if (obj
->ino
== sb
.st_ino
&& obj
->dev
== sb
.st_dev
) {
149 if (obj
== NULL
) { /* First use of this object, so we must map it in */
150 obj
= _rtld_map_object(filepath
, fd
, &sb
);
154 _rtld_digest_dynamic(filepath
, obj
);
156 *_rtld_objtail
= obj
;
157 _rtld_objtail
= &obj
->next
;
159 _rtld_linkmap_add(obj
); /* for GDB */
161 dbg((" %p .. %p: %s", obj
->mapbase
,
162 obj
->mapbase
+ obj
->mapsize
- 1, obj
->path
));
164 dbg((" WARNING: %s has impure text", obj
->path
));
169 if (mode
& RTLD_MAIN
&& !obj
->mainref
) {
171 rdbg(("adding %p (%s) to _rtld_list_main", obj
, obj
->path
));
172 _rtld_objlist_push_tail(&_rtld_list_main
, obj
);
174 if (mode
& RTLD_GLOBAL
&& !obj
->globalref
) {
176 rdbg(("adding %p (%s) to _rtld_list_global", obj
, obj
->path
));
177 _rtld_objlist_push_tail(&_rtld_list_global
, obj
);
184 _rtld_load_by_name(const char *name
, Obj_Entry
*obj
, Needed_Entry
**needed
, int mode
)
186 Library_Xform
*x
= _rtld_xforms
;
197 dbg(("load by name %s %p", name
, x
));
198 for (; x
; x
= x
->next
) {
199 if (strcmp(x
->name
, name
) != 0)
203 if ((i
= _rtld_sysctl(x
->ctlname
, &val
, &j
)) == -1) {
204 xwarnx(_PATH_LD_HINTS
": invalid/unknown sysctl for %s (%d)",
211 xsnprintf(val
.s
, sizeof(val
.s
), "%" PRIu64
, val
.q
);
214 xsnprintf(val
.s
, sizeof(val
.s
), "%d", val
.i
);
219 xwarnx("unsupported sysctl type %d", (int)i
);
223 dbg(("sysctl returns %s", val
.s
));
225 for (i
= 0; i
< RTLD_MAX_ENTRY
&& x
->entry
[i
].value
!= NULL
;
227 dbg(("entry %ld", (unsigned long)i
));
228 if (strcmp(x
->entry
[i
].value
, val
.s
) == 0)
232 if (i
== RTLD_MAX_ENTRY
) {
233 xwarnx("sysctl value %s not found for lib%s",
237 /* XXX: This can mess up debuggers, cause we lie about
238 * what we loaded in the needed objects */
239 for (j
= 0; j
< RTLD_MAX_LIBRARY
&&
240 x
->entry
[i
].library
[j
] != NULL
; j
++) {
241 o
= _rtld_load_library(x
->entry
[i
].library
[j
], obj
,
244 xwarnx("could not load %s for %s",
245 x
->entry
[i
].library
[j
], name
);
252 /* make a new one and put it in the chain */
253 Needed_Entry
*ne
= xmalloc(sizeof(*ne
));
254 ne
->name
= (*needed
)->name
;
256 ne
->next
= (*needed
)->next
;
257 (*needed
)->next
= ne
;
268 return ((*needed
)->obj
= _rtld_load_library(name
, obj
, mode
)) != NULL
;
273 * Given a shared object, traverse its list of needed objects, and load
274 * each of them. Returns 0 on success. Generates an error message and
275 * returns -1 on failure.
278 _rtld_load_needed_objects(Obj_Entry
*first
, int mode
)
283 for (obj
= first
; obj
!= NULL
; obj
= obj
->next
) {
284 Needed_Entry
*needed
;
286 for (needed
= obj
->needed
; needed
!= NULL
;
287 needed
= needed
->next
) {
288 const char *name
= obj
->strtab
+ needed
->name
;
289 if (!_rtld_load_by_name(name
, obj
, &needed
, mode
))
290 status
= -1; /* FIXME - cleanup */
303 _rtld_preload(const char *preload_path
)
309 if (preload_path
!= NULL
&& *preload_path
!= '\0') {
310 cp
= buf
= xstrdup(preload_path
);
311 while ((path
= strsep(&cp
, " :")) != NULL
&& status
== 0) {
312 if (!_rtld_load_object(path
, RTLD_MAIN
))
315 dbg((" preloaded \"%s\"", path
));