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