rtld.c revision 1.11 1 /* $NetBSD: rtld.c,v 1.11 1999/01/09 18:10:19 castor Exp $ */
2
3 /*
4 * Copyright 1996 John D. Polstra.
5 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by John Polstra.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Dynamic linker for ELF.
36 *
37 * John Polstra <jdp (at) polstra.com>.
38 */
39
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <sys/param.h>
49 #include <sys/mman.h>
50 #include <dirent.h>
51
52 #include <ctype.h>
53
54 #include <dlfcn.h>
55 #include "debug.h"
56 #include "rtld.h"
57
58 #include "sysident.h"
59
60 /*
61 * Debugging support.
62 */
63
64 typedef void (*funcptr)(void);
65
66 /*
67 * Function declarations.
68 */
69 static void _rtld_init(caddr_t);
70 static void _rtld_exit(void);
71
72 /*
73 * Data declarations.
74 */
75 static char *error_message; /* Message for dlopen(), or NULL */
76
77 struct r_debug _rtld_debug; /* for GDB; */
78 bool _rtld_trust; /* False for setuid and setgid programs */
79 Obj_Entry *_rtld_objlist; /* Head of linked list of shared objects */
80 Obj_Entry **_rtld_objtail; /* Link field of last object in list */
81 Obj_Entry *_rtld_objmain; /* The main program shared object */
82 Obj_Entry _rtld_objself; /* The dynamic linker shared object */
83 char _rtld_path[] = _PATH_RTLD;
84
85 Search_Path *_rtld_paths;
86 /*
87 * Global declarations normally provided by crt0.
88 */
89 char *__progname;
90 char **environ;
91
92 #ifdef OLD_GOT
93 extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
94 #else
95 extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
96 extern Elf_Dyn _DYNAMIC;
97 #endif
98
99 static void
100 _rtld_call_fini_functions(
101 Obj_Entry *first)
102 {
103 Obj_Entry *obj;
104
105 for (obj = first; obj != NULL; obj = obj->next)
106 if (obj->fini != NULL)
107 (*obj->fini)();
108 }
109
110 static void
111 _rtld_call_init_functions(
112 Obj_Entry *first)
113 {
114 if (first != NULL) {
115 _rtld_call_init_functions(first->next);
116 if (first->init != NULL)
117 (*first->init)();
118 }
119 }
120
121 /*
123 * Initialize the dynamic linker. The argument is the address at which
124 * the dynamic linker has been mapped into memory. The primary task of
125 * this function is to relocate the dynamic linker.
126 */
127 static void
128 _rtld_init(
129 caddr_t mapbase)
130 {
131 _rtld_add_paths(&_rtld_paths, RTLD_DEFAULT_LIBRARY_PATH);
132
133 /* Conjure up an Obj_Entry structure for the dynamic linker. */
134
135 _rtld_objself.path = _rtld_path;
136 _rtld_objself.rtld = true;
137 _rtld_objself.mapbase = mapbase;
138 #ifdef __mips__
139 /* mips ld.so currently linked at load address, so no relocation needed */
140 _rtld_objself.relocbase = 0;
141 #else
142 _rtld_objself.relocbase = mapbase;
143 #endif
144 _rtld_objself.pltgot = NULL;
145 #ifdef OLD_GOT
146 _rtld_objself.dynamic = (Elf_Dyn *) _GLOBAL_OFFSET_TABLE_[0];
147 #else
148 _rtld_objself.dynamic = &_DYNAMIC;
149 #endif
150
151 _rtld_digest_dynamic(&_rtld_objself);
152 #ifdef __alpha__
153 /* XXX XXX XXX */
154 _rtld_objself.pltgot = NULL;
155 #endif
156 assert(_rtld_objself.needed == NULL);
157 #ifndef __mips__ /* no relocation for mips */
158 assert(!_rtld_objself.textrel);
159 #endif
160
161 /* Set up the _rtld_objlist pointer, so that rtld symbols can be found. */
162 _rtld_objlist = &_rtld_objself;
163
164 _rtld_relocate_objects(&_rtld_objself, true);
165
166 /* Make the object list empty again. */
167 _rtld_objlist = NULL;
168 _rtld_objtail = &_rtld_objlist;
169
170 _rtld_debug.r_brk = _rtld_debug_state;
171 _rtld_debug.r_state = RT_CONSISTENT;
172 }
173
174 /*
176 * Cleanup procedure. It will be called (by the atexit() mechanism) just
177 * before the process exits.
178 */
179 static void
180 _rtld_exit(void)
181 {
182 dbg("rtld_exit()");
183
184 _rtld_call_fini_functions(_rtld_objlist->next);
185 }
186
187 /*
189 * Main entry point for dynamic linking. The argument is the stack
190 * pointer. The stack is expected to be laid out as described in the
191 * SVR4 ABI specification, Intel 386 Processor Supplement. Specifically,
192 * the stack pointer points to a word containing ARGC. Following that
193 * in the stack is a null-terminated sequence of pointers to argument
194 * strings. Then comes a null-terminated sequence of pointers to
195 * environment strings. Finally, there is a sequence of "auxiliary
196 * vector" entries.
197 *
198 * This function returns the entry point for the main program in %eax,
199 * and the dynamic linker's exit procedure in %edx. We accomplish this
200 * by declaring the return value to have the 64-bit type "long long".
201 * Such values are returned with their most-significant 32 bits in %edx,
202 * and their least-significant 32 bits in %eax.
203 */
204 Elf_Addr _rtld(Elf_Word *);
205
206 Elf_Addr
207 _rtld(
208 Elf_Word *sp)
209 {
210 const AuxInfo *pAUX_base, *pAUX_entry, *pAUX_execfd,
211 *pAUX_phdr, *pAUX_phent, *pAUX_phnum;
212 char **env;
213 const AuxInfo *aux;
214 const AuxInfo *auxp;
215 Elf_Word * const osp = sp;
216 bool bind_now = 0;
217 const char *ld_bind_now;
218 const char **argv;
219
220 /*
221 * On entry, the dynamic linker itself has not been relocated yet.
222 * Be very careful not to reference any global data until after
223 * _rtld_init has returned. It is OK to reference file-scope statics
224 * and string constants, and to call static and global functions.
225 */
226 /* Find the auxiliary vector on the stack. */
227 /* first Elf_Word reserved to address of exit routine */
228 #ifdef RTLD_DEBUG
229 int i;
230 xprintf("sp = %p, argc = %d, argv = %p <%s>\n", sp, sp[2], &sp[3], sp[3]);
231 xprintf("got is at %p, dynamic is at %p\n", _GLOBAL_OFFSET_TABLE_, &_DYNAMIC);
232 debug = 1;
233 xprintf("_ctype_ is %p\n", _ctype_);
234 #endif
235
236 sp += 2; /* skip over return argument space */
237 argv = (const char **) &sp[1];
238 sp += sp[0] + 2; /* Skip over argc, arguments, and NULL terminator */
239 env = (char **) sp;
240 while (*sp++ != 0) { /* Skip over environment, and NULL terminator */
241 #ifdef RTLD_DEBUG
242 xprintf("env[%d] = %p\n", i++, sp[-1]);
243 #endif
244 }
245 aux = (const AuxInfo *) sp;
246
247 /* Digest the auxiliary vector. */
248 pAUX_base = pAUX_entry = pAUX_execfd =
249 pAUX_phdr = pAUX_phent = pAUX_phnum = NULL;
250 for (auxp = aux; auxp->au_id != AUX_null; ++auxp) {
251 switch(auxp->au_id) {
252 case AUX_base:
253 pAUX_base = auxp; break;
254 case AUX_entry:
255 pAUX_entry = auxp; break;
256 case AUX_execfd:
257 pAUX_execfd = auxp; break;
258 case AUX_phdr:
259 pAUX_phdr = auxp; break;
260 case AUX_phent:
261 pAUX_phent = auxp; break;
262 case AUX_phnum:
263 pAUX_phnum = auxp; break;
264 }
265 }
266
267 /* Initialize and relocate ourselves. */
268 assert(pAUX_base != NULL);
269 _rtld_init((caddr_t) pAUX_base->au_v);
270
271 #ifdef RTLD_DEBUG
272 xprintf("_ctype_ is %p\n", _ctype_);
273 #endif
274
275 __progname = _rtld_objself.path;
276 environ = env;
277
278 _rtld_trust = geteuid() == getuid() && getegid() == getgid();
279
280 ld_bind_now = getenv("LD_BIND_NOW");
281 if (ld_bind_now != NULL && *ld_bind_now != '\0')
282 bind_now = true;
283 if (_rtld_trust) {
284 #ifdef DEBUG
285 const char *ld_debug = getenv("LD_DEBUG");
286 if (ld_debug != NULL && *ld_debug != '\0')
287 debug = 1;
288 #endif
289 _rtld_add_paths(&_rtld_paths, getenv("LD_LIBRARY_PATH"));
290 }
291
292 dbg("%s is initialized, base address = %p", __progname, pAUX_base->au_v);
293
294 /*
295 * Load the main program, or process its program header if it is
296 * already loaded.
297 */
298 if (pAUX_execfd != NULL) { /* Load the main program. */
299 int fd = pAUX_execfd->au_v;
300 dbg("loading main program");
301 _rtld_objmain = _rtld_map_object(argv[0], fd);
302 close(fd);
303 if (_rtld_objmain == NULL)
304 _rtld_die();
305 } else { /* Main program already loaded. */
306 const Elf_Phdr *phdr;
307 int phnum;
308 caddr_t entry;
309
310 dbg("processing main program's program header");
311 assert(pAUX_phdr != NULL);
312 phdr = (const Elf_Phdr *) pAUX_phdr->au_v;
313 assert(pAUX_phnum != NULL);
314 phnum = pAUX_phnum->au_v;
315 assert(pAUX_phent != NULL);
316 assert(pAUX_phent->au_v == sizeof(Elf_Phdr));
317 assert(pAUX_entry != NULL);
318 entry = (caddr_t) pAUX_entry->au_v;
319 _rtld_objmain = _rtld_digest_phdr(phdr, phnum, entry);
320 }
321
322 _rtld_objmain->path = xstrdup("main program");
323 _rtld_objmain->mainprog = true;
324 _rtld_digest_dynamic(_rtld_objmain);
325
326 _rtld_linkmap_add(_rtld_objmain);
327 _rtld_linkmap_add(&_rtld_objself);
328
329 /* Link the main program into the list of objects. */
330 *_rtld_objtail = _rtld_objmain;
331 _rtld_objtail = &_rtld_objmain->next;
332 ++_rtld_objmain->refcount;
333
334 dbg("loading needed objects");
335 if (_rtld_load_needed_objects(_rtld_objmain) == -1)
336 _rtld_die();
337
338 dbg("relocating objects");
339 if (_rtld_relocate_objects(_rtld_objmain, bind_now) == -1)
340 _rtld_die();
341
342 dbg("doing copy relocations");
343 if (_rtld_do_copy_relocations(_rtld_objmain) == -1)
344 _rtld_die();
345
346 dbg("calling _init functions");
347 _rtld_call_init_functions(_rtld_objmain->next);
348
349 dbg("transferring control to program entry point = %p",
350 _rtld_objmain->entry);
351
352 /* Return with the entry point and the exit procedure in at the top of
353 * stack.
354 */
355
356 _rtld_debug_state(); /* say hello to gdb! */
357
358 ((void **) osp)[0] = _rtld_exit;
359 ((void **) osp)[1] = _rtld_objmain;
360 return (Elf_Addr) _rtld_objmain->entry;
361 }
362
363 void
364 _rtld_die(
365 void)
366 {
367 const char *msg = _rtld_dlerror();
368
369 if (msg == NULL)
370 msg = "Fatal error";
371 xerrx(1, "%s\n", msg);
372 }
373
374 static Obj_Entry *
375 _rtld_dlcheck(
376 void *handle)
377 {
378 Obj_Entry *obj;
379
380 for (obj = _rtld_objlist; obj != NULL; obj = obj->next)
381 if (obj == (Obj_Entry *) handle)
382 break;
383
384 if (obj == NULL || obj->dl_refcount == 0) {
385 xwarnx("Invalid shared object handle %p", handle);
386 return NULL;
387 }
388 return obj;
389 }
390
391 static void
392 _rtld_unref_object_dag(
393 Obj_Entry *root)
394 {
395 assert(root->refcount != 0);
396 --root->refcount;
397 if (root->refcount == 0) {
398 const Needed_Entry *needed;
399
400 for (needed = root->needed; needed != NULL; needed = needed->next)
401 _rtld_unref_object_dag(needed->obj);
402 }
403 }
404
405 int
406 _rtld_dlclose(
407 void *handle)
408 {
409 Obj_Entry *root = _rtld_dlcheck(handle);
410
411 if (root == NULL)
412 return -1;
413
414 _rtld_debug.r_state = RT_DELETE;
415 _rtld_debug_state();
416
417 --root->dl_refcount;
418 _rtld_unref_object_dag(root);
419 if (root->refcount == 0) { /* We are finished with some objects. */
420 Obj_Entry *obj;
421 Obj_Entry **linkp;
422
423 /* Finalize objects that are about to be unmapped. */
424 for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
425 if (obj->refcount == 0 && obj->fini != NULL)
426 (*obj->fini)();
427
428 /* Unmap all objects that are no longer referenced. */
429 linkp = &_rtld_objlist->next;
430 while((obj = *linkp) != NULL) {
431 if (obj->refcount == 0) {
432 munmap(obj->mapbase, obj->mapsize);
433 free(obj->path);
434 while(obj->needed != NULL) {
435 Needed_Entry *needed = obj->needed;
436 obj->needed = needed->next;
437 free(needed);
438 }
439 _rtld_linkmap_delete(obj);
440 *linkp = obj->next;
441 if (obj->next == NULL)
442 _rtld_objtail = linkp;
443 free(obj);
444 } else
445 linkp = &obj->next;
446 }
447 }
448
449 _rtld_debug.r_state = RT_CONSISTENT;
450 _rtld_debug_state();
451
452 return 0;
453 }
454
455 char *
456 _rtld_dlerror(
457 void)
458 {
459 char *msg = error_message;
460 error_message = NULL;
461 return msg;
462 }
463
464 void *
465 _rtld_dlopen(
466 const char *name,
467 int mode)
468 {
469 Obj_Entry **old_obj_tail = _rtld_objtail;
470 Obj_Entry *obj = NULL;
471
472 _rtld_debug.r_state = RT_ADD;
473 _rtld_debug_state();
474
475 if (name == NULL) {
476 obj = _rtld_objmain;
477 } else {
478 char *path = _rtld_find_library(name, NULL);
479 if (path != NULL)
480 obj = _rtld_load_object(path);
481 }
482
483 if (obj != NULL) {
484 ++obj->dl_refcount;
485 if (*old_obj_tail != NULL) { /* We loaded something new. */
486 assert(*old_obj_tail == obj);
487
488 /* FIXME - Clean up properly after an error. */
489 if (_rtld_load_needed_objects(obj) == -1) {
490 --obj->dl_refcount;
491 obj = NULL;
492 } else if (_rtld_relocate_objects(obj, (mode & 3) == RTLD_NOW) == -1) {
493 --obj->dl_refcount;
494 obj = NULL;
495 } else {
496 _rtld_call_init_functions(obj);
497 }
498 }
499 }
500
501 _rtld_debug.r_state = RT_CONSISTENT;
502 _rtld_debug_state();
503
504 return obj;
505 }
506
507 void *
508 _rtld_dlsym(
509 void *handle,
510 const char *name)
511 {
512 const Obj_Entry *obj = _rtld_dlcheck(handle);
513 const Elf_Sym *def;
514 const Obj_Entry *defobj;
515
516 if (obj == NULL)
517 return NULL;
518
519 /*
520 * FIXME - This isn't correct. The search should include the whole
521 * DAG rooted at the given object.
522 */
523 def = _rtld_find_symdef(_rtld_objlist, 0, name, obj, &defobj, false);
524 if (def != NULL)
525 return defobj->relocbase + def->st_value;
526
527 _rtld_error("Undefined symbol \"%s\"", name);
528 return NULL;
529 }
530
531 /*
532 * Error reporting function. Use it like printf. If formats the message
533 * into a buffer, and sets things up so that the next call to dlerror()
534 * will return the message.
535 */
536 void
537 _rtld_error(
538 const char *fmt, ...)
539 {
540 static char buf[512];
541 va_list ap;
542
543 va_start(ap, fmt);
544 xvsnprintf(buf, sizeof buf, fmt, ap);
545 error_message = buf;
546 va_end(ap);
547 }
548
549 void
551 _rtld_debug_state(
552 void)
553 {
554 /* do nothing */
555 }
556
557 void
558 _rtld_linkmap_add(
559 Obj_Entry *obj)
560 {
561 struct link_map *l = &obj->linkmap;
562 struct link_map *prev;
563
564 obj->linkmap.l_name = obj->path;
565 obj->linkmap.l_addr = obj->mapbase;
566 obj->linkmap.l_ld = obj->dynamic;
567 #ifdef __mips__
568 /* GDB needs load offset on MIPS to use the symbols */
569 obj->linkmap.l_offs = obj->relocbase;
570 #endif
571
572 if (_rtld_debug.r_map == NULL) {
573 _rtld_debug.r_map = l;
574 return;
575 }
576
577 for (prev = _rtld_debug.r_map; prev->l_next != NULL; prev = prev->l_next)
578 ;
579 l->l_prev = prev;
580 prev->l_next = l;
581 l->l_next = NULL;
582 }
583
584 void
585 _rtld_linkmap_delete(
586 Obj_Entry *obj)
587 {
588 struct link_map *l = &obj->linkmap;
589
590 if (l->l_prev == NULL) {
591 if ((_rtld_debug.r_map = l->l_next) != NULL)
592 l->l_next->l_prev = NULL;
593 return;
594 }
595
596 if ((l->l_prev->l_next = l->l_next) != NULL)
597 l->l_next->l_prev = l->l_prev;
598 }
599