link_elf.c revision 59751
138514Sdfr/*- 259603Sdfr * Copyright (c) 1998-2000 Doug Rabson 338514Sdfr * All rights reserved. 438514Sdfr * 538514Sdfr * Redistribution and use in source and binary forms, with or without 638514Sdfr * modification, are permitted provided that the following conditions 738514Sdfr * are met: 838514Sdfr * 1. Redistributions of source code must retain the above copyright 938514Sdfr * notice, this list of conditions and the following disclaimer. 1038514Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1138514Sdfr * notice, this list of conditions and the following disclaimer in the 1238514Sdfr * documentation and/or other materials provided with the distribution. 1338514Sdfr * 1438514Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538514Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638514Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738514Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838514Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938514Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038514Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138514Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238514Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338514Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438514Sdfr * SUCH DAMAGE. 2538514Sdfr * 2650477Speter * $FreeBSD: head/sys/kern/link_elf.c 59751 2000-04-29 13:19:31Z peter $ 2738514Sdfr */ 2838514Sdfr 2959603Sdfr#include "opt_ddb.h" 3059603Sdfr 3138514Sdfr#include <sys/param.h> 3238514Sdfr#include <sys/kernel.h> 3338514Sdfr#include <sys/systm.h> 3438514Sdfr#include <sys/malloc.h> 3538514Sdfr#include <sys/proc.h> 3638514Sdfr#include <sys/namei.h> 3738514Sdfr#include <sys/fcntl.h> 3838514Sdfr#include <sys/vnode.h> 3938514Sdfr#include <sys/linker.h> 4038514Sdfr#include <machine/elf.h> 4138514Sdfr 4239071Sdfr#include <vm/vm.h> 4339071Sdfr#include <vm/vm_param.h> 4454655Seivind#include <vm/vm_zone.h> 4539071Sdfr#include <sys/lock.h> 4652128Speter#ifdef SPARSE_MAPPING 4739071Sdfr#include <vm/vm_object.h> 4839071Sdfr#include <vm/vm_kern.h> 4939071Sdfr#include <vm/vm_extern.h> 5052128Speter#endif 5139071Sdfr#include <vm/pmap.h> 5239071Sdfr#include <vm/vm_map.h> 5359603Sdfr#include <link.h> 5439071Sdfr 5559603Sdfr#include "linker_if.h" 5638514Sdfr 5738514Sdfrtypedef struct elf_file { 5859603Sdfr struct linker_file lf; /* Common fields */ 5959603Sdfr int preloaded; /* Was file pre-loaded */ 6039071Sdfr caddr_t address; /* Relocation address */ 6139071Sdfr#ifdef SPARSE_MAPPING 6239071Sdfr vm_object_t object; /* VM object to hold file pages */ 6339071Sdfr#endif 6459603Sdfr Elf_Dyn* dynamic; /* Symbol table etc. */ 6538514Sdfr Elf_Off nbuckets; /* DT_HASH info */ 6638514Sdfr Elf_Off nchains; 6738514Sdfr const Elf_Off* buckets; 6838514Sdfr const Elf_Off* chains; 6938514Sdfr caddr_t hash; 7038514Sdfr caddr_t strtab; /* DT_STRTAB */ 7140254Speter int strsz; /* DT_STRSZ */ 7239071Sdfr const Elf_Sym* symtab; /* DT_SYMTAB */ 7339071Sdfr Elf_Addr* got; /* DT_PLTGOT */ 7439071Sdfr const Elf_Rel* pltrel; /* DT_JMPREL */ 7539071Sdfr int pltrelsize; /* DT_PLTRELSZ */ 7639071Sdfr const Elf_Rela* pltrela; /* DT_JMPREL */ 7739071Sdfr int pltrelasize; /* DT_PLTRELSZ */ 7839071Sdfr const Elf_Rel* rel; /* DT_REL */ 7939071Sdfr int relsize; /* DT_RELSZ */ 8039071Sdfr const Elf_Rela* rela; /* DT_RELA */ 8139071Sdfr int relasize; /* DT_RELASZ */ 8240254Speter caddr_t modptr; 8340254Speter const Elf_Sym* ddbsymtab; /* The symbol table we are using */ 8440254Speter long ddbsymcnt; /* Number of symbols */ 8540254Speter caddr_t ddbstrtab; /* String table */ 8640254Speter long ddbstrcnt; /* number of bytes in string table */ 8740292Speter caddr_t symbase; /* malloc'ed symbold base */ 8840292Speter caddr_t strbase; /* malloc'ed string base */ 8959603Sdfr#ifdef DDB 9059603Sdfr struct link_map gdb; /* hooks for gdb */ 9159603Sdfr#endif 9238514Sdfr} *elf_file_t; 9338514Sdfr 9459751Speterstatic int link_elf_link_preload(linker_class_t cls, 9559751Speter const char*, linker_file_t*); 9659751Speterstatic int link_elf_link_preload_finish(linker_file_t); 9759751Speterstatic int link_elf_load_file(linker_class_t, const char*, linker_file_t*); 9859603Sdfrstatic int link_elf_lookup_symbol(linker_file_t, const char*, 9959603Sdfr c_linker_sym_t*); 10059603Sdfrstatic int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); 10159603Sdfrstatic int link_elf_search_symbol(linker_file_t, caddr_t value, 10259603Sdfr c_linker_sym_t* sym, long* diffp); 10338514Sdfr 10459603Sdfrstatic void link_elf_unload_file(linker_file_t); 10559751Speterstatic void link_elf_unload_preload(linker_file_t); 10659603Sdfr 10759603Sdfrstatic kobj_method_t link_elf_methods[] = { 10859603Sdfr KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), 10959603Sdfr KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), 11059603Sdfr KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), 11159603Sdfr KOBJMETHOD(linker_unload, link_elf_unload_file), 11259751Speter KOBJMETHOD(linker_load_file, link_elf_load_file), 11359751Speter KOBJMETHOD(linker_link_preload, link_elf_link_preload), 11459751Speter KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), 11559603Sdfr { 0, 0 } 11659603Sdfr}; 11759603Sdfr 11859603Sdfrstatic struct linker_class link_elf_class = { 11959603Sdfr#if ELF_TARG_CLASS == ELFCLASS32 12059603Sdfr "elf32", 12159603Sdfr#else 12259603Sdfr "elf64", 12359603Sdfr#endif 12459603Sdfr link_elf_methods, sizeof(struct elf_file) 12559603Sdfr}; 12659603Sdfr 12759603Sdfrstatic int parse_dynamic(elf_file_t ef); 12859603Sdfrstatic int relocate_file(elf_file_t ef); 12959751Speterstatic int link_elf_preload_parse_symbols(elf_file_t ef); 13059603Sdfr 13159603Sdfr#ifdef DDB 13259603Sdfr 13338514Sdfr/* 13459603Sdfr * A list of loaded modules for GDB to use for loading symbols. 13559603Sdfr */ 13659603Sdfrstruct r_debug r_debug; 13759603Sdfr 13859603Sdfr#define GDB_STATE(s) r_debug.r_state = s; r_debug_state(); 13959603Sdfr 14059603Sdfr/* 14159603Sdfr * Function for the debugger to set a breakpoint on to gain control. 14259603Sdfr */ 14359603Sdfrvoid 14459603Sdfrr_debug_state(void) 14559603Sdfr{ 14659603Sdfr} 14759603Sdfr 14859603Sdfr#endif 14959603Sdfr 15059603Sdfr/* 15138514Sdfr * The kernel symbol table starts here. 15238514Sdfr */ 15338514Sdfrextern struct _dynamic _DYNAMIC; 15438514Sdfr 15538514Sdfrstatic void 15638514Sdfrlink_elf_init(void* arg) 15738514Sdfr{ 15840156Speter#ifdef __ELF__ 15940156Speter Elf_Dyn *dp; 16040156Speter caddr_t modptr, baseptr, sizeptr; 16140156Speter elf_file_t ef; 16240156Speter char *modname; 16340156Speter#endif 16438514Sdfr 16559603Sdfr linker_add_class(&link_elf_class); 16638514Sdfr 16740156Speter#ifdef __ELF__ 16840156Speter dp = (Elf_Dyn*) &_DYNAMIC; 16938514Sdfr if (dp) { 17040156Speter modname = NULL; 17140156Speter modptr = preload_search_by_type("elf kernel"); 17240156Speter if (modptr) 17340156Speter modname = (char *)preload_search_info(modptr, MODINFO_NAME); 17440156Speter if (modname == NULL) 17540156Speter modname = "kernel"; 17659603Sdfr linker_kernel_file = linker_make_file(modname, &link_elf_class); 17738514Sdfr if (linker_kernel_file == NULL) 17838514Sdfr panic("link_elf_init: Can't create linker structures for kernel"); 17959603Sdfr 18059603Sdfr ef = (elf_file_t) linker_kernel_file; 18159751Speter ef->preloaded = 1; 18259603Sdfr ef->address = 0; 18359603Sdfr#ifdef SPARSE_MAPPING 18459603Sdfr ef->object = 0; 18559603Sdfr#endif 18659603Sdfr ef->dynamic = dp; 18759603Sdfr 18859603Sdfr parse_dynamic(ef); 18946694Speter linker_kernel_file->address = (caddr_t) KERNBASE; 19050275Sbde linker_kernel_file->size = -(intptr_t)linker_kernel_file->address; 19140156Speter 19240156Speter if (modptr) { 19340254Speter ef->modptr = modptr; 19440156Speter baseptr = preload_search_info(modptr, MODINFO_ADDR); 19540156Speter if (baseptr) 19640156Speter linker_kernel_file->address = *(caddr_t *)baseptr; 19740156Speter sizeptr = preload_search_info(modptr, MODINFO_SIZE); 19840156Speter if (sizeptr) 19940156Speter linker_kernel_file->size = *(size_t *)sizeptr; 20040156Speter } 20159751Speter (void)link_elf_preload_parse_symbols(ef); 20259603Sdfr 20359603Sdfr#ifdef DDB 20459603Sdfr ef->gdb.l_addr = linker_kernel_file->address; 20559603Sdfr ef->gdb.l_name = modname; 20659603Sdfr ef->gdb.l_ld = dp; 20759603Sdfr ef->gdb.l_prev = 0; 20859603Sdfr ef->gdb.l_next = 0; 20959603Sdfr 21059603Sdfr r_debug.r_map = &ef->gdb; 21159603Sdfr r_debug.r_brk = r_debug_state; 21259603Sdfr r_debug.r_state = RT_CONSISTENT; 21359603Sdfr 21459603Sdfr r_debug_state(); /* say hello to gdb! */ 21559603Sdfr#endif 21659603Sdfr 21738514Sdfr } 21840156Speter#endif 21938514Sdfr} 22038514Sdfr 22140156SpeterSYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); 22238514Sdfr 22338514Sdfrstatic int 22459751Speterlink_elf_preload_parse_symbols(elf_file_t ef) 22540254Speter{ 22640254Speter caddr_t pointer; 22740254Speter caddr_t ssym, esym, base; 22840254Speter caddr_t strtab; 22940254Speter int strcnt; 23040254Speter Elf_Sym* symtab; 23140254Speter int symcnt; 23240254Speter 23340292Speter if (ef->modptr == NULL) 23440292Speter return 0; 23540254Speter pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM); 23640254Speter if (pointer == NULL) 23740254Speter return 0; 23840254Speter ssym = *(caddr_t *)pointer; 23940254Speter pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM); 24040254Speter if (pointer == NULL) 24140254Speter return 0; 24240254Speter esym = *(caddr_t *)pointer; 24340254Speter 24440254Speter base = ssym; 24540254Speter 24640254Speter symcnt = *(long *)base; 24740254Speter base += sizeof(long); 24840254Speter symtab = (Elf_Sym *)base; 24940254Speter base += roundup(symcnt, sizeof(long)); 25040254Speter 25140254Speter if (base > esym || base < ssym) { 25240254Speter printf("Symbols are corrupt!\n"); 25340254Speter return EINVAL; 25440254Speter } 25540254Speter 25640254Speter strcnt = *(long *)base; 25740254Speter base += sizeof(long); 25840254Speter strtab = base; 25940254Speter base += roundup(strcnt, sizeof(long)); 26040254Speter 26140254Speter if (base > esym || base < ssym) { 26240254Speter printf("Symbols are corrupt!\n"); 26340254Speter return EINVAL; 26440254Speter } 26540254Speter 26640254Speter ef->ddbsymtab = symtab; 26740254Speter ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 26840254Speter ef->ddbstrtab = strtab; 26940254Speter ef->ddbstrcnt = strcnt; 27040254Speter 27140254Speter return 0; 27240254Speter} 27340254Speter 27440254Speterstatic int 27559603Sdfrparse_dynamic(elf_file_t ef) 27638514Sdfr{ 27759603Sdfr Elf_Dyn *dp; 27839071Sdfr int plttype = DT_REL; 27938514Sdfr 28038514Sdfr for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 28138514Sdfr switch (dp->d_tag) { 28238514Sdfr case DT_HASH: 28338514Sdfr { 28438514Sdfr /* From src/libexec/rtld-elf/rtld.c */ 28538514Sdfr const Elf_Off *hashtab = (const Elf_Off *) 28638514Sdfr (ef->address + dp->d_un.d_ptr); 28738514Sdfr ef->nbuckets = hashtab[0]; 28838514Sdfr ef->nchains = hashtab[1]; 28938514Sdfr ef->buckets = hashtab + 2; 29038514Sdfr ef->chains = ef->buckets + ef->nbuckets; 29138514Sdfr break; 29238514Sdfr } 29338514Sdfr case DT_STRTAB: 29439071Sdfr ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 29538514Sdfr break; 29640254Speter case DT_STRSZ: 29740254Speter ef->strsz = dp->d_un.d_val; 29840254Speter break; 29938514Sdfr case DT_SYMTAB: 30039071Sdfr ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 30138514Sdfr break; 30238514Sdfr case DT_SYMENT: 30338514Sdfr if (dp->d_un.d_val != sizeof(Elf_Sym)) 30438514Sdfr return ENOEXEC; 30539071Sdfr break; 30639071Sdfr case DT_PLTGOT: 30739071Sdfr ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 30839071Sdfr break; 30939071Sdfr case DT_REL: 31039071Sdfr ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 31139071Sdfr break; 31239071Sdfr case DT_RELSZ: 31339071Sdfr ef->relsize = dp->d_un.d_val; 31439071Sdfr break; 31539071Sdfr case DT_RELENT: 31639071Sdfr if (dp->d_un.d_val != sizeof(Elf_Rel)) 31739071Sdfr return ENOEXEC; 31839071Sdfr break; 31939071Sdfr case DT_JMPREL: 32039071Sdfr ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 32139071Sdfr break; 32239071Sdfr case DT_PLTRELSZ: 32339071Sdfr ef->pltrelsize = dp->d_un.d_val; 32439071Sdfr break; 32539071Sdfr case DT_RELA: 32639071Sdfr ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 32739071Sdfr break; 32839071Sdfr case DT_RELASZ: 32939071Sdfr ef->relasize = dp->d_un.d_val; 33039071Sdfr break; 33139071Sdfr case DT_RELAENT: 33239071Sdfr if (dp->d_un.d_val != sizeof(Elf_Rela)) 33339071Sdfr return ENOEXEC; 33439071Sdfr break; 33539071Sdfr case DT_PLTREL: 33639071Sdfr plttype = dp->d_un.d_val; 33739071Sdfr if (plttype != DT_REL && plttype != DT_RELA) 33839071Sdfr return ENOEXEC; 33939071Sdfr break; 34059603Sdfr#ifdef DDB 34159603Sdfr case DT_DEBUG: 34259603Sdfr dp->d_un.d_ptr = (Elf_Addr) &r_debug; 34359603Sdfr break; 34459603Sdfr#endif 34538514Sdfr } 34638514Sdfr } 34739071Sdfr 34839071Sdfr if (plttype == DT_RELA) { 34939071Sdfr ef->pltrela = (const Elf_Rela *) ef->pltrel; 35039071Sdfr ef->pltrel = NULL; 35139071Sdfr ef->pltrelasize = ef->pltrelsize; 35239071Sdfr ef->pltrelsize = 0; 35339071Sdfr } 35439071Sdfr 35540254Speter ef->ddbsymtab = ef->symtab; 35640254Speter ef->ddbsymcnt = ef->nchains; 35740254Speter ef->ddbstrtab = ef->strtab; 35840254Speter ef->ddbstrcnt = ef->strsz; 35940254Speter 36038514Sdfr return 0; 36138514Sdfr} 36238514Sdfr 36339071Sdfrstatic void 36439071Sdfrlink_elf_error(const char *s) 36539071Sdfr{ 36639071Sdfr printf("kldload: %s\n", s); 36739071Sdfr} 36839071Sdfr 36959603Sdfr#ifdef DDB 37059603Sdfr 37159603Sdfrstatic void 37259603Sdfrlink_elf_add_gdb(struct link_map *l) 37359603Sdfr{ 37459603Sdfr struct link_map *prev; 37559603Sdfr 37659603Sdfr /* 37759603Sdfr * Scan to the end of the list. 37859603Sdfr */ 37959603Sdfr for (prev = r_debug.r_map; prev->l_next != NULL; prev = prev->l_next) 38059603Sdfr ; 38159603Sdfr 38259603Sdfr /* Link in the new entry. */ 38359603Sdfr l->l_prev = prev; 38459603Sdfr l->l_next = prev->l_next; 38559603Sdfr prev->l_next = l; 38659603Sdfr} 38759603Sdfr 38859603Sdfrstatic void 38959603Sdfrlink_elf_delete_gdb(struct link_map *l) 39059603Sdfr{ 39159603Sdfr if (l->l_prev == NULL) { 39259603Sdfr if ((r_debug.r_map = l->l_next) != NULL) 39359603Sdfr l->l_next->l_prev = NULL; 39459603Sdfr return; 39559603Sdfr } 39659603Sdfr 39759603Sdfr if ((l->l_prev->l_next = l->l_next) != NULL) 39859603Sdfr l->l_next->l_prev = l->l_prev; 39959603Sdfr} 40059603Sdfr 40159603Sdfr#endif /* DDB */ 40259603Sdfr 40338514Sdfrstatic int 40459751Speterlink_elf_link_preload(linker_class_t cls, 40559751Speter const char* filename, linker_file_t *result) 40640156Speter{ 40740156Speter caddr_t modptr, baseptr, sizeptr, dynptr; 40840156Speter char *type; 40940156Speter elf_file_t ef; 41040156Speter linker_file_t lf; 41140156Speter int error; 41240156Speter vm_offset_t dp; 41340156Speter 41459751Speter /* Look to see if we have the file preloaded */ 41540156Speter modptr = preload_search_by_name(filename); 41640156Speter if (modptr == NULL) 41759751Speter return ENOENT; 41840156Speter 41940156Speter type = (char *)preload_search_info(modptr, MODINFO_TYPE); 42040156Speter baseptr = preload_search_info(modptr, MODINFO_ADDR); 42140156Speter sizeptr = preload_search_info(modptr, MODINFO_SIZE); 42240156Speter dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC); 42340156Speter if (type == NULL || strcmp(type, "elf module") != 0) 42440156Speter return (EFTYPE); 42540156Speter if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) 42640156Speter return (EINVAL); 42740156Speter 42859603Sdfr lf = linker_make_file(filename, &link_elf_class); 42959603Sdfr if (lf == NULL) { 43059603Sdfr return ENOMEM; 43159603Sdfr } 43259603Sdfr 43359603Sdfr ef = (elf_file_t) lf; 43459603Sdfr ef->preloaded = 1; 43540292Speter ef->modptr = modptr; 43640156Speter ef->address = *(caddr_t *)baseptr; 43740156Speter#ifdef SPARSE_MAPPING 43840156Speter ef->object = 0; 43940156Speter#endif 44040156Speter dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; 44140156Speter ef->dynamic = (Elf_Dyn *)dp; 44240156Speter lf->address = ef->address; 44340156Speter lf->size = *(size_t *)sizeptr; 44440156Speter 44559603Sdfr error = parse_dynamic(ef); 44640156Speter if (error) { 44740156Speter linker_file_unload(lf); 44840156Speter return error; 44940156Speter } 45059751Speter *result = lf; 45159751Speter return (0); 45259751Speter} 45359751Speter 45459751Speterstatic int 45559751Speterlink_elf_link_preload_finish(linker_file_t lf) 45659751Speter{ 45759751Speter elf_file_t ef; 45859751Speter int error; 45959751Speter 46059751Speter ef = (elf_file_t) lf; 46159751Speter#if 0 /* this will be more trouble than it's worth for now */ 46259751Speter for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 46359751Speter if (dp->d_tag != DT_NEEDED) 46459751Speter continue; 46559751Speter modname = ef->strtab + dp->d_un.d_val; 46659751Speter error = linker_load_module(modname, lf); 46759751Speter if (error) 46859751Speter goto out; 46940156Speter } 47059751Speter#endif 47159603Sdfr error = relocate_file(ef); 47259751Speter if (error) 47340156Speter return error; 47459751Speter (void)link_elf_preload_parse_symbols(ef); 47559603Sdfr 47659603Sdfr#ifdef DDB 47759603Sdfr GDB_STATE(RT_ADD); 47859603Sdfr ef->gdb.l_addr = lf->address; 47959751Speter ef->gdb.l_name = lf->filename; 48059603Sdfr ef->gdb.l_ld = ef->dynamic; 48159603Sdfr link_elf_add_gdb(&ef->gdb); 48259603Sdfr GDB_STATE(RT_CONSISTENT); 48359603Sdfr#endif 48459603Sdfr 48540156Speter return (0); 48640156Speter} 48740156Speter 48840156Speterstatic int 48959751Speterlink_elf_load_file(linker_class_t cls, const char* filename, linker_file_t* result) 49038514Sdfr{ 49138514Sdfr struct nameidata nd; 49238514Sdfr struct proc* p = curproc; /* XXX */ 49340962Speter Elf_Ehdr *hdr; 49440962Speter caddr_t firstpage; 49539071Sdfr int nbytes, i; 49639071Sdfr Elf_Phdr *phdr; 49739071Sdfr Elf_Phdr *phlimit; 49839071Sdfr Elf_Phdr *segs[2]; 49939071Sdfr int nsegs; 50039071Sdfr Elf_Phdr *phdyn; 50139071Sdfr Elf_Phdr *phphdr; 50239071Sdfr caddr_t mapbase; 50339071Sdfr size_t mapsize; 50439071Sdfr Elf_Off base_offset; 50539071Sdfr Elf_Addr base_vaddr; 50639071Sdfr Elf_Addr base_vlimit; 50738514Sdfr int error = 0; 50838514Sdfr int resid; 50938514Sdfr elf_file_t ef; 51038514Sdfr linker_file_t lf; 51140292Speter Elf_Shdr *shdr; 51240292Speter int symtabindex; 51340292Speter int symstrindex; 51440292Speter int symcnt; 51540292Speter int strcnt; 51638514Sdfr 51740292Speter shdr = NULL; 51840292Speter lf = NULL; 51940292Speter 52059751Speter NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); 52138514Sdfr error = vn_open(&nd, FREAD, 0); 52238514Sdfr if (error) 52338514Sdfr return error; 52454655Seivind NDFREE(&nd, NDF_ONLY_PNBUF); 52538514Sdfr 52638514Sdfr /* 52739071Sdfr * Read the elf header from the file. 52838514Sdfr */ 52940962Speter firstpage = malloc(PAGE_SIZE, M_LINKER, M_WAITOK); 53040962Speter if (firstpage == NULL) { 53140962Speter error = ENOMEM; 53240962Speter goto out; 53340962Speter } 53440962Speter hdr = (Elf_Ehdr *)firstpage; 53540962Speter error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0, 53638514Sdfr UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 53740962Speter nbytes = PAGE_SIZE - resid; 53838514Sdfr if (error) 53938514Sdfr goto out; 54038514Sdfr 54140962Speter if (!IS_ELF(*hdr)) { 54239071Sdfr error = ENOEXEC; 54338514Sdfr goto out; 54439071Sdfr } 54538514Sdfr 54640962Speter if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS 54740962Speter || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { 54839071Sdfr link_elf_error("Unsupported file layout"); 54939071Sdfr error = ENOEXEC; 55039071Sdfr goto out; 55139071Sdfr } 55240962Speter if (hdr->e_ident[EI_VERSION] != EV_CURRENT 55340962Speter || hdr->e_version != EV_CURRENT) { 55439071Sdfr link_elf_error("Unsupported file version"); 55539071Sdfr error = ENOEXEC; 55639071Sdfr goto out; 55739071Sdfr } 55840962Speter if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { 55939071Sdfr link_elf_error("Unsupported file type"); 56039071Sdfr error = ENOEXEC; 56139071Sdfr goto out; 56239071Sdfr } 56340962Speter if (hdr->e_machine != ELF_TARG_MACH) { 56439071Sdfr link_elf_error("Unsupported machine"); 56539071Sdfr error = ENOEXEC; 56639071Sdfr goto out; 56739071Sdfr } 56839071Sdfr 56938514Sdfr /* 57039071Sdfr * We rely on the program header being in the first page. This is 57139071Sdfr * not strictly required by the ABI specification, but it seems to 57239071Sdfr * always true in practice. And, it simplifies things considerably. 57338514Sdfr */ 57440962Speter if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) && 57540962Speter (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) && 57640962Speter (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes))) 57739071Sdfr link_elf_error("Unreadable program headers"); 57839071Sdfr 57938514Sdfr /* 58039071Sdfr * Scan the program header entries, and save key information. 58139071Sdfr * 58239071Sdfr * We rely on there being exactly two load segments, text and data, 58339071Sdfr * in that order. 58438514Sdfr */ 58540962Speter phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff); 58640962Speter phlimit = phdr + hdr->e_phnum; 58739071Sdfr nsegs = 0; 58839071Sdfr phdyn = NULL; 58939071Sdfr phphdr = NULL; 59039071Sdfr while (phdr < phlimit) { 59139071Sdfr switch (phdr->p_type) { 59239071Sdfr 59339071Sdfr case PT_LOAD: 59439071Sdfr if (nsegs == 2) { 59539071Sdfr link_elf_error("Too many sections"); 59639071Sdfr error = ENOEXEC; 59739071Sdfr goto out; 59839071Sdfr } 59939071Sdfr segs[nsegs] = phdr; 60039071Sdfr ++nsegs; 60139071Sdfr break; 60239071Sdfr 60339071Sdfr case PT_PHDR: 60439071Sdfr phphdr = phdr; 60539071Sdfr break; 60639071Sdfr 60739071Sdfr case PT_DYNAMIC: 60839071Sdfr phdyn = phdr; 60939071Sdfr break; 61039071Sdfr } 61139071Sdfr 61239071Sdfr ++phdr; 61339071Sdfr } 61439071Sdfr if (phdyn == NULL) { 61539071Sdfr link_elf_error("Object is not dynamically-linked"); 61639071Sdfr error = ENOEXEC; 61738514Sdfr goto out; 61839071Sdfr } 61938514Sdfr 62038514Sdfr /* 62139071Sdfr * Allocate the entire address space of the object, to stake out our 62239071Sdfr * contiguous region, and to establish the base address for relocation. 62338514Sdfr */ 62439071Sdfr base_offset = trunc_page(segs[0]->p_offset); 62539071Sdfr base_vaddr = trunc_page(segs[0]->p_vaddr); 62639071Sdfr base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); 62739071Sdfr mapsize = base_vlimit - base_vaddr; 62839071Sdfr 62959603Sdfr lf = linker_make_file(filename, &link_elf_class); 63059603Sdfr if (!lf) { 63159603Sdfr error = ENOMEM; 63259603Sdfr goto out; 63359603Sdfr } 63459603Sdfr 63559603Sdfr ef = (elf_file_t) lf; 63639071Sdfr#ifdef SPARSE_MAPPING 63739071Sdfr ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); 63839071Sdfr if (ef->object == NULL) { 63938514Sdfr free(ef, M_LINKER); 64039071Sdfr error = ENOMEM; 64138514Sdfr goto out; 64238514Sdfr } 64339071Sdfr vm_object_reference(ef->object); 64439071Sdfr ef->address = (caddr_t) vm_map_min(kernel_map); 64539071Sdfr error = vm_map_find(kernel_map, ef->object, 0, 64639071Sdfr (vm_offset_t *) &ef->address, 64739071Sdfr mapsize, 1, 64839071Sdfr VM_PROT_ALL, VM_PROT_ALL, 0); 64939071Sdfr if (error) { 65039071Sdfr vm_object_deallocate(ef->object); 65159603Sdfr ef->object = 0; 65239071Sdfr goto out; 65339071Sdfr } 65439071Sdfr#else 65539071Sdfr ef->address = malloc(mapsize, M_LINKER, M_WAITOK); 65659603Sdfr if (!ef->address) { 65759603Sdfr error = ENOMEM; 65859603Sdfr goto out; 65959603Sdfr } 66039071Sdfr#endif 66139071Sdfr mapbase = ef->address; 66238514Sdfr 66339071Sdfr /* 66439071Sdfr * Read the text and data sections and zero the bss. 66539071Sdfr */ 66639071Sdfr for (i = 0; i < 2; i++) { 66739071Sdfr caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; 66839071Sdfr error = vn_rdwr(UIO_READ, nd.ni_vp, 66939071Sdfr segbase, segs[i]->p_filesz, segs[i]->p_offset, 67039071Sdfr UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 67139071Sdfr if (error) { 67239071Sdfr goto out; 67339071Sdfr } 67439071Sdfr bzero(segbase + segs[i]->p_filesz, 67539071Sdfr segs[i]->p_memsz - segs[i]->p_filesz); 67639071Sdfr 67739071Sdfr#ifdef SPARSE_MAPPING 67839071Sdfr /* 67939071Sdfr * Wire down the pages 68039071Sdfr */ 68139071Sdfr vm_map_pageable(kernel_map, 68239071Sdfr (vm_offset_t) segbase, 68339071Sdfr (vm_offset_t) segbase + segs[i]->p_memsz, 68439071Sdfr FALSE); 68539071Sdfr#endif 68639071Sdfr } 68739071Sdfr 68859603Sdfr ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); 68939071Sdfr 69038514Sdfr lf->address = ef->address; 69139071Sdfr lf->size = mapsize; 69238514Sdfr 69359603Sdfr error = parse_dynamic(ef); 69440292Speter if (error) 69538514Sdfr goto out; 69659751Speter error = linker_load_dependancies(lf); 69740292Speter if (error) 69840156Speter goto out; 69959751Speter#if 0 /* this will be more trouble than it's worth for now */ 70059751Speter for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 70159751Speter if (dp->d_tag != DT_NEEDED) 70259751Speter continue; 70359751Speter modname = ef->strtab + dp->d_un.d_val; 70459751Speter error = linker_load_module(modname, lf); 70559751Speter if (error) 70659751Speter goto out; 70759751Speter } 70859751Speter#endif 70959603Sdfr error = relocate_file(ef); 71040292Speter if (error) 71140156Speter goto out; 71240292Speter 71340292Speter /* Try and load the symbol table if it's present. (you can strip it!) */ 71440962Speter nbytes = hdr->e_shnum * hdr->e_shentsize; 71540962Speter if (nbytes == 0 || hdr->e_shoff == 0) 71640292Speter goto nosyms; 71740292Speter shdr = malloc(nbytes, M_LINKER, M_WAITOK); 71840292Speter if (shdr == NULL) { 71940292Speter error = ENOMEM; 72040292Speter goto out; 72140156Speter } 72240397Speter bzero(shdr, nbytes); 72340292Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 72440962Speter (caddr_t)shdr, nbytes, hdr->e_shoff, 72540292Speter UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 72640292Speter if (error) 72740292Speter goto out; 72840292Speter symtabindex = -1; 72940292Speter symstrindex = -1; 73040962Speter for (i = 0; i < hdr->e_shnum; i++) { 73140292Speter if (shdr[i].sh_type == SHT_SYMTAB) { 73240292Speter symtabindex = i; 73340292Speter symstrindex = shdr[i].sh_link; 73440292Speter } 73540292Speter } 73640292Speter if (symtabindex < 0 || symstrindex < 0) 73740292Speter goto nosyms; 73840156Speter 73940292Speter symcnt = shdr[symtabindex].sh_size; 74040292Speter ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK); 74140292Speter strcnt = shdr[symstrindex].sh_size; 74240292Speter ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK); 74340292Speter 74440292Speter if (ef->symbase == NULL || ef->strbase == NULL) { 74540292Speter error = ENOMEM; 74640292Speter goto out; 74740292Speter } 74840292Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 74940292Speter ef->symbase, symcnt, shdr[symtabindex].sh_offset, 75040292Speter UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 75140292Speter if (error) 75240292Speter goto out; 75340292Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 75440292Speter ef->strbase, strcnt, shdr[symstrindex].sh_offset, 75540292Speter UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 75640292Speter if (error) 75740292Speter goto out; 75840292Speter 75940292Speter ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 76040292Speter ef->ddbsymtab = (const Elf_Sym *)ef->symbase; 76140292Speter ef->ddbstrcnt = strcnt; 76240292Speter ef->ddbstrtab = ef->strbase; 76340292Speter 76459603Sdfr#ifdef DDB 76559603Sdfr GDB_STATE(RT_ADD); 76659603Sdfr ef->gdb.l_addr = lf->address; 76759751Speter ef->gdb.l_name = filename; 76859603Sdfr ef->gdb.l_ld = ef->dynamic; 76959603Sdfr link_elf_add_gdb(&ef->gdb); 77059603Sdfr GDB_STATE(RT_CONSISTENT); 77159603Sdfr#endif 77259603Sdfr 77340292Speternosyms: 77440292Speter 77538514Sdfr *result = lf; 77638514Sdfr 77738514Sdfrout: 77840292Speter if (error && lf) 77940292Speter linker_file_unload(lf); 78040292Speter if (shdr) 78140292Speter free(shdr, M_LINKER); 78240962Speter if (firstpage) 78340962Speter free(firstpage, M_LINKER); 78438514Sdfr VOP_UNLOCK(nd.ni_vp, 0, p); 78538514Sdfr vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 78638514Sdfr 78738514Sdfr return error; 78838514Sdfr} 78938514Sdfr 79038514Sdfrstatic void 79140156Speterlink_elf_unload_file(linker_file_t file) 79238514Sdfr{ 79359603Sdfr elf_file_t ef = (elf_file_t) file; 79438514Sdfr 79559603Sdfr#ifdef DDB 79659603Sdfr if (ef->gdb.l_ld) { 79759603Sdfr GDB_STATE(RT_DELETE); 79859603Sdfr link_elf_delete_gdb(&ef->gdb); 79959603Sdfr GDB_STATE(RT_CONSISTENT); 80059603Sdfr } 80159603Sdfr#endif 80259603Sdfr 80359603Sdfr if (ef->preloaded) { 80459751Speter link_elf_unload_preload(file); 80559603Sdfr return; 80659603Sdfr } 80739071Sdfr#ifdef SPARSE_MAPPING 80859603Sdfr if (ef->object) { 80959603Sdfr vm_map_remove(kernel_map, (vm_offset_t) ef->address, 81059603Sdfr (vm_offset_t) ef->address 81159603Sdfr + (ef->object->size << PAGE_SHIFT)); 81259603Sdfr vm_object_deallocate(ef->object); 81359603Sdfr } 81439071Sdfr#else 81559603Sdfr if (ef->address) 81659603Sdfr free(ef->address, M_LINKER); 81739071Sdfr#endif 81859603Sdfr if (ef->symbase) 81959603Sdfr free(ef->symbase, M_LINKER); 82059603Sdfr if (ef->strbase) 82159603Sdfr free(ef->strbase, M_LINKER); 82238514Sdfr} 82338514Sdfr 82440156Speterstatic void 82559751Speterlink_elf_unload_preload(linker_file_t file) 82640156Speter{ 82740156Speter if (file->filename) 82840156Speter preload_delete_name(file->filename); 82940156Speter} 83040156Speter 83139071Sdfrstatic const char * 83240435Spetersymbol_name(elf_file_t ef, Elf_Word r_info) 83338514Sdfr{ 83439071Sdfr const Elf_Sym *ref; 83538514Sdfr 83640435Speter if (ELF_R_SYM(r_info)) { 83740435Speter ref = ef->symtab + ELF_R_SYM(r_info); 83840397Speter return ef->strtab + ref->st_name; 83939071Sdfr } else 84039071Sdfr return NULL; 84138514Sdfr} 84238514Sdfr 84338514Sdfrstatic int 84459603Sdfrrelocate_file(elf_file_t ef) 84538514Sdfr{ 84639071Sdfr const Elf_Rel *rellim; 84739071Sdfr const Elf_Rel *rel; 84839071Sdfr const Elf_Rela *relalim; 84939071Sdfr const Elf_Rela *rela; 85040435Speter const char *symname; 85138514Sdfr 85239071Sdfr /* Perform relocations without addend if there are any: */ 85340435Speter rel = ef->rel; 85440435Speter if (rel) { 85543388Sbde rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize); 85640435Speter while (rel < rellim) { 85740435Speter symname = symbol_name(ef, rel->r_info); 85859603Sdfr if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) { 85959744Speter printf("link_elf: symbol %s undefined\n", symname); 86040435Speter return ENOENT; 86142200Speter } 86240435Speter rel++; 86340435Speter } 86439071Sdfr } 86538514Sdfr 86639071Sdfr /* Perform relocations with addend if there are any: */ 86740435Speter rela = ef->rela; 86840435Speter if (rela) { 86943388Sbde relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize); 87040435Speter while (rela < relalim) { 87140435Speter symname = symbol_name(ef, rela->r_info); 87259603Sdfr if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) { 87359744Speter printf("link_elf: symbol %s undefined\n", symname); 87440435Speter return ENOENT; 87542200Speter } 87640435Speter rela++; 87740435Speter } 87839071Sdfr } 87938514Sdfr 88039071Sdfr /* Perform PLT relocations without addend if there are any: */ 88140435Speter rel = ef->pltrel; 88240435Speter if (rel) { 88343388Sbde rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize); 88440435Speter while (rel < rellim) { 88540435Speter symname = symbol_name(ef, rel->r_info); 88659603Sdfr if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) { 88759744Speter printf("link_elf: symbol %s undefined\n", symname); 88840435Speter return ENOENT; 88942200Speter } 89040435Speter rel++; 89140435Speter } 89239071Sdfr } 89338514Sdfr 89439071Sdfr /* Perform relocations with addend if there are any: */ 89540435Speter rela = ef->pltrela; 89640435Speter if (rela) { 89743388Sbde relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize); 89840435Speter while (rela < relalim) { 89940435Speter symname = symbol_name(ef, rela->r_info); 90059603Sdfr if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) { 90159744Speter printf("link_elf: symbol %s undefined\n", symname); 90240435Speter return ENOENT; 90342200Speter } 90440435Speter rela++; 90540435Speter } 90638514Sdfr } 90738514Sdfr 90838514Sdfr return 0; 90938514Sdfr} 91038514Sdfr 91139071Sdfr/* 91239071Sdfr * Hash function for symbol table lookup. Don't even think about changing 91339071Sdfr * this. It is specified by the System V ABI. 91439071Sdfr */ 91539071Sdfrstatic unsigned long 91639071Sdfrelf_hash(const char *name) 91738514Sdfr{ 91839071Sdfr const unsigned char *p = (const unsigned char *) name; 91939071Sdfr unsigned long h = 0; 92039071Sdfr unsigned long g; 92138514Sdfr 92239071Sdfr while (*p != '\0') { 92339071Sdfr h = (h << 4) + *p++; 92439071Sdfr if ((g = h & 0xf0000000) != 0) 92539071Sdfr h ^= g >> 24; 92639071Sdfr h &= ~g; 92739071Sdfr } 92839071Sdfr return h; 92938514Sdfr} 93038514Sdfr 93138514Sdfrint 93243301Sdillonlink_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym) 93338514Sdfr{ 93459603Sdfr elf_file_t ef = (elf_file_t) lf; 93539071Sdfr unsigned long symnum; 93640254Speter const Elf_Sym* symp; 93740254Speter const char *strp; 93839071Sdfr unsigned long hash; 93939071Sdfr int i; 94038514Sdfr 94140254Speter /* First, search hashed global symbols */ 94239071Sdfr hash = elf_hash(name); 94339071Sdfr symnum = ef->buckets[hash % ef->nbuckets]; 94439071Sdfr 94539071Sdfr while (symnum != STN_UNDEF) { 94639071Sdfr if (symnum >= ef->nchains) { 94739071Sdfr printf("link_elf_lookup_symbol: corrupt symbol table\n"); 94839071Sdfr return ENOENT; 94938514Sdfr } 95038514Sdfr 95139071Sdfr symp = ef->symtab + symnum; 95239071Sdfr if (symp->st_name == 0) { 95339071Sdfr printf("link_elf_lookup_symbol: corrupt symbol table\n"); 95439071Sdfr return ENOENT; 95539071Sdfr } 95639071Sdfr 95739071Sdfr strp = ef->strtab + symp->st_name; 95839071Sdfr 95939071Sdfr if (strcmp(name, strp) == 0) { 96039071Sdfr if (symp->st_shndx != SHN_UNDEF || 96139071Sdfr (symp->st_value != 0 && 96239071Sdfr ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 96343301Sdillon *sym = (c_linker_sym_t) symp; 96439071Sdfr return 0; 96539071Sdfr } else 96639071Sdfr return ENOENT; 96739071Sdfr } 96839071Sdfr 96939071Sdfr symnum = ef->chains[symnum]; 97039071Sdfr } 97139071Sdfr 97240254Speter /* If we have not found it, look at the full table (if loaded) */ 97340254Speter if (ef->symtab == ef->ddbsymtab) 97440254Speter return ENOENT; 97540254Speter 97640254Speter /* Exhaustive search */ 97740254Speter for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 97840254Speter strp = ef->ddbstrtab + symp->st_name; 97940254Speter if (strcmp(name, strp) == 0) { 98040254Speter if (symp->st_shndx != SHN_UNDEF || 98140254Speter (symp->st_value != 0 && 98240254Speter ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 98343301Sdillon *sym = (c_linker_sym_t) symp; 98440254Speter return 0; 98540254Speter } else 98640254Speter return ENOENT; 98740254Speter } 98840254Speter } 98940254Speter 99039071Sdfr return ENOENT; 99138514Sdfr} 99238514Sdfr 99340156Speterstatic int 99443309Sdillonlink_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval) 99538514Sdfr{ 99659603Sdfr elf_file_t ef = (elf_file_t) lf; 99743311Sdillon const Elf_Sym* es = (const Elf_Sym*) sym; 99838514Sdfr 99940254Speter if (es >= ef->symtab && ((es - ef->symtab) < ef->nchains)) { 100040254Speter symval->name = ef->strtab + es->st_name; 100140254Speter symval->value = (caddr_t) ef->address + es->st_value; 100240254Speter symval->size = es->st_size; 100340254Speter return 0; 100440254Speter } 100540254Speter if (ef->symtab == ef->ddbsymtab) 100640254Speter return ENOENT; 100740254Speter if (es >= ef->ddbsymtab && ((es - ef->ddbsymtab) < ef->ddbsymcnt)) { 100840254Speter symval->name = ef->ddbstrtab + es->st_name; 100940254Speter symval->value = (caddr_t) ef->address + es->st_value; 101040254Speter symval->size = es->st_size; 101140254Speter return 0; 101240254Speter } 101340254Speter return ENOENT; 101438514Sdfr} 101538514Sdfr 101638514Sdfrstatic int 101738514Sdfrlink_elf_search_symbol(linker_file_t lf, caddr_t value, 101843301Sdillon c_linker_sym_t* sym, long* diffp) 101938514Sdfr{ 102059603Sdfr elf_file_t ef = (elf_file_t) lf; 102155090Sbde u_long off = (uintptr_t) (void *) value; 102238514Sdfr u_long diff = off; 102355090Sbde u_long st_value; 102439071Sdfr const Elf_Sym* es; 102539071Sdfr const Elf_Sym* best = 0; 102638514Sdfr int i; 102738514Sdfr 102840254Speter for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { 102938514Sdfr if (es->st_name == 0) 103038514Sdfr continue; 103155090Sbde st_value = es->st_value + (uintptr_t) (void *) ef->address; 103253820Speter if (off >= st_value) { 103353820Speter if (off - st_value < diff) { 103453820Speter diff = off - st_value; 103538514Sdfr best = es; 103638514Sdfr if (diff == 0) 103738514Sdfr break; 103853820Speter } else if (off - st_value == diff) { 103938514Sdfr best = es; 104038514Sdfr } 104138514Sdfr } 104238514Sdfr } 104338514Sdfr if (best == 0) 104438514Sdfr *diffp = off; 104538514Sdfr else 104638514Sdfr *diffp = diff; 104743301Sdillon *sym = (c_linker_sym_t) best; 104838514Sdfr 104938514Sdfr return 0; 105038514Sdfr} 1051