link_elf.c revision 78161
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 78161 2001-06-13 10:58:39Z peter $ 2738514Sdfr */ 2838514Sdfr 2959603Sdfr#include "opt_ddb.h" 3059603Sdfr 3138514Sdfr#include <sys/param.h> 3276166Smarkm#include <sys/systm.h> 3338514Sdfr#include <sys/kernel.h> 3476166Smarkm#include <sys/lock.h> 3538514Sdfr#include <sys/malloc.h> 3677642Sdd#include <sys/mutex.h> 3738514Sdfr#include <sys/proc.h> 3838514Sdfr#include <sys/namei.h> 3938514Sdfr#include <sys/fcntl.h> 4038514Sdfr#include <sys/vnode.h> 4138514Sdfr#include <sys/linker.h> 4276166Smarkm 4338514Sdfr#include <machine/elf.h> 4438514Sdfr 4539071Sdfr#include <vm/vm.h> 4639071Sdfr#include <vm/vm_param.h> 4752128Speter#ifdef SPARSE_MAPPING 4839071Sdfr#include <vm/vm_object.h> 4939071Sdfr#include <vm/vm_kern.h> 5039071Sdfr#include <vm/vm_extern.h> 5152128Speter#endif 5239071Sdfr#include <vm/pmap.h> 5339071Sdfr#include <vm/vm_map.h> 5476166Smarkm 5573016Speter#ifdef __AOUT__ 5673016Speter#include <nlist.h> 5773016Speter#endif 5859603Sdfr#include <link.h> 5939071Sdfr 6059603Sdfr#include "linker_if.h" 6138514Sdfr 6238514Sdfrtypedef struct elf_file { 6359603Sdfr struct linker_file lf; /* Common fields */ 6459603Sdfr int preloaded; /* Was file pre-loaded */ 6539071Sdfr caddr_t address; /* Relocation address */ 6639071Sdfr#ifdef SPARSE_MAPPING 6739071Sdfr vm_object_t object; /* VM object to hold file pages */ 6839071Sdfr#endif 6959603Sdfr Elf_Dyn* dynamic; /* Symbol table etc. */ 7038514Sdfr Elf_Off nbuckets; /* DT_HASH info */ 7138514Sdfr Elf_Off nchains; 7238514Sdfr const Elf_Off* buckets; 7338514Sdfr const Elf_Off* chains; 7438514Sdfr caddr_t hash; 7538514Sdfr caddr_t strtab; /* DT_STRTAB */ 7640254Speter int strsz; /* DT_STRSZ */ 7739071Sdfr const Elf_Sym* symtab; /* DT_SYMTAB */ 7839071Sdfr Elf_Addr* got; /* DT_PLTGOT */ 7939071Sdfr const Elf_Rel* pltrel; /* DT_JMPREL */ 8039071Sdfr int pltrelsize; /* DT_PLTRELSZ */ 8139071Sdfr const Elf_Rela* pltrela; /* DT_JMPREL */ 8239071Sdfr int pltrelasize; /* DT_PLTRELSZ */ 8339071Sdfr const Elf_Rel* rel; /* DT_REL */ 8439071Sdfr int relsize; /* DT_RELSZ */ 8539071Sdfr const Elf_Rela* rela; /* DT_RELA */ 8639071Sdfr int relasize; /* DT_RELASZ */ 8740254Speter caddr_t modptr; 8840254Speter const Elf_Sym* ddbsymtab; /* The symbol table we are using */ 8940254Speter long ddbsymcnt; /* Number of symbols */ 9040254Speter caddr_t ddbstrtab; /* String table */ 9140254Speter long ddbstrcnt; /* number of bytes in string table */ 9240292Speter caddr_t symbase; /* malloc'ed symbold base */ 9340292Speter caddr_t strbase; /* malloc'ed string base */ 9459603Sdfr#ifdef DDB 9559603Sdfr struct link_map gdb; /* hooks for gdb */ 9659603Sdfr#endif 9738514Sdfr} *elf_file_t; 9838514Sdfr 9959751Speterstatic int link_elf_link_preload(linker_class_t cls, 10059751Speter const char*, linker_file_t*); 10159751Speterstatic int link_elf_link_preload_finish(linker_file_t); 10259751Speterstatic int link_elf_load_file(linker_class_t, const char*, linker_file_t*); 10359603Sdfrstatic int link_elf_lookup_symbol(linker_file_t, const char*, 10459603Sdfr c_linker_sym_t*); 10559603Sdfrstatic int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); 10659603Sdfrstatic int link_elf_search_symbol(linker_file_t, caddr_t value, 10759603Sdfr c_linker_sym_t* sym, long* diffp); 10838514Sdfr 10959603Sdfrstatic void link_elf_unload_file(linker_file_t); 11059751Speterstatic void link_elf_unload_preload(linker_file_t); 11178161Speterstatic int link_elf_lookup_set(linker_file_t, const char *, 11278161Speter void ***, void ***, int *); 11359603Sdfr 11459603Sdfrstatic kobj_method_t link_elf_methods[] = { 11559603Sdfr KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), 11659603Sdfr KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), 11759603Sdfr KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), 11859603Sdfr KOBJMETHOD(linker_unload, link_elf_unload_file), 11959751Speter KOBJMETHOD(linker_load_file, link_elf_load_file), 12059751Speter KOBJMETHOD(linker_link_preload, link_elf_link_preload), 12159751Speter KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), 12278161Speter KOBJMETHOD(linker_lookup_set, link_elf_lookup_set), 12359603Sdfr { 0, 0 } 12459603Sdfr}; 12559603Sdfr 12659603Sdfrstatic struct linker_class link_elf_class = { 12759603Sdfr#if ELF_TARG_CLASS == ELFCLASS32 12859603Sdfr "elf32", 12959603Sdfr#else 13059603Sdfr "elf64", 13159603Sdfr#endif 13259603Sdfr link_elf_methods, sizeof(struct elf_file) 13359603Sdfr}; 13459603Sdfr 13559603Sdfrstatic int parse_dynamic(elf_file_t ef); 13659603Sdfrstatic int relocate_file(elf_file_t ef); 13759751Speterstatic int link_elf_preload_parse_symbols(elf_file_t ef); 13859603Sdfr 13959603Sdfr#ifdef DDB 14066719Sjhbstatic void r_debug_state(struct r_debug *dummy_one, 14166719Sjhb struct link_map *dummy_two); 14259603Sdfr 14338514Sdfr/* 14459603Sdfr * A list of loaded modules for GDB to use for loading symbols. 14559603Sdfr */ 14659603Sdfrstruct r_debug r_debug; 14759603Sdfr 14866719Sjhb#define GDB_STATE(s) r_debug.r_state = s; r_debug_state(NULL, NULL); 14959603Sdfr 15059603Sdfr/* 15159603Sdfr * Function for the debugger to set a breakpoint on to gain control. 15259603Sdfr */ 15359603Sdfrvoid 15466719Sjhbr_debug_state(struct r_debug *dummy_one __unused, 15566719Sjhb struct link_map *dummy_two __unused) 15659603Sdfr{ 15759603Sdfr} 15859603Sdfr 15959603Sdfr#endif 16059603Sdfr 16159603Sdfr/* 16238514Sdfr * The kernel symbol table starts here. 16338514Sdfr */ 16466454Sdfr#ifndef __ia64__ 16538514Sdfrextern struct _dynamic _DYNAMIC; 16666454Sdfr#endif 16738514Sdfr 16838514Sdfrstatic void 16938514Sdfrlink_elf_init(void* arg) 17038514Sdfr{ 17140156Speter#ifdef __ELF__ 17240156Speter Elf_Dyn *dp; 17340156Speter caddr_t modptr, baseptr, sizeptr; 17440156Speter elf_file_t ef; 17540156Speter char *modname; 17640156Speter#endif 17738514Sdfr 17859603Sdfr linker_add_class(&link_elf_class); 17938514Sdfr 18040156Speter#ifdef __ELF__ 18166454Sdfr#ifndef __ia64__ 18240156Speter dp = (Elf_Dyn*) &_DYNAMIC; 18366454Sdfr#else 18466454Sdfr dp = 0; 18566454Sdfr#endif 18638514Sdfr if (dp) { 18740156Speter modname = NULL; 18840156Speter modptr = preload_search_by_type("elf kernel"); 18940156Speter if (modptr) 19040156Speter modname = (char *)preload_search_info(modptr, MODINFO_NAME); 19140156Speter if (modname == NULL) 19240156Speter modname = "kernel"; 19359603Sdfr linker_kernel_file = linker_make_file(modname, &link_elf_class); 19438514Sdfr if (linker_kernel_file == NULL) 19538514Sdfr panic("link_elf_init: Can't create linker structures for kernel"); 19659603Sdfr 19759603Sdfr ef = (elf_file_t) linker_kernel_file; 19859751Speter ef->preloaded = 1; 19959603Sdfr ef->address = 0; 20059603Sdfr#ifdef SPARSE_MAPPING 20159603Sdfr ef->object = 0; 20259603Sdfr#endif 20359603Sdfr ef->dynamic = dp; 20459603Sdfr 20559603Sdfr parse_dynamic(ef); 20646694Speter linker_kernel_file->address = (caddr_t) KERNBASE; 20750275Sbde linker_kernel_file->size = -(intptr_t)linker_kernel_file->address; 20840156Speter 20940156Speter if (modptr) { 21040254Speter ef->modptr = modptr; 21140156Speter baseptr = preload_search_info(modptr, MODINFO_ADDR); 21240156Speter if (baseptr) 21340156Speter linker_kernel_file->address = *(caddr_t *)baseptr; 21440156Speter sizeptr = preload_search_info(modptr, MODINFO_SIZE); 21540156Speter if (sizeptr) 21640156Speter linker_kernel_file->size = *(size_t *)sizeptr; 21740156Speter } 21859751Speter (void)link_elf_preload_parse_symbols(ef); 21959603Sdfr 22059603Sdfr#ifdef DDB 22159603Sdfr ef->gdb.l_addr = linker_kernel_file->address; 22259603Sdfr ef->gdb.l_name = modname; 22359603Sdfr ef->gdb.l_ld = dp; 22459603Sdfr ef->gdb.l_prev = 0; 22559603Sdfr ef->gdb.l_next = 0; 22659603Sdfr 22759603Sdfr r_debug.r_map = &ef->gdb; 22859603Sdfr r_debug.r_brk = r_debug_state; 22959603Sdfr r_debug.r_state = RT_CONSISTENT; 23059603Sdfr 23166719Sjhb r_debug_state(NULL, NULL); /* say hello to gdb! */ 23259603Sdfr#endif 23359603Sdfr 23438514Sdfr } 23540156Speter#endif 23638514Sdfr} 23738514Sdfr 23840156SpeterSYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); 23938514Sdfr 24038514Sdfrstatic int 24159751Speterlink_elf_preload_parse_symbols(elf_file_t ef) 24240254Speter{ 24340254Speter caddr_t pointer; 24440254Speter caddr_t ssym, esym, base; 24540254Speter caddr_t strtab; 24640254Speter int strcnt; 24740254Speter Elf_Sym* symtab; 24840254Speter int symcnt; 24940254Speter 25040292Speter if (ef->modptr == NULL) 25140292Speter return 0; 25240254Speter pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM); 25340254Speter if (pointer == NULL) 25440254Speter return 0; 25540254Speter ssym = *(caddr_t *)pointer; 25640254Speter pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM); 25740254Speter if (pointer == NULL) 25840254Speter return 0; 25940254Speter esym = *(caddr_t *)pointer; 26040254Speter 26140254Speter base = ssym; 26240254Speter 26340254Speter symcnt = *(long *)base; 26440254Speter base += sizeof(long); 26540254Speter symtab = (Elf_Sym *)base; 26640254Speter base += roundup(symcnt, sizeof(long)); 26740254Speter 26840254Speter if (base > esym || base < ssym) { 26940254Speter printf("Symbols are corrupt!\n"); 27040254Speter return EINVAL; 27140254Speter } 27240254Speter 27340254Speter strcnt = *(long *)base; 27440254Speter base += sizeof(long); 27540254Speter strtab = base; 27640254Speter base += roundup(strcnt, sizeof(long)); 27740254Speter 27840254Speter if (base > esym || base < ssym) { 27940254Speter printf("Symbols are corrupt!\n"); 28040254Speter return EINVAL; 28140254Speter } 28240254Speter 28340254Speter ef->ddbsymtab = symtab; 28440254Speter ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 28540254Speter ef->ddbstrtab = strtab; 28640254Speter ef->ddbstrcnt = strcnt; 28740254Speter 28840254Speter return 0; 28940254Speter} 29040254Speter 29140254Speterstatic int 29259603Sdfrparse_dynamic(elf_file_t ef) 29338514Sdfr{ 29459603Sdfr Elf_Dyn *dp; 29539071Sdfr int plttype = DT_REL; 29638514Sdfr 29738514Sdfr for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 29838514Sdfr switch (dp->d_tag) { 29938514Sdfr case DT_HASH: 30038514Sdfr { 30138514Sdfr /* From src/libexec/rtld-elf/rtld.c */ 30238514Sdfr const Elf_Off *hashtab = (const Elf_Off *) 30338514Sdfr (ef->address + dp->d_un.d_ptr); 30438514Sdfr ef->nbuckets = hashtab[0]; 30538514Sdfr ef->nchains = hashtab[1]; 30638514Sdfr ef->buckets = hashtab + 2; 30738514Sdfr ef->chains = ef->buckets + ef->nbuckets; 30838514Sdfr break; 30938514Sdfr } 31038514Sdfr case DT_STRTAB: 31139071Sdfr ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 31238514Sdfr break; 31340254Speter case DT_STRSZ: 31440254Speter ef->strsz = dp->d_un.d_val; 31540254Speter break; 31638514Sdfr case DT_SYMTAB: 31739071Sdfr ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 31838514Sdfr break; 31938514Sdfr case DT_SYMENT: 32038514Sdfr if (dp->d_un.d_val != sizeof(Elf_Sym)) 32138514Sdfr return ENOEXEC; 32239071Sdfr break; 32339071Sdfr case DT_PLTGOT: 32439071Sdfr ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 32539071Sdfr break; 32639071Sdfr case DT_REL: 32739071Sdfr ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 32839071Sdfr break; 32939071Sdfr case DT_RELSZ: 33039071Sdfr ef->relsize = dp->d_un.d_val; 33139071Sdfr break; 33239071Sdfr case DT_RELENT: 33339071Sdfr if (dp->d_un.d_val != sizeof(Elf_Rel)) 33439071Sdfr return ENOEXEC; 33539071Sdfr break; 33639071Sdfr case DT_JMPREL: 33739071Sdfr ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 33839071Sdfr break; 33939071Sdfr case DT_PLTRELSZ: 34039071Sdfr ef->pltrelsize = dp->d_un.d_val; 34139071Sdfr break; 34239071Sdfr case DT_RELA: 34339071Sdfr ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 34439071Sdfr break; 34539071Sdfr case DT_RELASZ: 34639071Sdfr ef->relasize = dp->d_un.d_val; 34739071Sdfr break; 34839071Sdfr case DT_RELAENT: 34939071Sdfr if (dp->d_un.d_val != sizeof(Elf_Rela)) 35039071Sdfr return ENOEXEC; 35139071Sdfr break; 35239071Sdfr case DT_PLTREL: 35339071Sdfr plttype = dp->d_un.d_val; 35439071Sdfr if (plttype != DT_REL && plttype != DT_RELA) 35539071Sdfr return ENOEXEC; 35639071Sdfr break; 35759603Sdfr#ifdef DDB 35859603Sdfr case DT_DEBUG: 35959603Sdfr dp->d_un.d_ptr = (Elf_Addr) &r_debug; 36059603Sdfr break; 36159603Sdfr#endif 36238514Sdfr } 36338514Sdfr } 36439071Sdfr 36539071Sdfr if (plttype == DT_RELA) { 36639071Sdfr ef->pltrela = (const Elf_Rela *) ef->pltrel; 36739071Sdfr ef->pltrel = NULL; 36839071Sdfr ef->pltrelasize = ef->pltrelsize; 36939071Sdfr ef->pltrelsize = 0; 37039071Sdfr } 37139071Sdfr 37240254Speter ef->ddbsymtab = ef->symtab; 37340254Speter ef->ddbsymcnt = ef->nchains; 37440254Speter ef->ddbstrtab = ef->strtab; 37540254Speter ef->ddbstrcnt = ef->strsz; 37640254Speter 37738514Sdfr return 0; 37838514Sdfr} 37938514Sdfr 38039071Sdfrstatic void 38139071Sdfrlink_elf_error(const char *s) 38239071Sdfr{ 38339071Sdfr printf("kldload: %s\n", s); 38439071Sdfr} 38539071Sdfr 38659603Sdfr#ifdef DDB 38759603Sdfr 38859603Sdfrstatic void 38959603Sdfrlink_elf_add_gdb(struct link_map *l) 39059603Sdfr{ 39159603Sdfr struct link_map *prev; 39259603Sdfr 39359603Sdfr /* 39459603Sdfr * Scan to the end of the list. 39559603Sdfr */ 39659603Sdfr for (prev = r_debug.r_map; prev->l_next != NULL; prev = prev->l_next) 39759603Sdfr ; 39859603Sdfr 39959603Sdfr /* Link in the new entry. */ 40059603Sdfr l->l_prev = prev; 40159603Sdfr l->l_next = prev->l_next; 40259603Sdfr prev->l_next = l; 40359603Sdfr} 40459603Sdfr 40559603Sdfrstatic void 40659603Sdfrlink_elf_delete_gdb(struct link_map *l) 40759603Sdfr{ 40859603Sdfr if (l->l_prev == NULL) { 40959603Sdfr if ((r_debug.r_map = l->l_next) != NULL) 41059603Sdfr l->l_next->l_prev = NULL; 41159603Sdfr return; 41259603Sdfr } 41359603Sdfr 41459603Sdfr if ((l->l_prev->l_next = l->l_next) != NULL) 41559603Sdfr l->l_next->l_prev = l->l_prev; 41659603Sdfr} 41759603Sdfr 41859603Sdfr#endif /* DDB */ 41959603Sdfr 42038514Sdfrstatic int 42159751Speterlink_elf_link_preload(linker_class_t cls, 42259751Speter const char* filename, linker_file_t *result) 42340156Speter{ 42440156Speter caddr_t modptr, baseptr, sizeptr, dynptr; 42540156Speter char *type; 42640156Speter elf_file_t ef; 42740156Speter linker_file_t lf; 42840156Speter int error; 42940156Speter vm_offset_t dp; 43040156Speter 43159751Speter /* Look to see if we have the file preloaded */ 43240156Speter modptr = preload_search_by_name(filename); 43340156Speter if (modptr == NULL) 43459751Speter return ENOENT; 43540156Speter 43640156Speter type = (char *)preload_search_info(modptr, MODINFO_TYPE); 43740156Speter baseptr = preload_search_info(modptr, MODINFO_ADDR); 43840156Speter sizeptr = preload_search_info(modptr, MODINFO_SIZE); 43940156Speter dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC); 44040156Speter if (type == NULL || strcmp(type, "elf module") != 0) 44140156Speter return (EFTYPE); 44240156Speter if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) 44340156Speter return (EINVAL); 44440156Speter 44559603Sdfr lf = linker_make_file(filename, &link_elf_class); 44659603Sdfr if (lf == NULL) { 44759603Sdfr return ENOMEM; 44859603Sdfr } 44959603Sdfr 45059603Sdfr ef = (elf_file_t) lf; 45159603Sdfr ef->preloaded = 1; 45240292Speter ef->modptr = modptr; 45340156Speter ef->address = *(caddr_t *)baseptr; 45440156Speter#ifdef SPARSE_MAPPING 45540156Speter ef->object = 0; 45640156Speter#endif 45740156Speter dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; 45840156Speter ef->dynamic = (Elf_Dyn *)dp; 45940156Speter lf->address = ef->address; 46040156Speter lf->size = *(size_t *)sizeptr; 46140156Speter 46259603Sdfr error = parse_dynamic(ef); 46340156Speter if (error) { 46440156Speter linker_file_unload(lf); 46540156Speter return error; 46640156Speter } 46759751Speter *result = lf; 46859751Speter return (0); 46959751Speter} 47059751Speter 47159751Speterstatic int 47259751Speterlink_elf_link_preload_finish(linker_file_t lf) 47359751Speter{ 47459751Speter elf_file_t ef; 47559751Speter int error; 47659751Speter 47759751Speter ef = (elf_file_t) lf; 47859751Speter#if 0 /* this will be more trouble than it's worth for now */ 47959751Speter for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 48059751Speter if (dp->d_tag != DT_NEEDED) 48159751Speter continue; 48259751Speter modname = ef->strtab + dp->d_un.d_val; 48359751Speter error = linker_load_module(modname, lf); 48459751Speter if (error) 48559751Speter goto out; 48640156Speter } 48759751Speter#endif 48859603Sdfr error = relocate_file(ef); 48959751Speter if (error) 49040156Speter return error; 49159751Speter (void)link_elf_preload_parse_symbols(ef); 49259603Sdfr 49359603Sdfr#ifdef DDB 49459603Sdfr GDB_STATE(RT_ADD); 49559603Sdfr ef->gdb.l_addr = lf->address; 49659751Speter ef->gdb.l_name = lf->filename; 49759603Sdfr ef->gdb.l_ld = ef->dynamic; 49859603Sdfr link_elf_add_gdb(&ef->gdb); 49959603Sdfr GDB_STATE(RT_CONSISTENT); 50059603Sdfr#endif 50159603Sdfr 50240156Speter return (0); 50340156Speter} 50440156Speter 50540156Speterstatic int 50659751Speterlink_elf_load_file(linker_class_t cls, const char* filename, linker_file_t* result) 50738514Sdfr{ 50838514Sdfr struct nameidata nd; 50938514Sdfr struct proc* p = curproc; /* XXX */ 51040962Speter Elf_Ehdr *hdr; 51140962Speter caddr_t firstpage; 51239071Sdfr int nbytes, i; 51339071Sdfr Elf_Phdr *phdr; 51439071Sdfr Elf_Phdr *phlimit; 51539071Sdfr Elf_Phdr *segs[2]; 51639071Sdfr int nsegs; 51739071Sdfr Elf_Phdr *phdyn; 51839071Sdfr Elf_Phdr *phphdr; 51939071Sdfr caddr_t mapbase; 52039071Sdfr size_t mapsize; 52139071Sdfr Elf_Off base_offset; 52239071Sdfr Elf_Addr base_vaddr; 52339071Sdfr Elf_Addr base_vlimit; 52438514Sdfr int error = 0; 52562550Smckusick int resid, flags; 52638514Sdfr elf_file_t ef; 52738514Sdfr linker_file_t lf; 52840292Speter Elf_Shdr *shdr; 52940292Speter int symtabindex; 53040292Speter int symstrindex; 53140292Speter int symcnt; 53240292Speter int strcnt; 53338514Sdfr 53440292Speter shdr = NULL; 53540292Speter lf = NULL; 53640292Speter 53759751Speter NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); 53862550Smckusick flags = FREAD; 53962550Smckusick error = vn_open(&nd, &flags, 0); 54038514Sdfr if (error) 54138514Sdfr return error; 54254655Seivind NDFREE(&nd, NDF_ONLY_PNBUF); 54338514Sdfr 54438514Sdfr /* 54539071Sdfr * Read the elf header from the file. 54638514Sdfr */ 54740962Speter firstpage = malloc(PAGE_SIZE, M_LINKER, M_WAITOK); 54840962Speter if (firstpage == NULL) { 54940962Speter error = ENOMEM; 55040962Speter goto out; 55140962Speter } 55240962Speter hdr = (Elf_Ehdr *)firstpage; 55340962Speter error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0, 55438514Sdfr UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 55540962Speter nbytes = PAGE_SIZE - resid; 55638514Sdfr if (error) 55738514Sdfr goto out; 55838514Sdfr 55940962Speter if (!IS_ELF(*hdr)) { 56039071Sdfr error = ENOEXEC; 56138514Sdfr goto out; 56239071Sdfr } 56338514Sdfr 56440962Speter if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS 56540962Speter || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { 56639071Sdfr link_elf_error("Unsupported file layout"); 56739071Sdfr error = ENOEXEC; 56839071Sdfr goto out; 56939071Sdfr } 57040962Speter if (hdr->e_ident[EI_VERSION] != EV_CURRENT 57140962Speter || hdr->e_version != EV_CURRENT) { 57239071Sdfr link_elf_error("Unsupported file version"); 57339071Sdfr error = ENOEXEC; 57439071Sdfr goto out; 57539071Sdfr } 57640962Speter if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { 57739071Sdfr link_elf_error("Unsupported file type"); 57839071Sdfr error = ENOEXEC; 57939071Sdfr goto out; 58039071Sdfr } 58140962Speter if (hdr->e_machine != ELF_TARG_MACH) { 58239071Sdfr link_elf_error("Unsupported machine"); 58339071Sdfr error = ENOEXEC; 58439071Sdfr goto out; 58539071Sdfr } 58639071Sdfr 58738514Sdfr /* 58839071Sdfr * We rely on the program header being in the first page. This is 58939071Sdfr * not strictly required by the ABI specification, but it seems to 59039071Sdfr * always true in practice. And, it simplifies things considerably. 59138514Sdfr */ 59240962Speter if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) && 59340962Speter (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) && 59440962Speter (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes))) 59539071Sdfr link_elf_error("Unreadable program headers"); 59639071Sdfr 59738514Sdfr /* 59839071Sdfr * Scan the program header entries, and save key information. 59939071Sdfr * 60039071Sdfr * We rely on there being exactly two load segments, text and data, 60139071Sdfr * in that order. 60238514Sdfr */ 60340962Speter phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff); 60440962Speter phlimit = phdr + hdr->e_phnum; 60539071Sdfr nsegs = 0; 60639071Sdfr phdyn = NULL; 60739071Sdfr phphdr = NULL; 60839071Sdfr while (phdr < phlimit) { 60939071Sdfr switch (phdr->p_type) { 61039071Sdfr 61139071Sdfr case PT_LOAD: 61239071Sdfr if (nsegs == 2) { 61339071Sdfr link_elf_error("Too many sections"); 61439071Sdfr error = ENOEXEC; 61539071Sdfr goto out; 61639071Sdfr } 61739071Sdfr segs[nsegs] = phdr; 61839071Sdfr ++nsegs; 61939071Sdfr break; 62039071Sdfr 62139071Sdfr case PT_PHDR: 62239071Sdfr phphdr = phdr; 62339071Sdfr break; 62439071Sdfr 62539071Sdfr case PT_DYNAMIC: 62639071Sdfr phdyn = phdr; 62739071Sdfr break; 62865503Sbp 62965503Sbp case PT_INTERP: 63065503Sbp link_elf_error("Unsupported file type"); 63165503Sbp error = ENOEXEC; 63265503Sbp goto out; 63339071Sdfr } 63439071Sdfr 63539071Sdfr ++phdr; 63639071Sdfr } 63739071Sdfr if (phdyn == NULL) { 63839071Sdfr link_elf_error("Object is not dynamically-linked"); 63939071Sdfr error = ENOEXEC; 64038514Sdfr goto out; 64139071Sdfr } 64238514Sdfr 64338514Sdfr /* 64439071Sdfr * Allocate the entire address space of the object, to stake out our 64539071Sdfr * contiguous region, and to establish the base address for relocation. 64638514Sdfr */ 64739071Sdfr base_offset = trunc_page(segs[0]->p_offset); 64839071Sdfr base_vaddr = trunc_page(segs[0]->p_vaddr); 64939071Sdfr base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); 65039071Sdfr mapsize = base_vlimit - base_vaddr; 65139071Sdfr 65259603Sdfr lf = linker_make_file(filename, &link_elf_class); 65359603Sdfr if (!lf) { 65459603Sdfr error = ENOMEM; 65559603Sdfr goto out; 65659603Sdfr } 65759603Sdfr 65859603Sdfr ef = (elf_file_t) lf; 65939071Sdfr#ifdef SPARSE_MAPPING 66076827Salfred mtx_lock(&vm_mtx); 66139071Sdfr ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); 66239071Sdfr if (ef->object == NULL) { 66376827Salfred mtx_unlock(&vm_mtx); 66438514Sdfr free(ef, M_LINKER); 66539071Sdfr error = ENOMEM; 66638514Sdfr goto out; 66738514Sdfr } 66839071Sdfr vm_object_reference(ef->object); 66939071Sdfr ef->address = (caddr_t) vm_map_min(kernel_map); 67039071Sdfr error = vm_map_find(kernel_map, ef->object, 0, 67139071Sdfr (vm_offset_t *) &ef->address, 67239071Sdfr mapsize, 1, 67339071Sdfr VM_PROT_ALL, VM_PROT_ALL, 0); 67439071Sdfr if (error) { 67539071Sdfr vm_object_deallocate(ef->object); 67676827Salfred mtx_unlock(&vm_mtx); 67759603Sdfr ef->object = 0; 67839071Sdfr goto out; 67939071Sdfr } 68076827Salfred mtx_unlock(&vm_mtx); 68139071Sdfr#else 68239071Sdfr ef->address = malloc(mapsize, M_LINKER, M_WAITOK); 68359603Sdfr if (!ef->address) { 68459603Sdfr error = ENOMEM; 68559603Sdfr goto out; 68659603Sdfr } 68739071Sdfr#endif 68839071Sdfr mapbase = ef->address; 68938514Sdfr 69039071Sdfr /* 69139071Sdfr * Read the text and data sections and zero the bss. 69239071Sdfr */ 69339071Sdfr for (i = 0; i < 2; i++) { 69439071Sdfr caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; 69539071Sdfr error = vn_rdwr(UIO_READ, nd.ni_vp, 69639071Sdfr segbase, segs[i]->p_filesz, segs[i]->p_offset, 69739071Sdfr UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 69839071Sdfr if (error) { 69939071Sdfr goto out; 70039071Sdfr } 70139071Sdfr bzero(segbase + segs[i]->p_filesz, 70239071Sdfr segs[i]->p_memsz - segs[i]->p_filesz); 70339071Sdfr 70439071Sdfr#ifdef SPARSE_MAPPING 70539071Sdfr /* 70639071Sdfr * Wire down the pages 70739071Sdfr */ 70876827Salfred mtx_lock(&vm_mtx); 70939071Sdfr vm_map_pageable(kernel_map, 71039071Sdfr (vm_offset_t) segbase, 71139071Sdfr (vm_offset_t) segbase + segs[i]->p_memsz, 71239071Sdfr FALSE); 71376827Salfred mtx_unlock(&vm_mtx); 71439071Sdfr#endif 71539071Sdfr } 71639071Sdfr 71759603Sdfr ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); 71839071Sdfr 71938514Sdfr lf->address = ef->address; 72039071Sdfr lf->size = mapsize; 72138514Sdfr 72259603Sdfr error = parse_dynamic(ef); 72340292Speter if (error) 72438514Sdfr goto out; 72559751Speter error = linker_load_dependancies(lf); 72640292Speter if (error) 72740156Speter goto out; 72859751Speter#if 0 /* this will be more trouble than it's worth for now */ 72959751Speter for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 73059751Speter if (dp->d_tag != DT_NEEDED) 73159751Speter continue; 73259751Speter modname = ef->strtab + dp->d_un.d_val; 73359751Speter error = linker_load_module(modname, lf); 73459751Speter if (error) 73559751Speter goto out; 73659751Speter } 73759751Speter#endif 73859603Sdfr error = relocate_file(ef); 73940292Speter if (error) 74040156Speter goto out; 74140292Speter 74240292Speter /* Try and load the symbol table if it's present. (you can strip it!) */ 74340962Speter nbytes = hdr->e_shnum * hdr->e_shentsize; 74440962Speter if (nbytes == 0 || hdr->e_shoff == 0) 74540292Speter goto nosyms; 74669781Sdwmalone shdr = malloc(nbytes, M_LINKER, M_WAITOK | M_ZERO); 74740292Speter if (shdr == NULL) { 74840292Speter error = ENOMEM; 74940292Speter goto out; 75040156Speter } 75140292Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 75240962Speter (caddr_t)shdr, nbytes, hdr->e_shoff, 75340292Speter UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 75440292Speter if (error) 75540292Speter goto out; 75640292Speter symtabindex = -1; 75740292Speter symstrindex = -1; 75840962Speter for (i = 0; i < hdr->e_shnum; i++) { 75940292Speter if (shdr[i].sh_type == SHT_SYMTAB) { 76040292Speter symtabindex = i; 76140292Speter symstrindex = shdr[i].sh_link; 76240292Speter } 76340292Speter } 76440292Speter if (symtabindex < 0 || symstrindex < 0) 76540292Speter goto nosyms; 76640156Speter 76740292Speter symcnt = shdr[symtabindex].sh_size; 76840292Speter ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK); 76940292Speter strcnt = shdr[symstrindex].sh_size; 77040292Speter ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK); 77140292Speter 77240292Speter if (ef->symbase == NULL || ef->strbase == NULL) { 77340292Speter error = ENOMEM; 77440292Speter goto out; 77540292Speter } 77640292Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 77740292Speter ef->symbase, symcnt, shdr[symtabindex].sh_offset, 77840292Speter UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 77940292Speter if (error) 78040292Speter goto out; 78140292Speter error = vn_rdwr(UIO_READ, nd.ni_vp, 78240292Speter ef->strbase, strcnt, shdr[symstrindex].sh_offset, 78340292Speter UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 78440292Speter if (error) 78540292Speter goto out; 78640292Speter 78740292Speter ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 78840292Speter ef->ddbsymtab = (const Elf_Sym *)ef->symbase; 78940292Speter ef->ddbstrcnt = strcnt; 79040292Speter ef->ddbstrtab = ef->strbase; 79140292Speter 79259603Sdfr#ifdef DDB 79359603Sdfr GDB_STATE(RT_ADD); 79459603Sdfr ef->gdb.l_addr = lf->address; 79559751Speter ef->gdb.l_name = filename; 79659603Sdfr ef->gdb.l_ld = ef->dynamic; 79759603Sdfr link_elf_add_gdb(&ef->gdb); 79859603Sdfr GDB_STATE(RT_CONSISTENT); 79959603Sdfr#endif 80059603Sdfr 80140292Speternosyms: 80240292Speter 80338514Sdfr *result = lf; 80438514Sdfr 80538514Sdfrout: 80640292Speter if (error && lf) 80740292Speter linker_file_unload(lf); 80840292Speter if (shdr) 80940292Speter free(shdr, M_LINKER); 81040962Speter if (firstpage) 81140962Speter free(firstpage, M_LINKER); 81238514Sdfr VOP_UNLOCK(nd.ni_vp, 0, p); 81338514Sdfr vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 81438514Sdfr 81538514Sdfr return error; 81638514Sdfr} 81738514Sdfr 81838514Sdfrstatic void 81940156Speterlink_elf_unload_file(linker_file_t file) 82038514Sdfr{ 82159603Sdfr elf_file_t ef = (elf_file_t) file; 82238514Sdfr 82359603Sdfr#ifdef DDB 82459603Sdfr if (ef->gdb.l_ld) { 82559603Sdfr GDB_STATE(RT_DELETE); 82659603Sdfr link_elf_delete_gdb(&ef->gdb); 82759603Sdfr GDB_STATE(RT_CONSISTENT); 82859603Sdfr } 82959603Sdfr#endif 83059603Sdfr 83159603Sdfr if (ef->preloaded) { 83259751Speter link_elf_unload_preload(file); 83359603Sdfr return; 83459603Sdfr } 83539071Sdfr#ifdef SPARSE_MAPPING 83659603Sdfr if (ef->object) { 83776827Salfred mtx_lock(&vm_mtx); 83859603Sdfr vm_map_remove(kernel_map, (vm_offset_t) ef->address, 83959603Sdfr (vm_offset_t) ef->address 84059603Sdfr + (ef->object->size << PAGE_SHIFT)); 84159603Sdfr vm_object_deallocate(ef->object); 84276827Salfred mtx_unlock(&vm_mtx); 84359603Sdfr } 84439071Sdfr#else 84559603Sdfr if (ef->address) 84659603Sdfr free(ef->address, M_LINKER); 84739071Sdfr#endif 84859603Sdfr if (ef->symbase) 84959603Sdfr free(ef->symbase, M_LINKER); 85059603Sdfr if (ef->strbase) 85159603Sdfr free(ef->strbase, M_LINKER); 85238514Sdfr} 85338514Sdfr 85440156Speterstatic void 85559751Speterlink_elf_unload_preload(linker_file_t file) 85640156Speter{ 85740156Speter if (file->filename) 85840156Speter preload_delete_name(file->filename); 85940156Speter} 86040156Speter 86139071Sdfrstatic const char * 86240435Spetersymbol_name(elf_file_t ef, Elf_Word r_info) 86338514Sdfr{ 86439071Sdfr const Elf_Sym *ref; 86538514Sdfr 86640435Speter if (ELF_R_SYM(r_info)) { 86740435Speter ref = ef->symtab + ELF_R_SYM(r_info); 86840397Speter return ef->strtab + ref->st_name; 86939071Sdfr } else 87039071Sdfr return NULL; 87138514Sdfr} 87238514Sdfr 87338514Sdfrstatic int 87459603Sdfrrelocate_file(elf_file_t ef) 87538514Sdfr{ 87639071Sdfr const Elf_Rel *rellim; 87739071Sdfr const Elf_Rel *rel; 87839071Sdfr const Elf_Rela *relalim; 87939071Sdfr const Elf_Rela *rela; 88040435Speter const char *symname; 88138514Sdfr 88239071Sdfr /* Perform relocations without addend if there are any: */ 88340435Speter rel = ef->rel; 88440435Speter if (rel) { 88543388Sbde rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize); 88640435Speter while (rel < rellim) { 88740435Speter symname = symbol_name(ef, rel->r_info); 88859603Sdfr if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) { 88959744Speter printf("link_elf: symbol %s undefined\n", symname); 89040435Speter return ENOENT; 89142200Speter } 89240435Speter rel++; 89340435Speter } 89439071Sdfr } 89538514Sdfr 89639071Sdfr /* Perform relocations with addend if there are any: */ 89740435Speter rela = ef->rela; 89840435Speter if (rela) { 89943388Sbde relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize); 90040435Speter while (rela < relalim) { 90140435Speter symname = symbol_name(ef, rela->r_info); 90259603Sdfr if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) { 90359744Speter printf("link_elf: symbol %s undefined\n", symname); 90440435Speter return ENOENT; 90542200Speter } 90640435Speter rela++; 90740435Speter } 90839071Sdfr } 90938514Sdfr 91039071Sdfr /* Perform PLT relocations without addend if there are any: */ 91140435Speter rel = ef->pltrel; 91240435Speter if (rel) { 91343388Sbde rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize); 91440435Speter while (rel < rellim) { 91540435Speter symname = symbol_name(ef, rel->r_info); 91659603Sdfr if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) { 91759744Speter printf("link_elf: symbol %s undefined\n", symname); 91840435Speter return ENOENT; 91942200Speter } 92040435Speter rel++; 92140435Speter } 92239071Sdfr } 92338514Sdfr 92439071Sdfr /* Perform relocations with addend if there are any: */ 92540435Speter rela = ef->pltrela; 92640435Speter if (rela) { 92743388Sbde relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize); 92840435Speter while (rela < relalim) { 92940435Speter symname = symbol_name(ef, rela->r_info); 93059603Sdfr if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) { 93159744Speter printf("link_elf: symbol %s undefined\n", symname); 93240435Speter return ENOENT; 93342200Speter } 93440435Speter rela++; 93540435Speter } 93638514Sdfr } 93738514Sdfr 93838514Sdfr return 0; 93938514Sdfr} 94038514Sdfr 94139071Sdfr/* 94239071Sdfr * Hash function for symbol table lookup. Don't even think about changing 94339071Sdfr * this. It is specified by the System V ABI. 94439071Sdfr */ 94539071Sdfrstatic unsigned long 94639071Sdfrelf_hash(const char *name) 94738514Sdfr{ 94839071Sdfr const unsigned char *p = (const unsigned char *) name; 94939071Sdfr unsigned long h = 0; 95039071Sdfr unsigned long g; 95138514Sdfr 95239071Sdfr while (*p != '\0') { 95339071Sdfr h = (h << 4) + *p++; 95439071Sdfr if ((g = h & 0xf0000000) != 0) 95539071Sdfr h ^= g >> 24; 95639071Sdfr h &= ~g; 95739071Sdfr } 95839071Sdfr return h; 95938514Sdfr} 96038514Sdfr 96138514Sdfrint 96243301Sdillonlink_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym) 96338514Sdfr{ 96459603Sdfr elf_file_t ef = (elf_file_t) lf; 96539071Sdfr unsigned long symnum; 96640254Speter const Elf_Sym* symp; 96740254Speter const char *strp; 96839071Sdfr unsigned long hash; 96939071Sdfr int i; 97038514Sdfr 97140254Speter /* First, search hashed global symbols */ 97239071Sdfr hash = elf_hash(name); 97339071Sdfr symnum = ef->buckets[hash % ef->nbuckets]; 97439071Sdfr 97539071Sdfr while (symnum != STN_UNDEF) { 97639071Sdfr if (symnum >= ef->nchains) { 97739071Sdfr printf("link_elf_lookup_symbol: corrupt symbol table\n"); 97839071Sdfr return ENOENT; 97938514Sdfr } 98038514Sdfr 98139071Sdfr symp = ef->symtab + symnum; 98239071Sdfr if (symp->st_name == 0) { 98339071Sdfr printf("link_elf_lookup_symbol: corrupt symbol table\n"); 98439071Sdfr return ENOENT; 98539071Sdfr } 98639071Sdfr 98739071Sdfr strp = ef->strtab + symp->st_name; 98839071Sdfr 98939071Sdfr if (strcmp(name, strp) == 0) { 99039071Sdfr if (symp->st_shndx != SHN_UNDEF || 99139071Sdfr (symp->st_value != 0 && 99239071Sdfr ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 99343301Sdillon *sym = (c_linker_sym_t) symp; 99439071Sdfr return 0; 99539071Sdfr } else 99639071Sdfr return ENOENT; 99739071Sdfr } 99839071Sdfr 99939071Sdfr symnum = ef->chains[symnum]; 100039071Sdfr } 100139071Sdfr 100240254Speter /* If we have not found it, look at the full table (if loaded) */ 100340254Speter if (ef->symtab == ef->ddbsymtab) 100440254Speter return ENOENT; 100540254Speter 100640254Speter /* Exhaustive search */ 100740254Speter for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 100840254Speter strp = ef->ddbstrtab + symp->st_name; 100940254Speter if (strcmp(name, strp) == 0) { 101040254Speter if (symp->st_shndx != SHN_UNDEF || 101140254Speter (symp->st_value != 0 && 101240254Speter ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 101343301Sdillon *sym = (c_linker_sym_t) symp; 101440254Speter return 0; 101540254Speter } else 101640254Speter return ENOENT; 101740254Speter } 101840254Speter } 101940254Speter 102039071Sdfr return ENOENT; 102138514Sdfr} 102238514Sdfr 102340156Speterstatic int 102443309Sdillonlink_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval) 102538514Sdfr{ 102659603Sdfr elf_file_t ef = (elf_file_t) lf; 102743311Sdillon const Elf_Sym* es = (const Elf_Sym*) sym; 102838514Sdfr 102940254Speter if (es >= ef->symtab && ((es - ef->symtab) < ef->nchains)) { 103040254Speter symval->name = ef->strtab + es->st_name; 103140254Speter symval->value = (caddr_t) ef->address + es->st_value; 103240254Speter symval->size = es->st_size; 103340254Speter return 0; 103440254Speter } 103540254Speter if (ef->symtab == ef->ddbsymtab) 103640254Speter return ENOENT; 103740254Speter if (es >= ef->ddbsymtab && ((es - ef->ddbsymtab) < ef->ddbsymcnt)) { 103840254Speter symval->name = ef->ddbstrtab + es->st_name; 103940254Speter symval->value = (caddr_t) ef->address + es->st_value; 104040254Speter symval->size = es->st_size; 104140254Speter return 0; 104240254Speter } 104340254Speter return ENOENT; 104438514Sdfr} 104538514Sdfr 104638514Sdfrstatic int 104738514Sdfrlink_elf_search_symbol(linker_file_t lf, caddr_t value, 104843301Sdillon c_linker_sym_t* sym, long* diffp) 104938514Sdfr{ 105059603Sdfr elf_file_t ef = (elf_file_t) lf; 105155090Sbde u_long off = (uintptr_t) (void *) value; 105238514Sdfr u_long diff = off; 105355090Sbde u_long st_value; 105439071Sdfr const Elf_Sym* es; 105539071Sdfr const Elf_Sym* best = 0; 105638514Sdfr int i; 105738514Sdfr 105840254Speter for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { 105938514Sdfr if (es->st_name == 0) 106038514Sdfr continue; 106155090Sbde st_value = es->st_value + (uintptr_t) (void *) ef->address; 106253820Speter if (off >= st_value) { 106353820Speter if (off - st_value < diff) { 106453820Speter diff = off - st_value; 106538514Sdfr best = es; 106638514Sdfr if (diff == 0) 106738514Sdfr break; 106853820Speter } else if (off - st_value == diff) { 106938514Sdfr best = es; 107038514Sdfr } 107138514Sdfr } 107238514Sdfr } 107338514Sdfr if (best == 0) 107438514Sdfr *diffp = off; 107538514Sdfr else 107638514Sdfr *diffp = diff; 107743301Sdillon *sym = (c_linker_sym_t) best; 107838514Sdfr 107938514Sdfr return 0; 108038514Sdfr} 108178161Speter 108278161Speter/* 108378161Speter * Look up a linker set on an ELF system. 108478161Speter */ 108578161Speterstatic int 108678161Speterlink_elf_lookup_set(linker_file_t lf, const char *name, 108778161Speter void ***startp, void ***stopp, int *countp) 108878161Speter{ 108978161Speter c_linker_sym_t sym; 109078161Speter linker_symval_t symval; 109178161Speter char *setsym; 109278161Speter void **start, **stop; 109378161Speter int len, error = 0, count; 109478161Speter 109578161Speter len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */ 109678161Speter setsym = malloc(len, M_LINKER, M_WAITOK); 109778161Speter if (setsym == NULL) 109878161Speter return ENOMEM; 109978161Speter 110078161Speter /* get address of first entry */ 110178161Speter snprintf(setsym, len, "%s%s", "__start_set_", name); 110278161Speter error = link_elf_lookup_symbol(lf, setsym, &sym); 110378161Speter if (error) 110478161Speter goto out; 110578161Speter link_elf_symbol_values(lf, sym, &symval); 110678161Speter if (symval.value == 0) { 110778161Speter error = ESRCH; 110878161Speter goto out; 110978161Speter } 111078161Speter start = (void **)symval.value; 111178161Speter 111278161Speter /* get address of last entry */ 111378161Speter snprintf(setsym, len, "%s%s", "__stop_set_", name); 111478161Speter error = link_elf_lookup_symbol(lf, setsym, &sym); 111578161Speter if (error) 111678161Speter goto out; 111778161Speter link_elf_symbol_values(lf, sym, &symval); 111878161Speter if (symval.value == 0) { 111978161Speter error = ESRCH; 112078161Speter goto out; 112178161Speter } 112278161Speter stop = (void **)symval.value; 112378161Speter 112478161Speter /* and the number of entries */ 112578161Speter count = stop - start; 112678161Speter 112778161Speter /* and copy out */ 112878161Speter if (startp) 112978161Speter *startp = start; 113078161Speter if (stopp) 113178161Speter *stopp = stop; 113278161Speter if (countp) 113378161Speter *countp = count; 113478161Speter 113578161Speterout: 113678161Speter free(setsym, M_LINKER); 113778161Speter return error; 113878161Speter} 1139