rtld.c revision 39321
143412Snewton/*-
243412Snewton * Copyright 1996-1998 John D. Polstra.
343412Snewton * All rights reserved.
443412Snewton *
543412Snewton * Redistribution and use in source and binary forms, with or without
643412Snewton * modification, are permitted provided that the following conditions
743412Snewton * are met:
843412Snewton * 1. Redistributions of source code must retain the above copyright
943412Snewton *    notice, this list of conditions and the following disclaimer.
1043412Snewton * 2. Redistributions in binary form must reproduce the above copyright
1143412Snewton *    notice, this list of conditions and the following disclaimer in the
1243412Snewton *    documentation and/or other materials provided with the distribution.
1343412Snewton *
1443412Snewton * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1543412Snewton * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1643412Snewton * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1743412Snewton * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1843412Snewton * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1943412Snewton * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2043412Snewton * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2143412Snewton * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2243412Snewton * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2343412Snewton * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2443412Snewton *
2543412Snewton *      $Id: rtld.c,v 1.9 1998/09/15 21:07:52 jdp Exp $
2643412Snewton */
2743412Snewton
2843412Snewton/*
2943412Snewton * Dynamic linker for ELF.
3043412Snewton *
3143412Snewton * John Polstra <jdp@polstra.com>.
3243412Snewton */
3343412Snewton
3443412Snewton#ifndef __GNUC__
35116174Sobrien#error "GCC is needed to compile this file"
36116174Sobrien#endif
37116174Sobrien
38101709Srwatson#include <sys/param.h>
39101709Srwatson#include <sys/mman.h>
4043412Snewton
4143412Snewton#include <dlfcn.h>
4243412Snewton#include <err.h>
4376166Smarkm#include <errno.h>
4443412Snewton#include <fcntl.h>
4543412Snewton#include <stdarg.h>
4676166Smarkm#include <stdio.h>
47101709Srwatson#include <stdlib.h>
4876166Smarkm#include <string.h>
4976166Smarkm#include <unistd.h>
5043412Snewton
5143412Snewton#include "debug.h"
5276166Smarkm#include "rtld.h"
5376166Smarkm
5476166Smarkm/*
5576166Smarkm * Debugging support.
5676166Smarkm */
5743412Snewton
5843412Snewton#define assert(cond)	((cond) ? (void) 0 :\
5976166Smarkm    (msg("oops: " __XSTRING(__LINE__) "\n"), abort()))
60138129Sdas#define msg(s)		(write(1, s, strlen(s)))
6176166Smarkm#define trace()		msg("trace: " __XSTRING(__LINE__) "\n");
6274940Sjhb
63139739Sjhb#define END_SYM		"end"
6476166Smarkm
6576166Smarkm/* Types. */
6676166Smarkmtypedef void (*func_ptr_type)();
6743412Snewton
6876166Smarkm/*
6943412Snewton * Function declarations.
7043412Snewton */
7165302Sobrienstatic void call_fini_functions(Obj_Entry *);
7265302Sobrienstatic void call_init_functions(Obj_Entry *);
7365302Sobrienstatic void die(void);
7465302Sobrienstatic void digest_dynamic(Obj_Entry *);
7565302Sobrienstatic Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t);
7665302Sobrienstatic Obj_Entry *dlcheck(void *);
7765302Sobrienstatic char *find_library(const char *, const Obj_Entry *);
7865302Sobrienstatic const char *gethints(void);
7965302Sobrienstatic void init_rtld(caddr_t);
8065302Sobrienstatic bool is_exported(const Elf_Sym *);
8165302Sobrienstatic void linkmap_add(Obj_Entry *);
8265302Sobrienstatic void linkmap_delete(Obj_Entry *);
8365302Sobrienstatic int load_needed_objects(Obj_Entry *);
8443412Snewtonstatic Obj_Entry *load_object(char *);
8543412Snewtonstatic Obj_Entry *obj_from_addr(const void *);
8643412Snewtonstatic int relocate_objects(Obj_Entry *, bool);
8743412Snewtonstatic void rtld_exit(void);
8843412Snewtonstatic char *search_library_path(const char *, const char *);
8971452Sjhbstatic void unref_object_dag(Obj_Entry *);
9092787Sjeffstatic void trace_loaded_objects(Obj_Entry *obj);
91109254Sdillon
9271452Sjhbvoid r_debug_state(void);
9343412Snewtonvoid xprintf(const char *, ...);
9443412Snewton
9543412Snewton#ifdef DEBUG
9643412Snewtonstatic const char *basename(const char *);
9743412Snewton#endif
9843412Snewton
9943412Snewton/* Assembly language entry point for lazy binding. */
10043412Snewtonextern void _rtld_bind_start(void);
10143412Snewton
10292761Salfred/*
10392761Salfred * Assembly language macro for getting the GOT pointer.
10443412Snewton */
10592761Salfred#ifdef __i386__
10692761Salfred#define get_got_address()				\
10743412Snewton    ({ Elf_Addr *thegot;				\
10843412Snewton       __asm__("movl %%ebx,%0" : "=rm"(thegot));	\
10992761Salfred       thegot; })
11092761Salfred#elif __alpha__
11192761Salfred#define get_got_address()	NULL
11292761Salfred#else
11392761Salfred#error "This file only supports the i386 and alpha architectures"
11492761Salfred#endif
11592761Salfred
11643412Snewton/*
11743412Snewton * Data declarations.
11843412Snewton */
11943412Snewtonstatic char *error_message;	/* Message for dlerror(), or NULL */
12083366Sjulianstruct r_debug r_debug;	/* for GDB; */
12183366Sjulianstatic bool trust;		/* False for setuid and setgid programs */
12243412Snewtonstatic char *ld_bind_now;	/* Environment variable for immediate binding */
12343412Snewtonstatic char *ld_debug;		/* Environment variable for debugging */
12483366Sjulianstatic char *ld_library_path;	/* Environment variable for search path */
12543412Snewtonstatic char *ld_tracing;	/* Called from ldd to print libs */
12643412Snewtonstatic Obj_Entry **main_tail;	/* Value of obj_tail after loading main and
12743412Snewton				   its needed shared libraries */
12843412Snewtonstatic Obj_Entry *obj_list;	/* Head of linked list of shared objects */
12943412Snewtonstatic Obj_Entry **obj_tail;	/* Link field of last object in list */
13083366Sjulianstatic Obj_Entry *obj_main;	/* The main program shared object */
13183366Sjulianstatic Obj_Entry obj_rtld;	/* The dynamic linker shared object */
13243412Snewton
13343412Snewton#define GDB_STATE(s)	r_debug.r_state = s; r_debug_state();
134127140Sjhb
13543412Snewtonextern Elf_Dyn _DYNAMIC;
136127140Sjhb
137127140Sjhb/*
138127140Sjhb * These are the functions the dynamic linker exports to application
13943412Snewton * programs.  They are the only symbols the dynamic linker is willing
14043412Snewton * to export from itself.
14143412Snewton */
14243412Snewtonstatic func_ptr_type exports[] = {
14351793Smarcel    (func_ptr_type) &_rtld_error,
14443412Snewton    (func_ptr_type) &dlclose,
14543412Snewton    (func_ptr_type) &dlerror,
14643412Snewton    (func_ptr_type) &dlopen,
14751793Smarcel    (func_ptr_type) &dlsym,
14843412Snewton    NULL
14943412Snewton};
15043412Snewton
15143412Snewton/*
15243412Snewton * Global declarations normally provided by crt1.  The dynamic linker is
15343412Snewton * not build with crt1, so we have to provide them ourselves.
154127140Sjhb */
15543412Snewtonchar *__progname;
156107849Salfredchar **environ;
157127140Sjhb
15843412Snewton/*
159127140Sjhb * Main entry point for dynamic linking.  The first argument is the
16043412Snewton * stack pointer.  The stack is expected to be laid out as described
16143412Snewton * in the SVR4 ABI specification, Intel 386 Processor Supplement.
16243412Snewton * Specifically, the stack pointer points to a word containing
16383366Sjulian * ARGC.  Following that in the stack is a null-terminated sequence
16483366Sjulian * of pointers to argument strings.  Then comes a null-terminated
16543412Snewton * sequence of pointers to environment strings.  Finally, there is a
16643412Snewton * sequence of "auxiliary vector" entries.
16743412Snewton *
16843412Snewton * The second argument points to a place to store the dynamic linker's
16943412Snewton * exit procedure pointer and the third to a place to store the main
17043412Snewton * program's object.
171107849Salfred *
17243412Snewton * The return value is the main program's entry point.
173107849Salfred */
174107849Salfredfunc_ptr_type
175107849Salfred_rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
17643412Snewton{
17783366Sjulian    Elf_Auxinfo *aux_info[AT_COUNT];
17843412Snewton    int i;
17943412Snewton    int argc;
18043412Snewton    char **argv;
18183366Sjulian    char **env;
18283366Sjulian    Elf_Auxinfo *aux;
18343412Snewton    Elf_Auxinfo *auxp;
18443412Snewton
18543412Snewton    /*
18643412Snewton     * On entry, the dynamic linker itself has not been relocated yet.
18743412Snewton     * Be very careful not to reference any global data until after
18843412Snewton     * init_rtld has returned.  It is OK to reference file-scope statics
18983366Sjulian     * and string constants, and to call static and global functions.
19043412Snewton     */
191107849Salfred
192107849Salfred    /* Find the auxiliary vector on the stack. */
193107849Salfred    argc = *sp++;
19443412Snewton    argv = (char **) sp;
19583366Sjulian    sp += argc + 1;	/* Skip over arguments and NULL terminator */
19643412Snewton    env = (char **) sp;
19743412Snewton    while (*sp++ != 0)	/* Skip over environment, and NULL terminator */
19843412Snewton	;
19983366Sjulian    aux = (Elf_Auxinfo *) sp;
20083366Sjulian
20143412Snewton    /* Digest the auxiliary vector. */
20243412Snewton    for (i = 0;  i < AT_COUNT;  i++)
20343412Snewton	aux_info[i] = NULL;
20443412Snewton    for (auxp = aux;  auxp->a_type != AT_NULL;  auxp++) {
20543412Snewton	if (auxp->a_type < AT_COUNT)
20643412Snewton	    aux_info[auxp->a_type] = auxp;
20743412Snewton    }
208107849Salfred
209107849Salfred    /* Initialize and relocate ourselves. */
210107849Salfred    assert(aux_info[AT_BASE] != NULL);
21183366Sjulian    init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr);
21243412Snewton
21343412Snewton    __progname = obj_rtld.path;
21443412Snewton    environ = env;
21543412Snewton
21643412Snewton    trust = geteuid() == getuid() && getegid() == getgid();
21743412Snewton
21843412Snewton    ld_bind_now = getenv("LD_BIND_NOW");
21954494Snewton    if (trust) {
22043412Snewton	ld_debug = getenv("LD_DEBUG");
22154494Snewton	ld_library_path = getenv("LD_LIBRARY_PATH");
22254494Snewton    }
22354494Snewton    ld_tracing = getenv("LD_TRACE_LOADED_OBJECTS");
22443412Snewton
22543412Snewton    if (ld_debug != NULL && *ld_debug != '\0')
22683366Sjulian	debug = 1;
22783366Sjulian    dbg("%s is initialized, base address = %p", __progname,
22843412Snewton	(caddr_t) aux_info[AT_BASE]->a_un.a_ptr);
22943412Snewton
23054494Snewton    /*
23143412Snewton     * Load the main program, or process its program header if it is
23254494Snewton     * already loaded.
23354494Snewton     */
23454494Snewton    if (aux_info[AT_EXECFD] != NULL) {	/* Load the main program. */
23554494Snewton	int fd = aux_info[AT_EXECFD]->a_un.a_val;
23643412Snewton	dbg("loading main program");
23743412Snewton	obj_main = map_object(fd);
23843412Snewton	close(fd);
23954494Snewton	if (obj_main == NULL)
24054494Snewton	    die();
24154494Snewton    } else {				/* Main program already loaded. */
24254494Snewton	const Elf_Phdr *phdr;
24354494Snewton	int phnum;
24443412Snewton	caddr_t entry;
24554494Snewton
246107849Salfred	dbg("processing main program's program header");
247107849Salfred	assert(aux_info[AT_PHDR] != NULL);
24843412Snewton	phdr = (const Elf_Phdr *) aux_info[AT_PHDR]->a_un.a_ptr;
24954494Snewton	assert(aux_info[AT_PHNUM] != NULL);
25043412Snewton	phnum = aux_info[AT_PHNUM]->a_un.a_val;
25189306Salfred	assert(aux_info[AT_PHENT] != NULL);
25289306Salfred	assert(aux_info[AT_PHENT]->a_un.a_val == sizeof(Elf_Phdr));
25343412Snewton	assert(aux_info[AT_ENTRY] != NULL);
25489306Salfred	entry = (caddr_t) aux_info[AT_ENTRY]->a_un.a_ptr;
25543412Snewton	obj_main = digest_phdr(phdr, phnum, entry);
256116678Sphk    }
25754494Snewton
25889306Salfred    obj_main->path = xstrdup(argv[0]);
25989306Salfred    obj_main->mainprog = true;
26043412Snewton    digest_dynamic(obj_main);
26189306Salfred
26243412Snewton    linkmap_add(obj_main);
263107849Salfred    linkmap_add(&obj_rtld);
26454494Snewton
26554494Snewton    /* Link the main program into the list of objects. */
26654494Snewton    *obj_tail = obj_main;
26754494Snewton    obj_tail = &obj_main->next;
26854494Snewton    obj_main->refcount++;
26954494Snewton
27054494Snewton    dbg("loading needed objects");
27154494Snewton    if (load_needed_objects(obj_main) == -1)
27254494Snewton	die();
27354494Snewton    main_tail = obj_tail;
27454494Snewton
275111119Simp    if (ld_tracing) {		/* We're done */
27683366Sjulian	trace_loaded_objects(obj_main);
27743412Snewton	exit(0);
27843412Snewton    }
27943412Snewton
28043412Snewton    dbg("relocating objects");
28143412Snewton    if (relocate_objects(obj_main,
28243412Snewton	ld_bind_now != NULL && *ld_bind_now != '\0') == -1)
28343412Snewton	die();
28483366Sjulian
28543412Snewton    dbg("doing copy relocations");
28643412Snewton    if (do_copy_relocations(obj_main) == -1)
28743412Snewton	die();
28854494Snewton
28954494Snewton    dbg("calling _init functions");
29054494Snewton    call_init_functions(obj_main->next);
29154494Snewton
29254494Snewton    dbg("transferring control to program entry point = %p", obj_main->entry);
293101709Srwatson
294101709Srwatson    r_debug_state();		/* say hello to gdb! */
295101709Srwatson
296101924Srwatson    /* Return the exit procedure and the program entry point. */
297101709Srwatson    *exit_proc = rtld_exit;
298101709Srwatson    *objp = obj_main;
29954494Snewton    return (func_ptr_type) obj_main->entry;
30054494Snewton}
30154494Snewton
30243412Snewtoncaddr_t
30354494Snewton_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
30443412Snewton{
30543412Snewton    const Elf_Rel *rel;
306107849Salfred    const Elf_Sym *def;
30754494Snewton    const Obj_Entry *defobj;
30854494Snewton    Elf_Addr *where;
30943412Snewton    caddr_t target;
31054494Snewton
31143412Snewton    if (obj->pltrel)
31254494Snewton	rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff);
31354494Snewton    else
31454494Snewton	rel = (const Elf_Rel *) ((caddr_t) obj->pltrela + reloff);
31554494Snewton
31654494Snewton    where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
31754494Snewton    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
31854494Snewton    if (def == NULL)
31954494Snewton	die();
32054494Snewton
32154494Snewton    target = (caddr_t) (defobj->relocbase + def->st_value);
32254494Snewton
32354494Snewton    dbg("\"%s\" in \"%s\" ==> %p in \"%s\"",
32454494Snewton      defobj->strtab + def->st_name, basename(obj->path),
32554494Snewton      target, basename(defobj->path));
32654494Snewton
32754494Snewton    *where = (Elf_Addr) target;
32854494Snewton    return target;
32954494Snewton}
33054494Snewton
33154494Snewton/*
33254494Snewton * Error reporting function.  Use it like printf.  If formats the message
33354494Snewton * into a buffer, and sets things up so that the next call to dlerror()
33454494Snewton * will return the message.
33543412Snewton */
33654494Snewtonvoid
33754494Snewton_rtld_error(const char *fmt, ...)
33854494Snewton{
33954494Snewton    static char buf[512];
34054494Snewton    va_list ap;
34154494Snewton
34243412Snewton    va_start(ap, fmt);
34354494Snewton    vsnprintf(buf, sizeof buf, fmt, ap);
34454494Snewton    error_message = buf;
34554494Snewton    va_end(ap);
34654494Snewton}
34754494Snewton
34854494Snewton#ifdef DEBUG
34954494Snewtonstatic const char *
35043412Snewtonbasename(const char *name)
35143412Snewton{
35254494Snewton    const char *p = strrchr(name, '/');
35354494Snewton    return p != NULL ? p + 1 : name;
35443412Snewton}
35543412Snewton#endif
35643412Snewton
35754494Snewtonstatic void
35854494Snewtoncall_fini_functions(Obj_Entry *first)
35954494Snewton{
36054494Snewton    Obj_Entry *obj;
36154494Snewton
36254494Snewton    for (obj = first;  obj != NULL;  obj = obj->next)
36354494Snewton	if (obj->fini != NULL)
36454494Snewton	    (*obj->fini)();
36554494Snewton}
36654494Snewton
36754494Snewtonstatic void
36854494Snewtoncall_init_functions(Obj_Entry *first)
36954494Snewton{
37043412Snewton    if (first != NULL) {
37143412Snewton	call_init_functions(first->next);
37254494Snewton	if (first->init != NULL)
37354494Snewton	    (*first->init)();
37454494Snewton    }
37554494Snewton}
37654494Snewton
37754494Snewtonstatic void
37854494Snewtondie(void)
37954494Snewton{
38054494Snewton    const char *msg = dlerror();
38154494Snewton
38254494Snewton    if (msg == NULL)
38354494Snewton	msg = "Fatal error";
384107849Salfred    errx(1, "%s", msg);
38543412Snewton}
38654494Snewton
38743412Snewton/*
38854494Snewton * Process a shared object's DYNAMIC section, and save the important
38954494Snewton * information in its Obj_Entry structure.
39054494Snewton */
39143412Snewtonstatic void
39283366Sjuliandigest_dynamic(Obj_Entry *obj)
39343412Snewton{
39489306Salfred    const Elf_Dyn *dynp;
39589306Salfred    Needed_Entry **needed_tail = &obj->needed;
39654494Snewton    const Elf_Dyn *dyn_rpath = NULL;
39754494Snewton    int plttype = DT_REL;
39843412Snewton
39943412Snewton    for (dynp = obj->dynamic;  dynp->d_tag != DT_NULL;  dynp++) {
40043412Snewton	switch (dynp->d_tag) {
40143412Snewton
40243412Snewton	case DT_REL:
40343412Snewton	    obj->rel = (const Elf_Rel *) (obj->relocbase + dynp->d_un.d_ptr);
40483366Sjulian	    break;
40583366Sjulian
40643412Snewton	case DT_RELSZ:
40743412Snewton	    obj->relsize = dynp->d_un.d_val;
40843412Snewton	    break;
40943412Snewton
41043412Snewton	case DT_RELENT:
41143412Snewton	    assert(dynp->d_un.d_val == sizeof(Elf_Rel));
41243412Snewton	    break;
41343412Snewton
41443412Snewton	case DT_JMPREL:
41543412Snewton	    obj->pltrel = (const Elf_Rel *)
41643412Snewton	      (obj->relocbase + dynp->d_un.d_ptr);
41743412Snewton	    break;
41843412Snewton
41943412Snewton	case DT_PLTRELSZ:
42043412Snewton	    obj->pltrelsize = dynp->d_un.d_val;
42183366Sjulian	    break;
42243412Snewton
423121275Stjr	case DT_RELA:
424121275Stjr	    obj->rela = (const Elf_Rela *) (obj->relocbase + dynp->d_un.d_ptr);
425121275Stjr	    break;
426107849Salfred
42743412Snewton	case DT_RELASZ:
42843412Snewton	    obj->relasize = dynp->d_un.d_val;
42989306Salfred	    break;
43089306Salfred
43143412Snewton	case DT_RELAENT:
43289306Salfred	    assert(dynp->d_un.d_val == sizeof(Elf_Rela));
43343412Snewton	    break;
434116678Sphk
43589306Salfred	case DT_PLTREL:
43689306Salfred	    plttype = dynp->d_un.d_val;
43743412Snewton	    assert(dynp->d_un.d_val == DT_REL || plttype == DT_RELA);
43889306Salfred	    break;
43943412Snewton
440107849Salfred	case DT_SYMTAB:
441111119Simp	    obj->symtab = (const Elf_Sym *)
44283366Sjulian	      (obj->relocbase + dynp->d_un.d_ptr);
44343412Snewton	    break;
44443412Snewton
44543412Snewton	case DT_SYMENT:
44643412Snewton	    assert(dynp->d_un.d_val == sizeof(Elf_Sym));
44743412Snewton	    break;
44843412Snewton
44943412Snewton	case DT_STRTAB:
45043412Snewton	    obj->strtab = (const char *) (obj->relocbase + dynp->d_un.d_ptr);
45183366Sjulian	    break;
45243412Snewton
45343412Snewton	case DT_STRSZ:
454101709Srwatson	    obj->strsize = dynp->d_un.d_val;
455101709Srwatson	    break;
456101709Srwatson
457101709Srwatson	case DT_HASH:
458101709Srwatson	    {
459101709Srwatson		const Elf_Addr *hashtab = (const Elf_Addr *)
460101709Srwatson		  (obj->relocbase + dynp->d_un.d_ptr);
46143412Snewton		obj->nbuckets = hashtab[0];
46243412Snewton		obj->nchains = hashtab[1];
46343412Snewton		obj->buckets = hashtab + 2;
46443412Snewton		obj->chains = obj->buckets + obj->nbuckets;
46543412Snewton	    }
46643412Snewton	    break;
46789306Salfred
46843412Snewton	case DT_NEEDED:
46989306Salfred	    assert(!obj->rtld);
47043412Snewton	    {
47143412Snewton		Needed_Entry *nep = NEW(Needed_Entry);
472107849Salfred		nep->name = dynp->d_un.d_val;
473107849Salfred		nep->obj = NULL;
47443412Snewton		nep->next = NULL;
47543412Snewton
47643412Snewton		*needed_tail = nep;
47743412Snewton		needed_tail = &nep->next;
47843412Snewton	    }
47943412Snewton	    break;
48043412Snewton
48154494Snewton	case DT_PLTGOT:
48243412Snewton	    obj->got = (Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr);
48343412Snewton	    break;
48454494Snewton
48543412Snewton	case DT_TEXTREL:
48643412Snewton	    obj->textrel = true;
48743412Snewton	    break;
48843412Snewton
48943412Snewton	case DT_SYMBOLIC:
49043412Snewton	    obj->symbolic = true;
49143412Snewton	    break;
49243412Snewton
49343412Snewton	case DT_RPATH:
49443412Snewton	    /*
49543412Snewton	     * We have to wait until later to process this, because we
49643412Snewton	     * might not have gotten the address of the string table yet.
49743412Snewton	     */
49843412Snewton	    dyn_rpath = dynp;
49943412Snewton	    break;
50043412Snewton
50143412Snewton	case DT_SONAME:
50243412Snewton	    /* Not used by the dynamic linker. */
50343412Snewton	    break;
50443412Snewton
50543412Snewton	case DT_INIT:
50643412Snewton	    obj->init = (void (*)(void)) (obj->relocbase + dynp->d_un.d_ptr);
50743412Snewton	    break;
50843412Snewton
50943412Snewton	case DT_FINI:
51043412Snewton	    obj->fini = (void (*)(void)) (obj->relocbase + dynp->d_un.d_ptr);
51143412Snewton	    break;
51243412Snewton
51343412Snewton	case DT_DEBUG:
51443412Snewton	    /* XXX - not implemented yet */
51543412Snewton	    dbg("Filling in DT_DEBUG entry");
51643412Snewton	    ((Elf_Dyn*)dynp)->d_un.d_ptr = (Elf_Addr) &r_debug;
517107849Salfred	    break;
51843412Snewton
51943412Snewton	default:
52043412Snewton	    xprintf("Ignored d_tag %d\n",dynp->d_tag);
52143412Snewton            break;
522107849Salfred	}
52343412Snewton    }
52483366Sjulian
52589306Salfred    obj->traced = false;
52643412Snewton
52743412Snewton    if (plttype == DT_RELA) {
52843412Snewton	obj->pltrela = (const Elf_Rela *) obj->pltrel;
52943412Snewton	obj->pltrel = NULL;
53043412Snewton	obj->pltrelasize = obj->pltrelsize;
53143412Snewton	obj->pltrelsize = 0;
53243412Snewton    }
53343412Snewton
53483366Sjulian    if (dyn_rpath != NULL)
53583366Sjulian	obj->rpath = obj->strtab + dyn_rpath->d_un.d_val;
53643412Snewton}
53743412Snewton
53843412Snewton/*
53943412Snewton * Process a shared object's program header.  This is used only for the
54043412Snewton * main program, when the kernel has already loaded the main program
54183366Sjulian * into memory before calling the dynamic linker.  It creates and
54243412Snewton * returns an Obj_Entry structure.
54343412Snewton */
54443412Snewtonstatic Obj_Entry *
54543412Snewtondigest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
546107849Salfred{
54743412Snewton    Obj_Entry *obj = CNEW(Obj_Entry);
54843412Snewton    const Elf_Phdr *phlimit = phdr + phnum;
549107849Salfred    const Elf_Phdr *ph;
55043412Snewton    int nsegs = 0;
55143412Snewton
552107849Salfred    for (ph = phdr;  ph < phlimit;  ph++) {
553107849Salfred	switch (ph->p_type) {
554107849Salfred
555107849Salfred	case PT_PHDR:
556107849Salfred	    assert((const Elf_Phdr *) ph->p_vaddr == phdr);
557107849Salfred	    obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
55843412Snewton	    obj->phsize = ph->p_memsz;
55983366Sjulian	    break;
56043412Snewton
56143412Snewton	case PT_LOAD:
56243412Snewton	    assert(nsegs < 2);
56383366Sjulian	    if (nsegs == 0) {	/* First load segment */
56483366Sjulian		obj->vaddrbase = trunc_page(ph->p_vaddr);
56543412Snewton		obj->mapbase = (caddr_t) obj->vaddrbase;
56643412Snewton		obj->relocbase = obj->mapbase - obj->vaddrbase;
56743412Snewton		obj->textsize = round_page(ph->p_vaddr + ph->p_memsz) -
56843412Snewton		  obj->vaddrbase;
56943412Snewton	    } else {		/* Last load segment */
57043412Snewton		obj->mapsize = round_page(ph->p_vaddr + ph->p_memsz) -
57143412Snewton		  obj->vaddrbase;
57243412Snewton	    }
57343412Snewton	    nsegs++;
574107849Salfred	    break;
57543412Snewton
57643412Snewton	case PT_DYNAMIC:
577107849Salfred	    obj->dynamic = (const Elf_Dyn *) ph->p_vaddr;
57843412Snewton	    break;
57943412Snewton	}
580107849Salfred    }
581107849Salfred    assert(nsegs == 2);
582107849Salfred
583107849Salfred    obj->entry = entry;
584107849Salfred    return obj;
585107849Salfred}
58643412Snewton
58784783Spsstatic Obj_Entry *
588107849Salfreddlcheck(void *handle)
589107849Salfred{
590107849Salfred    Obj_Entry *obj;
59143412Snewton
59283366Sjulian    for (obj = obj_list;  obj != NULL;  obj = obj->next)
59343412Snewton	if (obj == (Obj_Entry *) handle)
59443412Snewton	    break;
59543412Snewton
59643412Snewton    if (obj == NULL || obj->dl_refcount == 0) {
59783366Sjulian	_rtld_error("Invalid shared object handle %p", handle);
59883366Sjulian	return NULL;
59943412Snewton    }
60043412Snewton    return obj;
60183366Sjulian}
60289535Salfred
60343412Snewton/*
60443412Snewton * Hash function for symbol table lookup.  Don't even think about changing
60543412Snewton * this.  It is specified by the System V ABI.
60693593Sjhb */
60743412Snewtonunsigned long
608107849Salfredelf_hash(const char *name)
60943412Snewton{
610116678Sphk    const unsigned char *p = (const unsigned char *) name;
61183366Sjulian    unsigned long h = 0;
61243412Snewton    unsigned long g;
61343412Snewton
61471699Sjhb    while (*p != '\0') {
61591406Sjhb	h = (h << 4) + *p++;
61683366Sjulian	if ((g = h & 0xf0000000) != 0)
61789535Salfred	    h ^= g >> 24;
61889306Salfred	h &= ~g;
61943412Snewton    }
62089306Salfred    return h;
62143412Snewton}
622137647Sphk
62389306Salfred/*
62443412Snewton * Find the library with the given name, and return its full pathname.
625137647Sphk * The returned string is dynamically allocated.  Generates an error
62689306Salfred * message and returns NULL if the library cannot be found.
62789306Salfred *
62889306Salfred * If the second argument is non-NULL, then it refers to an already-
62943412Snewton * loaded shared object, whose library search path will be searched.
63043412Snewton *
63143412Snewton * The search order is:
63243412Snewton *   LD_LIBRARY_PATH
63343412Snewton *   ldconfig hints
63483366Sjulian *   rpath in the referencing file
63583366Sjulian *   /usr/lib
63643412Snewton */
63743412Snewtonstatic char *
63843412Snewtonfind_library(const char *name, const Obj_Entry *refobj)
63943412Snewton{
64043412Snewton    char *pathname;
64143412Snewton
64243412Snewton    if (strchr(name, '/') != NULL) {	/* Hard coded pathname */
64383366Sjulian	if (name[0] != '/' && !trust) {
64443412Snewton	    _rtld_error("Absolute pathname required for shared object \"%s\"",
64543412Snewton	      name);
64643412Snewton	    return NULL;
647107849Salfred	}
648107849Salfred	return xstrdup(name);
64983366Sjulian    }
65043412Snewton
65143412Snewton    dbg(" Searching for \"%s\"", name);
652107849Salfred
653107849Salfred    if ((pathname = search_library_path(name, ld_library_path)) != NULL ||
654107849Salfred      (pathname = search_library_path(name, gethints())) != NULL ||
65583366Sjulian      (refobj != NULL &&
65643412Snewton      (pathname = search_library_path(name, refobj->rpath)) != NULL) ||
65743412Snewton      (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL)
65843412Snewton	return pathname;
65943412Snewton
66043412Snewton    _rtld_error("Shared object \"%s\" not found", name);
66183366Sjulian    return NULL;
66283366Sjulian}
66343412Snewton
66443412Snewton/*
66583366Sjulian * Given a symbol number in a referencing object, find the corresponding
66683366Sjulian * definition of the symbol.  Returns a pointer to the symbol, or NULL if
667107849Salfred * no definition was found.  Returns a pointer to the Obj_Entry of the
668107849Salfred * defining object via the reference parameter DEFOBJ_OUT.
66943412Snewton */
67043412Snewtonconst Elf_Sym *
67143412Snewtonfind_symdef(unsigned long symnum, const Obj_Entry *refobj,
67243412Snewton    const Obj_Entry **defobj_out, bool in_plt)
67383366Sjulian{
67483366Sjulian    const Elf_Sym *ref;
67543412Snewton    const Elf_Sym *strongdef;
67643412Snewton    const Elf_Sym *weakdef;
67783366Sjulian    const Obj_Entry *obj;
67883366Sjulian    const Obj_Entry *strongobj;
679107849Salfred    const Obj_Entry *weakobj;
680107849Salfred    const char *name;
68143412Snewton    unsigned long hash;
68243412Snewton
68343412Snewton    ref = refobj->symtab + symnum;
68443412Snewton    name = refobj->strtab + ref->st_name;
68583366Sjulian    hash = elf_hash(name);
68683366Sjulian
68743412Snewton    if (refobj->symbolic) {	/* Look first in the referencing object */
68843412Snewton	const Elf_Sym *def = symlook_obj(name, hash, refobj, in_plt);
68943412Snewton	if (def != NULL) {
69043412Snewton	    *defobj_out = refobj;
69143412Snewton	    return def;
69243412Snewton	}
69343412Snewton    }
69483366Sjulian
69583366Sjulian    /*
69643412Snewton     * Look in all loaded objects.  Skip the referencing object, if
69743412Snewton     * we have already searched it.  We keep track of the first weak
69843412Snewton     * definition and the first strong definition we encounter.  If
69943412Snewton     * we find a strong definition we stop searching, because there
70083366Sjulian     * won't be anything better than that.
70143412Snewton     */
702107849Salfred    strongdef = weakdef = NULL;
70343412Snewton    strongobj = weakobj = NULL;
70443412Snewton    for (obj = obj_list;  obj != NULL;  obj = obj->next) {
70543412Snewton	if (obj != refobj || !refobj->symbolic) {
70643412Snewton	    const Elf_Sym *def = symlook_obj(name, hash, obj, in_plt);
70743412Snewton	    if (def != NULL) {
70843412Snewton		if (ELF_ST_BIND(def->st_info) == STB_WEAK) {
70943412Snewton		    if (weakdef == NULL) {
71043412Snewton			weakdef = def;
71143412Snewton			weakobj = obj;
71243412Snewton		    }
71343412Snewton		} else {
71443412Snewton		    strongdef = def;
71543412Snewton		    strongobj = obj;
71643412Snewton		    break;	/* We are done. */
71743412Snewton		}
71843412Snewton	    }
71943412Snewton	}
72043412Snewton    }
72143412Snewton
72243412Snewton    /*
72343412Snewton     * If we still don't have a strong definition, search the dynamic
72443412Snewton     * linker itself, and possibly resolve the symbol from there.
72543412Snewton     * This is how the application links to dynamic linker services
72643412Snewton     * such as dlopen.  Only the values listed in the "exports" array
72743412Snewton     * can be resolved from the dynamic linker.
72843412Snewton     */
72943412Snewton    if (strongdef == NULL) {
73043412Snewton	const Elf_Sym *def = symlook_obj(name, hash, &obj_rtld, in_plt);
73143412Snewton	if (def != NULL && is_exported(def)) {
73243412Snewton	    if (ELF_ST_BIND(def->st_info) == STB_WEAK) {
73343412Snewton		if (weakdef == NULL) {
73443412Snewton		    weakdef = def;
73543412Snewton		    weakobj = &obj_rtld;
73643412Snewton		}
73743412Snewton	    } else {
73843412Snewton		strongdef = def;
73943412Snewton		strongobj = &obj_rtld;
74043412Snewton	    }
74143412Snewton	}
74243412Snewton    }
74343412Snewton
74443412Snewton    if (strongdef != NULL) {
74543412Snewton	*defobj_out = strongobj;
74643412Snewton	return strongdef;
74743412Snewton    }
74843412Snewton    if (weakdef != NULL) {
74943412Snewton	*defobj_out = weakobj;
75043412Snewton	return weakdef;
75143412Snewton    }
75243412Snewton
75343412Snewton    _rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name);
75443412Snewton    return NULL;
75543412Snewton}
75643412Snewton
75743412Snewton/*
75843412Snewton * Return the search path from the ldconfig hints file, reading it if
75943412Snewton * necessary.  Returns NULL if there are problems with the hints file,
76043412Snewton * or if the search path there is empty.
76143412Snewton */
76243412Snewtonstatic const char *
76343412Snewtongethints(void)
76443412Snewton{
76543412Snewton    static char *hints;
76643412Snewton
76743412Snewton    if (hints == NULL) {
76843412Snewton	int fd;
76943412Snewton	struct elfhints_hdr hdr;
77043412Snewton	char *p;
77143412Snewton
77243412Snewton	/* Keep from trying again in case the hints file is bad. */
77343412Snewton	hints = "";
77443412Snewton
77543412Snewton	if ((fd = open(_PATH_ELF_HINTS, O_RDONLY)) == -1)
77643412Snewton	    return NULL;
77743412Snewton	if (read(fd, &hdr, sizeof hdr) != sizeof hdr ||
77843412Snewton	  hdr.magic != ELFHINTS_MAGIC ||
77943412Snewton	  hdr.version != 1) {
78043412Snewton	    close(fd);
78143412Snewton	    return NULL;
78243412Snewton	}
78343412Snewton	p = xmalloc(hdr.dirlistlen + 1);
78443412Snewton	if (lseek(fd, hdr.strtab + hdr.dirlist, SEEK_SET) == -1 ||
78543412Snewton	  read(fd, p, hdr.dirlistlen + 1) != hdr.dirlistlen + 1) {
78643412Snewton	    free(p);
78743412Snewton	    close(fd);
78843412Snewton	    return NULL;
78943412Snewton	}
79043412Snewton	hints = p;
79143412Snewton	close(fd);
79243412Snewton    }
79343412Snewton    return hints[0] != '\0' ? hints : NULL;
79483366Sjulian}
79583366Sjulian
79643412Snewton/*
79743412Snewton * Initialize the dynamic linker.  The argument is the address at which
798102727Sjake * the dynamic linker has been mapped into memory.  The primary task of
799102727Sjake * this function is to relocate the dynamic linker.
80043412Snewton */
80143412Snewtonstatic void
80243412Snewtoninit_rtld(caddr_t mapbase)
80343412Snewton{
804107849Salfred    /*
80543412Snewton     * Conjure up an Obj_Entry structure for the dynamic linker.
80643412Snewton     *
807125454Sjhb     * The "path" member is supposed to be dynamically-allocated, but we
808125454Sjhb     * aren't yet initialized sufficiently to do that.  Below we will
809125454Sjhb     * replace the static version with a dynamically-allocated copy.
81043412Snewton     */
811125454Sjhb    obj_rtld.path = "/usr/libexec/ld-elf.so.1";
812125454Sjhb    obj_rtld.rtld = true;
813125454Sjhb    obj_rtld.mapbase = mapbase;
814125454Sjhb    obj_rtld.relocbase = mapbase;
81543412Snewton    obj_rtld.got = get_got_address();
81643412Snewton#ifdef	__alpha__
81743412Snewton    obj_rtld.dynamic = (const Elf_Dyn *) &_DYNAMIC;
81843412Snewton#else
81943412Snewton    obj_rtld.dynamic = (const Elf_Dyn *) (obj_rtld.mapbase + obj_rtld.got[0]);
82043412Snewton#endif
82143412Snewton
82243412Snewton    digest_dynamic(&obj_rtld);
82343412Snewton#ifdef __alpha__
82443412Snewton/* XXX XXX XXX */
82543412Snewtonobj_rtld.got = NULL;
82643412Snewton#endif
82743412Snewton    assert(obj_rtld.needed == NULL);
82843412Snewton    assert(!obj_rtld.textrel);
829125454Sjhb
830125454Sjhb    /*
831125454Sjhb     * Temporarily put the dynamic linker entry into the object list, so
832102630Sdillon     * that symbols can be found.
833125454Sjhb     */
834125454Sjhb    obj_list = &obj_rtld;
83543412Snewton    obj_tail = &obj_rtld.next;
83643412Snewton
83743412Snewton    relocate_objects(&obj_rtld, true);
83843412Snewton
83943412Snewton    /* Make the object list empty again. */
84043412Snewton    obj_list = NULL;
84143412Snewton    obj_tail = &obj_list;
84243412Snewton
84343412Snewton    /* Replace the path with a dynamically allocated copy. */
84443412Snewton    obj_rtld.path = xstrdup(obj_rtld.path);
84543412Snewton
84643412Snewton    r_debug.r_brk = r_debug_state;
84743412Snewton    r_debug.r_state = RT_CONSISTENT;
84843412Snewton}
84943412Snewton
85043412Snewtonstatic bool
85143412Snewtonis_exported(const Elf_Sym *def)
85243412Snewton{
85343412Snewton    func_ptr_type value;
85443412Snewton    const func_ptr_type *p;
85543412Snewton
85643412Snewton    value = (func_ptr_type)(obj_rtld.relocbase + def->st_value);
85743412Snewton    for (p = exports;  *p != NULL;  p++)
85843412Snewton	if (*p == value)
85943412Snewton	    return true;
86043412Snewton    return false;
86183366Sjulian}
86283366Sjulian
86343412Snewton/*
86443412Snewton * Given a shared object, traverse its list of needed objects, and load
865136152Sjhb * each of them.  Returns 0 on success.  Generates an error message and
866136152Sjhb * returns -1 on failure.
867136152Sjhb */
868136152Sjhbstatic int
86943412Snewtonload_needed_objects(Obj_Entry *first)
870136152Sjhb{
871136152Sjhb    Obj_Entry *obj;
872136152Sjhb
873136152Sjhb    for (obj = first;  obj != NULL;  obj = obj->next) {
874136152Sjhb	Needed_Entry *needed;
87543412Snewton
876136152Sjhb	for (needed = obj->needed;  needed != NULL;  needed = needed->next) {
877136152Sjhb	    const char *name = obj->strtab + needed->name;
87843412Snewton	    char *path = find_library(name, obj);
879136152Sjhb
880136152Sjhb	    needed->obj = NULL;
88143412Snewton	    if (path == NULL && !ld_tracing)
882136152Sjhb		return -1;
88343412Snewton
884136152Sjhb	    if (path) {
88543412Snewton		needed->obj = load_object(path);
886136152Sjhb		if (needed->obj == NULL && !ld_tracing)
887136152Sjhb		    return -1;		/* XXX - cleanup */
888136152Sjhb	    }
88943412Snewton	}
89043412Snewton    }
89143412Snewton
89243412Snewton    return 0;
89383366Sjulian}
89483366Sjulian
89543412Snewton/*
89643412Snewton * Load a shared object into memory, if it is not already loaded.  The
89783366Sjulian * argument must be a string allocated on the heap.  This function assumes
898125454Sjhb * responsibility for freeing it when necessary.
89943412Snewton *
900107849Salfred * Returns a pointer to the Obj_Entry for the object.  Returns NULL
90143412Snewton * on failure.
902125454Sjhb */
903125454Sjhbstatic Obj_Entry *
904125454Sjhbload_object(char *path)
90543412Snewton{
90643412Snewton    Obj_Entry *obj;
90743412Snewton
90843412Snewton    for (obj = obj_list->next;  obj != NULL;  obj = obj->next)
90943412Snewton	if (strcmp(obj->path, path) == 0)
91043412Snewton	    break;
91143412Snewton
91243412Snewton    if (obj == NULL) {	/* First use of this object, so we must map it in */
913107849Salfred	int fd;
914125454Sjhb
915125454Sjhb	if ((fd = open(path, O_RDONLY)) == -1) {
916125454Sjhb	    _rtld_error("Cannot open \"%s\"", path);
91743412Snewton	    return NULL;
918125454Sjhb	}
91943412Snewton	obj = map_object(fd);
92043412Snewton	close(fd);
92143412Snewton	if (obj == NULL) {
922125454Sjhb	    free(path);
923125454Sjhb	    return NULL;
924125454Sjhb	}
92543412Snewton
92643412Snewton	obj->path = path;
92743412Snewton	digest_dynamic(obj);
92843412Snewton
92943412Snewton	*obj_tail = obj;
93043412Snewton	obj_tail = &obj->next;
93143412Snewton	linkmap_add(obj);	/* for GDB */
93283366Sjulian
93371452Sjhb	dbg("  %p .. %p: %s", obj->mapbase,
93443412Snewton	  obj->mapbase + obj->mapsize - 1, obj->path);
935125454Sjhb	if (obj->textrel)
936125454Sjhb	    dbg("  WARNING: %s has impure text", obj->path);
937125454Sjhb    } else
93871452Sjhb	free(path);
93943412Snewton
94043412Snewton    obj->refcount++;
941125454Sjhb    return obj;
94243412Snewton}
943125454Sjhb
94443412Snewtonstatic Obj_Entry *
94543412Snewtonobj_from_addr(const void *addr)
94643412Snewton{
94743412Snewton    unsigned long endhash;
94843412Snewton    Obj_Entry *obj;
94943412Snewton
95043412Snewton    endhash = elf_hash(END_SYM);
951125454Sjhb    for (obj = obj_list;  obj != NULL;  obj = obj->next) {
952125454Sjhb	const Elf_Sym *endsym;
953125454Sjhb
95443412Snewton	if (addr < (void *) obj->mapbase)
95543412Snewton	    continue;
95643412Snewton	if ((endsym = symlook_obj(END_SYM, endhash, obj, true)) == NULL)
95743412Snewton	    continue;	/* No "end" symbol?! */
95843412Snewton	if (addr < (void *) (obj->relocbase + endsym->st_value))
95943412Snewton	    return obj;
96043412Snewton    }
96143412Snewton    return NULL;
96243412Snewton}
96343412Snewton
96443412Snewton/*
96543412Snewton * Relocate newly-loaded shared objects.  The argument is a pointer to
96643412Snewton * the Obj_Entry for the first such object.  All objects from the first
96743412Snewton * to the end of the list of objects are relocated.  Returns 0 on success,
96843412Snewton * or -1 on failure.
96943412Snewton */
97071452Sjhbstatic int
97171452Sjhbrelocate_objects(Obj_Entry *first, bool bind_now)
97271452Sjhb{
97343412Snewton    Obj_Entry *obj;
97469947Sjake
97543412Snewton    for (obj = first;  obj != NULL;  obj = obj->next) {
97643412Snewton	if (obj->nbuckets == 0 || obj->nchains == 0 || obj->buckets == NULL ||
97743412Snewton	    obj->symtab == NULL || obj->strtab == NULL) {
97843412Snewton	    _rtld_error("%s: Shared object has no run-time symbol table",
97983366Sjulian	      obj->path);
98083366Sjulian	    return -1;
98143412Snewton	}
98243412Snewton
98383366Sjulian	if (obj->textrel) {
98483366Sjulian	    /* There are relocations to the write-protected text segment. */
98543412Snewton	    if (mprotect(obj->mapbase, obj->textsize,
986107849Salfred	      PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
98743412Snewton		_rtld_error("%s: Cannot write-enable text segment: %s",
98843412Snewton		  obj->path, strerror(errno));
98943412Snewton		return -1;
99043412Snewton	    }
99143412Snewton	}
99243412Snewton
99343412Snewton	/* Process the non-PLT relocations. */
99443412Snewton	if (reloc_non_plt(obj, &obj_rtld))
99583366Sjulian		return -1;
99643412Snewton
99743412Snewton	if (obj->textrel) {	/* Re-protected the text segment. */
99843412Snewton	    if (mprotect(obj->mapbase, obj->textsize,
99991140Stanimura	      PROT_READ|PROT_EXEC) == -1) {
100043412Snewton		_rtld_error("%s: Cannot write-protect text segment: %s",
100191140Stanimura		  obj->path, strerror(errno));
100243412Snewton		return -1;
100343412Snewton	    }
100443412Snewton	}
1005107849Salfred
100689545Stanimura	/* Process the PLT relocations. */
1007107849Salfred	if (reloc_plt(obj, bind_now))
100843412Snewton		return -1;
100943412Snewton
101043412Snewton	/*
101143412Snewton	 * Set up the magic number and version in the Obj_Entry.  These
101243412Snewton	 * were checked in the crt1.o from the original ElfKit, so we
101389541Stanimura	 * set them for backward compatibility.
101475893Sjhb	 */
101543412Snewton	obj->magic = RTLD_MAGIC;
101643412Snewton	obj->version = RTLD_VERSION;
101743412Snewton
101883366Sjulian	/* Set the special GOT entries. */
101943412Snewton	if (obj->got) {
102043412Snewton#ifdef __i386__
102143412Snewton	    obj->got[1] = (Elf_Addr) obj;
1022107849Salfred	    obj->got[2] = (Elf_Addr) &_rtld_bind_start;
102389545Stanimura#endif
1024107849Salfred#ifdef __alpha__
102543412Snewton	    /* This function will be called to perform the relocation.  */
102643412Snewton	    obj->got[2] = (Elf_Addr) &_rtld_bind_start;
102743412Snewton	    /* Identify this shared object */
102875893Sjhb	    obj->got[3] = (Elf_Addr) obj;
102943412Snewton#endif
103043412Snewton	}
103143412Snewton    }
103243412Snewton
103343412Snewton    return 0;
103443412Snewton}
1035107849Salfred
1036107849Salfred/*
103783366Sjulian * Cleanup procedure.  It will be called (by the atexit mechanism) just
103843412Snewton * before the process exits.
103943412Snewton */
104043412Snewtonstatic void
104143412Snewtonrtld_exit(void)
104243412Snewton{
104343412Snewton    dbg("rtld_exit()");
104443412Snewton    call_fini_functions(obj_list->next);
104543412Snewton}
104643412Snewton
104743412Snewtonstatic char *
104843412Snewtonsearch_library_path(const char *name, const char *path)
104943412Snewton{
105043412Snewton    size_t namelen = strlen(name);
105143412Snewton    const char *p = path;
105243412Snewton
105343412Snewton    if (p == NULL)
105443412Snewton	return NULL;
105543412Snewton
105643412Snewton    p += strspn(p, ":;");
105783366Sjulian    while (*p != '\0') {
105883366Sjulian	size_t len = strcspn(p, ":;");
105943412Snewton
106043412Snewton	if (*p == '/' || trust) {
106143412Snewton	    char *pathname;
1062107849Salfred	    const char *dir = p;
106343412Snewton	    size_t dirlen = len;
106443412Snewton
106543412Snewton	    pathname = xmalloc(dirlen + 1 + namelen + 1);
106643412Snewton	    strncpy(pathname, dir, dirlen);
106743412Snewton	    pathname[dirlen] = '/';
106843412Snewton	    strcpy(pathname + dirlen + 1, name);
106943412Snewton
107043412Snewton	    dbg("  Trying \"%s\"", pathname);
107143412Snewton	    if (access(pathname, F_OK) == 0)		/* We found it */
107243412Snewton		return pathname;
1073107849Salfred
1074107849Salfred	    free(pathname);
107543412Snewton	}
107643412Snewton	p += len;
1077107849Salfred	p += strspn(p, ":;");
107843412Snewton    }
107943412Snewton
108043412Snewton    return NULL;
108143412Snewton}
108243412Snewton
108343412Snewtonint
108443412Snewtondlclose(void *handle)
1085107849Salfred{
108643412Snewton    Obj_Entry *root = dlcheck(handle);
108743412Snewton
108843412Snewton    if (root == NULL)
108943412Snewton	return -1;
109043412Snewton
109143412Snewton    GDB_STATE(RT_DELETE);
109243412Snewton
109343412Snewton    root->dl_refcount--;
109443412Snewton    unref_object_dag(root);
109543412Snewton    if (root->refcount == 0) {	/* We are finished with some objects. */
1096107849Salfred	Obj_Entry *obj;
109743412Snewton	Obj_Entry **linkp;
109843412Snewton
109943412Snewton	/* Finalize objects that are about to be unmapped. */
110043412Snewton	for (obj = obj_list->next;  obj != NULL;  obj = obj->next)
110143412Snewton	    if (obj->refcount == 0 && obj->fini != NULL)
110243412Snewton		(*obj->fini)();
110383366Sjulian
110483366Sjulian	/* Unmap all objects that are no longer referenced. */
110543412Snewton	linkp = &obj_list->next;
110643412Snewton	while ((obj = *linkp) != NULL) {
110783366Sjulian	    if (obj->refcount == 0) {
110843412Snewton		munmap(obj->mapbase, obj->mapsize);
1109107849Salfred		free(obj->path);
111043412Snewton		while (obj->needed != NULL) {
111183366Sjulian		    Needed_Entry *needed = obj->needed;
111243412Snewton		    obj->needed = needed->next;
111343412Snewton		    free(needed);
111443412Snewton		}
111543412Snewton		linkmap_delete(obj);
111643412Snewton		*linkp = obj->next;
111743412Snewton		free(obj);
111843412Snewton	    } else
111943412Snewton		linkp = &obj->next;
112043412Snewton	}
112143412Snewton    }
112243412Snewton
112343412Snewton    GDB_STATE(RT_CONSISTENT);
112443412Snewton
112543412Snewton    return 0;
112643412Snewton}
1127107849Salfred
112843412Snewtonconst char *
112943412Snewtondlerror(void)
113043412Snewton{
113143412Snewton    char *msg = error_message;
113243412Snewton    error_message = NULL;
113343412Snewton    return msg;
113443412Snewton}
113543412Snewton
113643412Snewtonvoid *
113743412Snewtondlopen(const char *name, int mode)
113843412Snewton{
1139136152Sjhb    Obj_Entry **old_obj_tail = obj_tail;
114043412Snewton    Obj_Entry *obj = NULL;
114143412Snewton
114243412Snewton    GDB_STATE(RT_ADD);
114343412Snewton
114443412Snewton    if (name == NULL)
114543412Snewton	obj = obj_main;
114643412Snewton    else {
114743412Snewton	char *path = find_library(name, NULL);
114843412Snewton	if (path != NULL)
114943412Snewton	    obj = load_object(path);
1150136152Sjhb    }
1151136152Sjhb
1152136152Sjhb    if (obj) {
1153136152Sjhb	obj->dl_refcount++;
1154136152Sjhb	if (*old_obj_tail != NULL) {		/* We loaded something new. */
115543412Snewton	    assert(*old_obj_tail == obj);
115643412Snewton
115743412Snewton	    /* XXX - Clean up properly after an error. */
115843412Snewton	    if (load_needed_objects(obj) == -1) {
115943412Snewton		obj->dl_refcount--;
116043412Snewton		obj = NULL;
116143412Snewton	    } else if (relocate_objects(obj, mode == RTLD_NOW) == -1) {
116243412Snewton		obj->dl_refcount--;
116351793Smarcel		obj = NULL;
116443412Snewton	    } else
116543412Snewton		call_init_functions(obj);
116643412Snewton	}
116743412Snewton    }
116843412Snewton
116943412Snewton    GDB_STATE(RT_CONSISTENT);
117043412Snewton
117143412Snewton    return obj;
117251793Smarcel}
117343412Snewton
117443412Snewtonvoid *
117543412Snewtondlsym(void *handle, const char *name)
117643412Snewton{
117743412Snewton    const Obj_Entry *obj;
117843412Snewton    unsigned long hash;
117943412Snewton    const Elf_Sym *def;
118043412Snewton
118143412Snewton    hash = elf_hash(name);
118243412Snewton    def = NULL;
118343412Snewton
118443412Snewton    if (handle == NULL || handle == RTLD_NEXT) {
118543412Snewton	void *retaddr;
118643412Snewton
118743412Snewton	retaddr = __builtin_return_address(0);	/* __GNUC__ only */
118883366Sjulian	if ((obj = obj_from_addr(retaddr)) == NULL) {
118983366Sjulian	    _rtld_error("Cannot determine caller's shared object");
119043412Snewton	    return NULL;
119143412Snewton	}
119243412Snewton	if (handle == NULL)	/* Just the caller's shared object. */
119383366Sjulian	    def = symlook_obj(name, hash, obj, true);
1194135762Sjhb	else {			/* All the shared objects after the caller's */
119543412Snewton	    while ((obj = obj->next) != NULL)
1196135762Sjhb		if ((def = symlook_obj(name, hash, obj, true)) != NULL)
1197107849Salfred		    break;
119843412Snewton	}
119943412Snewton    } else {
120043412Snewton	if ((obj = dlcheck(handle)) == NULL)
120143412Snewton	    return NULL;
1202135762Sjhb
1203135762Sjhb	if (obj->mainprog) {
1204135762Sjhb	    /* Search main program and all libraries loaded by it. */
120543412Snewton	    for ( ;  obj != *main_tail;  obj = obj->next)
120643412Snewton		if ((def = symlook_obj(name, hash, obj, true)) != NULL)
120743412Snewton		    break;
1208107849Salfred	} else {
120943412Snewton	    /*
121043412Snewton	     * XXX - This isn't correct.  The search should include the whole
121143412Snewton	     * DAG rooted at the given object.
121243412Snewton	     */
121343412Snewton	    def = symlook_obj(name, hash, obj, true);
121443412Snewton	}
121543412Snewton    }
1216107849Salfred
1217107849Salfred    if (def != NULL)
121843412Snewton	return obj->relocbase + def->st_value;
121943412Snewton
122043412Snewton    _rtld_error("Undefined symbol \"%s\"", name);
122174927Sjhb    return NULL;
1222135762Sjhb}
122389306Salfred
1224107849Salfredstatic void
1225107849Salfredlinkmap_add(Obj_Entry *obj)
1226107849Salfred{
122789306Salfred    struct link_map *l = &obj->linkmap;
122843412Snewton    struct link_map *prev;
1229107849Salfred
123043412Snewton    obj->linkmap.l_name = obj->path;
123143412Snewton    obj->linkmap.l_addr = obj->mapbase;
123243412Snewton    obj->linkmap.l_ld = obj->dynamic;
123399072Sjulian#ifdef __mips__
1234107849Salfred    /* GDB needs load offset on MIPS to use the symbols */
123571452Sjhb    obj->linkmap.l_offs = obj->relocbase;
123674927Sjhb#endif
123743412Snewton
123843412Snewton    if (r_debug.r_map == NULL) {
1239107849Salfred	r_debug.r_map = l;
124071452Sjhb	return;
124143412Snewton    }
124243412Snewton
124343412Snewton    /*
1244107849Salfred     * Scan to the end of the list, but not past the entry for the
124543412Snewton     * dynamic linker, which we want to keep at the very end.
124643412Snewton     */
124743412Snewton    for (prev = r_debug.r_map;
124843412Snewton      prev->l_next != NULL && prev->l_next != &obj_rtld.linkmap;
124943412Snewton      prev = prev->l_next)
125043412Snewton	;
125143412Snewton
125243412Snewton    /* Link in the new entry. */
125371452Sjhb    l->l_prev = prev;
125443412Snewton    l->l_next = prev->l_next;
125543412Snewton    if (l->l_next != NULL)
125643412Snewton	l->l_next->l_prev = l;
125774927Sjhb    prev->l_next = l;
125871452Sjhb}
125970317Sjake
126070317Sjakestatic void
126173907Sjhblinkmap_delete(Obj_Entry *obj)
126270317Sjake{
126391140Stanimura    struct link_map *l = &obj->linkmap;
126491140Stanimura
126591140Stanimura    if (l->l_prev == NULL) {
126691140Stanimura	if ((r_debug.r_map = l->l_next) != NULL)
126773907Sjhb	    l->l_next->l_prev = NULL;
126891140Stanimura	return;
126973907Sjhb    }
127070317Sjake
127171452Sjhb    if ((l->l_prev->l_next = l->l_next) != NULL)
127273907Sjhb	l->l_next->l_prev = l->l_prev;
127375893Sjhb}
127473907Sjhb
127574927Sjhb/*
127670317Sjake * Function for the debugger to set a breakpoint on to gain control.
127770317Sjake */
127873907Sjhbvoid
127973907Sjhbr_debug_state(void)
128074927Sjhb{
128143412Snewton}
1282136152Sjhb
1283136152Sjhb/*
128443412Snewton * Search the symbol table of a single shared object for a symbol of
1285135573Sjhb * the given name.  Returns a pointer to the symbol, or NULL if no
128643412Snewton * definition was found.
128743412Snewton *
128871452Sjhb * The symbol's hash value is passed in for efficiency reasons; that
128943412Snewton * eliminates many recomputations of the hash value.
129077183Srwatson */
129143412Snewtonconst Elf_Sym *
129243412Snewtonsymlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj,
129371452Sjhb  bool in_plt)
129443412Snewton{
129571452Sjhb    unsigned long symnum = obj->buckets[hash % obj->nbuckets];
129671452Sjhb
129743412Snewton    while (symnum != STN_UNDEF) {
129843412Snewton	const Elf_Sym *symp;
129943412Snewton	const char *strp;
130043412Snewton
130177183Srwatson	assert(symnum < obj->nchains);
130277183Srwatson	symp = obj->symtab + symnum;
130343412Snewton	assert(symp->st_name != 0);
130443412Snewton	strp = obj->strtab + symp->st_name;
130571452Sjhb
130643412Snewton	if (strcmp(name, strp) == 0)
130793295Salfred	    return symp->st_shndx != SHN_UNDEF ||
130871452Sjhb	      (!in_plt && symp->st_value != 0 &&
130943412Snewton	      ELF_ST_TYPE(symp->st_info) == STT_FUNC) ? symp : NULL;
131043412Snewton
131171452Sjhb	symnum = obj->chains[symnum];
131271452Sjhb    }
131371452Sjhb
131494858Sjhb    return NULL;
131571452Sjhb}
131671452Sjhb
131774927Sjhbstatic void
131871452Sjhbtrace_loaded_objects(Obj_Entry *obj)
131974927Sjhb{
132071452Sjhb    char	*fmt1, *fmt2, *fmt, *main_local;
132171452Sjhb    int		c;
132274927Sjhb
132371452Sjhb    if ((main_local = getenv("LD_TRACE_LOADED_OBJECTS_PROGNAME")) == NULL)
132471452Sjhb	main_local = "";
1325114983Sjhb
1326114983Sjhb    if ((fmt1 = getenv("LD_TRACE_LOADED_OBJECTS_FMT1")) == NULL)
132771452Sjhb	fmt1 = "\t%o => %p (%x)\n";
132871452Sjhb
132971452Sjhb    if ((fmt2 = getenv("LD_TRACE_LOADED_OBJECTS_FMT2")) == NULL)
133043412Snewton	fmt2 = "\t%o (%x)\n";
133143412Snewton
133243412Snewton    for (; obj; obj = obj->next) {
133343412Snewton	Needed_Entry		*needed;
1334109203Sdillon	char			*name, *path;
133543412Snewton	bool			is_lib;
133643412Snewton
133743412Snewton	for (needed = obj->needed; needed; needed = needed->next) {
133871452Sjhb	    if (needed->obj != NULL) {
133971452Sjhb		if (needed->obj->traced)
1340109203Sdillon		    continue;
1341109203Sdillon		needed->obj->traced = true;
1342109203Sdillon		path = needed->obj->path;
134392787Sjeff	    } else
134471452Sjhb		path = "not found";
134543412Snewton
134643412Snewton	    name = (char *)obj->strtab + needed->name;
134743412Snewton	    is_lib = strncmp(name, "lib", 3) == 0;	/* XXX - bogus */
134899072Sjulian
134999072Sjulian	    fmt = is_lib ? fmt1 : fmt2;
135043412Snewton	    while ((c = *fmt++) != '\0') {
1351107849Salfred		switch (c) {
135243412Snewton		default:
1353107849Salfred		    putchar(c);
135443412Snewton		    continue;
135571452Sjhb		case '\\':
135643412Snewton		    switch (c = *fmt) {
135743412Snewton		    case '\0':
1358107849Salfred			continue;
135943412Snewton		    case 'n':
136071452Sjhb			putchar('\n');
136143412Snewton			break;
136243412Snewton		    case 't':
136343412Snewton			putchar('\t');
136443412Snewton			break;
136543412Snewton		    }
1366107849Salfred		    break;
136743412Snewton		case '%':
1368107849Salfred		    switch (c = *fmt) {
136943412Snewton		    case '\0':
137043412Snewton			continue;
137143412Snewton		    case '%':
137243412Snewton		    default:
1373135762Sjhb			putchar(c);
137443412Snewton			break;
137543412Snewton		    case 'A':
137643412Snewton			printf("%s", main_local);
137743412Snewton			break;
137843412Snewton		    case 'a':
137943412Snewton			printf("%s", obj_main->path);
138043412Snewton			break;
138143412Snewton		    case 'o':
138243412Snewton			printf("%s", name);
138343412Snewton			break;
138443412Snewton#if 0
138543412Snewton		    case 'm':
138643412Snewton			printf("%d", sodp->sod_major);
138743412Snewton			break;
138843412Snewton		    case 'n':
138943412Snewton			printf("%d", sodp->sod_minor);
139043412Snewton			break;
139143412Snewton#endif
139243412Snewton		    case 'p':
139343412Snewton			printf("%s", path);
139443412Snewton			break;
139543412Snewton		    case 'x':
139643412Snewton			printf("%p", needed->obj ? needed->obj->mapbase : 0);
139743412Snewton			break;
139843412Snewton		    }
139943412Snewton		    break;
140043412Snewton		}
140143412Snewton		++fmt;
140243412Snewton	    }
140343412Snewton	}
140443412Snewton    }
140543412Snewton}
140643412Snewton
140743412Snewtonstatic void
140843412Snewtonunref_object_dag(Obj_Entry *root)
140943412Snewton{
141043412Snewton    assert(root->refcount != 0);
141143412Snewton    root->refcount--;
141243412Snewton    if (root->refcount == 0) {
141343412Snewton	const Needed_Entry *needed;
141443412Snewton
141543412Snewton	for (needed = root->needed;  needed != NULL;  needed = needed->next)
141643412Snewton	    unref_object_dag(needed->obj);
141743412Snewton    }
141843412Snewton}
141943412Snewton
142043412Snewton/*
142143412Snewton * Non-mallocing printf, for use by malloc itself.
142243412Snewton * XXX - This doesn't belong in this module.
142343412Snewton */
142443412Snewtonvoid
142543412Snewtonxprintf(const char *fmt, ...)
142643412Snewton{
142743412Snewton    char buf[256];
142843412Snewton    va_list ap;
142943412Snewton
143043412Snewton    va_start(ap, fmt);
143143412Snewton    vsprintf(buf, fmt, ap);
143283366Sjulian    (void)write(1, buf, strlen(buf));
143383366Sjulian    va_end(ap);
143443412Snewton}
143543412Snewton