1a4f67738SDoug Rabson /*- 2a4f67738SDoug Rabson * Copyright (c) 1998 Doug Rabson 3a4f67738SDoug Rabson * All rights reserved. 4a4f67738SDoug Rabson * 5a4f67738SDoug Rabson * Redistribution and use in source and binary forms, with or without 6a4f67738SDoug Rabson * modification, are permitted provided that the following conditions 7a4f67738SDoug Rabson * are met: 8a4f67738SDoug Rabson * 1. Redistributions of source code must retain the above copyright 9a4f67738SDoug Rabson * notice, this list of conditions and the following disclaimer. 10a4f67738SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 11a4f67738SDoug Rabson * notice, this list of conditions and the following disclaimer in the 12a4f67738SDoug Rabson * documentation and/or other materials provided with the distribution. 13a4f67738SDoug Rabson * 14a4f67738SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a4f67738SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a4f67738SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a4f67738SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a4f67738SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a4f67738SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a4f67738SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a4f67738SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a4f67738SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a4f67738SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a4f67738SDoug Rabson * SUCH DAMAGE. 25a4f67738SDoug Rabson * 26ca65d5c7SPeter Wemm * $Id: link_elf.c,v 1.4 1998/10/12 09:13:47 peter Exp $ 27a4f67738SDoug Rabson */ 28a4f67738SDoug Rabson 29a4f67738SDoug Rabson #include <sys/param.h> 30a4f67738SDoug Rabson #include <sys/kernel.h> 31a4f67738SDoug Rabson #include <sys/systm.h> 32a4f67738SDoug Rabson #include <sys/malloc.h> 33a4f67738SDoug Rabson #include <sys/proc.h> 34a4f67738SDoug Rabson #include <sys/namei.h> 35a4f67738SDoug Rabson #include <sys/fcntl.h> 36a4f67738SDoug Rabson #include <sys/vnode.h> 37a4f67738SDoug Rabson #include <sys/linker.h> 38a4f67738SDoug Rabson #include <machine/elf.h> 39a4f67738SDoug Rabson 40fe3db7c7SDoug Rabson #include <vm/vm.h> 41fe3db7c7SDoug Rabson #include <vm/vm_prot.h> 42fe3db7c7SDoug Rabson #include <vm/vm_param.h> 43fe3db7c7SDoug Rabson #include <sys/lock.h> 44fe3db7c7SDoug Rabson #include <vm/vm_object.h> 45fe3db7c7SDoug Rabson #include <vm/vm_kern.h> 46fe3db7c7SDoug Rabson #include <vm/vm_extern.h> 47fe3db7c7SDoug Rabson #include <vm/pmap.h> 48fe3db7c7SDoug Rabson #include <vm/vm_map.h> 49fe3db7c7SDoug Rabson 50de78ca7eSPeter Wemm static int link_elf_load_module(const char*, linker_file_t*); 51a4f67738SDoug Rabson static int link_elf_load_file(const char*, linker_file_t*); 52a4f67738SDoug Rabson static int link_elf_lookup_symbol(linker_file_t, const char*, 53a4f67738SDoug Rabson linker_sym_t*); 54de78ca7eSPeter Wemm static int link_elf_symbol_values(linker_file_t, linker_sym_t, linker_symval_t*); 55a4f67738SDoug Rabson static int link_elf_search_symbol(linker_file_t, caddr_t value, 56a4f67738SDoug Rabson linker_sym_t* sym, long* diffp); 57a4f67738SDoug Rabson 58de78ca7eSPeter Wemm static void link_elf_unload_file(linker_file_t); 59de78ca7eSPeter Wemm static void link_elf_unload_module(linker_file_t); 60a4f67738SDoug Rabson 61a4f67738SDoug Rabson /* 62a4f67738SDoug Rabson * The file representing the currently running kernel. This contains 63a4f67738SDoug Rabson * the global symbol table. 64a4f67738SDoug Rabson */ 65a4f67738SDoug Rabson 66a4f67738SDoug Rabson linker_file_t linker_kernel_file; 67a4f67738SDoug Rabson 68a4f67738SDoug Rabson static struct linker_class_ops link_elf_class_ops = { 69de78ca7eSPeter Wemm link_elf_load_module, 70a4f67738SDoug Rabson }; 71a4f67738SDoug Rabson 72a4f67738SDoug Rabson static struct linker_file_ops link_elf_file_ops = { 73a4f67738SDoug Rabson link_elf_lookup_symbol, 74a4f67738SDoug Rabson link_elf_symbol_values, 75a4f67738SDoug Rabson link_elf_search_symbol, 76de78ca7eSPeter Wemm link_elf_unload_file, 77a4f67738SDoug Rabson }; 78a4f67738SDoug Rabson 79de78ca7eSPeter Wemm static struct linker_file_ops link_elf_module_ops = { 80de78ca7eSPeter Wemm link_elf_lookup_symbol, 81de78ca7eSPeter Wemm link_elf_symbol_values, 82de78ca7eSPeter Wemm link_elf_search_symbol, 83de78ca7eSPeter Wemm link_elf_unload_module, 84de78ca7eSPeter Wemm }; 85a4f67738SDoug Rabson typedef struct elf_file { 86fe3db7c7SDoug Rabson caddr_t address; /* Relocation address */ 87fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 88fe3db7c7SDoug Rabson vm_object_t object; /* VM object to hold file pages */ 89fe3db7c7SDoug Rabson #endif 90fe3db7c7SDoug Rabson const Elf_Dyn* dynamic; /* Symbol table etc. */ 91a4f67738SDoug Rabson Elf_Off nbuckets; /* DT_HASH info */ 92a4f67738SDoug Rabson Elf_Off nchains; 93a4f67738SDoug Rabson const Elf_Off* buckets; 94a4f67738SDoug Rabson const Elf_Off* chains; 95a4f67738SDoug Rabson caddr_t hash; 96a4f67738SDoug Rabson caddr_t strtab; /* DT_STRTAB */ 972d636ab0SPeter Wemm int strsz; /* DT_STRSZ */ 98fe3db7c7SDoug Rabson const Elf_Sym* symtab; /* DT_SYMTAB */ 99fe3db7c7SDoug Rabson Elf_Addr* got; /* DT_PLTGOT */ 100fe3db7c7SDoug Rabson const Elf_Rel* pltrel; /* DT_JMPREL */ 101fe3db7c7SDoug Rabson int pltrelsize; /* DT_PLTRELSZ */ 102fe3db7c7SDoug Rabson const Elf_Rela* pltrela; /* DT_JMPREL */ 103fe3db7c7SDoug Rabson int pltrelasize; /* DT_PLTRELSZ */ 104fe3db7c7SDoug Rabson const Elf_Rel* rel; /* DT_REL */ 105fe3db7c7SDoug Rabson int relsize; /* DT_RELSZ */ 106fe3db7c7SDoug Rabson const Elf_Rela* rela; /* DT_RELA */ 107fe3db7c7SDoug Rabson int relasize; /* DT_RELASZ */ 1082d636ab0SPeter Wemm caddr_t modptr; 1092d636ab0SPeter Wemm const Elf_Sym* ddbsymtab; /* The symbol table we are using */ 1102d636ab0SPeter Wemm long ddbsymcnt; /* Number of symbols */ 1112d636ab0SPeter Wemm caddr_t ddbstrtab; /* String table */ 1122d636ab0SPeter Wemm long ddbstrcnt; /* number of bytes in string table */ 113ca65d5c7SPeter Wemm caddr_t symbase; /* malloc'ed symbold base */ 114ca65d5c7SPeter Wemm caddr_t strbase; /* malloc'ed string base */ 115a4f67738SDoug Rabson } *elf_file_t; 116a4f67738SDoug Rabson 117a4f67738SDoug Rabson static int parse_dynamic(linker_file_t lf); 118a4f67738SDoug Rabson static int load_dependancies(linker_file_t lf); 119a4f67738SDoug Rabson static int relocate_file(linker_file_t lf); 1202d636ab0SPeter Wemm static int parse_module_symbols(linker_file_t lf); 121a4f67738SDoug Rabson 122a4f67738SDoug Rabson /* 123a4f67738SDoug Rabson * The kernel symbol table starts here. 124a4f67738SDoug Rabson */ 125a4f67738SDoug Rabson extern struct _dynamic _DYNAMIC; 126a4f67738SDoug Rabson 127a4f67738SDoug Rabson static void 128a4f67738SDoug Rabson link_elf_init(void* arg) 129a4f67738SDoug Rabson { 130de78ca7eSPeter Wemm #ifdef __ELF__ 131de78ca7eSPeter Wemm Elf_Dyn *dp; 132de78ca7eSPeter Wemm caddr_t modptr, baseptr, sizeptr; 133de78ca7eSPeter Wemm elf_file_t ef; 134de78ca7eSPeter Wemm char *modname; 135de78ca7eSPeter Wemm #endif 136a4f67738SDoug Rabson 137a4f67738SDoug Rabson #if ELF_TARG_CLASS == ELFCLASS32 138a4f67738SDoug Rabson linker_add_class("elf32", NULL, &link_elf_class_ops); 139a4f67738SDoug Rabson #else 140a4f67738SDoug Rabson linker_add_class("elf64", NULL, &link_elf_class_ops); 141a4f67738SDoug Rabson #endif 142a4f67738SDoug Rabson 143de78ca7eSPeter Wemm #ifdef __ELF__ 144de78ca7eSPeter Wemm dp = (Elf_Dyn*) &_DYNAMIC; 145a4f67738SDoug Rabson if (dp) { 146a4f67738SDoug Rabson ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT); 147a4f67738SDoug Rabson if (ef == NULL) 148a4f67738SDoug Rabson panic("link_elf_init: Can't create linker structures for kernel"); 149a4f67738SDoug Rabson 150a4f67738SDoug Rabson ef->address = 0; 151fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 152fe3db7c7SDoug Rabson ef->object = 0; 153fe3db7c7SDoug Rabson #endif 154a4f67738SDoug Rabson ef->dynamic = dp; 155de78ca7eSPeter Wemm modname = NULL; 156de78ca7eSPeter Wemm modptr = preload_search_by_type("elf kernel"); 157de78ca7eSPeter Wemm if (modptr) 158de78ca7eSPeter Wemm modname = (char *)preload_search_info(modptr, MODINFO_NAME); 159de78ca7eSPeter Wemm if (modname == NULL) 160de78ca7eSPeter Wemm modname = "kernel"; 161de78ca7eSPeter Wemm linker_kernel_file = linker_make_file(modname, ef, &link_elf_file_ops); 162a4f67738SDoug Rabson if (linker_kernel_file == NULL) 163a4f67738SDoug Rabson panic("link_elf_init: Can't create linker structures for kernel"); 164a4f67738SDoug Rabson parse_dynamic(linker_kernel_file); 165de78ca7eSPeter Wemm /* Sigh, magic constants. */ 166a4f67738SDoug Rabson #ifdef __alpha__ 167a4f67738SDoug Rabson linker_kernel_file->address = (caddr_t) 0xfffffc0000300000; 168a4f67738SDoug Rabson #else 169a4f67738SDoug Rabson linker_kernel_file->address = (caddr_t) 0xf0100000; 170a4f67738SDoug Rabson #endif 171a4f67738SDoug Rabson linker_kernel_file->size = -(long)linker_kernel_file->address; 172de78ca7eSPeter Wemm 173de78ca7eSPeter Wemm if (modptr) { 1742d636ab0SPeter Wemm ef->modptr = modptr; 175de78ca7eSPeter Wemm baseptr = preload_search_info(modptr, MODINFO_ADDR); 176de78ca7eSPeter Wemm if (baseptr) 177de78ca7eSPeter Wemm linker_kernel_file->address = *(caddr_t *)baseptr; 178de78ca7eSPeter Wemm sizeptr = preload_search_info(modptr, MODINFO_SIZE); 179de78ca7eSPeter Wemm if (sizeptr) 180de78ca7eSPeter Wemm linker_kernel_file->size = *(size_t *)sizeptr; 181de78ca7eSPeter Wemm } 1822d636ab0SPeter Wemm (void)parse_module_symbols(linker_kernel_file); 183a4f67738SDoug Rabson linker_current_file = linker_kernel_file; 184a4f67738SDoug Rabson } 185de78ca7eSPeter Wemm #endif 186a4f67738SDoug Rabson } 187a4f67738SDoug Rabson 188de78ca7eSPeter Wemm SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); 189a4f67738SDoug Rabson 190a4f67738SDoug Rabson static int 1912d636ab0SPeter Wemm parse_module_symbols(linker_file_t lf) 1922d636ab0SPeter Wemm { 1932d636ab0SPeter Wemm elf_file_t ef = lf->priv; 1942d636ab0SPeter Wemm caddr_t pointer; 1952d636ab0SPeter Wemm caddr_t ssym, esym, base; 1962d636ab0SPeter Wemm caddr_t strtab; 1972d636ab0SPeter Wemm int strcnt; 1982d636ab0SPeter Wemm Elf_Sym* symtab; 1992d636ab0SPeter Wemm int symcnt; 2002d636ab0SPeter Wemm 201ca65d5c7SPeter Wemm if (ef->modptr == NULL) 202ca65d5c7SPeter Wemm return 0; 2032d636ab0SPeter Wemm pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM); 2042d636ab0SPeter Wemm if (pointer == NULL) 2052d636ab0SPeter Wemm return 0; 2062d636ab0SPeter Wemm ssym = *(caddr_t *)pointer; 2072d636ab0SPeter Wemm pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM); 2082d636ab0SPeter Wemm if (pointer == NULL) 2092d636ab0SPeter Wemm return 0; 2102d636ab0SPeter Wemm esym = *(caddr_t *)pointer; 2112d636ab0SPeter Wemm 2122d636ab0SPeter Wemm base = ssym; 2132d636ab0SPeter Wemm 2142d636ab0SPeter Wemm symcnt = *(long *)base; 2152d636ab0SPeter Wemm base += sizeof(long); 2162d636ab0SPeter Wemm symtab = (Elf_Sym *)base; 2172d636ab0SPeter Wemm base += roundup(symcnt, sizeof(long)); 2182d636ab0SPeter Wemm 2192d636ab0SPeter Wemm if (base > esym || base < ssym) { 2202d636ab0SPeter Wemm printf("Symbols are corrupt!\n"); 2212d636ab0SPeter Wemm return EINVAL; 2222d636ab0SPeter Wemm } 2232d636ab0SPeter Wemm 2242d636ab0SPeter Wemm strcnt = *(long *)base; 2252d636ab0SPeter Wemm base += sizeof(long); 2262d636ab0SPeter Wemm strtab = base; 2272d636ab0SPeter Wemm base += roundup(strcnt, sizeof(long)); 2282d636ab0SPeter Wemm 2292d636ab0SPeter Wemm if (base > esym || base < ssym) { 2302d636ab0SPeter Wemm printf("Symbols are corrupt!\n"); 2312d636ab0SPeter Wemm return EINVAL; 2322d636ab0SPeter Wemm } 2332d636ab0SPeter Wemm 2342d636ab0SPeter Wemm ef->ddbsymtab = symtab; 2352d636ab0SPeter Wemm ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 2362d636ab0SPeter Wemm ef->ddbstrtab = strtab; 2372d636ab0SPeter Wemm ef->ddbstrcnt = strcnt; 2382d636ab0SPeter Wemm 2392d636ab0SPeter Wemm return 0; 2402d636ab0SPeter Wemm } 2412d636ab0SPeter Wemm 2422d636ab0SPeter Wemm static int 243a4f67738SDoug Rabson parse_dynamic(linker_file_t lf) 244a4f67738SDoug Rabson { 245a4f67738SDoug Rabson elf_file_t ef = lf->priv; 246fe3db7c7SDoug Rabson const Elf_Dyn *dp; 247fe3db7c7SDoug Rabson int plttype = DT_REL; 248a4f67738SDoug Rabson 249a4f67738SDoug Rabson for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 250a4f67738SDoug Rabson switch (dp->d_tag) { 251a4f67738SDoug Rabson case DT_HASH: 252a4f67738SDoug Rabson { 253a4f67738SDoug Rabson /* From src/libexec/rtld-elf/rtld.c */ 254a4f67738SDoug Rabson const Elf_Off *hashtab = (const Elf_Off *) 255a4f67738SDoug Rabson (ef->address + dp->d_un.d_ptr); 256a4f67738SDoug Rabson ef->nbuckets = hashtab[0]; 257a4f67738SDoug Rabson ef->nchains = hashtab[1]; 258a4f67738SDoug Rabson ef->buckets = hashtab + 2; 259a4f67738SDoug Rabson ef->chains = ef->buckets + ef->nbuckets; 260a4f67738SDoug Rabson break; 261a4f67738SDoug Rabson } 262a4f67738SDoug Rabson case DT_STRTAB: 263fe3db7c7SDoug Rabson ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 264a4f67738SDoug Rabson break; 2652d636ab0SPeter Wemm case DT_STRSZ: 2662d636ab0SPeter Wemm ef->strsz = dp->d_un.d_val; 2672d636ab0SPeter Wemm break; 268a4f67738SDoug Rabson case DT_SYMTAB: 269fe3db7c7SDoug Rabson ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 270a4f67738SDoug Rabson break; 271a4f67738SDoug Rabson case DT_SYMENT: 272a4f67738SDoug Rabson if (dp->d_un.d_val != sizeof(Elf_Sym)) 273a4f67738SDoug Rabson return ENOEXEC; 274fe3db7c7SDoug Rabson break; 275fe3db7c7SDoug Rabson case DT_PLTGOT: 276fe3db7c7SDoug Rabson ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 277fe3db7c7SDoug Rabson break; 278fe3db7c7SDoug Rabson case DT_REL: 279fe3db7c7SDoug Rabson ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 280fe3db7c7SDoug Rabson break; 281fe3db7c7SDoug Rabson case DT_RELSZ: 282fe3db7c7SDoug Rabson ef->relsize = dp->d_un.d_val; 283fe3db7c7SDoug Rabson break; 284fe3db7c7SDoug Rabson case DT_RELENT: 285fe3db7c7SDoug Rabson if (dp->d_un.d_val != sizeof(Elf_Rel)) 286fe3db7c7SDoug Rabson return ENOEXEC; 287fe3db7c7SDoug Rabson break; 288fe3db7c7SDoug Rabson case DT_JMPREL: 289fe3db7c7SDoug Rabson ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 290fe3db7c7SDoug Rabson break; 291fe3db7c7SDoug Rabson case DT_PLTRELSZ: 292fe3db7c7SDoug Rabson ef->pltrelsize = dp->d_un.d_val; 293fe3db7c7SDoug Rabson break; 294fe3db7c7SDoug Rabson case DT_RELA: 295fe3db7c7SDoug Rabson ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 296fe3db7c7SDoug Rabson break; 297fe3db7c7SDoug Rabson case DT_RELASZ: 298fe3db7c7SDoug Rabson ef->relasize = dp->d_un.d_val; 299fe3db7c7SDoug Rabson break; 300fe3db7c7SDoug Rabson case DT_RELAENT: 301fe3db7c7SDoug Rabson if (dp->d_un.d_val != sizeof(Elf_Rela)) 302fe3db7c7SDoug Rabson return ENOEXEC; 303fe3db7c7SDoug Rabson break; 304fe3db7c7SDoug Rabson case DT_PLTREL: 305fe3db7c7SDoug Rabson plttype = dp->d_un.d_val; 306fe3db7c7SDoug Rabson if (plttype != DT_REL && plttype != DT_RELA) 307fe3db7c7SDoug Rabson return ENOEXEC; 308fe3db7c7SDoug Rabson break; 309a4f67738SDoug Rabson } 310a4f67738SDoug Rabson } 311fe3db7c7SDoug Rabson 312fe3db7c7SDoug Rabson if (plttype == DT_RELA) { 313fe3db7c7SDoug Rabson ef->pltrela = (const Elf_Rela *) ef->pltrel; 314fe3db7c7SDoug Rabson ef->pltrel = NULL; 315fe3db7c7SDoug Rabson ef->pltrelasize = ef->pltrelsize; 316fe3db7c7SDoug Rabson ef->pltrelsize = 0; 317fe3db7c7SDoug Rabson } 318fe3db7c7SDoug Rabson 3192d636ab0SPeter Wemm ef->ddbsymtab = ef->symtab; 3202d636ab0SPeter Wemm ef->ddbsymcnt = ef->nchains; 3212d636ab0SPeter Wemm ef->ddbstrtab = ef->strtab; 3222d636ab0SPeter Wemm ef->ddbstrcnt = ef->strsz; 3232d636ab0SPeter Wemm 324a4f67738SDoug Rabson return 0; 325a4f67738SDoug Rabson } 326a4f67738SDoug Rabson 327fe3db7c7SDoug Rabson static void 328fe3db7c7SDoug Rabson link_elf_error(const char *s) 329fe3db7c7SDoug Rabson { 330fe3db7c7SDoug Rabson printf("kldload: %s\n", s); 331fe3db7c7SDoug Rabson } 332fe3db7c7SDoug Rabson 333a4f67738SDoug Rabson static int 334de78ca7eSPeter Wemm link_elf_load_module(const char *filename, linker_file_t *result) 335de78ca7eSPeter Wemm { 336de78ca7eSPeter Wemm caddr_t modptr, baseptr, sizeptr, dynptr; 337de78ca7eSPeter Wemm char *type; 338de78ca7eSPeter Wemm elf_file_t ef; 339de78ca7eSPeter Wemm linker_file_t lf; 340de78ca7eSPeter Wemm int error; 341de78ca7eSPeter Wemm vm_offset_t dp; 342de78ca7eSPeter Wemm 343de78ca7eSPeter Wemm /* Look to see if we have the module preloaded */ 344de78ca7eSPeter Wemm modptr = preload_search_by_name(filename); 345de78ca7eSPeter Wemm if (modptr == NULL) 346de78ca7eSPeter Wemm return (link_elf_load_file(filename, result)); 347de78ca7eSPeter Wemm 348de78ca7eSPeter Wemm /* It's preloaded, check we can handle it and collect information */ 349de78ca7eSPeter Wemm type = (char *)preload_search_info(modptr, MODINFO_TYPE); 350de78ca7eSPeter Wemm baseptr = preload_search_info(modptr, MODINFO_ADDR); 351de78ca7eSPeter Wemm sizeptr = preload_search_info(modptr, MODINFO_SIZE); 352de78ca7eSPeter Wemm dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC); 353de78ca7eSPeter Wemm if (type == NULL || strcmp(type, "elf module") != 0) 354de78ca7eSPeter Wemm return (EFTYPE); 355de78ca7eSPeter Wemm if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) 356de78ca7eSPeter Wemm return (EINVAL); 357de78ca7eSPeter Wemm 358de78ca7eSPeter Wemm ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); 359de78ca7eSPeter Wemm if (ef == NULL) 360de78ca7eSPeter Wemm return (ENOMEM); 361ca65d5c7SPeter Wemm ef->modptr = modptr; 362de78ca7eSPeter Wemm ef->address = *(caddr_t *)baseptr; 363de78ca7eSPeter Wemm #ifdef SPARSE_MAPPING 364de78ca7eSPeter Wemm ef->object = 0; 365de78ca7eSPeter Wemm #endif 366de78ca7eSPeter Wemm dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; 367de78ca7eSPeter Wemm ef->dynamic = (Elf_Dyn *)dp; 368de78ca7eSPeter Wemm lf = linker_make_file(filename, ef, &link_elf_module_ops); 369de78ca7eSPeter Wemm if (lf == NULL) { 370de78ca7eSPeter Wemm free(ef, M_LINKER); 371de78ca7eSPeter Wemm return ENOMEM; 372de78ca7eSPeter Wemm } 373de78ca7eSPeter Wemm lf->address = ef->address; 374de78ca7eSPeter Wemm lf->size = *(size_t *)sizeptr; 375de78ca7eSPeter Wemm 376de78ca7eSPeter Wemm error = parse_dynamic(lf); 377de78ca7eSPeter Wemm if (error) { 378de78ca7eSPeter Wemm linker_file_unload(lf); 379de78ca7eSPeter Wemm return error; 380de78ca7eSPeter Wemm } 381de78ca7eSPeter Wemm error = load_dependancies(lf); 382de78ca7eSPeter Wemm if (error) { 383de78ca7eSPeter Wemm linker_file_unload(lf); 384de78ca7eSPeter Wemm return error; 385de78ca7eSPeter Wemm } 386de78ca7eSPeter Wemm error = relocate_file(lf); 387de78ca7eSPeter Wemm if (error) { 388de78ca7eSPeter Wemm linker_file_unload(lf); 389de78ca7eSPeter Wemm return error; 390de78ca7eSPeter Wemm } 3912d636ab0SPeter Wemm (void)parse_module_symbols(lf); 392de78ca7eSPeter Wemm *result = lf; 393de78ca7eSPeter Wemm return (0); 394de78ca7eSPeter Wemm } 395de78ca7eSPeter Wemm 396de78ca7eSPeter Wemm static int 397a4f67738SDoug Rabson link_elf_load_file(const char* filename, linker_file_t* result) 398a4f67738SDoug Rabson { 399a4f67738SDoug Rabson struct nameidata nd; 400a4f67738SDoug Rabson struct proc* p = curproc; /* XXX */ 401fe3db7c7SDoug Rabson union { 402fe3db7c7SDoug Rabson Elf_Ehdr hdr; 403fe3db7c7SDoug Rabson char buf[PAGE_SIZE]; 404fe3db7c7SDoug Rabson } u; 405fe3db7c7SDoug Rabson int nbytes, i; 406fe3db7c7SDoug Rabson Elf_Phdr *phdr; 407fe3db7c7SDoug Rabson Elf_Phdr *phlimit; 408fe3db7c7SDoug Rabson Elf_Phdr *segs[2]; 409fe3db7c7SDoug Rabson int nsegs; 410fe3db7c7SDoug Rabson Elf_Phdr *phdyn; 411fe3db7c7SDoug Rabson Elf_Phdr *phphdr; 412fe3db7c7SDoug Rabson caddr_t mapbase; 413fe3db7c7SDoug Rabson size_t mapsize; 414fe3db7c7SDoug Rabson Elf_Off base_offset; 415fe3db7c7SDoug Rabson Elf_Addr base_vaddr; 416fe3db7c7SDoug Rabson Elf_Addr base_vlimit; 417fe3db7c7SDoug Rabson caddr_t base_addr; 418fe3db7c7SDoug Rabson Elf_Off data_offset; 419fe3db7c7SDoug Rabson Elf_Addr data_vaddr; 420fe3db7c7SDoug Rabson Elf_Addr data_vlimit; 421fe3db7c7SDoug Rabson caddr_t data_addr; 422fe3db7c7SDoug Rabson Elf_Addr clear_vaddr; 423fe3db7c7SDoug Rabson caddr_t clear_addr; 424fe3db7c7SDoug Rabson size_t nclear; 425fe3db7c7SDoug Rabson Elf_Addr bss_vaddr; 426fe3db7c7SDoug Rabson Elf_Addr bss_vlimit; 427fe3db7c7SDoug Rabson caddr_t bss_addr; 428a4f67738SDoug Rabson int error = 0; 429a4f67738SDoug Rabson int resid; 430a4f67738SDoug Rabson elf_file_t ef; 431a4f67738SDoug Rabson linker_file_t lf; 432de78ca7eSPeter Wemm char *pathname; 433ca65d5c7SPeter Wemm Elf_Shdr *shdr; 434ca65d5c7SPeter Wemm int symtabindex; 435ca65d5c7SPeter Wemm int symstrindex; 436ca65d5c7SPeter Wemm int symcnt; 437ca65d5c7SPeter Wemm int strcnt; 438ca65d5c7SPeter Wemm 439ca65d5c7SPeter Wemm shdr = NULL; 440ca65d5c7SPeter Wemm lf = NULL; 441a4f67738SDoug Rabson 442de78ca7eSPeter Wemm pathname = linker_search_path(filename); 443de78ca7eSPeter Wemm if (pathname == NULL) 444de78ca7eSPeter Wemm return ENOENT; 445de78ca7eSPeter Wemm NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p); 446a4f67738SDoug Rabson error = vn_open(&nd, FREAD, 0); 447de78ca7eSPeter Wemm free(pathname, M_LINKER); 448a4f67738SDoug Rabson if (error) 449a4f67738SDoug Rabson return error; 450a4f67738SDoug Rabson 451a4f67738SDoug Rabson /* 452fe3db7c7SDoug Rabson * Read the elf header from the file. 453a4f67738SDoug Rabson */ 454fe3db7c7SDoug Rabson error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &u, sizeof u, 0, 455a4f67738SDoug Rabson UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 456fe3db7c7SDoug Rabson nbytes = sizeof u - resid; 457a4f67738SDoug Rabson if (error) 458a4f67738SDoug Rabson goto out; 459a4f67738SDoug Rabson 460fe3db7c7SDoug Rabson if (!IS_ELF(u.hdr)) { 461fe3db7c7SDoug Rabson error = ENOEXEC; 462a4f67738SDoug Rabson goto out; 463fe3db7c7SDoug Rabson } 464fe3db7c7SDoug Rabson 465fe3db7c7SDoug Rabson if (u.hdr.e_ident[EI_CLASS] != ELF_TARG_CLASS 466fe3db7c7SDoug Rabson || u.hdr.e_ident[EI_DATA] != ELF_TARG_DATA) { 467fe3db7c7SDoug Rabson link_elf_error("Unsupported file layout"); 468fe3db7c7SDoug Rabson error = ENOEXEC; 469fe3db7c7SDoug Rabson goto out; 470fe3db7c7SDoug Rabson } 471fe3db7c7SDoug Rabson if (u.hdr.e_ident[EI_VERSION] != EV_CURRENT 472fe3db7c7SDoug Rabson || u.hdr.e_version != EV_CURRENT) { 473fe3db7c7SDoug Rabson link_elf_error("Unsupported file version"); 474fe3db7c7SDoug Rabson error = ENOEXEC; 475fe3db7c7SDoug Rabson goto out; 476fe3db7c7SDoug Rabson } 477fe3db7c7SDoug Rabson if (u.hdr.e_type != ET_EXEC && u.hdr.e_type != ET_DYN) { 478fe3db7c7SDoug Rabson link_elf_error("Unsupported file type"); 479fe3db7c7SDoug Rabson error = ENOEXEC; 480fe3db7c7SDoug Rabson goto out; 481fe3db7c7SDoug Rabson } 482fe3db7c7SDoug Rabson if (u.hdr.e_machine != ELF_TARG_MACH) { 483fe3db7c7SDoug Rabson link_elf_error("Unsupported machine"); 484fe3db7c7SDoug Rabson error = ENOEXEC; 485fe3db7c7SDoug Rabson goto out; 486fe3db7c7SDoug Rabson } 487a4f67738SDoug Rabson 488a4f67738SDoug Rabson /* 489fe3db7c7SDoug Rabson * We rely on the program header being in the first page. This is 490fe3db7c7SDoug Rabson * not strictly required by the ABI specification, but it seems to 491fe3db7c7SDoug Rabson * always true in practice. And, it simplifies things considerably. 492a4f67738SDoug Rabson */ 493fe3db7c7SDoug Rabson if (!((u.hdr.e_phentsize == sizeof(Elf_Phdr)) 494fe3db7c7SDoug Rabson || (u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) 495fe3db7c7SDoug Rabson || (u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= nbytes))) 496fe3db7c7SDoug Rabson link_elf_error("Unreadable program headers"); 497fe3db7c7SDoug Rabson 498fe3db7c7SDoug Rabson /* 499fe3db7c7SDoug Rabson * Scan the program header entries, and save key information. 500fe3db7c7SDoug Rabson * 501fe3db7c7SDoug Rabson * We rely on there being exactly two load segments, text and data, 502fe3db7c7SDoug Rabson * in that order. 503fe3db7c7SDoug Rabson */ 504fe3db7c7SDoug Rabson phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff); 505fe3db7c7SDoug Rabson phlimit = phdr + u.hdr.e_phnum; 506fe3db7c7SDoug Rabson nsegs = 0; 507fe3db7c7SDoug Rabson phdyn = NULL; 508fe3db7c7SDoug Rabson phphdr = NULL; 509fe3db7c7SDoug Rabson while (phdr < phlimit) { 510fe3db7c7SDoug Rabson switch (phdr->p_type) { 511fe3db7c7SDoug Rabson 512fe3db7c7SDoug Rabson case PT_LOAD: 513fe3db7c7SDoug Rabson if (nsegs == 2) { 514fe3db7c7SDoug Rabson link_elf_error("Too many sections"); 515fe3db7c7SDoug Rabson error = ENOEXEC; 516fe3db7c7SDoug Rabson goto out; 517fe3db7c7SDoug Rabson } 518fe3db7c7SDoug Rabson segs[nsegs] = phdr; 519fe3db7c7SDoug Rabson ++nsegs; 520fe3db7c7SDoug Rabson break; 521fe3db7c7SDoug Rabson 522fe3db7c7SDoug Rabson case PT_PHDR: 523fe3db7c7SDoug Rabson phphdr = phdr; 524fe3db7c7SDoug Rabson break; 525fe3db7c7SDoug Rabson 526fe3db7c7SDoug Rabson case PT_DYNAMIC: 527fe3db7c7SDoug Rabson phdyn = phdr; 528fe3db7c7SDoug Rabson break; 529fe3db7c7SDoug Rabson } 530fe3db7c7SDoug Rabson 531fe3db7c7SDoug Rabson ++phdr; 532fe3db7c7SDoug Rabson } 533fe3db7c7SDoug Rabson if (phdyn == NULL) { 534fe3db7c7SDoug Rabson link_elf_error("Object is not dynamically-linked"); 535fe3db7c7SDoug Rabson error = ENOEXEC; 536fe3db7c7SDoug Rabson goto out; 537fe3db7c7SDoug Rabson } 538fe3db7c7SDoug Rabson 539fe3db7c7SDoug Rabson /* 540fe3db7c7SDoug Rabson * Allocate the entire address space of the object, to stake out our 541fe3db7c7SDoug Rabson * contiguous region, and to establish the base address for relocation. 542fe3db7c7SDoug Rabson */ 543fe3db7c7SDoug Rabson base_offset = trunc_page(segs[0]->p_offset); 544fe3db7c7SDoug Rabson base_vaddr = trunc_page(segs[0]->p_vaddr); 545fe3db7c7SDoug Rabson base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); 546fe3db7c7SDoug Rabson mapsize = base_vlimit - base_vaddr; 547fe3db7c7SDoug Rabson 548a4f67738SDoug Rabson ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); 549fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 550fe3db7c7SDoug Rabson ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); 551fe3db7c7SDoug Rabson if (ef->object == NULL) { 552fe3db7c7SDoug Rabson free(ef, M_LINKER); 553fe3db7c7SDoug Rabson error = ENOMEM; 554fe3db7c7SDoug Rabson goto out; 555fe3db7c7SDoug Rabson } 556fe3db7c7SDoug Rabson vm_object_reference(ef->object); 557fe3db7c7SDoug Rabson ef->address = (caddr_t) vm_map_min(kernel_map); 558fe3db7c7SDoug Rabson error = vm_map_find(kernel_map, ef->object, 0, 559fe3db7c7SDoug Rabson (vm_offset_t *) &ef->address, 560fe3db7c7SDoug Rabson mapsize, 1, 561fe3db7c7SDoug Rabson VM_PROT_ALL, VM_PROT_ALL, 0); 562fe3db7c7SDoug Rabson if (error) { 563fe3db7c7SDoug Rabson vm_object_deallocate(ef->object); 564fe3db7c7SDoug Rabson free(ef, M_LINKER); 565fe3db7c7SDoug Rabson goto out; 566fe3db7c7SDoug Rabson } 567fe3db7c7SDoug Rabson #else 568fe3db7c7SDoug Rabson ef->address = malloc(mapsize, M_LINKER, M_WAITOK); 569fe3db7c7SDoug Rabson #endif 570fe3db7c7SDoug Rabson mapbase = ef->address; 571a4f67738SDoug Rabson 572a4f67738SDoug Rabson /* 573a4f67738SDoug Rabson * Read the text and data sections and zero the bss. 574a4f67738SDoug Rabson */ 575fe3db7c7SDoug Rabson for (i = 0; i < 2; i++) { 576fe3db7c7SDoug Rabson caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; 577fe3db7c7SDoug Rabson error = vn_rdwr(UIO_READ, nd.ni_vp, 578fe3db7c7SDoug Rabson segbase, segs[i]->p_filesz, segs[i]->p_offset, 579a4f67738SDoug Rabson UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 580fe3db7c7SDoug Rabson if (error) { 581fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 582fe3db7c7SDoug Rabson vm_map_remove(kernel_map, (vm_offset_t) ef->address, 583fe3db7c7SDoug Rabson (vm_offset_t) ef->address 584fe3db7c7SDoug Rabson + (ef->object->size << PAGE_SHIFT)); 585fe3db7c7SDoug Rabson vm_object_deallocate(ef->object); 586fe3db7c7SDoug Rabson #else 587a4f67738SDoug Rabson free(ef->address, M_LINKER); 588fe3db7c7SDoug Rabson #endif 589a4f67738SDoug Rabson free(ef, M_LINKER); 590a4f67738SDoug Rabson goto out; 591a4f67738SDoug Rabson } 592fe3db7c7SDoug Rabson bzero(segbase + segs[i]->p_filesz, 593fe3db7c7SDoug Rabson segs[i]->p_memsz - segs[i]->p_filesz); 594fe3db7c7SDoug Rabson 595fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 596fe3db7c7SDoug Rabson /* 597fe3db7c7SDoug Rabson * Wire down the pages 598fe3db7c7SDoug Rabson */ 599fe3db7c7SDoug Rabson vm_map_pageable(kernel_map, 600fe3db7c7SDoug Rabson (vm_offset_t) segbase, 601fe3db7c7SDoug Rabson (vm_offset_t) segbase + segs[i]->p_memsz, 602fe3db7c7SDoug Rabson FALSE); 603fe3db7c7SDoug Rabson #endif 604fe3db7c7SDoug Rabson } 605fe3db7c7SDoug Rabson 606fe3db7c7SDoug Rabson ef->dynamic = (const Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); 607a4f67738SDoug Rabson 608a4f67738SDoug Rabson lf = linker_make_file(filename, ef, &link_elf_file_ops); 609a4f67738SDoug Rabson if (lf == NULL) { 610fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 611fe3db7c7SDoug Rabson vm_map_remove(kernel_map, (vm_offset_t) ef->address, 612fe3db7c7SDoug Rabson (vm_offset_t) ef->address 613fe3db7c7SDoug Rabson + (ef->object->size << PAGE_SHIFT)); 614fe3db7c7SDoug Rabson vm_object_deallocate(ef->object); 615fe3db7c7SDoug Rabson #else 616a4f67738SDoug Rabson free(ef->address, M_LINKER); 617fe3db7c7SDoug Rabson #endif 618a4f67738SDoug Rabson free(ef, M_LINKER); 619a4f67738SDoug Rabson error = ENOMEM; 620a4f67738SDoug Rabson goto out; 621a4f67738SDoug Rabson } 622a4f67738SDoug Rabson lf->address = ef->address; 623fe3db7c7SDoug Rabson lf->size = mapsize; 624a4f67738SDoug Rabson 625de78ca7eSPeter Wemm error = parse_dynamic(lf); 626ca65d5c7SPeter Wemm if (error) 627de78ca7eSPeter Wemm goto out; 628de78ca7eSPeter Wemm error = load_dependancies(lf); 629ca65d5c7SPeter Wemm if (error) 630de78ca7eSPeter Wemm goto out; 631de78ca7eSPeter Wemm error = relocate_file(lf); 632ca65d5c7SPeter Wemm if (error) 633ca65d5c7SPeter Wemm goto out; 634ca65d5c7SPeter Wemm 635ca65d5c7SPeter Wemm /* Try and load the symbol table if it's present. (you can strip it!) */ 636ca65d5c7SPeter Wemm nbytes = u.hdr.e_shnum * u.hdr.e_shentsize; 637ca65d5c7SPeter Wemm if (nbytes == 0 || u.hdr.e_shoff == 0) 638ca65d5c7SPeter Wemm goto nosyms; 639ca65d5c7SPeter Wemm shdr = malloc(nbytes, M_LINKER, M_WAITOK); 640ca65d5c7SPeter Wemm if (shdr == NULL) { 641ca65d5c7SPeter Wemm error = ENOMEM; 642a4f67738SDoug Rabson goto out; 643a4f67738SDoug Rabson } 644ca65d5c7SPeter Wemm error = vn_rdwr(UIO_READ, nd.ni_vp, 645ca65d5c7SPeter Wemm (caddr_t)shdr, nbytes, u.hdr.e_shoff, 646ca65d5c7SPeter Wemm UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 647ca65d5c7SPeter Wemm if (error) 648ca65d5c7SPeter Wemm goto out; 649ca65d5c7SPeter Wemm symtabindex = -1; 650ca65d5c7SPeter Wemm symstrindex = -1; 651ca65d5c7SPeter Wemm for (i = 0; i < u.hdr.e_shnum; i++) { 652ca65d5c7SPeter Wemm if (shdr[i].sh_type == SHT_SYMTAB) { 653ca65d5c7SPeter Wemm symtabindex = i; 654ca65d5c7SPeter Wemm symstrindex = shdr[i].sh_link; 655ca65d5c7SPeter Wemm } 656ca65d5c7SPeter Wemm } 657ca65d5c7SPeter Wemm if (symtabindex < 0 || symstrindex < 0) 658ca65d5c7SPeter Wemm goto nosyms; 659ca65d5c7SPeter Wemm 660ca65d5c7SPeter Wemm symcnt = shdr[symtabindex].sh_size; 661ca65d5c7SPeter Wemm ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK); 662ca65d5c7SPeter Wemm strcnt = shdr[symstrindex].sh_size; 663ca65d5c7SPeter Wemm ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK); 664ca65d5c7SPeter Wemm 665ca65d5c7SPeter Wemm if (ef->symbase == NULL || ef->strbase == NULL) { 666ca65d5c7SPeter Wemm error = ENOMEM; 667ca65d5c7SPeter Wemm goto out; 668ca65d5c7SPeter Wemm } 669ca65d5c7SPeter Wemm error = vn_rdwr(UIO_READ, nd.ni_vp, 670ca65d5c7SPeter Wemm ef->symbase, symcnt, shdr[symtabindex].sh_offset, 671ca65d5c7SPeter Wemm UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 672ca65d5c7SPeter Wemm if (error) 673ca65d5c7SPeter Wemm goto out; 674ca65d5c7SPeter Wemm error = vn_rdwr(UIO_READ, nd.ni_vp, 675ca65d5c7SPeter Wemm ef->strbase, strcnt, shdr[symstrindex].sh_offset, 676ca65d5c7SPeter Wemm UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 677ca65d5c7SPeter Wemm if (error) 678ca65d5c7SPeter Wemm goto out; 679ca65d5c7SPeter Wemm 680ca65d5c7SPeter Wemm ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 681ca65d5c7SPeter Wemm ef->ddbsymtab = (const Elf_Sym *)ef->symbase; 682ca65d5c7SPeter Wemm ef->ddbstrcnt = strcnt; 683ca65d5c7SPeter Wemm ef->ddbstrtab = ef->strbase; 684ca65d5c7SPeter Wemm 685ca65d5c7SPeter Wemm nosyms: 686a4f67738SDoug Rabson 687a4f67738SDoug Rabson *result = lf; 688a4f67738SDoug Rabson 689a4f67738SDoug Rabson out: 690ca65d5c7SPeter Wemm if (error && lf) 691ca65d5c7SPeter Wemm linker_file_unload(lf); 692ca65d5c7SPeter Wemm if (shdr) 693ca65d5c7SPeter Wemm free(shdr, M_LINKER); 694a4f67738SDoug Rabson VOP_UNLOCK(nd.ni_vp, 0, p); 695a4f67738SDoug Rabson vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 696a4f67738SDoug Rabson 697a4f67738SDoug Rabson return error; 698a4f67738SDoug Rabson } 699a4f67738SDoug Rabson 700a4f67738SDoug Rabson static void 701de78ca7eSPeter Wemm link_elf_unload_file(linker_file_t file) 702a4f67738SDoug Rabson { 703a4f67738SDoug Rabson elf_file_t ef = file->priv; 704a4f67738SDoug Rabson 705a4f67738SDoug Rabson if (ef) { 706fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 707fe3db7c7SDoug Rabson if (ef->object) { 708fe3db7c7SDoug Rabson vm_map_remove(kernel_map, (vm_offset_t) ef->address, 709fe3db7c7SDoug Rabson (vm_offset_t) ef->address 710fe3db7c7SDoug Rabson + (ef->object->size << PAGE_SHIFT)); 711fe3db7c7SDoug Rabson vm_object_deallocate(ef->object); 712fe3db7c7SDoug Rabson } 713fe3db7c7SDoug Rabson #else 714ca65d5c7SPeter Wemm if (ef->address) 715a4f67738SDoug Rabson free(ef->address, M_LINKER); 716fe3db7c7SDoug Rabson #endif 717ca65d5c7SPeter Wemm if (ef->symbase) 718ca65d5c7SPeter Wemm free(ef->symbase, M_LINKER); 719ca65d5c7SPeter Wemm if (ef->strbase) 720ca65d5c7SPeter Wemm free(ef->strbase, M_LINKER); 721a4f67738SDoug Rabson free(ef, M_LINKER); 722a4f67738SDoug Rabson } 723a4f67738SDoug Rabson } 724a4f67738SDoug Rabson 725de78ca7eSPeter Wemm static void 726de78ca7eSPeter Wemm link_elf_unload_module(linker_file_t file) 727de78ca7eSPeter Wemm { 728de78ca7eSPeter Wemm elf_file_t ef = file->priv; 729de78ca7eSPeter Wemm 730de78ca7eSPeter Wemm if (ef) 731de78ca7eSPeter Wemm free(ef, M_LINKER); 732de78ca7eSPeter Wemm if (file->filename) 733de78ca7eSPeter Wemm preload_delete_name(file->filename); 734de78ca7eSPeter Wemm } 735de78ca7eSPeter Wemm 736a4f67738SDoug Rabson static int 737a4f67738SDoug Rabson load_dependancies(linker_file_t lf) 738a4f67738SDoug Rabson { 739a4f67738SDoug Rabson elf_file_t ef = lf->priv; 740a4f67738SDoug Rabson linker_file_t lfdep; 741a4f67738SDoug Rabson char* name; 742a4f67738SDoug Rabson char* filename = 0; 743fe3db7c7SDoug Rabson const Elf_Dyn *dp; 744a4f67738SDoug Rabson int error = 0; 745a4f67738SDoug Rabson 746a4f67738SDoug Rabson /* 747a4f67738SDoug Rabson * All files are dependant on /kernel. 748a4f67738SDoug Rabson */ 749a4f67738SDoug Rabson linker_kernel_file->refs++; 750a4f67738SDoug Rabson linker_file_add_dependancy(lf, linker_kernel_file); 751a4f67738SDoug Rabson 752a4f67738SDoug Rabson 753fe3db7c7SDoug Rabson for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 754fe3db7c7SDoug Rabson if (dp->d_tag == DT_NEEDED) { 755fe3db7c7SDoug Rabson name = ef->strtab + dp->d_un.d_val; 756a4f67738SDoug Rabson 757a4f67738SDoug Rabson error = linker_load_file(name, &lfdep); 758a4f67738SDoug Rabson if (error) 759a4f67738SDoug Rabson goto out; 760a4f67738SDoug Rabson error = linker_file_add_dependancy(lf, lfdep); 761a4f67738SDoug Rabson if (error) 762a4f67738SDoug Rabson goto out; 763fe3db7c7SDoug Rabson } 764a4f67738SDoug Rabson } 765a4f67738SDoug Rabson 766a4f67738SDoug Rabson out: 767a4f67738SDoug Rabson if (filename) 768a4f67738SDoug Rabson free(filename, M_TEMP); 769a4f67738SDoug Rabson return error; 770a4f67738SDoug Rabson } 771a4f67738SDoug Rabson 772fe3db7c7SDoug Rabson static const char * 773fe3db7c7SDoug Rabson symbol_name(elf_file_t ef, const Elf_Rela *rela) 774a4f67738SDoug Rabson { 775fe3db7c7SDoug Rabson const Elf_Sym *ref; 776a4f67738SDoug Rabson 777fe3db7c7SDoug Rabson if (ELF_R_SYM(rela->r_info)) { 7782d636ab0SPeter Wemm ref = ef->ddbsymtab + ELF_R_SYM(rela->r_info); 7792d636ab0SPeter Wemm return ef->ddbstrtab + ref->st_name; 780fe3db7c7SDoug Rabson } else 781fe3db7c7SDoug Rabson return NULL; 782a4f67738SDoug Rabson } 783a4f67738SDoug Rabson 784a4f67738SDoug Rabson static int 785a4f67738SDoug Rabson relocate_file(linker_file_t lf) 786a4f67738SDoug Rabson { 787a4f67738SDoug Rabson elf_file_t ef = lf->priv; 788fe3db7c7SDoug Rabson const Elf_Rel *rellim; 789fe3db7c7SDoug Rabson const Elf_Rel *rel; 790fe3db7c7SDoug Rabson const Elf_Rela *relalim; 791fe3db7c7SDoug Rabson const Elf_Rela *rela; 792a4f67738SDoug Rabson 793fe3db7c7SDoug Rabson /* Perform relocations without addend if there are any: */ 794fe3db7c7SDoug Rabson rellim = (const Elf_Rel *) ((caddr_t) ef->rel + ef->relsize); 795fe3db7c7SDoug Rabson for (rel = ef->rel; ef->rel != NULL && rel < rellim; rel++) { 796fe3db7c7SDoug Rabson Elf_Rela locrela; 797a4f67738SDoug Rabson 798fe3db7c7SDoug Rabson locrela.r_info = rel->r_info; 799fe3db7c7SDoug Rabson locrela.r_offset = rel->r_offset; 800fe3db7c7SDoug Rabson locrela.r_addend = 0; 801fe3db7c7SDoug Rabson if (elf_reloc(lf, &locrela, symbol_name(ef, &locrela))) 802a4f67738SDoug Rabson return ENOENT; 803a4f67738SDoug Rabson } 804a4f67738SDoug Rabson 805fe3db7c7SDoug Rabson /* Perform relocations with addend if there are any: */ 806fe3db7c7SDoug Rabson relalim = (const Elf_Rela *) ((caddr_t) ef->rela + ef->relasize); 807fe3db7c7SDoug Rabson for (rela = ef->rela; ef->rela != NULL && rela < relalim; rela++) { 808fe3db7c7SDoug Rabson if (elf_reloc(lf, rela, symbol_name(ef, rela))) 809fe3db7c7SDoug Rabson return ENOENT; 810a4f67738SDoug Rabson } 811a4f67738SDoug Rabson 812fe3db7c7SDoug Rabson /* Perform PLT relocations without addend if there are any: */ 813fe3db7c7SDoug Rabson rellim = (const Elf_Rel *) ((caddr_t) ef->pltrel + ef->pltrelsize); 814fe3db7c7SDoug Rabson for (rel = ef->pltrel; ef->pltrel != NULL && rel < rellim; rel++) { 815fe3db7c7SDoug Rabson Elf_Rela locrela; 816a4f67738SDoug Rabson 817fe3db7c7SDoug Rabson locrela.r_info = rel->r_info; 818fe3db7c7SDoug Rabson locrela.r_offset = rel->r_offset; 819fe3db7c7SDoug Rabson locrela.r_addend = 0; 820fe3db7c7SDoug Rabson if (elf_reloc(lf, &locrela, symbol_name(ef, &locrela))) 821fe3db7c7SDoug Rabson return ENOENT; 822a4f67738SDoug Rabson } 823a4f67738SDoug Rabson 824fe3db7c7SDoug Rabson /* Perform relocations with addend if there are any: */ 825fe3db7c7SDoug Rabson relalim = (const Elf_Rela *) ((caddr_t) ef->pltrela + ef->pltrelasize); 826fe3db7c7SDoug Rabson for (rela = ef->pltrela; ef->pltrela != NULL && rela < relalim; rela++) { 827fe3db7c7SDoug Rabson if (elf_reloc(lf, rela, symbol_name(ef, rela))) 828fe3db7c7SDoug Rabson return ENOENT; 829a4f67738SDoug Rabson } 830a4f67738SDoug Rabson 831a4f67738SDoug Rabson return 0; 832a4f67738SDoug Rabson } 833a4f67738SDoug Rabson 834fe3db7c7SDoug Rabson /* 835fe3db7c7SDoug Rabson * Hash function for symbol table lookup. Don't even think about changing 836fe3db7c7SDoug Rabson * this. It is specified by the System V ABI. 837fe3db7c7SDoug Rabson */ 838fe3db7c7SDoug Rabson static unsigned long 839fe3db7c7SDoug Rabson elf_hash(const char *name) 840a4f67738SDoug Rabson { 841fe3db7c7SDoug Rabson const unsigned char *p = (const unsigned char *) name; 842fe3db7c7SDoug Rabson unsigned long h = 0; 843fe3db7c7SDoug Rabson unsigned long g; 844a4f67738SDoug Rabson 845fe3db7c7SDoug Rabson while (*p != '\0') { 846fe3db7c7SDoug Rabson h = (h << 4) + *p++; 847fe3db7c7SDoug Rabson if ((g = h & 0xf0000000) != 0) 848fe3db7c7SDoug Rabson h ^= g >> 24; 849fe3db7c7SDoug Rabson h &= ~g; 850a4f67738SDoug Rabson } 851fe3db7c7SDoug Rabson return h; 852fe3db7c7SDoug Rabson } 853a4f67738SDoug Rabson 854a4f67738SDoug Rabson int 855a4f67738SDoug Rabson link_elf_lookup_symbol(linker_file_t lf, const char* name, linker_sym_t* sym) 856a4f67738SDoug Rabson { 857a4f67738SDoug Rabson elf_file_t ef = lf->priv; 858fe3db7c7SDoug Rabson unsigned long symnum; 8592d636ab0SPeter Wemm const Elf_Sym* symp; 8602d636ab0SPeter Wemm const char *strp; 861fe3db7c7SDoug Rabson unsigned long hash; 862a4f67738SDoug Rabson int i; 863a4f67738SDoug Rabson 8642d636ab0SPeter Wemm /* First, search hashed global symbols */ 865fe3db7c7SDoug Rabson hash = elf_hash(name); 866fe3db7c7SDoug Rabson symnum = ef->buckets[hash % ef->nbuckets]; 867fe3db7c7SDoug Rabson 868fe3db7c7SDoug Rabson while (symnum != STN_UNDEF) { 869fe3db7c7SDoug Rabson if (symnum >= ef->nchains) { 870fe3db7c7SDoug Rabson printf("link_elf_lookup_symbol: corrupt symbol table\n"); 871fe3db7c7SDoug Rabson return ENOENT; 872a4f67738SDoug Rabson } 873fe3db7c7SDoug Rabson 874fe3db7c7SDoug Rabson symp = ef->symtab + symnum; 875fe3db7c7SDoug Rabson if (symp->st_name == 0) { 876fe3db7c7SDoug Rabson printf("link_elf_lookup_symbol: corrupt symbol table\n"); 877fe3db7c7SDoug Rabson return ENOENT; 878fe3db7c7SDoug Rabson } 879fe3db7c7SDoug Rabson 880fe3db7c7SDoug Rabson strp = ef->strtab + symp->st_name; 881fe3db7c7SDoug Rabson 882fe3db7c7SDoug Rabson if (strcmp(name, strp) == 0) { 883fe3db7c7SDoug Rabson if (symp->st_shndx != SHN_UNDEF || 884fe3db7c7SDoug Rabson (symp->st_value != 0 && 885fe3db7c7SDoug Rabson ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 886fe3db7c7SDoug Rabson *sym = (linker_sym_t) symp; 887fe3db7c7SDoug Rabson return 0; 888fe3db7c7SDoug Rabson } else 889fe3db7c7SDoug Rabson return ENOENT; 890fe3db7c7SDoug Rabson } 891fe3db7c7SDoug Rabson 892fe3db7c7SDoug Rabson symnum = ef->chains[symnum]; 893a4f67738SDoug Rabson } 894a4f67738SDoug Rabson 8952d636ab0SPeter Wemm /* If we have not found it, look at the full table (if loaded) */ 8962d636ab0SPeter Wemm if (ef->symtab == ef->ddbsymtab) 8972d636ab0SPeter Wemm return ENOENT; 8982d636ab0SPeter Wemm 8992d636ab0SPeter Wemm /* Exhaustive search */ 9002d636ab0SPeter Wemm for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 9012d636ab0SPeter Wemm strp = ef->ddbstrtab + symp->st_name; 9022d636ab0SPeter Wemm if (strcmp(name, strp) == 0) { 9032d636ab0SPeter Wemm if (symp->st_shndx != SHN_UNDEF || 9042d636ab0SPeter Wemm (symp->st_value != 0 && 9052d636ab0SPeter Wemm ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 9062d636ab0SPeter Wemm *sym = (linker_sym_t) symp; 9072d636ab0SPeter Wemm return 0; 9082d636ab0SPeter Wemm } else 9092d636ab0SPeter Wemm return ENOENT; 9102d636ab0SPeter Wemm } 9112d636ab0SPeter Wemm } 9122d636ab0SPeter Wemm 913a4f67738SDoug Rabson return ENOENT; 914a4f67738SDoug Rabson } 915a4f67738SDoug Rabson 916de78ca7eSPeter Wemm static int 917a4f67738SDoug Rabson link_elf_symbol_values(linker_file_t lf, linker_sym_t sym, linker_symval_t* symval) 918a4f67738SDoug Rabson { 919a4f67738SDoug Rabson elf_file_t ef = lf->priv; 920a4f67738SDoug Rabson Elf_Sym* es = (Elf_Sym*) sym; 921a4f67738SDoug Rabson 9222d636ab0SPeter Wemm if (es >= ef->symtab && ((es - ef->symtab) < ef->nchains)) { 923a4f67738SDoug Rabson symval->name = ef->strtab + es->st_name; 924fe3db7c7SDoug Rabson symval->value = (caddr_t) ef->address + es->st_value; 925a4f67738SDoug Rabson symval->size = es->st_size; 926de78ca7eSPeter Wemm return 0; 927a4f67738SDoug Rabson } 9282d636ab0SPeter Wemm if (ef->symtab == ef->ddbsymtab) 9292d636ab0SPeter Wemm return ENOENT; 9302d636ab0SPeter Wemm if (es >= ef->ddbsymtab && ((es - ef->ddbsymtab) < ef->ddbsymcnt)) { 9312d636ab0SPeter Wemm symval->name = ef->ddbstrtab + es->st_name; 9322d636ab0SPeter Wemm symval->value = (caddr_t) ef->address + es->st_value; 9332d636ab0SPeter Wemm symval->size = es->st_size; 9342d636ab0SPeter Wemm return 0; 9352d636ab0SPeter Wemm } 9362d636ab0SPeter Wemm return ENOENT; 9372d636ab0SPeter Wemm } 938a4f67738SDoug Rabson 939a4f67738SDoug Rabson static int 940a4f67738SDoug Rabson link_elf_search_symbol(linker_file_t lf, caddr_t value, 941a4f67738SDoug Rabson linker_sym_t* sym, long* diffp) 942a4f67738SDoug Rabson { 943a4f67738SDoug Rabson elf_file_t ef = lf->priv; 944a4f67738SDoug Rabson u_long off = (u_long) value; 945a4f67738SDoug Rabson u_long diff = off; 946fe3db7c7SDoug Rabson const Elf_Sym* es; 947fe3db7c7SDoug Rabson const Elf_Sym* best = 0; 948a4f67738SDoug Rabson int i; 949a4f67738SDoug Rabson 9502d636ab0SPeter Wemm for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { 951a4f67738SDoug Rabson if (es->st_name == 0) 952a4f67738SDoug Rabson continue; 953a4f67738SDoug Rabson if (off >= es->st_value) { 954a4f67738SDoug Rabson if (off - es->st_value < diff) { 955a4f67738SDoug Rabson diff = off - es->st_value; 956a4f67738SDoug Rabson best = es; 957a4f67738SDoug Rabson if (diff == 0) 958a4f67738SDoug Rabson break; 959a4f67738SDoug Rabson } else if (off - es->st_value == diff) { 960a4f67738SDoug Rabson best = es; 961a4f67738SDoug Rabson } 962a4f67738SDoug Rabson } 963a4f67738SDoug Rabson } 964a4f67738SDoug Rabson if (best == 0) 965a4f67738SDoug Rabson *diffp = off; 966a4f67738SDoug Rabson else 967a4f67738SDoug Rabson *diffp = diff; 968a4f67738SDoug Rabson *sym = (linker_sym_t) best; 969a4f67738SDoug Rabson 970a4f67738SDoug Rabson return 0; 971a4f67738SDoug Rabson } 972