1 /* $NetBSD: load.c,v 1.42 2010/12/24 12:41:43 skrll 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.42 2010/12/24 12:41:43 skrll Exp $");
54 #include <sys/types.h>
55 #include <sys/param.h>
57 #include <sys/sysctl.h>
61 #define munmap minix_munmap
67 static bool _rtld_load_by_name(const char *, Obj_Entry
*, Needed_Entry
**,
71 Objlist _rtld_list_main
= /* Objects loaded at program startup */
72 SIMPLEQ_HEAD_INITIALIZER(_rtld_list_main
);
73 Objlist _rtld_list_global
= /* Objects dlopened with RTLD_GLOBAL */
74 SIMPLEQ_HEAD_INITIALIZER(_rtld_list_global
);
77 _rtld_objlist_push_head(Objlist
*list
, Obj_Entry
*obj
)
81 elm
= NEW(Objlist_Entry
);
83 SIMPLEQ_INSERT_HEAD(list
, elm
, link
);
87 _rtld_objlist_push_tail(Objlist
*list
, Obj_Entry
*obj
)
91 elm
= NEW(Objlist_Entry
);
93 SIMPLEQ_INSERT_TAIL(list
, elm
, link
);
97 _rtld_objlist_find(Objlist
*list
, const Obj_Entry
*obj
)
101 SIMPLEQ_FOREACH(elm
, list
, link
) {
110 * Load a shared object into memory, if it is not already loaded.
112 * Returns a pointer to the Obj_Entry for the object. Returns NULL
116 _rtld_load_object(const char *filepath
, int flags
)
121 size_t pathlen
= strlen(filepath
);
123 for (obj
= _rtld_objlist
->next
; obj
!= NULL
; obj
= obj
->next
)
124 if (pathlen
== obj
->pathlen
&& !strcmp(obj
->path
, filepath
))
128 * If we didn't find a match by pathname, open the file and check
129 * again by device and inode. This avoids false mismatches caused
130 * by multiple links or ".." in pathnames.
132 * To avoid a race, we open the file and use fstat() rather than
136 if ((fd
= open(filepath
, O_RDONLY
)) == -1) {
137 _rtld_error("Cannot open \"%s\"", filepath
);
140 if (fstat(fd
, &sb
) == -1) {
141 _rtld_error("Cannot fstat \"%s\"", filepath
);
145 for (obj
= _rtld_objlist
->next
; obj
!= NULL
; obj
= obj
->next
) {
146 if (obj
->ino
== sb
.st_ino
&& obj
->dev
== sb
.st_dev
) {
153 if (obj
== NULL
) { /* First use of this object, so we must map it in */
154 obj
= _rtld_map_object(filepath
, fd
, &sb
);
158 _rtld_digest_dynamic(filepath
, obj
);
160 if (flags
& _RTLD_DLOPEN
) {
161 if (obj
->z_noopen
|| (flags
& _RTLD_NOLOAD
)) {
162 dbg(("refusing to load non-loadable \"%s\"",
164 _rtld_error("Cannot dlopen non-loadable %s",
166 munmap(obj
->mapbase
, obj
->mapsize
);
172 *_rtld_objtail
= obj
;
173 _rtld_objtail
= &obj
->next
;
177 _rtld_linkmap_add(obj
); /* for GDB */
179 dbg((" %p .. %p: %s", obj
->mapbase
,
180 obj
->mapbase
+ obj
->mapsize
- 1, obj
->path
));
182 dbg((" WARNING: %s has impure text", obj
->path
));
187 if (flags
& _RTLD_MAIN
&& !obj
->mainref
) {
189 dbg(("adding %p (%s) to _rtld_list_main", obj
, obj
->path
));
190 _rtld_objlist_push_tail(&_rtld_list_main
, obj
);
192 if (flags
& _RTLD_GLOBAL
&& !obj
->globalref
) {
194 dbg(("adding %p (%s) to _rtld_list_global", obj
, obj
->path
));
195 _rtld_objlist_push_tail(&_rtld_list_global
, obj
);
202 _rtld_load_by_name(const char *name
, Obj_Entry
*obj
, Needed_Entry
**needed
,
205 #if !defined(__minix)
206 Library_Xform
*x
= _rtld_xforms
;
210 #endif /* !defined(__minix) */
212 #if !defined(__minix)
218 #endif /* !defined(__minix) */
220 #if !defined(__minix)
221 dbg(("load by name %s %p", name
, x
));
222 for (; x
; x
= x
->next
) {
223 if (strcmp(x
->name
, name
) != 0)
227 if ((i
= _rtld_sysctl(x
->ctlname
, &val
, &j
)) == -1) {
228 xwarnx(_PATH_LD_HINTS
": invalid/unknown sysctl for %s (%d)",
235 xsnprintf(val
.s
, sizeof(val
.s
), "%" PRIu64
, val
.q
);
238 xsnprintf(val
.s
, sizeof(val
.s
), "%d", val
.i
);
243 xwarnx("unsupported sysctl type %d", (int)i
);
247 dbg(("sysctl returns %s", val
.s
));
249 for (i
= 0; i
< RTLD_MAX_ENTRY
&& x
->entry
[i
].value
!= NULL
;
251 dbg(("entry %ld", (unsigned long)i
));
252 if (strcmp(x
->entry
[i
].value
, val
.s
) == 0)
256 if (i
== RTLD_MAX_ENTRY
) {
257 xwarnx("sysctl value %s not found for lib%s",
262 for (j
= 0; j
< RTLD_MAX_LIBRARY
&&
263 x
->entry
[i
].library
[j
] != NULL
; j
++) {
264 o
= _rtld_load_library(x
->entry
[i
].library
[j
], obj
,
267 xwarnx("could not load %s for %s",
268 x
->entry
[i
].library
[j
], name
);
275 /* make a new one and put it in the chain */
276 Needed_Entry
*ne
= xmalloc(sizeof(*ne
));
277 ne
->name
= (*needed
)->name
;
279 ne
->next
= (*needed
)->next
;
280 (*needed
)->next
= ne
;
287 #endif /* !defined(__minix) */
292 return ((*needed
)->obj
= _rtld_load_library(name
, obj
, flags
)) != NULL
;
297 * Given a shared object, traverse its list of needed objects, and load
298 * each of them. Returns 0 on success. Generates an error message and
299 * returns -1 on failure.
302 _rtld_load_needed_objects(Obj_Entry
*first
, int flags
)
307 for (obj
= first
; obj
!= NULL
; obj
= obj
->next
) {
308 Needed_Entry
*needed
;
310 for (needed
= obj
->needed
; needed
!= NULL
;
311 needed
= needed
->next
) {
312 const char *name
= obj
->strtab
+ needed
->name
;
316 if (!_rtld_load_by_name(name
, obj
, &needed
,
317 flags
& ~_RTLD_NOLOAD
))
318 status
= -1; /* FIXME - cleanup */
323 if (flags
& _RTLD_MAIN
)
327 if (nobj
->z_nodelete
&& !obj
->ref_nodel
) {
328 dbg(("obj %s nodelete", nobj
->path
));
330 nobj
->ref_nodel
= true;
341 _rtld_preload(const char *preload_path
)
347 if (preload_path
!= NULL
&& *preload_path
!= '\0') {
348 cp
= buf
= xstrdup(preload_path
);
349 while ((path
= strsep(&cp
, " :")) != NULL
&& status
== 0) {
350 if (!_rtld_load_object(path
, _RTLD_MAIN
))
353 dbg((" preloaded \"%s\"", path
));