link_elf.c revision 62550
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 62550 2000-07-04 03:34:11Z mckusick $ 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> 4439071Sdfr#include <sys/lock.h> 4552128Speter#ifdef SPARSE_MAPPING 4639071Sdfr#include <vm/vm_object.h> 4739071Sdfr#include <vm/vm_kern.h> 4839071Sdfr#include <vm/vm_extern.h> 4952128Speter#endif 5039071Sdfr#include <vm/pmap.h> 5139071Sdfr#include <vm/vm_map.h> 5259603Sdfr#include <link.h> 5339071Sdfr 5459603Sdfr#include "linker_if.h" 5538514Sdfr 5638514Sdfrtypedef struct elf_file { 5759603Sdfr struct linker_file lf; /* Common fields */ 5859603Sdfr int preloaded; /* Was file pre-loaded */ 5939071Sdfr caddr_t address; /* Relocation address */ 6039071Sdfr#ifdef SPARSE_MAPPING 6139071Sdfr vm_object_t object; /* VM object to hold file pages */ 6239071Sdfr#endif 6359603Sdfr Elf_Dyn* dynamic; /* Symbol table etc. */ 6438514Sdfr Elf_Off nbuckets; /* DT_HASH info */ 6538514Sdfr Elf_Off nchains; 6638514Sdfr const Elf_Off* buckets; 6738514Sdfr const Elf_Off* chains; 6838514Sdfr caddr_t hash; 6938514Sdfr caddr_t strtab; /* DT_STRTAB */ 7040254Speter int strsz; /* DT_STRSZ */ 7139071Sdfr const Elf_Sym* symtab; /* DT_SYMTAB */ 7239071Sdfr Elf_Addr* got; /* DT_PLTGOT */ 7339071Sdfr const Elf_Rel* pltrel; /* DT_JMPREL */ 7439071Sdfr int pltrelsize; /* DT_PLTRELSZ */ 7539071Sdfr const Elf_Rela* pltrela; /* DT_JMPREL */ 7639071Sdfr int pltrelasize; /* DT_PLTRELSZ */ 7739071Sdfr const Elf_Rel* rel; /* DT_REL */ 7839071Sdfr int relsize; /* DT_RELSZ */ 7939071Sdfr const Elf_Rela* rela; /* DT_RELA */ 8039071Sdfr int relasize; /* DT_RELASZ */ 8140254Speter caddr_t modptr; 8240254Speter const Elf_Sym* ddbsymtab; /* The symbol table we are using */ 8340254Speter long ddbsymcnt; /* Number of symbols */ 8440254Speter caddr_t ddbstrtab; /* String table */ 8540254Speter long ddbstrcnt; /* number of bytes in string table */ 8640292Speter caddr_t symbase; /* malloc'ed symbold base */ 8740292Speter caddr_t strbase; /* malloc'ed string base */ 8859603Sdfr#ifdef DDB 8959603Sdfr struct link_map gdb; /* hooks for gdb */ 9059603Sdfr#endif 9138514Sdfr} *elf_file_t; 9238514Sdfr 9359751Speterstatic int link_elf_link_preload(linker_class_t cls, 9459751Speter const char*, linker_file_t*); 9559751Speterstatic int link_elf_link_preload_finish(linker_file_t); 9659751Speterstatic int link_elf_load_file(linker_class_t, const char*, linker_file_t*); 9759603Sdfrstatic int link_elf_lookup_symbol(linker_file_t, const char*, 9859603Sdfr c_linker_sym_t*); 9959603Sdfrstatic int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); 10059603Sdfrstatic int link_elf_search_symbol(linker_file_t, caddr_t value, 10159603Sdfr c_linker_sym_t* sym, long* diffp); 10238514Sdfr 10359603Sdfrstatic void link_elf_unload_file(linker_file_t); 10459751Speterstatic void link_elf_unload_preload(linker_file_t); 10559603Sdfr 10659603Sdfrstatic kobj_method_t link_elf_methods[] = { 10759603Sdfr KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), 10859603Sdfr KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), 10959603Sdfr KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), 11059603Sdfr KOBJMETHOD(linker_unload, link_elf_unload_file), 11159751Speter KOBJMETHOD(linker_load_file, link_elf_load_file), 11259751Speter KOBJMETHOD(linker_link_preload, link_elf_link_preload), 11359751Speter KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), 11459603Sdfr { 0, 0 } 11559603Sdfr}; 11659603Sdfr 11759603Sdfrstatic struct linker_class link_elf_class = { 11859603Sdfr#if ELF_TARG_CLASS == ELFCLASS32 11959603Sdfr "elf32", 12059603Sdfr#else 12159603Sdfr "elf64", 12259603Sdfr#endif 12359603Sdfr link_elf_methods, sizeof(struct elf_file) 12459603Sdfr}; 12559603Sdfr 12659603Sdfrstatic int parse_dynamic(elf_file_t ef); 12759603Sdfrstatic int relocate_file(elf_file_t ef); 12859751Speterstatic int link_elf_preload_parse_symbols(elf_file_t ef); 12959603Sdfr 13059603Sdfr#ifdef DDB 13159603Sdfr 13238514Sdfr/* 13359603Sdfr * A list of loaded modules for GDB to use for loading symbols. 13459603Sdfr */ 13559603Sdfrstruct r_debug r_debug; 13659603Sdfr 13759603Sdfr#define GDB_STATE(s) r_debug.r_state = s; r_debug_state(); 13859603Sdfr 13959603Sdfr/* 14059603Sdfr * Function for the debugger to set a breakpoint on to gain control. 14159603Sdfr */ 14259603Sdfrvoid 14359603Sdfrr_debug_state(void) 14459603Sdfr{ 14559603Sdfr} 14659603Sdfr 14759603Sdfr#endif 14859603Sdfr 14959603Sdfr/* 15038514Sdfr * The kernel symbol table starts here. 15138514Sdfr */ 15238514Sdfrextern struct _dynamic _DYNAMIC; 15338514Sdfr 15438514Sdfrstatic void 15538514Sdfrlink_elf_init(void* arg) 15638514Sdfr{ 15740156Speter#ifdef __ELF__ 15840156Speter Elf_Dyn *dp; 15940156Speter caddr_t modptr, baseptr, sizeptr; 16040156Speter elf_file_t ef; 16140156Speter char *modname; 16240156Speter#endif 16338514Sdfr 16459603Sdfr linker_add_class(&link_elf_class); 16538514Sdfr 16640156Speter#ifdef __ELF__ 16740156Speter dp = (Elf_Dyn*) &_DYNAMIC; 16838514Sdfr if (dp) { 16940156Speter modname = NULL; 17040156Speter modptr = preload_search_by_type("elf kernel"); 17140156Speter if (modptr) 17240156Speter modname = (char *)preload_search_info(modptr, MODINFO_NAME); 17340156Speter if (modname == NULL) 17440156Speter modname = "kernel"; 17559603Sdfr linker_kernel_file = linker_make_file(modname, &link_elf_class); 17638514Sdfr if (linker_kernel_file == NULL) 17738514Sdfr panic("link_elf_init: Can't create linker structures for kernel"); 17859603Sdfr 17959603Sdfr ef = (elf_file_t) linker_kernel_file; 18059751Speter ef->preloaded = 1; 18159603Sdfr ef->address = 0; 18259603Sdfr#ifdef SPARSE_MAPPING 18359603Sdfr ef->object = 0; 18459603Sdfr#endif 18559603Sdfr ef->dynamic = dp; 18659603Sdfr 18759603Sdfr parse_dynamic(ef); 18846694Speter linker_kernel_file->address = (caddr_t) KERNBASE; 18950275Sbde linker_kernel_file->size = -(intptr_t)linker_kernel_file->address; 19040156Speter 19140156Speter if (modptr) { 19240254Speter ef->modptr = modptr; 19340156Speter baseptr = preload_search_info(modptr, MODINFO_ADDR); 19440156Speter if (baseptr) 19540156Speter linker_kernel_file->address = *(caddr_t *)baseptr; 19640156Speter sizeptr = preload_search_info(modptr, MODINFO_SIZE); 19740156Speter if (sizeptr) 19840156Speter linker_kernel_file->size = *(size_t *)sizeptr; 19940156Speter } 20059751Speter (void)link_elf_preload_parse_symbols(ef); 20159603Sdfr 20259603Sdfr#ifdef DDB 20359603Sdfr ef->gdb.l_addr = linker_kernel_file->address; 20459603Sdfr ef->gdb.l_name = modname; 20559603Sdfr ef->gdb.l_ld = dp; 20659603Sdfr ef->gdb.l_prev = 0; 20759603Sdfr ef->gdb.l_next = 0; 20859603Sdfr 20959603Sdfr r_debug.r_map = &ef->gdb; 21059603Sdfr r_debug.r_brk = r_debug_state; 21159603Sdfr r_debug.r_state = RT_CONSISTENT; 21259603Sdfr 21359603Sdfr r_debug_state(); /* say hello to gdb! */ 21459603Sdfr#endif 21559603Sdfr 21638514Sdfr } 21740156Speter#endif 21838514Sdfr} 21938514Sdfr 22040156SpeterSYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); 22138514Sdfr 22238514Sdfrstatic int 22359751Speterlink_elf_preload_parse_symbols(elf_file_t ef) 22440254Speter{ 22540254Speter caddr_t pointer; 22640254Speter caddr_t ssym, esym, base; 22740254Speter caddr_t strtab; 22840254Speter int strcnt; 22940254Speter Elf_Sym* symtab; 23040254Speter int symcnt; 23140254Speter 23240292Speter if (ef->modptr == NULL) 23340292Speter return 0; 23440254Speter pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM); 23540254Speter if (pointer == NULL) 23640254Speter return 0; 23740254Speter ssym = *(caddr_t *)pointer; 23840254Speter pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM); 23940254Speter if (pointer == NULL) 24040254Speter return 0; 24140254Speter esym = *(caddr_t *)pointer; 24240254Speter 24340254Speter base = ssym; 24440254Speter 24540254Speter symcnt = *(long *)base; 24640254Speter base += sizeof(long); 24740254Speter symtab = (Elf_Sym *)base; 24840254Speter base += roundup(symcnt, sizeof(long)); 24940254Speter 25040254Speter if (base > esym || base < ssym) { 25140254Speter printf("Symbols are corrupt!\n"); 25240254Speter return EINVAL; 25340254Speter } 25440254Speter 25540254Speter strcnt = *(long *)base; 25640254Speter base += sizeof(long); 25740254Speter strtab = base; 25840254Speter base += roundup(strcnt, sizeof(long)); 25940254Speter 26040254Speter if (base > esym || base < ssym) { 26140254Speter printf("Symbols are corrupt!\n"); 26240254Speter return EINVAL; 26340254Speter } 26440254Speter 26540254Speter ef->ddbsymtab = symtab; 26640254Speter ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 26740254Speter ef->ddbstrtab = strtab; 26840254Speter ef->ddbstrcnt = strcnt; 26940254Speter 27040254Speter return 0; 27140254Speter} 27240254Speter 27340254Speterstatic int 27459603Sdfrparse_dynamic(elf_file_t ef) 27538514Sdfr{ 27659603Sdfr Elf_Dyn *dp; 27739071Sdfr int plttype = DT_REL; 27838514Sdfr 27938514Sdfr for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 28038514Sdfr switch (dp->d_tag) { 28138514Sdfr case DT_HASH: 28238514Sdfr { 28338514Sdfr /* From src/libexec/rtld-elf/rtld.c */ 28438514Sdfr const Elf_Off *hashtab = (const Elf_Off *) 28538514Sdfr (ef->address + dp->d_un.d_ptr); 28638514Sdfr ef->nbuckets = hashtab[0]; 28738514Sdfr ef->nchains = hashtab[1]; 28838514Sdfr ef->buckets = hashtab + 2; 28938514Sdfr ef->chains = ef->buckets + ef->nbuckets; 29038514Sdfr break; 29138514Sdfr } 29238514Sdfr case DT_STRTAB: 29339071Sdfr ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 29438514Sdfr break; 29540254Speter case DT_STRSZ: 29640254Speter ef->strsz = dp->d_un.d_val; 29740254Speter break; 29838514Sdfr case DT_SYMTAB: 29939071Sdfr ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 30038514Sdfr break; 30138514Sdfr case DT_SYMENT: 30238514Sdfr if (dp->d_un.d_val != sizeof(Elf_Sym)) 30338514Sdfr return ENOEXEC; 30439071Sdfr break; 30539071Sdfr case DT_PLTGOT: 30639071Sdfr ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 30739071Sdfr break; 30839071Sdfr case DT_REL: 30939071Sdfr ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 31039071Sdfr break; 31139071Sdfr case DT_RELSZ: 31239071Sdfr ef->relsize = dp->d_un.d_val; 31339071Sdfr break; 31439071Sdfr case DT_RELENT: 31539071Sdfr if (dp->d_un.d_val != sizeof(Elf_Rel)) 31639071Sdfr return ENOEXEC; 31739071Sdfr break; 31839071Sdfr case DT_JMPREL: 31939071Sdfr ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 32039071Sdfr break; 32139071Sdfr case DT_PLTRELSZ: 32239071Sdfr ef->pltrelsize = dp->d_un.d_val; 32339071Sdfr break; 32439071Sdfr case DT_RELA: 32539071Sdfr ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 32639071Sdfr break; 32739071Sdfr case DT_RELASZ: 32839071Sdfr ef->relasize = dp->d_un.d_val; 32939071Sdfr break; 33039071Sdfr case DT_RELAENT: 33139071Sdfr if (dp->d_un.d_val != sizeof(Elf_Rela)) 33239071Sdfr return ENOEXEC; 33339071Sdfr break; 33439071Sdfr case DT_PLTREL: 33539071Sdfr plttype = dp->d_un.d_val; 33639071Sdfr if (plttype != DT_REL && plttype != DT_RELA) 33739071Sdfr return ENOEXEC; 33839071Sdfr break; 33959603Sdfr#ifdef DDB 34059603Sdfr case DT_DEBUG: 34159603Sdfr dp->d_un.d_ptr = (Elf_Addr) &r_debug; 34259603Sdfr break; 34359603Sdfr#endif 34438514Sdfr } 34538514Sdfr } 34639071Sdfr 34739071Sdfr if (plttype == DT_RELA) { 34839071Sdfr ef->pltrela = (const Elf_Rela *) ef->pltrel; 34939071Sdfr ef->pltrel = NULL; 35039071Sdfr ef->pltrelasize = ef->pltrelsize; 35139071Sdfr ef->pltrelsize = 0; 35239071Sdfr } 35339071Sdfr 35440254Speter ef->ddbsymtab = ef->symtab; 35540254Speter ef->ddbsymcnt = ef->nchains; 35640254Speter ef->ddbstrtab = ef->strtab; 35740254Speter ef->ddbstrcnt = ef->strsz; 35840254Speter 35938514Sdfr return 0; 36038514Sdfr} 36138514Sdfr 36239071Sdfrstatic void 36339071Sdfrlink_elf_error(const char *s) 36439071Sdfr{ 36539071Sdfr printf("kldload: %s\n", s); 36639071Sdfr} 36739071Sdfr 36859603Sdfr#ifdef DDB 36959603Sdfr 37059603Sdfrstatic void 37159603Sdfrlink_elf_add_gdb(struct link_map *l) 37259603Sdfr{ 37359603Sdfr struct link_map *prev; 37459603Sdfr 37559603Sdfr /* 37659603Sdfr * Scan to the end of the list. 37759603Sdfr */ 37859603Sdfr for (prev = r_debug.r_map; prev->l_next != NULL; prev = prev->l_next) 37959603Sdfr ; 38059603Sdfr 38159603Sdfr /* Link in the new entry. */ 38259603Sdfr l->l_prev = prev; 38359603Sdfr l->l_next = prev->l_next; 38459603Sdfr prev->l_next = l; 38559603Sdfr} 38659603Sdfr 38759603Sdfrstatic void 38859603Sdfrlink_elf_delete_gdb(struct link_map *l) 38959603Sdfr{ 39059603Sdfr if (l->l_prev == NULL) { 39159603Sdfr if ((r_debug.r_map = l->l_next) != NULL) 39259603Sdfr l->l_next->l_prev = NULL; 39359603Sdfr return; 39459603Sdfr } 39559603Sdfr 39659603Sdfr if ((l->l_prev->l_next = l->l_next) != NULL) 39759603Sdfr l->l_next->l_prev = l->l_prev; 39859603Sdfr} 39959603Sdfr 40059603Sdfr#endif /* DDB */ 40159603Sdfr 40238514Sdfrstatic int 40359751Speterlink_elf_link_preload(linker_class_t cls, 40459751Speter const char* filename, linker_file_t *result) 40540156Speter{ 40640156Speter caddr_t modptr, baseptr, sizeptr, dynptr; 40740156Speter char *type; 40840156Speter elf_file_t ef; 40940156Speter linker_file_t lf; 41040156Speter int error; 41140156Speter vm_offset_t dp; 41240156Speter 41359751Speter /* Look to see if we have the file preloaded */ 41440156Speter modptr = preload_search_by_name(filename); 41540156Speter if (modptr == NULL) 41659751Speter return ENOENT; 41740156Speter 41840156Speter type = (char *)preload_search_info(modptr, MODINFO_TYPE); 41940156Speter baseptr = preload_search_info(modptr, MODINFO_ADDR); 42040156Speter sizeptr = preload_search_info(modptr, MODINFO_SIZE); 42140156Speter dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC); 42240156Speter if (type == NULL || strcmp(type, "elf module") != 0) 42340156Speter return (EFTYPE); 42440156Speter if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) 42540156Speter return (EINVAL); 42640156Speter 42759603Sdfr lf = linker_make_file(filename, &link_elf_class); 42859603Sdfr if (lf == NULL) { 42959603Sdfr return ENOMEM; 43059603Sdfr } 43159603Sdfr 43259603Sdfr ef = (elf_file_t) lf; 43359603Sdfr ef->preloaded = 1; 43440292Speter ef->modptr = modptr; 43540156Speter ef->address = *(caddr_t *)baseptr; 43640156Speter#ifdef SPARSE_MAPPING 43740156Speter ef->object = 0; 43840156Speter#endif 43940156Speter dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; 44040156Speter ef->dynamic = (Elf_Dyn *)dp; 44140156Speter lf->address = ef->address; 44240156Speter lf->size = *(size_t *)sizeptr; 44340156Speter 44459603Sdfr error = parse_dynamic(ef); 44540156Speter if (error) { 44640156Speter linker_file_unload(lf); 44740156Speter return error; 44840156Speter } 44959751Speter *result = lf; 45059751Speter return (0); 45159751Speter} 45259751Speter 45359751Speterstatic int 45459751Speterlink_elf_link_preload_finish(linker_file_t lf) 45559751Speter{ 45659751Speter elf_file_t ef; 45759751Speter int error; 45859751Speter 45959751Speter ef = (elf_file_t) lf; 46059751Speter#if 0 /* this will be more trouble than it's worth for now */ 46159751Speter for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 46259751Speter if (dp->d_tag != DT_NEEDED) 46359751Speter continue; 46459751Speter modname = ef->strtab + dp->d_un.d_val; 46559751Speter error = linker_load_module(modname, lf); 46659751Speter if (error) 46759751Speter goto out; 46840156Speter } 46959751Speter#endif 47059603Sdfr error = relocate_file(ef); 47159751Speter if (error) 47240156Speter return error; 47359751Speter (void)link_elf_preload_parse_symbols(ef); 47459603Sdfr 47559603Sdfr#ifdef DDB 47659603Sdfr GDB_STATE(RT_ADD); 47759603Sdfr ef->gdb.l_addr = lf->address; 47859751Speter ef->gdb.l_name = lf->filename; 47959603Sdfr ef->gdb.l_ld = ef->dynamic; 48059603Sdfr link_elf_add_gdb(&ef->gdb); 48159603Sdfr GDB_STATE(RT_CONSISTENT); 48259603Sdfr#endif 48359603Sdfr 48440156Speter return (0); 48540156Speter} 48640156Speter 48740156Speterstatic int 48859751Speterlink_elf_load_file(linker_class_t cls, const char* filename, linker_file_t* result) 48938514Sdfr{ 49038514Sdfr struct nameidata nd; 49138514Sdfr struct proc* p = curproc; /* XXX */ 49240962Speter Elf_Ehdr *hdr; 49340962Speter caddr_t firstpage; 49439071Sdfr int nbytes, i; 49539071Sdfr Elf_Phdr *phdr; 49639071Sdfr Elf_Phdr *phlimit; 49739071Sdfr Elf_Phdr *segs[2]; 49839071Sdfr int nsegs; 49939071Sdfr Elf_Phdr *phdyn; 50039071Sdfr Elf_Phdr *phphdr; 50139071Sdfr caddr_t mapbase; 50239071Sdfr size_t mapsize; 50339071Sdfr Elf_Off base_offset; 50439071Sdfr Elf_Addr base_vaddr; 50539071Sdfr Elf_Addr base_vlimit; 50638514Sdfr int error = 0; 50762550Smckusick int resid, flags; 50838514Sdfr elf_file_t ef; 50938514Sdfr linker_file_t lf; 51040292Speter Elf_Shdr *shdr; 51140292Speter int symtabindex; 51240292Speter int symstrindex; 51340292Speter int symcnt; 51440292Speter int strcnt; 51538514Sdfr 51640292Speter shdr = NULL; 51740292Speter lf = NULL; 51840292Speter 51959751Speter NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); 52062550Smckusick flags = FREAD; 52162550Smckusick error = vn_open(&nd, &flags, 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