1 /* $NetBSD: load.c,v 1.47 2013/11/27 18:01:33 christos 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.47 2013/11/27 18:01:33 christos 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 flags
)
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
) {
150 if (pathlen
== _rtld_objself
.pathlen
&&
151 strcmp(_rtld_objself
.path
, filepath
) == 0) {
153 return &_rtld_objself
;
157 if (obj
== NULL
) { /* First use of this object, so we must map it in */
158 obj
= _rtld_map_object(filepath
, fd
, &sb
);
162 _rtld_digest_dynamic(filepath
, obj
);
164 if (flags
& _RTLD_DLOPEN
) {
165 if (obj
->z_noopen
|| (flags
& _RTLD_NOLOAD
)) {
166 dbg(("refusing to load non-loadable \"%s\"",
168 _rtld_error("Cannot dlopen non-loadable %s",
170 munmap(obj
->mapbase
, obj
->mapsize
);
176 *_rtld_objtail
= obj
;
177 _rtld_objtail
= &obj
->next
;
181 _rtld_linkmap_add(obj
); /* for GDB */
183 dbg((" %p .. %p: %s", obj
->mapbase
,
184 obj
->mapbase
+ obj
->mapsize
- 1, obj
->path
));
186 dbg((" WARNING: %s has impure text", obj
->path
));
191 if (flags
& _RTLD_MAIN
&& !obj
->mainref
) {
193 dbg(("adding %p (%s) to _rtld_list_main", obj
, obj
->path
));
194 _rtld_objlist_push_tail(&_rtld_list_main
, obj
);
196 if (flags
& _RTLD_GLOBAL
&& !obj
->globalref
) {
198 dbg(("adding %p (%s) to _rtld_list_global", obj
, obj
->path
));
199 _rtld_objlist_push_tail(&_rtld_list_global
, obj
);
206 _rtld_load_by_name(const char *name
, Obj_Entry
*obj
, Needed_Entry
**needed
,
209 #if !defined(__minix)
210 Library_Xform
*x
= _rtld_xforms
;
211 #endif /* !defined(__minix) */
213 #if !defined(__minix)
216 #endif /* !defined(__minix) */
218 #if !defined(__minix)
225 dbg(("load by name %s %p", name
, x
));
226 #endif /* !defined(__minix) */
227 for (o
= _rtld_objlist
->next
; o
!= NULL
; o
= o
->next
)
228 if (_rtld_object_match_name(o
, name
)) {
234 #if !defined(__minix)
235 for (; x
; x
= x
->next
) {
236 if (strcmp(x
->name
, name
) != 0)
240 if ((i
= _rtld_sysctl(x
->ctlname
, &val
, &j
)) == -1) {
241 xwarnx(_PATH_LD_HINTS
": invalid/unknown sysctl for %s (%d)",
248 xsnprintf(val
.s
, sizeof(val
.s
), "%" PRIu64
, val
.q
);
251 xsnprintf(val
.s
, sizeof(val
.s
), "%d", val
.i
);
256 xwarnx("unsupported sysctl type %d", (int)i
);
260 dbg(("sysctl returns %s", val
.s
));
262 for (i
= 0; i
< RTLD_MAX_ENTRY
&& x
->entry
[i
].value
!= NULL
;
264 dbg(("entry %ld", (unsigned long)i
));
265 if (strcmp(x
->entry
[i
].value
, val
.s
) == 0)
269 if (i
== RTLD_MAX_ENTRY
) {
270 xwarnx("sysctl value %s not found for lib%s",
275 for (j
= 0; j
< RTLD_MAX_LIBRARY
&&
276 x
->entry
[i
].library
[j
] != NULL
; j
++) {
277 o
= _rtld_load_library(x
->entry
[i
].library
[j
], obj
,
280 xwarnx("could not load %s for %s",
281 x
->entry
[i
].library
[j
], name
);
288 /* make a new one and put it in the chain */
289 Needed_Entry
*ne
= xmalloc(sizeof(*ne
));
290 ne
->name
= (*needed
)->name
;
292 ne
->next
= (*needed
)->next
;
293 (*needed
)->next
= ne
;
300 #endif /* !defined(__minix) */
305 return ((*needed
)->obj
= _rtld_load_library(name
, obj
, flags
)) != NULL
;
310 * Given a shared object, traverse its list of needed objects, and load
311 * each of them. Returns 0 on success. Generates an error message and
312 * returns -1 on failure.
315 _rtld_load_needed_objects(Obj_Entry
*first
, int flags
)
320 for (obj
= first
; obj
!= NULL
; obj
= obj
->next
) {
321 Needed_Entry
*needed
;
323 for (needed
= obj
->needed
; needed
!= NULL
;
324 needed
= needed
->next
) {
325 const char *name
= obj
->strtab
+ needed
->name
;
329 if (!_rtld_load_by_name(name
, obj
, &needed
,
330 flags
& ~_RTLD_NOLOAD
))
331 status
= -1; /* FIXME - cleanup */
336 if (flags
& _RTLD_MAIN
)
340 if (nobj
->z_nodelete
&& !obj
->ref_nodel
) {
341 dbg(("obj %s nodelete", nobj
->path
));
343 nobj
->ref_nodel
= true;
354 _rtld_preload(const char *preload_path
)
360 if (preload_path
!= NULL
&& *preload_path
!= '\0') {
361 cp
= buf
= xstrdup(preload_path
);
362 while ((path
= strsep(&cp
, " :")) != NULL
&& status
== 0) {
363 if (!_rtld_load_object(path
, _RTLD_MAIN
))
366 dbg((" preloaded \"%s\"", path
));