link_elf.c revision 103436
138032Speter/*- 2147081Sgshapiro * Copyright (c) 1998-2000 Doug Rabson 364565Sgshapiro * All rights reserved. 438032Speter * 538032Speter * Redistribution and use in source and binary forms, with or without 638032Speter * modification, are permitted provided that the following conditions 738032Speter * are met: 838032Speter * 1. Redistributions of source code must retain the above copyright 938032Speter * notice, this list of conditions and the following disclaimer. 1038032Speter * 2. Redistributions in binary form must reproduce the above copyright 1138032Speter * notice, this list of conditions and the following disclaimer in the 12120259Sgshapiro * documentation and/or other materials provided with the distribution. 1338032Speter * 1438032Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1564565Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1664565Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17147081Sgshapiro * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1864565Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1964565Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2064565Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2164565Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2264565Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338032Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438032Speter * SUCH DAMAGE. 2564565Sgshapiro * 2664565Sgshapiro * $FreeBSD: head/sys/kern/link_elf.c 103436 2002-09-17 01:49:00Z peter $ 2764565Sgshapiro */ 2864565Sgshapiro 2964565Sgshapiro#include "opt_ddb.h" 3090795Sgshapiro 3164565Sgshapiro#include <sys/param.h> 3238032Speter#include <sys/systm.h> 3338032Speter#include <sys/kernel.h> 3438032Speter#include <sys/lock.h> 3538032Speter#include <sys/malloc.h> 3638032Speter#include <sys/mutex.h> 3738032Speter#include <sys/proc.h> 3838032Speter#include <sys/namei.h> 3938032Speter#include <sys/fcntl.h> 4038032Speter#include <sys/vnode.h> 4138032Speter#include <sys/linker.h> 4238032Speter 4338032Speter#include <machine/elf.h> 4438032Speter#ifdef GPROF 4538032Speter#include <machine/profile.h> 4638032Speter#endif 4738032Speter 4838032Speter#include <vm/vm.h> 4938032Speter#include <vm/vm_param.h> 5038032Speter#ifdef SPARSE_MAPPING 5138032Speter#include <vm/vm_object.h> 5238032Speter#include <vm/vm_kern.h> 5338032Speter#include <vm/vm_extern.h> 5438032Speter#endif 5538032Speter#include <vm/pmap.h> 5638032Speter#include <vm/vm_map.h> 5738032Speter 5838032Speter#include <sys/link_elf.h> 5938032Speter 6038032Speter#include "linker_if.h" 6138032Speter 6238032Spetertypedef struct elf_file { 6364565Sgshapiro struct linker_file lf; /* Common fields */ 6438032Speter int preloaded; /* Was file pre-loaded */ 6590795Sgshapiro caddr_t address; /* Relocation address */ 6638032Speter#ifdef SPARSE_MAPPING 6738032Speter vm_object_t object; /* VM object to hold file pages */ 6838032Speter#endif 6938032Speter Elf_Dyn* dynamic; /* Symbol table etc. */ 7038032Speter Elf_Hashelt nbuckets; /* DT_HASH info */ 7138032Speter Elf_Hashelt nchains; 7238032Speter const Elf_Hashelt* buckets; 7338032Speter const Elf_Hashelt* chains; 7438032Speter caddr_t hash; 7538032Speter caddr_t strtab; /* DT_STRTAB */ 7638032Speter int strsz; /* DT_STRSZ */ 7738032Speter const Elf_Sym* symtab; /* DT_SYMTAB */ 7838032Speter Elf_Addr* got; /* DT_PLTGOT */ 7938032Speter const Elf_Rel* pltrel; /* DT_JMPREL */ 8038032Speter int pltrelsize; /* DT_PLTRELSZ */ 8138032Speter const Elf_Rela* pltrela; /* DT_JMPREL */ 8238032Speter int pltrelasize; /* DT_PLTRELSZ */ 8338032Speter const Elf_Rel* rel; /* DT_REL */ 8438032Speter int relsize; /* DT_RELSZ */ 8538032Speter const Elf_Rela* rela; /* DT_RELA */ 8638032Speter int relasize; /* DT_RELASZ */ 8738032Speter caddr_t modptr; 8838032Speter const Elf_Sym* ddbsymtab; /* The symbol table we are using */ 8938032Speter long ddbsymcnt; /* Number of symbols */ 9038032Speter caddr_t ddbstrtab; /* String table */ 9138032Speter long ddbstrcnt; /* number of bytes in string table */ 9238032Speter caddr_t symbase; /* malloc'ed symbold base */ 9338032Speter caddr_t strbase; /* malloc'ed string base */ 9438032Speter#ifdef DDB 9538032Speter struct link_map gdb; /* hooks for gdb */ 9638032Speter#endif 9738032Speter} *elf_file_t; 9838032Speter 9938032Speterstatic int link_elf_link_preload(linker_class_t cls, 10038032Speter const char*, linker_file_t*); 10138032Speterstatic int link_elf_link_preload_finish(linker_file_t); 10238032Speterstatic int link_elf_load_file(linker_class_t, const char*, linker_file_t*); 10338032Speterstatic int link_elf_lookup_symbol(linker_file_t, const char*, 10490795Sgshapiro c_linker_sym_t*); 10538032Speterstatic int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); 10638032Speterstatic int link_elf_search_symbol(linker_file_t, caddr_t value, 10790795Sgshapiro c_linker_sym_t* sym, long* diffp); 10890795Sgshapiro 10938032Speterstatic void link_elf_unload_file(linker_file_t); 11038032Speterstatic void link_elf_unload_preload(linker_file_t); 11164565Sgshapirostatic int link_elf_lookup_set(linker_file_t, const char *, 11290795Sgshapiro void ***, void ***, int *); 11390795Sgshapirostatic int link_elf_each_function_name(linker_file_t, 11438032Speter int (*)(const char *, void *), 11538032Speter void *); 11638032Speter 11738032Speterstatic kobj_method_t link_elf_methods[] = { 11890795Sgshapiro KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), 11938032Speter KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), 12038032Speter KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), 12138032Speter KOBJMETHOD(linker_unload, link_elf_unload_file), 12238032Speter KOBJMETHOD(linker_load_file, link_elf_load_file), 12338032Speter KOBJMETHOD(linker_link_preload, link_elf_link_preload), 12438032Speter KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), 12538032Speter KOBJMETHOD(linker_lookup_set, link_elf_lookup_set), 12638032Speter KOBJMETHOD(linker_each_function_name, link_elf_each_function_name), 12738032Speter { 0, 0 } 12838032Speter}; 12938032Speter 13038032Speterstatic struct linker_class link_elf_class = { 13138032Speter#if ELF_TARG_CLASS == ELFCLASS32 13238032Speter "elf32", 13338032Speter#else 13438032Speter "elf64", 13538032Speter#endif 13638032Speter link_elf_methods, sizeof(struct elf_file) 13738032Speter}; 13838032Speter 13938032Speterstatic int parse_dynamic(elf_file_t ef); 14038032Speterstatic int relocate_file(elf_file_t ef); 14138032Speterstatic int link_elf_preload_parse_symbols(elf_file_t ef); 14238032Speter 14338032Speter#ifdef DDB 14438032Speterstatic void r_debug_state(struct r_debug *dummy_one, 14538032Speter struct link_map *dummy_two); 14690795Sgshapiro 14764565Sgshapiro/* 14864565Sgshapiro * A list of loaded modules for GDB to use for loading symbols. 14938032Speter */ 15038032Speterstruct r_debug r_debug; 15138032Speter 15238032Speter#define GDB_STATE(s) r_debug.r_state = s; r_debug_state(NULL, NULL); 15338032Speter 15438032Speter/* 15538032Speter * Function for the debugger to set a breakpoint on to gain control. 15638032Speter */ 15738032Spetervoid 15838032Speterr_debug_state(struct r_debug *dummy_one __unused, 15938032Speter struct link_map *dummy_two __unused) 16038032Speter{ 16194337Sgshapiro} 16264565Sgshapiro 16364565Sgshapiro#endif 16464565Sgshapiro 16564565Sgshapiro#ifdef __ia64__ 16638032SpeterElf_Addr link_elf_get_gp(linker_file_t); 16764565Sgshapiro#endif 16838032Speter 16964565Sgshapiro/* 17064565Sgshapiro * The kernel symbol table starts here. 17190795Sgshapiro */ 17238032Speterextern struct _dynamic _DYNAMIC; 17338032Speter 17438032Speterstatic void 17538032Speterlink_elf_init(void* arg) 17638032Speter{ 17738032Speter Elf_Dyn *dp; 17838032Speter caddr_t modptr, baseptr, sizeptr; 17938032Speter elf_file_t ef; 18038032Speter char *modname; 18190795Sgshapiro#ifdef DDB 18238032Speter char *newfilename; 18338032Speter#endif 18438032Speter 18538032Speter linker_add_class(&link_elf_class); 18638032Speter 18738032Speter dp = (Elf_Dyn*) &_DYNAMIC; 18890795Sgshapiro modname = NULL; 18990795Sgshapiro modptr = preload_search_by_type("elf kernel"); 19038032Speter if (modptr) 19138032Speter modname = (char *)preload_search_info(modptr, MODINFO_NAME); 19238032Speter if (modname == NULL) 19338032Speter modname = "kernel"; 19438032Speter linker_kernel_file = linker_make_file(modname, &link_elf_class); 19538032Speter if (linker_kernel_file == NULL) 19664565Sgshapiro panic("link_elf_init: Can't create linker structures for kernel"); 19738032Speter 19838032Speter ef = (elf_file_t) linker_kernel_file; 19938032Speter ef->preloaded = 1; 20038032Speter ef->address = 0; 20138032Speter#ifdef SPARSE_MAPPING 20238032Speter ef->object = 0; 20338032Speter#endif 20438032Speter ef->dynamic = dp; 20538032Speter 20638032Speter if (dp) 20738032Speter parse_dynamic(ef); 20838032Speter linker_kernel_file->address = (caddr_t) KERNBASE; 20938032Speter linker_kernel_file->size = -(intptr_t)linker_kernel_file->address; 21038032Speter 21138032Speter if (modptr) { 21238032Speter ef->modptr = modptr; 21338032Speter baseptr = preload_search_info(modptr, MODINFO_ADDR); 21490795Sgshapiro if (baseptr) 21590795Sgshapiro linker_kernel_file->address = *(caddr_t *)baseptr; 21690795Sgshapiro sizeptr = preload_search_info(modptr, MODINFO_SIZE); 21738032Speter if (sizeptr) 21838032Speter linker_kernel_file->size = *(size_t *)sizeptr; 21964565Sgshapiro } 22090795Sgshapiro (void)link_elf_preload_parse_symbols(ef); 22190795Sgshapiro 22238032Speter#ifdef DDB 22364565Sgshapiro ef->gdb.l_addr = linker_kernel_file->address; 22438032Speter newfilename = malloc(strlen(modname) + 1, M_LINKER, M_WAITOK); 22538032Speter strcpy(newfilename, modname); 22638032Speter ef->gdb.l_name = newfilename; 22738032Speter ef->gdb.l_ld = dp; 22838032Speter ef->gdb.l_prev = 0; 22938032Speter ef->gdb.l_next = 0; 23038032Speter 23138032Speter r_debug.r_map = &ef->gdb; 23238032Speter r_debug.r_brk = r_debug_state; 23390795Sgshapiro r_debug.r_state = RT_CONSISTENT; 23438032Speter 23590795Sgshapiro r_debug_state(NULL, NULL); /* say hello to gdb! */ 23638032Speter#endif 23738032Speter} 23838032Speter 23938032SpeterSYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); 24090795Sgshapiro 24138032Speterstatic int 24290795Sgshapirolink_elf_preload_parse_symbols(elf_file_t ef) 24338032Speter{ 24438032Speter caddr_t pointer; 24538032Speter caddr_t ssym, esym, base; 24638032Speter caddr_t strtab; 24738032Speter int strcnt; 24890795Sgshapiro Elf_Sym* symtab; 24990795Sgshapiro int symcnt; 25090795Sgshapiro 25190795Sgshapiro if (ef->modptr == NULL) 25290795Sgshapiro return 0; 25390795Sgshapiro pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM); 25438032Speter if (pointer == NULL) 25590795Sgshapiro return 0; 25690795Sgshapiro ssym = *(caddr_t *)pointer; 25790795Sgshapiro pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM); 25890795Sgshapiro if (pointer == NULL) 25990795Sgshapiro return 0; 26090795Sgshapiro esym = *(caddr_t *)pointer; 26190795Sgshapiro 26290795Sgshapiro base = ssym; 26390795Sgshapiro 26490795Sgshapiro symcnt = *(long *)base; 26538032Speter base += sizeof(long); 26690795Sgshapiro symtab = (Elf_Sym *)base; 26738032Speter base += roundup(symcnt, sizeof(long)); 26838032Speter 26938032Speter if (base > esym || base < ssym) { 27090795Sgshapiro printf("Symbols are corrupt!\n"); 27190795Sgshapiro return EINVAL; 27238032Speter } 27338032Speter 27438032Speter strcnt = *(long *)base; 27538032Speter base += sizeof(long); 27638032Speter strtab = base; 27738032Speter base += roundup(strcnt, sizeof(long)); 27838032Speter 27938032Speter if (base > esym || base < ssym) { 28038032Speter printf("Symbols are corrupt!\n"); 28138032Speter return EINVAL; 28238032Speter } 28338032Speter 28438032Speter ef->ddbsymtab = symtab; 28538032Speter ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 28638032Speter ef->ddbstrtab = strtab; 28738032Speter ef->ddbstrcnt = strcnt; 28838032Speter 28971348Sgshapiro return 0; 29038032Speter} 29138032Speter 29271348Sgshapirostatic int 29338032Speterparse_dynamic(elf_file_t ef) 29490795Sgshapiro{ 29538032Speter Elf_Dyn *dp; 29690795Sgshapiro int plttype = DT_REL; 29790795Sgshapiro 29890795Sgshapiro for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 29990795Sgshapiro switch (dp->d_tag) { 30090795Sgshapiro case DT_HASH: 30190795Sgshapiro { 30290795Sgshapiro /* From src/libexec/rtld-elf/rtld.c */ 30338032Speter const Elf_Hashelt *hashtab = (const Elf_Hashelt *) 30438032Speter (ef->address + dp->d_un.d_ptr); 30538032Speter ef->nbuckets = hashtab[0]; 30638032Speter ef->nchains = hashtab[1]; 30738032Speter ef->buckets = hashtab + 2; 30838032Speter ef->chains = ef->buckets + ef->nbuckets; 30938032Speter break; 31038032Speter } 31138032Speter case DT_STRTAB: 31238032Speter ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 31338032Speter break; 31438032Speter case DT_STRSZ: 31564565Sgshapiro ef->strsz = dp->d_un.d_val; 31638032Speter break; 31738032Speter case DT_SYMTAB: 31838032Speter ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 31938032Speter break; 32038032Speter case DT_SYMENT: 32171348Sgshapiro if (dp->d_un.d_val != sizeof(Elf_Sym)) 32264565Sgshapiro return ENOEXEC; 32338032Speter break; 32438032Speter case DT_PLTGOT: 32538032Speter ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 32690795Sgshapiro break; 32790795Sgshapiro case DT_REL: 32890795Sgshapiro ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 32990795Sgshapiro break; 33090795Sgshapiro case DT_RELSZ: 33190795Sgshapiro ef->relsize = dp->d_un.d_val; 33290795Sgshapiro break; 33390795Sgshapiro case DT_RELENT: 33490795Sgshapiro if (dp->d_un.d_val != sizeof(Elf_Rel)) 33590795Sgshapiro return ENOEXEC; 33690795Sgshapiro break; 33790795Sgshapiro case DT_JMPREL: 33890795Sgshapiro ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 33964565Sgshapiro break; 34090795Sgshapiro case DT_PLTRELSZ: 34164565Sgshapiro ef->pltrelsize = dp->d_un.d_val; 34264565Sgshapiro break; 34364565Sgshapiro case DT_RELA: 34464565Sgshapiro ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 34564565Sgshapiro break; 34664565Sgshapiro case DT_RELASZ: 34738032Speter ef->relasize = dp->d_un.d_val; 34838032Speter break; 34990795Sgshapiro case DT_RELAENT: 35064565Sgshapiro if (dp->d_un.d_val != sizeof(Elf_Rela)) 35138032Speter return ENOEXEC; 35238032Speter break; 35338032Speter case DT_PLTREL: 35438032Speter plttype = dp->d_un.d_val; 35538032Speter if (plttype != DT_REL && plttype != DT_RELA) 35638032Speter return ENOEXEC; 35738032Speter break; 35838032Speter#ifdef DDB 35990795Sgshapiro case DT_DEBUG: 36038032Speter dp->d_un.d_ptr = (Elf_Addr) &r_debug; 36138032Speter break; 36238032Speter#endif 36338032Speter } 36438032Speter } 36538032Speter 36638032Speter if (plttype == DT_RELA) { 36738032Speter ef->pltrela = (const Elf_Rela *) ef->pltrel; 36838032Speter ef->pltrel = NULL; 36938032Speter ef->pltrelasize = ef->pltrelsize; 37038032Speter ef->pltrelsize = 0; 37138032Speter } 37238032Speter 37338032Speter ef->ddbsymtab = ef->symtab; 37438032Speter ef->ddbsymcnt = ef->nchains; 37538032Speter ef->ddbstrtab = ef->strtab; 37638032Speter ef->ddbstrcnt = ef->strsz; 37738032Speter 37890795Sgshapiro return 0; 37938032Speter} 38038032Speter 38138032Speterstatic void 38290795Sgshapirolink_elf_error(const char *s) 38390795Sgshapiro{ 38438032Speter printf("kldload: %s\n", s); 38538032Speter} 38638032Speter 38738032Speter#ifdef DDB 38838032Speter 38938032Speterstatic void 39038032Speterlink_elf_add_gdb(struct link_map *l) 39138032Speter{ 39294337Sgshapiro struct link_map *prev; 39338032Speter 39438032Speter /* 39538032Speter * Scan to the end of the list. 39638032Speter */ 39738032Speter for (prev = r_debug.r_map; prev->l_next != NULL; prev = prev->l_next) 39838032Speter ; 39938032Speter 40038032Speter /* Link in the new entry. */ 40138032Speter l->l_prev = prev; 402141887Sgshapiro l->l_next = prev->l_next; 40390795Sgshapiro prev->l_next = l; 404141887Sgshapiro} 405141887Sgshapiro 406141887Sgshapirostatic void 407141887Sgshapirolink_elf_delete_gdb(struct link_map *l) 408141887Sgshapiro{ 409141887Sgshapiro if (l->l_prev == NULL) { 410141887Sgshapiro if ((r_debug.r_map = l->l_next) != NULL) 411141887Sgshapiro l->l_next->l_prev = NULL; 412141887Sgshapiro return; 413141887Sgshapiro } 414141887Sgshapiro 415141887Sgshapiro if ((l->l_prev->l_next = l->l_next) != NULL) 416141887Sgshapiro l->l_next->l_prev = l->l_prev; 417141887Sgshapiro} 418141887Sgshapiro 419141887Sgshapiro#endif /* DDB */ 420141887Sgshapiro 421141887Sgshapirostatic int 422141887Sgshapirolink_elf_link_preload(linker_class_t cls, 423141887Sgshapiro const char* filename, linker_file_t *result) 424141887Sgshapiro{ 425141887Sgshapiro caddr_t modptr, baseptr, sizeptr, dynptr; 426141887Sgshapiro char *type; 427141887Sgshapiro elf_file_t ef; 428141887Sgshapiro linker_file_t lf; 429141887Sgshapiro int error; 430141887Sgshapiro vm_offset_t dp; 431141887Sgshapiro 432141887Sgshapiro /* Look to see if we have the file preloaded */ 433141887Sgshapiro modptr = preload_search_by_name(filename); 434141887Sgshapiro if (modptr == NULL) 435141887Sgshapiro return ENOENT; 436141887Sgshapiro 437141887Sgshapiro type = (char *)preload_search_info(modptr, MODINFO_TYPE); 438141887Sgshapiro baseptr = preload_search_info(modptr, MODINFO_ADDR); 439141887Sgshapiro sizeptr = preload_search_info(modptr, MODINFO_SIZE); 440141887Sgshapiro dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC); 441141887Sgshapiro if (type == NULL || strcmp(type, "elf module") != 0) 442141887Sgshapiro return (EFTYPE); 443141887Sgshapiro if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) 444141887Sgshapiro return (EINVAL); 445141887Sgshapiro 446141887Sgshapiro lf = linker_make_file(filename, &link_elf_class); 447141887Sgshapiro if (lf == NULL) { 448141887Sgshapiro return ENOMEM; 449141887Sgshapiro } 450141887Sgshapiro 451141887Sgshapiro ef = (elf_file_t) lf; 452141887Sgshapiro ef->preloaded = 1; 453141887Sgshapiro ef->modptr = modptr; 45490795Sgshapiro ef->address = *(caddr_t *)baseptr; 45590795Sgshapiro#ifdef SPARSE_MAPPING 45690795Sgshapiro ef->object = 0; 45790795Sgshapiro#endif 45890795Sgshapiro dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; 45990795Sgshapiro ef->dynamic = (Elf_Dyn *)dp; 46090795Sgshapiro lf->address = ef->address; 46190795Sgshapiro lf->size = *(size_t *)sizeptr; 46290795Sgshapiro 46390795Sgshapiro error = parse_dynamic(ef); 46490795Sgshapiro if (error) { 46590795Sgshapiro linker_file_unload(lf); 46690795Sgshapiro return error; 46790795Sgshapiro } 46890795Sgshapiro *result = lf; 46990795Sgshapiro return (0); 47090795Sgshapiro} 47190795Sgshapiro 47290795Sgshapirostatic int 47390795Sgshapirolink_elf_link_preload_finish(linker_file_t lf) 47490795Sgshapiro{ 47590795Sgshapiro elf_file_t ef; 47690795Sgshapiro int error; 47790795Sgshapiro#ifdef DDB 47890795Sgshapiro char *newfilename; 47964565Sgshapiro#endif 48090795Sgshapiro 48190795Sgshapiro ef = (elf_file_t) lf; 48290795Sgshapiro#if 0 /* this will be more trouble than it's worth for now */ 48390795Sgshapiro for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 48490795Sgshapiro if (dp->d_tag != DT_NEEDED) 48590795Sgshapiro continue; 48690795Sgshapiro modname = ef->strtab + dp->d_un.d_val; 48764565Sgshapiro error = linker_load_module(modname, lf); 48864565Sgshapiro if (error) 48964565Sgshapiro goto out; 49064565Sgshapiro } 49164565Sgshapiro#endif 49264565Sgshapiro error = relocate_file(ef); 49364565Sgshapiro if (error) 49464565Sgshapiro return error; 49564565Sgshapiro (void)link_elf_preload_parse_symbols(ef); 49664565Sgshapiro 49771348Sgshapiro#ifdef DDB 49890795Sgshapiro GDB_STATE(RT_ADD); 49964565Sgshapiro ef->gdb.l_addr = lf->address; 50064565Sgshapiro newfilename = malloc(strlen(lf->filename) + 1, M_LINKER, M_WAITOK); 50190795Sgshapiro strcpy(newfilename, lf->filename); 50264565Sgshapiro ef->gdb.l_name = newfilename; 50364565Sgshapiro ef->gdb.l_ld = ef->dynamic; 50490795Sgshapiro link_elf_add_gdb(&ef->gdb); 50564565Sgshapiro GDB_STATE(RT_CONSISTENT); 50690795Sgshapiro#endif 50738032Speter 50838032Speter return (0); 50938032Speter} 51038032Speter 51138032Speterstatic int 51238032Speterlink_elf_load_file(linker_class_t cls, const char* filename, linker_file_t* result) 51338032Speter{ 51438032Speter struct nameidata nd; 51538032Speter struct thread* td = curthread; /* XXX */ 51638032Speter Elf_Ehdr *hdr; 51738032Speter caddr_t firstpage; 51838032Speter int nbytes, i; 51938032Speter Elf_Phdr *phdr; 52038032Speter Elf_Phdr *phlimit; 52138032Speter Elf_Phdr *segs[2]; 52238032Speter int nsegs; 52338032Speter Elf_Phdr *phdyn; 52438032Speter Elf_Phdr *phphdr; 52538032Speter caddr_t mapbase; 52638032Speter size_t mapsize; 52738032Speter Elf_Off base_offset; 52838032Speter Elf_Addr base_vaddr; 52938032Speter Elf_Addr base_vlimit; 53090795Sgshapiro int error = 0; 53190795Sgshapiro int resid, flags; 53290795Sgshapiro elf_file_t ef; 53390795Sgshapiro linker_file_t lf; 53490795Sgshapiro Elf_Shdr *shdr; 53538032Speter int symtabindex; 53690795Sgshapiro int symstrindex; 53738032Speter int symcnt; 53890795Sgshapiro int strcnt; 53938032Speter#ifdef DDB 54038032Speter char *newfilename; 54138032Speter#endif 542132946Sgshapiro 54338032Speter GIANT_REQUIRED; 54438032Speter 54538032Speter shdr = NULL; 54638032Speter lf = NULL; 54738032Speter 54838032Speter NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); 54938032Speter flags = FREAD; 55038032Speter error = vn_open(&nd, &flags, 0); 55138032Speter if (error) 55238032Speter return error; 55338032Speter NDFREE(&nd, NDF_ONLY_PNBUF); 55438032Speter 55538032Speter /* 55638032Speter * Read the elf header from the file. 55764565Sgshapiro */ 55838032Speter firstpage = malloc(PAGE_SIZE, M_LINKER, M_WAITOK); 55938032Speter if (firstpage == NULL) { 56038032Speter error = ENOMEM; 56138032Speter goto out; 56238032Speter } 56338032Speter hdr = (Elf_Ehdr *)firstpage; 56438032Speter error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0, 56538032Speter UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 56638032Speter &resid, td); 56738032Speter nbytes = PAGE_SIZE - resid; 56838032Speter if (error) 56938032Speter goto out; 57038032Speter 57138032Speter if (!IS_ELF(*hdr)) { 57290795Sgshapiro error = ENOEXEC; 57390795Sgshapiro goto out; 57490795Sgshapiro } 57590795Sgshapiro 57690795Sgshapiro if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS 57790795Sgshapiro || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { 57890795Sgshapiro link_elf_error("Unsupported file layout"); 57990795Sgshapiro error = ENOEXEC; 58090795Sgshapiro goto out; 58171348Sgshapiro } 58238032Speter if (hdr->e_ident[EI_VERSION] != EV_CURRENT 58338032Speter || hdr->e_version != EV_CURRENT) { 58438032Speter link_elf_error("Unsupported file version"); 585132946Sgshapiro error = ENOEXEC; 586132946Sgshapiro goto out; 58738032Speter } 58838032Speter if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { 58938032Speter link_elf_error("Unsupported file type"); 59038032Speter error = ENOEXEC; 59138032Speter goto out; 59238032Speter } 59338032Speter if (hdr->e_machine != ELF_TARG_MACH) { 59438032Speter link_elf_error("Unsupported machine"); 59538032Speter error = ENOEXEC; 59690795Sgshapiro goto out; 59738032Speter } 59838032Speter 59938032Speter /* 60090795Sgshapiro * We rely on the program header being in the first page. This is 60138032Speter * not strictly required by the ABI specification, but it seems to 60238032Speter * always true in practice. And, it simplifies things considerably. 60390795Sgshapiro */ 60438032Speter if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) && 605120259Sgshapiro (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) && 606120259Sgshapiro (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes))) 607120259Sgshapiro link_elf_error("Unreadable program headers"); 608120259Sgshapiro 609120259Sgshapiro /* 610120259Sgshapiro * Scan the program header entries, and save key information. 611120259Sgshapiro * 612120259Sgshapiro * We rely on there being exactly two load segments, text and data, 613120259Sgshapiro * in that order. 614120259Sgshapiro */ 61538032Speter phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff); 61638032Speter phlimit = phdr + hdr->e_phnum; 61738032Speter nsegs = 0; 61838032Speter phdyn = NULL; 619120259Sgshapiro phphdr = NULL; 62038032Speter while (phdr < phlimit) { 62138032Speter switch (phdr->p_type) { 62238032Speter 62338032Speter case PT_LOAD: 62490795Sgshapiro if (nsegs == 2) { 62590795Sgshapiro link_elf_error("Too many sections"); 62638032Speter error = ENOEXEC; 62738032Speter goto out; 62838032Speter } 62938032Speter segs[nsegs] = phdr; 63090795Sgshapiro ++nsegs; 63190795Sgshapiro break; 63290795Sgshapiro 63338032Speter case PT_PHDR: 63438032Speter phphdr = phdr; 63564565Sgshapiro break; 63638032Speter 63790795Sgshapiro case PT_DYNAMIC: 63838032Speter phdyn = phdr; 63990795Sgshapiro break; 64038032Speter 64138032Speter case PT_INTERP: 64238032Speter link_elf_error("Unsupported file type"); 64390795Sgshapiro error = ENOEXEC; 64438032Speter goto out; 64590795Sgshapiro } 64638032Speter 64790795Sgshapiro ++phdr; 64838032Speter } 64990795Sgshapiro if (phdyn == NULL) { 65038032Speter link_elf_error("Object is not dynamically-linked"); 65138032Speter error = ENOEXEC; 65238032Speter goto out; 65338032Speter } 654132946Sgshapiro 65538032Speter /* 65690795Sgshapiro * Allocate the entire address space of the object, to stake out our 65738032Speter * contiguous region, and to establish the base address for relocation. 65838032Speter */ 65938032Speter base_offset = trunc_page(segs[0]->p_offset); 660132946Sgshapiro base_vaddr = trunc_page(segs[0]->p_vaddr); 66138032Speter base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); 66238032Speter mapsize = base_vlimit - base_vaddr; 66338032Speter 66438032Speter lf = linker_make_file(filename, &link_elf_class); 66538032Speter if (!lf) { 66638032Speter error = ENOMEM; 66738032Speter goto out; 66838032Speter } 669132946Sgshapiro 670132946Sgshapiro ef = (elf_file_t) lf; 67138032Speter#ifdef SPARSE_MAPPING 67238032Speter ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); 67338032Speter if (ef->object == NULL) { 67438032Speter free(ef, M_LINKER); 67538032Speter error = ENOMEM; 67638032Speter goto out; 67738032Speter } 67838032Speter vm_object_reference(ef->object); 679132946Sgshapiro ef->address = (caddr_t) vm_map_min(kernel_map); 68038032Speter error = vm_map_find(kernel_map, ef->object, 0, 68190795Sgshapiro (vm_offset_t *) &ef->address, 68242580Speter mapsize, 1, 68338032Speter VM_PROT_ALL, VM_PROT_ALL, 0); 68438032Speter if (error) { 68538032Speter vm_object_deallocate(ef->object); 68638032Speter ef->object = 0; 68738032Speter goto out; 68838032Speter } 68990795Sgshapiro#else 69038032Speter ef->address = malloc(mapsize, M_LINKER, M_WAITOK); 69138032Speter if (!ef->address) { 69238032Speter error = ENOMEM; 69338032Speter goto out; 69438032Speter } 69538032Speter#endif 69664565Sgshapiro mapbase = ef->address; 69738032Speter 69838032Speter /* 69938032Speter * Read the text and data sections and zero the bss. 70038032Speter */ 70138032Speter for (i = 0; i < 2; i++) { 70238032Speter caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; 70338032Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 70438032Speter segbase, segs[i]->p_filesz, segs[i]->p_offset, 70538032Speter UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 70638032Speter &resid, td); 70790795Sgshapiro if (error) { 70838032Speter goto out; 70938032Speter } 71038032Speter bzero(segbase + segs[i]->p_filesz, 71138032Speter segs[i]->p_memsz - segs[i]->p_filesz); 71238032Speter 71338032Speter#ifdef SPARSE_MAPPING 71438032Speter /* 71538032Speter * Wire down the pages 71638032Speter */ 71764565Sgshapiro vm_map_wire(kernel_map, 71838032Speter (vm_offset_t) segbase, 71938032Speter (vm_offset_t) segbase + segs[i]->p_memsz, 72038032Speter FALSE); 72164565Sgshapiro#endif 72238032Speter } 72398125Sgshapiro 72438032Speter#ifdef GPROF 72538032Speter /* Update profiling information with the new text segment. */ 72638032Speter kmupetext((uintfptr_t)(mapbase + segs[0]->p_vaddr - base_vaddr + 72738032Speter segs[0]->p_memsz)); 72838032Speter#endif 72990795Sgshapiro 73090795Sgshapiro ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); 73138032Speter 73290795Sgshapiro lf->address = ef->address; 73390795Sgshapiro lf->size = mapsize; 73438032Speter 73538032Speter error = parse_dynamic(ef); 73638032Speter if (error) 73790795Sgshapiro goto out; 73890795Sgshapiro error = linker_load_dependencies(lf); 73938032Speter if (error) 74038032Speter goto out; 74138032Speter#if 0 /* this will be more trouble than it's worth for now */ 74238032Speter for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 74338032Speter if (dp->d_tag != DT_NEEDED) 74438032Speter continue; 74564565Sgshapiro modname = ef->strtab + dp->d_un.d_val; 74638032Speter error = linker_load_module(modname, lf); 74738032Speter if (error) 74838032Speter goto out; 74990795Sgshapiro } 75038032Speter#endif 75138032Speter error = relocate_file(ef); 75238032Speter if (error) 75390795Sgshapiro goto out; 75490795Sgshapiro 75538032Speter /* Try and load the symbol table if it's present. (you can strip it!) */ 75638032Speter nbytes = hdr->e_shnum * hdr->e_shentsize; 75790795Sgshapiro if (nbytes == 0 || hdr->e_shoff == 0) 75864565Sgshapiro goto nosyms; 75990795Sgshapiro shdr = malloc(nbytes, M_LINKER, M_WAITOK | M_ZERO); 76038032Speter if (shdr == NULL) { 76138032Speter error = ENOMEM; 76238032Speter goto out; 76338032Speter } 76438032Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 76538032Speter (caddr_t)shdr, nbytes, hdr->e_shoff, 76690795Sgshapiro UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 76738032Speter &resid, td); 76838032Speter if (error) 76964565Sgshapiro goto out; 77038032Speter symtabindex = -1; 77138032Speter symstrindex = -1; 77290795Sgshapiro for (i = 0; i < hdr->e_shnum; i++) { 77338032Speter if (shdr[i].sh_type == SHT_SYMTAB) { 77438032Speter symtabindex = i; 77538032Speter symstrindex = shdr[i].sh_link; 77638032Speter } 77738032Speter } 77838032Speter if (symtabindex < 0 || symstrindex < 0) 77938032Speter goto nosyms; 78038032Speter 78138032Speter symcnt = shdr[symtabindex].sh_size; 78238032Speter ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK); 78338032Speter strcnt = shdr[symstrindex].sh_size; 78438032Speter ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK); 78538032Speter 78638032Speter if (ef->symbase == NULL || ef->strbase == NULL) { 78738032Speter error = ENOMEM; 78838032Speter goto out; 78964565Sgshapiro } 79038032Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 79138032Speter ef->symbase, symcnt, shdr[symtabindex].sh_offset, 79238032Speter UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 79338032Speter &resid, td); 79490795Sgshapiro if (error) 79538032Speter goto out; 79638032Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 79738032Speter ef->strbase, strcnt, shdr[symstrindex].sh_offset, 79838032Speter UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 79938032Speter &resid, td); 80038032Speter if (error) 80138032Speter goto out; 80238032Speter 80338032Speter ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 80490795Sgshapiro ef->ddbsymtab = (const Elf_Sym *)ef->symbase; 80538032Speter ef->ddbstrcnt = strcnt; 80638032Speter ef->ddbstrtab = ef->strbase; 80738032Speter 80838032Speter#ifdef DDB 80990795Sgshapiro GDB_STATE(RT_ADD); 81038032Speter ef->gdb.l_addr = lf->address; 81138032Speter newfilename = malloc(strlen(filename) + 1, M_LINKER, M_WAITOK); 81238032Speter strcpy(newfilename, filename); 81338032Speter ef->gdb.l_name = (const char *)newfilename; 81438032Speter ef->gdb.l_ld = ef->dynamic; 81590795Sgshapiro link_elf_add_gdb(&ef->gdb); 81638032Speter GDB_STATE(RT_CONSISTENT); 81738032Speter#endif 81838032Speter 81964565Sgshapironosyms: 82038032Speter 82190795Sgshapiro *result = lf; 82242580Speter 82338032Speterout: 82438032Speter if (error && lf) 82538032Speter linker_file_unload(lf); 82638032Speter if (shdr) 82738032Speter free(shdr, M_LINKER); 82890795Sgshapiro if (firstpage) 82938032Speter free(firstpage, M_LINKER); 83038032Speter VOP_UNLOCK(nd.ni_vp, 0, td); 83190795Sgshapiro vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 83290795Sgshapiro 83338032Speter return error; 83438032Speter} 83564565Sgshapiro 83638032Speterstatic void 83738032Speterlink_elf_unload_file(linker_file_t file) 83838032Speter{ 83964565Sgshapiro elf_file_t ef = (elf_file_t) file; 84090795Sgshapiro 84190795Sgshapiro#ifdef DDB 84298125Sgshapiro if (ef->gdb.l_ld) { 84338032Speter GDB_STATE(RT_DELETE); 84438032Speter free((void *)(uintptr_t)ef->gdb.l_name, M_LINKER); 84538032Speter link_elf_delete_gdb(&ef->gdb); 84638032Speter GDB_STATE(RT_CONSISTENT); 84790795Sgshapiro } 84890795Sgshapiro#endif 84938032Speter 85038032Speter if (ef->preloaded) { 85138032Speter link_elf_unload_preload(file); 85290795Sgshapiro return; 85364565Sgshapiro } 85438032Speter#ifdef SPARSE_MAPPING 85538032Speter if (ef->object) { 85690795Sgshapiro vm_map_remove(kernel_map, (vm_offset_t) ef->address, 85738032Speter (vm_offset_t) ef->address 85838032Speter + (ef->object->size << PAGE_SHIFT)); 85990795Sgshapiro vm_object_deallocate(ef->object); 86090795Sgshapiro } 86164565Sgshapiro#else 86290795Sgshapiro if (ef->address) 86390795Sgshapiro free(ef->address, M_LINKER); 86438032Speter#endif 86538032Speter if (ef->symbase) 86638032Speter free(ef->symbase, M_LINKER); 86790795Sgshapiro if (ef->strbase) 86838032Speter free(ef->strbase, M_LINKER); 86938032Speter} 87038032Speter 87138032Speterstatic void 87238032Speterlink_elf_unload_preload(linker_file_t file) 87338032Speter{ 87438032Speter if (file->filename) 87538032Speter preload_delete_name(file->filename); 87638032Speter} 87790795Sgshapiro 87890795Sgshapirostatic const char * 87938032Spetersymbol_name(elf_file_t ef, Elf_Word r_info) 88038032Speter{ 88138032Speter const Elf_Sym *ref; 88238032Speter 88390795Sgshapiro if (ELF_R_SYM(r_info)) { 88490795Sgshapiro ref = ef->symtab + ELF_R_SYM(r_info); 88564565Sgshapiro return ef->strtab + ref->st_name; 88664565Sgshapiro } else 88764565Sgshapiro return NULL; 88890795Sgshapiro} 88990795Sgshapiro 89064565Sgshapirostatic int 89138032Speterrelocate_file(elf_file_t ef) 89290795Sgshapiro{ 89338032Speter const Elf_Rel *rellim; 89438032Speter const Elf_Rel *rel; 89564565Sgshapiro const Elf_Rela *relalim; 89638032Speter const Elf_Rela *rela; 89738032Speter const char *symname; 89890795Sgshapiro 89938032Speter /* Perform relocations without addend if there are any: */ 90038032Speter rel = ef->rel; 90138032Speter if (rel) { 90238032Speter rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize); 90338032Speter while (rel < rellim) { 90438032Speter if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) { 90538032Speter symname = symbol_name(ef, rel->r_info); 90638032Speter printf("link_elf: symbol %s undefined\n", symname); 90738032Speter return ENOENT; 90838032Speter } 90938032Speter rel++; 91038032Speter } 91138032Speter } 91238032Speter 91338032Speter /* Perform relocations with addend if there are any: */ 91438032Speter rela = ef->rela; 91538032Speter if (rela) { 91638032Speter relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize); 91764565Sgshapiro while (rela < relalim) { 91838032Speter if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) { 91990795Sgshapiro symname = symbol_name(ef, rela->r_info); 92038032Speter printf("link_elf: symbol %s undefined\n", symname); 92138032Speter return ENOENT; 92238032Speter } 92338032Speter rela++; 92438032Speter } 92538032Speter } 92638032Speter 92738032Speter /* Perform PLT relocations without addend if there are any: */ 92838032Speter rel = ef->pltrel; 92938032Speter if (rel) { 93038032Speter rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize); 93138032Speter while (rel < rellim) { 93238032Speter if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) { 93390795Sgshapiro symname = symbol_name(ef, rel->r_info); 93490795Sgshapiro printf("link_elf: symbol %s undefined\n", symname); 93538032Speter return ENOENT; 93638032Speter } 93790795Sgshapiro rel++; 93890795Sgshapiro } 93938032Speter } 94090795Sgshapiro 94138032Speter /* Perform relocations with addend if there are any: */ 94238032Speter rela = ef->pltrela; 94390795Sgshapiro if (rela) { 94438032Speter relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize); 94538032Speter while (rela < relalim) { 94638032Speter if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) { 94738032Speter symname = symbol_name(ef, rela->r_info); 94838032Speter printf("link_elf: symbol %s undefined\n", symname); 94938032Speter return ENOENT; 95038032Speter } 95138032Speter rela++; 95238032Speter } 95338032Speter } 95438032Speter 95538032Speter return 0; 95638032Speter} 95738032Speter 95838032Speter/* 95938032Speter * Hash function for symbol table lookup. Don't even think about changing 96038032Speter * this. It is specified by the System V ABI. 96138032Speter */ 96238032Speterstatic unsigned long 96338032Speterelf_hash(const char *name) 96438032Speter{ 96538032Speter const unsigned char *p = (const unsigned char *) name; 96638032Speter unsigned long h = 0; 96738032Speter unsigned long g; 96838032Speter 96938032Speter while (*p != '\0') { 97038032Speter h = (h << 4) + *p++; 97138032Speter if ((g = h & 0xf0000000) != 0) 97238032Speter h ^= g >> 24; 97338032Speter h &= ~g; 97438032Speter } 97538032Speter return h; 97638032Speter} 97738032Speter 97838032Speterint 97938032Speterlink_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym) 98038032Speter{ 98138032Speter elf_file_t ef = (elf_file_t) lf; 98238032Speter unsigned long symnum; 98390795Sgshapiro const Elf_Sym* symp; 984132946Sgshapiro const char *strp; 98538032Speter unsigned long hash; 98638032Speter int i; 98738032Speter 98838032Speter /* First, search hashed global symbols */ 98938032Speter hash = elf_hash(name); 99038032Speter symnum = ef->buckets[hash % ef->nbuckets]; 99138032Speter 99238032Speter while (symnum != STN_UNDEF) { 99338032Speter if (symnum >= ef->nchains) { 99438032Speter printf("link_elf_lookup_symbol: corrupt symbol table\n"); 99538032Speter return ENOENT; 99638032Speter } 99790795Sgshapiro 99890795Sgshapiro symp = ef->symtab + symnum; 99938032Speter if (symp->st_name == 0) { 100038032Speter printf("link_elf_lookup_symbol: corrupt symbol table\n"); 100138032Speter return ENOENT; 100238032Speter } 100390795Sgshapiro 100438032Speter strp = ef->strtab + symp->st_name; 100538032Speter 100638032Speter if (strcmp(name, strp) == 0) { 100738032Speter if (symp->st_shndx != SHN_UNDEF || 100838032Speter (symp->st_value != 0 && 100938032Speter ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 101038032Speter *sym = (c_linker_sym_t) symp; 101138032Speter return 0; 101238032Speter } else 101338032Speter return ENOENT; 101438032Speter } 101538032Speter 101638032Speter symnum = ef->chains[symnum]; 101738032Speter } 101838032Speter 101938032Speter /* If we have not found it, look at the full table (if loaded) */ 102064565Sgshapiro if (ef->symtab == ef->ddbsymtab) 102138032Speter return ENOENT; 102238032Speter 102338032Speter /* Exhaustive search */ 102438032Speter for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 102590795Sgshapiro strp = ef->ddbstrtab + symp->st_name; 102638032Speter if (strcmp(name, strp) == 0) { 102738032Speter if (symp->st_shndx != SHN_UNDEF || 102838032Speter (symp->st_value != 0 && 102938032Speter ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 103038032Speter *sym = (c_linker_sym_t) symp; 103138032Speter return 0; 103238032Speter } else 103390795Sgshapiro return ENOENT; 103490795Sgshapiro } 103538032Speter } 103638032Speter 103738032Speter return ENOENT; 103838032Speter} 103990795Sgshapiro 104038032Speterstatic int 104138032Speterlink_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval) 104238032Speter{ 104390795Sgshapiro elf_file_t ef = (elf_file_t) lf; 104438032Speter const Elf_Sym* es = (const Elf_Sym*) sym; 104590795Sgshapiro 104690795Sgshapiro if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) { 104764565Sgshapiro symval->name = ef->strtab + es->st_name; 104838032Speter symval->value = (caddr_t) ef->address + es->st_value; 104990795Sgshapiro symval->size = es->st_size; 105090795Sgshapiro return 0; 105190795Sgshapiro } 105290795Sgshapiro if (ef->symtab == ef->ddbsymtab) 105390795Sgshapiro return ENOENT; 105490795Sgshapiro if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) { 105590795Sgshapiro symval->name = ef->ddbstrtab + es->st_name; 105638032Speter symval->value = (caddr_t) ef->address + es->st_value; 105790795Sgshapiro symval->size = es->st_size; 105890795Sgshapiro return 0; 105990795Sgshapiro } 106038032Speter return ENOENT; 106190795Sgshapiro} 106290795Sgshapiro 106390795Sgshapirostatic int 106490795Sgshapirolink_elf_search_symbol(linker_file_t lf, caddr_t value, 106590795Sgshapiro c_linker_sym_t* sym, long* diffp) 106690795Sgshapiro{ 106738032Speter elf_file_t ef = (elf_file_t) lf; 106890795Sgshapiro u_long off = (uintptr_t) (void *) value; 106938032Speter u_long diff = off; 107064565Sgshapiro u_long st_value; 107138032Speter const Elf_Sym* es; 107238032Speter const Elf_Sym* best = 0; 107390795Sgshapiro int i; 107438032Speter 107538032Speter for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { 107638032Speter if (es->st_name == 0) 107738032Speter continue; 107838032Speter st_value = es->st_value + (uintptr_t) (void *) ef->address; 107938032Speter if (off >= st_value) { 108038032Speter if (off - st_value < diff) { 108138032Speter diff = off - st_value; 108238032Speter best = es; 108338032Speter if (diff == 0) 108438032Speter break; 108538032Speter } else if (off - st_value == diff) { 108638032Speter best = es; 108738032Speter } 108838032Speter } 108938032Speter } 109038032Speter if (best == 0) 109138032Speter *diffp = off; 109238032Speter else 109338032Speter *diffp = diff; 109438032Speter *sym = (c_linker_sym_t) best; 109564565Sgshapiro 109638032Speter return 0; 109738032Speter} 109838032Speter 109938032Speter/* 1100141862Sgshapiro * Look up a linker set on an ELF system. 110138032Speter */ 110238032Speterstatic int 110338032Speterlink_elf_lookup_set(linker_file_t lf, const char *name, 110438032Speter void ***startp, void ***stopp, int *countp) 110538032Speter{ 110638032Speter c_linker_sym_t sym; 110738032Speter linker_symval_t symval; 110838032Speter char *setsym; 110938032Speter void **start, **stop; 111038032Speter int len, error = 0, count; 111138032Speter 111238032Speter len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */ 111390795Sgshapiro setsym = malloc(len, M_LINKER, M_WAITOK); 111438032Speter if (setsym == NULL) 111538032Speter return ENOMEM; 111638032Speter 111738032Speter /* get address of first entry */ 111838032Speter snprintf(setsym, len, "%s%s", "__start_set_", name); 111990795Sgshapiro error = link_elf_lookup_symbol(lf, setsym, &sym); 112090795Sgshapiro if (error) 112138032Speter goto out; 112238032Speter link_elf_symbol_values(lf, sym, &symval); 112338032Speter if (symval.value == 0) { 112438032Speter error = ESRCH; 112590795Sgshapiro goto out; 112690795Sgshapiro } 112790795Sgshapiro start = (void **)symval.value; 112838032Speter 112998125Sgshapiro /* get address of last entry */ 113038032Speter snprintf(setsym, len, "%s%s", "__stop_set_", name); 113138032Speter error = link_elf_lookup_symbol(lf, setsym, &sym); 113238032Speter if (error) 113338032Speter goto out; 113490795Sgshapiro link_elf_symbol_values(lf, sym, &symval); 113590795Sgshapiro if (symval.value == 0) { 113638032Speter error = ESRCH; 113738032Speter goto out; 113890795Sgshapiro } 113990795Sgshapiro stop = (void **)symval.value; 114038032Speter 114138032Speter /* and the number of entries */ 114290795Sgshapiro count = stop - start; 114338032Speter 114438032Speter /* and copy out */ 114538032Speter if (startp) 114638032Speter *startp = start; 114738032Speter if (stopp) 114838032Speter *stopp = stop; 114964565Sgshapiro if (countp) 115064565Sgshapiro *countp = count; 115164565Sgshapiro 115264565Sgshapiroout: 115364565Sgshapiro free(setsym, M_LINKER); 115464565Sgshapiro return error; 115590795Sgshapiro} 115664565Sgshapiro 115738032Speterstatic int 115890795Sgshapirolink_elf_each_function_name(linker_file_t file, 115964565Sgshapiro int (*callback)(const char *, void *), void *opaque) { 116064565Sgshapiro elf_file_t ef = (elf_file_t)file; 116164565Sgshapiro const Elf_Sym* symp; 116264565Sgshapiro int i, error; 116338032Speter 116490795Sgshapiro /* Exhaustive search */ 116564565Sgshapiro for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 116664565Sgshapiro if (symp->st_value != 0 && 116738032Speter ELF_ST_TYPE(symp->st_info) == STT_FUNC) { 116877352Sgshapiro error = callback(ef->ddbstrtab + symp->st_name, opaque); 116977352Sgshapiro if (error) 117064565Sgshapiro return (error); 117164565Sgshapiro } 117264565Sgshapiro } 117364565Sgshapiro return (0); 117490795Sgshapiro} 117564565Sgshapiro 117664565Sgshapiro#ifdef __ia64__ 117790795Sgshapiro/* 117864565Sgshapiro * Each KLD has its own GP. The GP value for each load module is given by 117938032Speter * DT_PLTGOT on ia64. We need GP to construct function descriptors, but 118038032Speter * don't have direct access to the ELF file structure. The link_elf_get_gp() 118190795Sgshapiro * function returns the GP given a pointer to a generic linker file struct. 118238032Speter */ 118338032SpeterElf_Addr 118438032Speterlink_elf_get_gp(linker_file_t lf) 118538032Speter{ 118638032Speter elf_file_t ef = (elf_file_t)lf; 118790795Sgshapiro return (Elf_Addr)ef->got; 118864565Sgshapiro} 118938032Speter#endif 119064565Sgshapiro 119190795Sgshapiro/* 119264565Sgshapiro * Symbol lookup function that can be used when the symbol index is known (ie 119364565Sgshapiro * in relocations). It uses the symbol index instead of doing a fully fledged 119438032Speter * hash table based lookup when such is valid. For example for local symbols. 119538032Speter * This is not only more efficient, it's also more correct. It's not always 119664565Sgshapiro * the case that the symbol can be found through the hash table. 119764565Sgshapiro */ 119864565SgshapiroElf_Addr 119964565Sgshapiroelf_lookup(linker_file_t lf, Elf_Word symidx, int deps) 120064565Sgshapiro{ 120164565Sgshapiro elf_file_t ef = (elf_file_t)lf; 120238032Speter const Elf_Sym *sym; 120338032Speter const char *symbol; 120438032Speter 120538032Speter /* Don't even try to lookup the symbol if the index is bogus. */ 120638032Speter if (symidx >= ef->nchains) 120738032Speter return (0); 120838032Speter 120938032Speter sym = ef->symtab + symidx; 121064565Sgshapiro 121138032Speter /* 121238032Speter * Don't do a full lookup when the symbol is local. It may even 121338032Speter * fail because it may not be found through the hash table. 121438032Speter */ 121538032Speter if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 121638032Speter /* Force lookup failure when we have an insanity. */ 121738032Speter if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0) 121838032Speter return (0); 121938032Speter return ((Elf_Addr)ef->address + sym->st_value); 122038032Speter } 1221120259Sgshapiro 122238032Speter /* 122338032Speter * XXX we can avoid doing a hash table based lookup for global 122438032Speter * symbols as well. This however is not always valid, so we'll 122538032Speter * just do it the hard way for now. Performance tweaks can 122638032Speter * always be added. 122738032Speter */ 122838032Speter 122938032Speter symbol = ef->strtab + sym->st_name; 123038032Speter 1231120259Sgshapiro /* Force a lookup failure if the symbol name is bogus. */ 123238032Speter if (*symbol == 0) 123338032Speter return (0); 123438032Speter 123538032Speter return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps)); 123642580Speter} 123742580Speter