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