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 */ 2638514Sdfr 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD$"); 29116182Sobrien 30179223Sjb#include "opt_ddb.h" 31131928Smarcel#include "opt_gdb.h" 3259603Sdfr 3338514Sdfr#include <sys/param.h> 3476166Smarkm#include <sys/systm.h> 35129443Sbde#ifdef GPROF 36129443Sbde#include <sys/gmon.h> 37129443Sbde#endif 3838514Sdfr#include <sys/kernel.h> 3976166Smarkm#include <sys/lock.h> 4038514Sdfr#include <sys/malloc.h> 4177642Sdd#include <sys/mutex.h> 42159808Sjhb#include <sys/mount.h> 43194784Sjeff#include <sys/pcpu.h> 4438514Sdfr#include <sys/proc.h> 4538514Sdfr#include <sys/namei.h> 4638514Sdfr#include <sys/fcntl.h> 4738514Sdfr#include <sys/vnode.h> 4838514Sdfr#include <sys/linker.h> 4976166Smarkm 5038514Sdfr#include <machine/elf.h> 5138514Sdfr 52195699Srwatson#include <net/vnet.h> 53195699Srwatson 54163606Srwatson#include <security/mac/mac_framework.h> 55163606Srwatson 5639071Sdfr#include <vm/vm.h> 5739071Sdfr#include <vm/vm_param.h> 5852128Speter#ifdef SPARSE_MAPPING 5939071Sdfr#include <vm/vm_object.h> 6039071Sdfr#include <vm/vm_kern.h> 6139071Sdfr#include <vm/vm_extern.h> 6252128Speter#endif 6339071Sdfr#include <vm/pmap.h> 6439071Sdfr#include <vm/vm_map.h> 6576166Smarkm 66102288Speter#include <sys/link_elf.h> 6739071Sdfr 68179223Sjb#ifdef DDB_CTF 69179223Sjb#include <net/zlib.h> 70179223Sjb#endif 71179223Sjb 7259603Sdfr#include "linker_if.h" 7338514Sdfr 74151430Speter#define MAXSEGS 4 75151430Speter 76180438Sobrientypedef struct elf_file { 77215013Smdf struct linker_file lf; /* Common fields */ 78215013Smdf int preloaded; /* Was file pre-loaded */ 79215013Smdf caddr_t address; /* Relocation address */ 80180438Sobrien#ifdef SPARSE_MAPPING 81215013Smdf vm_object_t object; /* VM object to hold file pages */ 82180438Sobrien#endif 83215013Smdf Elf_Dyn *dynamic; /* Symbol table etc. */ 84215013Smdf Elf_Hashelt nbuckets; /* DT_HASH info */ 85215013Smdf Elf_Hashelt nchains; 86215013Smdf const Elf_Hashelt *buckets; 87215013Smdf const Elf_Hashelt *chains; 88215013Smdf caddr_t hash; 89215013Smdf caddr_t strtab; /* DT_STRTAB */ 90215013Smdf int strsz; /* DT_STRSZ */ 91215013Smdf const Elf_Sym *symtab; /* DT_SYMTAB */ 92215013Smdf Elf_Addr *got; /* DT_PLTGOT */ 93215013Smdf const Elf_Rel *pltrel; /* DT_JMPREL */ 94215013Smdf int pltrelsize; /* DT_PLTRELSZ */ 95215013Smdf const Elf_Rela *pltrela; /* DT_JMPREL */ 96215013Smdf int pltrelasize; /* DT_PLTRELSZ */ 97215013Smdf const Elf_Rel *rel; /* DT_REL */ 98215013Smdf int relsize; /* DT_RELSZ */ 99215013Smdf const Elf_Rela *rela; /* DT_RELA */ 100215013Smdf int relasize; /* DT_RELASZ */ 101215013Smdf caddr_t modptr; 102215013Smdf const Elf_Sym *ddbsymtab; /* The symbol table we are using */ 103215013Smdf long ddbsymcnt; /* Number of symbols */ 104215013Smdf caddr_t ddbstrtab; /* String table */ 105215013Smdf long ddbstrcnt; /* number of bytes in string table */ 106215013Smdf caddr_t symbase; /* malloc'ed symbold base */ 107215013Smdf caddr_t strbase; /* malloc'ed string base */ 108215013Smdf caddr_t ctftab; /* CTF table */ 109215013Smdf long ctfcnt; /* number of bytes in CTF table */ 110215013Smdf caddr_t ctfoff; /* CTF offset table */ 111215013Smdf caddr_t typoff; /* Type offset table */ 112215013Smdf long typlen; /* Number of type entries. */ 113215013Smdf Elf_Addr pcpu_start; /* Pre-relocation pcpu set start. */ 114215013Smdf Elf_Addr pcpu_stop; /* Pre-relocation pcpu set stop. */ 115215013Smdf Elf_Addr pcpu_base; /* Relocated pcpu set address. */ 116195699Srwatson#ifdef VIMAGE 117215013Smdf Elf_Addr vnet_start; /* Pre-relocation vnet set start. */ 118215013Smdf Elf_Addr vnet_stop; /* Pre-relocation vnet set stop. */ 119215013Smdf Elf_Addr vnet_base; /* Relocated vnet set address. */ 120195699Srwatson#endif 121180438Sobrien#ifdef GDB 122215013Smdf struct link_map gdb; /* hooks for gdb */ 123180438Sobrien#endif 124180438Sobrien} *elf_file_t; 125180438Sobrien 126243308Strocinystruct elf_set { 127243308Strociny Elf_Addr es_start; 128243308Strociny Elf_Addr es_stop; 129243308Strociny Elf_Addr es_base; 130243308Strociny TAILQ_ENTRY(elf_set) es_link; 131243308Strociny}; 132243308Strociny 133243308StrocinyTAILQ_HEAD(elf_set_head, elf_set); 134243308Strociny 135179223Sjb#include <kern/kern_ctf.c> 136179223Sjb 137105468Smarcelstatic int link_elf_link_common_finish(linker_file_t); 13859751Speterstatic int link_elf_link_preload(linker_class_t cls, 139215013Smdf const char *, linker_file_t *); 14059751Speterstatic int link_elf_link_preload_finish(linker_file_t); 141215013Smdfstatic int link_elf_load_file(linker_class_t, const char *, 142215013Smdf linker_file_t *); 143215013Smdfstatic int link_elf_lookup_symbol(linker_file_t, const char *, 144215013Smdf c_linker_sym_t *); 145215013Smdfstatic int link_elf_symbol_values(linker_file_t, c_linker_sym_t, 146215013Smdf linker_symval_t *); 147215013Smdfstatic int link_elf_search_symbol(linker_file_t, caddr_t, 148215013Smdf c_linker_sym_t *, long *); 14938514Sdfr 15059603Sdfrstatic void link_elf_unload_file(linker_file_t); 15159751Speterstatic void link_elf_unload_preload(linker_file_t); 15278161Speterstatic int link_elf_lookup_set(linker_file_t, const char *, 153215013Smdf void ***, void ***, int *); 15485736Sgreenstatic int link_elf_each_function_name(linker_file_t, 155215013Smdf int (*)(const char *, void *), void *); 156179223Sjbstatic int link_elf_each_function_nameval(linker_file_t, 157215013Smdf linker_function_nameval_callback_t, void *); 158109605Sjakestatic void link_elf_reloc_local(linker_file_t); 159192859Sssonstatic long link_elf_symtab_get(linker_file_t, const Elf_Sym **); 160192859Sssonstatic long link_elf_strtab_get(linker_file_t, caddr_t *); 161215013Smdfstatic Elf_Addr elf_lookup(linker_file_t, Elf_Size, int); 16259603Sdfr 16359603Sdfrstatic kobj_method_t link_elf_methods[] = { 164215013Smdf KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), 165215013Smdf KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), 166215013Smdf KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), 167215013Smdf KOBJMETHOD(linker_unload, link_elf_unload_file), 168215013Smdf KOBJMETHOD(linker_load_file, link_elf_load_file), 169215013Smdf KOBJMETHOD(linker_link_preload, link_elf_link_preload), 170215013Smdf KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), 171215013Smdf KOBJMETHOD(linker_lookup_set, link_elf_lookup_set), 172215013Smdf KOBJMETHOD(linker_each_function_name, link_elf_each_function_name), 173215013Smdf KOBJMETHOD(linker_each_function_nameval, link_elf_each_function_nameval), 174215013Smdf KOBJMETHOD(linker_ctf_get, link_elf_ctf_get), 175215013Smdf KOBJMETHOD(linker_symtab_get, link_elf_symtab_get), 176215013Smdf KOBJMETHOD(linker_strtab_get, link_elf_strtab_get), 177215013Smdf { 0, 0 } 17859603Sdfr}; 17959603Sdfr 18059603Sdfrstatic struct linker_class link_elf_class = { 18159603Sdfr#if ELF_TARG_CLASS == ELFCLASS32 182215013Smdf "elf32", 18359603Sdfr#else 184215013Smdf "elf64", 18559603Sdfr#endif 186215013Smdf link_elf_methods, sizeof(struct elf_file) 18759603Sdfr}; 18859603Sdfr 189215013Smdfstatic int parse_dynamic(elf_file_t); 190215013Smdfstatic int relocate_file(elf_file_t); 191215013Smdfstatic int link_elf_preload_parse_symbols(elf_file_t); 19259603Sdfr 193243308Strocinystatic struct elf_set_head set_pcpu_list; 194243308Strociny#ifdef VIMAGE 195243308Strocinystatic struct elf_set_head set_vnet_list; 196243308Strociny#endif 197243308Strociny 198243308Strocinystatic void 199243308Strocinyelf_set_add(struct elf_set_head *list, Elf_Addr start, Elf_Addr stop, Elf_Addr base) 200243308Strociny{ 201243308Strociny struct elf_set *set, *iter; 202243308Strociny 203243308Strociny set = malloc(sizeof(*set), M_LINKER, M_WAITOK); 204243308Strociny set->es_start = start; 205243308Strociny set->es_stop = stop; 206243308Strociny set->es_base = base; 207243308Strociny 208243308Strociny TAILQ_FOREACH(iter, list, es_link) { 209243308Strociny 210243308Strociny KASSERT((set->es_start < iter->es_start && set->es_stop < iter->es_stop) || 211243308Strociny (set->es_start > iter->es_start && set->es_stop > iter->es_stop), 212243308Strociny ("linker sets intersection: to insert: 0x%jx-0x%jx; inserted: 0x%jx-0x%jx", 213243308Strociny (uintmax_t)set->es_start, (uintmax_t)set->es_stop, 214243308Strociny (uintmax_t)iter->es_start, (uintmax_t)iter->es_stop)); 215243308Strociny 216243308Strociny if (iter->es_start > set->es_start) { 217243308Strociny TAILQ_INSERT_BEFORE(iter, set, es_link); 218243308Strociny break; 219243308Strociny } 220243308Strociny } 221243308Strociny 222243308Strociny if (iter == NULL) 223243308Strociny TAILQ_INSERT_TAIL(list, set, es_link); 224243308Strociny} 225243308Strociny 226243308Strocinystatic int 227243308Strocinyelf_set_find(struct elf_set_head *list, Elf_Addr addr, Elf_Addr *start, Elf_Addr *base) 228243308Strociny{ 229243308Strociny struct elf_set *set; 230243308Strociny 231243308Strociny TAILQ_FOREACH(set, list, es_link) { 232243308Strociny if (addr < set->es_start) 233243308Strociny return (0); 234243308Strociny if (addr < set->es_stop) { 235243308Strociny *start = set->es_start; 236243308Strociny *base = set->es_base; 237243308Strociny return (1); 238243308Strociny } 239243308Strociny } 240243308Strociny 241243308Strociny return (0); 242243308Strociny} 243243308Strociny 244243308Strocinystatic void 245243308Strocinyelf_set_delete(struct elf_set_head *list, Elf_Addr start) 246243308Strociny{ 247243308Strociny struct elf_set *set; 248243308Strociny 249243308Strociny TAILQ_FOREACH(set, list, es_link) { 250243308Strociny if (start < set->es_start) 251243308Strociny break; 252243308Strociny if (start == set->es_start) { 253243308Strociny TAILQ_REMOVE(list, set, es_link); 254243308Strociny free(set, M_LINKER); 255243308Strociny return; 256243308Strociny } 257243308Strociny } 258243308Strociny KASSERT(0, ("deleting unknown linker set (start = 0x%jx)", 259243308Strociny (uintmax_t)start)); 260243308Strociny} 261243308Strociny 262131928Smarcel#ifdef GDB 263215013Smdfstatic void r_debug_state(struct r_debug *, struct link_map *); 26459603Sdfr 26538514Sdfr/* 26659603Sdfr * A list of loaded modules for GDB to use for loading symbols. 26759603Sdfr */ 26859603Sdfrstruct r_debug r_debug; 26959603Sdfr 270215013Smdf#define GDB_STATE(s) do { \ 271215013Smdf r_debug.r_state = s; r_debug_state(NULL, NULL); \ 272215013Smdf} while (0) 27359603Sdfr 27459603Sdfr/* 27559603Sdfr * Function for the debugger to set a breakpoint on to gain control. 27659603Sdfr */ 277104094Sphkstatic void 27866719Sjhbr_debug_state(struct r_debug *dummy_one __unused, 27966719Sjhb struct link_map *dummy_two __unused) 28059603Sdfr{ 28159603Sdfr} 28259603Sdfr 283105467Smarcelstatic void 284105467Smarcellink_elf_add_gdb(struct link_map *l) 285105467Smarcel{ 286215013Smdf struct link_map *prev; 28759603Sdfr 288215013Smdf l->l_next = NULL; 289105467Smarcel 290215013Smdf if (r_debug.r_map == NULL) { 291215013Smdf /* Add first. */ 292215013Smdf l->l_prev = NULL; 293215013Smdf r_debug.r_map = l; 294215013Smdf } else { 295215013Smdf /* Append to list. */ 296215013Smdf for (prev = r_debug.r_map; 297215013Smdf prev->l_next != NULL; 298215013Smdf prev = prev->l_next) 299215013Smdf ; 300215013Smdf l->l_prev = prev; 301215013Smdf prev->l_next = l; 302215013Smdf } 303105467Smarcel} 304105467Smarcel 305105467Smarcelstatic void 306105467Smarcellink_elf_delete_gdb(struct link_map *l) 307105467Smarcel{ 308215013Smdf if (l->l_prev == NULL) { 309215013Smdf /* Remove first. */ 310215013Smdf if ((r_debug.r_map = l->l_next) != NULL) 311215013Smdf l->l_next->l_prev = NULL; 312215013Smdf } else { 313215013Smdf /* Remove any but first. */ 314215013Smdf if ((l->l_prev->l_next = l->l_next) != NULL) 315215013Smdf l->l_next->l_prev = l->l_prev; 316215013Smdf } 317105467Smarcel} 318131928Smarcel#endif /* GDB */ 319105467Smarcel 32095228Smarcel#ifdef __ia64__ 32195228SmarcelElf_Addr link_elf_get_gp(linker_file_t); 32295228Smarcel#endif 32395228Smarcel 324180438Sobrien/* 325180438Sobrien * The kernel symbol table starts here. 326180438Sobrien */ 327180438Sobrienextern struct _dynamic _DYNAMIC; 328180438Sobrien 32938514Sdfrstatic void 330180374Sedwinlink_elf_error(const char *filename, const char *s) 331105467Smarcel{ 332180374Sedwin if (filename == NULL) 333180374Sedwin printf("kldload: %s\n", s); 334180374Sedwin else 335180374Sedwin printf("kldload: %s: %s\n", filename, s); 336105467Smarcel} 337105467Smarcel 338105468Smarcel/* 339105468Smarcel * Actions performed after linking/loading both the preloaded kernel and any 340105468Smarcel * modules; whether preloaded or dynamicly loaded. 341105468Smarcel */ 342105468Smarcelstatic int 343105468Smarcellink_elf_link_common_finish(linker_file_t lf) 344105468Smarcel{ 345131928Smarcel#ifdef GDB 346215013Smdf elf_file_t ef = (elf_file_t)lf; 347215013Smdf char *newfilename; 348105468Smarcel#endif 349215013Smdf int error; 350105468Smarcel 351215013Smdf /* Notify MD code that a module is being loaded. */ 352215013Smdf error = elf_cpu_load_file(lf); 353215013Smdf if (error != 0) 354215013Smdf return (error); 355105469Smarcel 356131928Smarcel#ifdef GDB 357215013Smdf GDB_STATE(RT_ADD); 358215013Smdf ef->gdb.l_addr = lf->address; 359215013Smdf newfilename = malloc(strlen(lf->filename) + 1, M_LINKER, M_WAITOK); 360215013Smdf strcpy(newfilename, lf->filename); 361215013Smdf ef->gdb.l_name = newfilename; 362215013Smdf ef->gdb.l_ld = ef->dynamic; 363215013Smdf link_elf_add_gdb(&ef->gdb); 364215013Smdf GDB_STATE(RT_CONSISTENT); 365105468Smarcel#endif 366105468Smarcel 367215013Smdf return (0); 368105468Smarcel} 369105468Smarcel 370105467Smarcelstatic void 37138514Sdfrlink_elf_init(void* arg) 37238514Sdfr{ 373215013Smdf Elf_Dyn *dp; 374215013Smdf caddr_t modptr, baseptr, sizeptr; 375215013Smdf elf_file_t ef; 376215013Smdf char *modname; 37738514Sdfr 378215013Smdf linker_add_class(&link_elf_class); 37938514Sdfr 380215013Smdf dp = (Elf_Dyn *)&_DYNAMIC; 381215013Smdf modname = NULL; 382215013Smdf modptr = preload_search_by_type("elf" __XSTRING(__ELF_WORD_SIZE) " kernel"); 383215013Smdf if (modptr == NULL) 384215013Smdf modptr = preload_search_by_type("elf kernel"); 385215013Smdf if (modptr != NULL) 386215013Smdf modname = (char *)preload_search_info(modptr, MODINFO_NAME); 387215013Smdf if (modname == NULL) 388215013Smdf modname = "kernel"; 389215013Smdf linker_kernel_file = linker_make_file(modname, &link_elf_class); 390215013Smdf if (linker_kernel_file == NULL) 391215013Smdf panic("%s: Can't create linker structures for kernel", 392215013Smdf __func__); 393105468Smarcel 394215013Smdf ef = (elf_file_t) linker_kernel_file; 395215013Smdf ef->preloaded = 1; 396215013Smdf ef->address = 0; 39759603Sdfr#ifdef SPARSE_MAPPING 398215013Smdf ef->object = 0; 39959603Sdfr#endif 400215013Smdf ef->dynamic = dp; 40159603Sdfr 402215013Smdf if (dp != NULL) 403215013Smdf parse_dynamic(ef); 404215013Smdf linker_kernel_file->address = (caddr_t) KERNBASE; 405215013Smdf linker_kernel_file->size = -(intptr_t)linker_kernel_file->address; 40640156Speter 407215013Smdf if (modptr != NULL) { 408215013Smdf ef->modptr = modptr; 409215013Smdf baseptr = preload_search_info(modptr, MODINFO_ADDR); 410215013Smdf if (baseptr != NULL) 411215013Smdf linker_kernel_file->address = *(caddr_t *)baseptr; 412215013Smdf sizeptr = preload_search_info(modptr, MODINFO_SIZE); 413215013Smdf if (sizeptr != NULL) 414215013Smdf linker_kernel_file->size = *(size_t *)sizeptr; 415215013Smdf } 416215013Smdf (void)link_elf_preload_parse_symbols(ef); 41759603Sdfr 418131928Smarcel#ifdef GDB 419215013Smdf r_debug.r_map = NULL; 420215013Smdf r_debug.r_brk = r_debug_state; 421215013Smdf r_debug.r_state = RT_CONSISTENT; 422105468Smarcel#endif 42359603Sdfr 424215013Smdf (void)link_elf_link_common_finish(linker_kernel_file); 425215013Smdf linker_kernel_file->flags |= LINKER_FILE_LINKED; 426243308Strociny TAILQ_INIT(&set_pcpu_list); 427243308Strociny#ifdef VIMAGE 428243308Strociny TAILQ_INIT(&set_vnet_list); 429243308Strociny#endif 43038514Sdfr} 43138514Sdfr 432160367SjkimSYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_THIRD, link_elf_init, 0); 43338514Sdfr 43438514Sdfrstatic int 43559751Speterlink_elf_preload_parse_symbols(elf_file_t ef) 43640254Speter{ 437215013Smdf caddr_t pointer; 438215013Smdf caddr_t ssym, esym, base; 439215013Smdf caddr_t strtab; 440215013Smdf int strcnt; 441215013Smdf Elf_Sym *symtab; 442215013Smdf int symcnt; 44340254Speter 444215013Smdf if (ef->modptr == NULL) 445215013Smdf return (0); 446215013Smdf pointer = preload_search_info(ef->modptr, 447215013Smdf MODINFO_METADATA | MODINFOMD_SSYM); 448215013Smdf if (pointer == NULL) 449215013Smdf return (0); 450215013Smdf ssym = *(caddr_t *)pointer; 451215013Smdf pointer = preload_search_info(ef->modptr, 452215013Smdf MODINFO_METADATA | MODINFOMD_ESYM); 453215013Smdf if (pointer == NULL) 454215013Smdf return (0); 455215013Smdf esym = *(caddr_t *)pointer; 45640254Speter 457215013Smdf base = ssym; 45840254Speter 459215013Smdf symcnt = *(long *)base; 460215013Smdf base += sizeof(long); 461215013Smdf symtab = (Elf_Sym *)base; 462215013Smdf base += roundup(symcnt, sizeof(long)); 46340254Speter 464215013Smdf if (base > esym || base < ssym) { 465215013Smdf printf("Symbols are corrupt!\n"); 466215013Smdf return (EINVAL); 467215013Smdf } 46840254Speter 469215013Smdf strcnt = *(long *)base; 470215013Smdf base += sizeof(long); 471215013Smdf strtab = base; 472215013Smdf base += roundup(strcnt, sizeof(long)); 47340254Speter 474215013Smdf if (base > esym || base < ssym) { 475215013Smdf printf("Symbols are corrupt!\n"); 476215013Smdf return (EINVAL); 477215013Smdf } 47840254Speter 479215013Smdf ef->ddbsymtab = symtab; 480215013Smdf ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 481215013Smdf ef->ddbstrtab = strtab; 482215013Smdf ef->ddbstrcnt = strcnt; 48340254Speter 484215013Smdf return (0); 48540254Speter} 48640254Speter 48740254Speterstatic int 48859603Sdfrparse_dynamic(elf_file_t ef) 48938514Sdfr{ 490215013Smdf Elf_Dyn *dp; 491215013Smdf int plttype = DT_REL; 49238514Sdfr 493215013Smdf for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 494215013Smdf switch (dp->d_tag) { 495215013Smdf case DT_HASH: 496215013Smdf { 497215013Smdf /* From src/libexec/rtld-elf/rtld.c */ 498215013Smdf const Elf_Hashelt *hashtab = (const Elf_Hashelt *) 499215013Smdf (ef->address + dp->d_un.d_ptr); 500215013Smdf ef->nbuckets = hashtab[0]; 501215013Smdf ef->nchains = hashtab[1]; 502215013Smdf ef->buckets = hashtab + 2; 503215013Smdf ef->chains = ef->buckets + ef->nbuckets; 504215013Smdf break; 505215013Smdf } 506215013Smdf case DT_STRTAB: 507215013Smdf ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 508215013Smdf break; 509215013Smdf case DT_STRSZ: 510215013Smdf ef->strsz = dp->d_un.d_val; 511215013Smdf break; 512215013Smdf case DT_SYMTAB: 513215013Smdf ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 514215013Smdf break; 515215013Smdf case DT_SYMENT: 516215013Smdf if (dp->d_un.d_val != sizeof(Elf_Sym)) 517215013Smdf return (ENOEXEC); 518215013Smdf break; 519215013Smdf case DT_PLTGOT: 520215013Smdf ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 521215013Smdf break; 522215013Smdf case DT_REL: 523215013Smdf ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 524215013Smdf break; 525215013Smdf case DT_RELSZ: 526215013Smdf ef->relsize = dp->d_un.d_val; 527215013Smdf break; 528215013Smdf case DT_RELENT: 529215013Smdf if (dp->d_un.d_val != sizeof(Elf_Rel)) 530215013Smdf return (ENOEXEC); 531215013Smdf break; 532215013Smdf case DT_JMPREL: 533215013Smdf ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 534215013Smdf break; 535215013Smdf case DT_PLTRELSZ: 536215013Smdf ef->pltrelsize = dp->d_un.d_val; 537215013Smdf break; 538215013Smdf case DT_RELA: 539215013Smdf ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 540215013Smdf break; 541215013Smdf case DT_RELASZ: 542215013Smdf ef->relasize = dp->d_un.d_val; 543215013Smdf break; 544215013Smdf case DT_RELAENT: 545215013Smdf if (dp->d_un.d_val != sizeof(Elf_Rela)) 546215013Smdf return (ENOEXEC); 547215013Smdf break; 548215013Smdf case DT_PLTREL: 549215013Smdf plttype = dp->d_un.d_val; 550215013Smdf if (plttype != DT_REL && plttype != DT_RELA) 551215013Smdf return (ENOEXEC); 552215013Smdf break; 553131928Smarcel#ifdef GDB 554215013Smdf case DT_DEBUG: 555215013Smdf dp->d_un.d_ptr = (Elf_Addr)&r_debug; 556215013Smdf break; 55759603Sdfr#endif 558215013Smdf } 55938514Sdfr } 56039071Sdfr 561215013Smdf if (plttype == DT_RELA) { 562215013Smdf ef->pltrela = (const Elf_Rela *)ef->pltrel; 563215013Smdf ef->pltrel = NULL; 564215013Smdf ef->pltrelasize = ef->pltrelsize; 565215013Smdf ef->pltrelsize = 0; 566215013Smdf } 56739071Sdfr 568215013Smdf ef->ddbsymtab = ef->symtab; 569215013Smdf ef->ddbsymcnt = ef->nchains; 570215013Smdf ef->ddbstrtab = ef->strtab; 571215013Smdf ef->ddbstrcnt = ef->strsz; 57240254Speter 573215013Smdf return (0); 57438514Sdfr} 57538514Sdfr 57638514Sdfrstatic int 577194784Sjeffparse_dpcpu(elf_file_t ef) 578194784Sjeff{ 579215013Smdf int count; 580215013Smdf int error; 581194784Sjeff 582215013Smdf ef->pcpu_start = 0; 583215013Smdf ef->pcpu_stop = 0; 584215013Smdf error = link_elf_lookup_set(&ef->lf, "pcpu", (void ***)&ef->pcpu_start, 585215013Smdf (void ***)&ef->pcpu_stop, &count); 586215013Smdf /* Error just means there is no pcpu set to relocate. */ 587215013Smdf if (error != 0) 588215013Smdf return (0); 589215013Smdf count *= sizeof(void *); 590215013Smdf /* 591215013Smdf * Allocate space in the primary pcpu area. Copy in our 592215013Smdf * initialization from the data section and then initialize 593215013Smdf * all per-cpu storage from that. 594215013Smdf */ 595215013Smdf ef->pcpu_base = (Elf_Addr)(uintptr_t)dpcpu_alloc(count); 596215013Smdf if (ef->pcpu_base == 0) 597215013Smdf return (ENOSPC); 598215013Smdf memcpy((void *)ef->pcpu_base, (void *)ef->pcpu_start, count); 599215013Smdf dpcpu_copy((void *)ef->pcpu_base, count); 600243308Strociny elf_set_add(&set_pcpu_list, ef->pcpu_start, ef->pcpu_stop, 601243308Strociny ef->pcpu_base); 602194784Sjeff 603215013Smdf return (0); 604194784Sjeff} 605194784Sjeff 606195699Srwatson#ifdef VIMAGE 607194784Sjeffstatic int 608195699Srwatsonparse_vnet(elf_file_t ef) 609195699Srwatson{ 610215013Smdf int count; 611215013Smdf int error; 612195699Srwatson 613215013Smdf ef->vnet_start = 0; 614215013Smdf ef->vnet_stop = 0; 615215013Smdf error = link_elf_lookup_set(&ef->lf, "vnet", (void ***)&ef->vnet_start, 616215013Smdf (void ***)&ef->vnet_stop, &count); 617215013Smdf /* Error just means there is no vnet data set to relocate. */ 618215013Smdf if (error != 0) 619215013Smdf return (0); 620215013Smdf count *= sizeof(void *); 621215013Smdf /* 622215013Smdf * Allocate space in the primary vnet area. Copy in our 623215013Smdf * initialization from the data section and then initialize 624215013Smdf * all per-vnet storage from that. 625215013Smdf */ 626215013Smdf ef->vnet_base = (Elf_Addr)(uintptr_t)vnet_data_alloc(count); 627215013Smdf if (ef->vnet_base == 0) 628215013Smdf return (ENOSPC); 629215013Smdf memcpy((void *)ef->vnet_base, (void *)ef->vnet_start, count); 630215013Smdf vnet_data_copy((void *)ef->vnet_base, count); 631243308Strociny elf_set_add(&set_vnet_list, ef->vnet_start, ef->vnet_stop, 632243308Strociny ef->vnet_base); 633195699Srwatson 634215013Smdf return (0); 635195699Srwatson} 636195699Srwatson#endif 637195699Srwatson 638195699Srwatsonstatic int 63959751Speterlink_elf_link_preload(linker_class_t cls, 640215013Smdf const char* filename, linker_file_t *result) 64140156Speter{ 642215013Smdf caddr_t modptr, baseptr, sizeptr, dynptr; 643215013Smdf char *type; 644215013Smdf elf_file_t ef; 645215013Smdf linker_file_t lf; 646215013Smdf int error; 647215013Smdf vm_offset_t dp; 64840156Speter 649215013Smdf /* Look to see if we have the file preloaded */ 650215013Smdf modptr = preload_search_by_name(filename); 651215013Smdf if (modptr == NULL) 652215013Smdf return (ENOENT); 65340156Speter 654215013Smdf type = (char *)preload_search_info(modptr, MODINFO_TYPE); 655215013Smdf baseptr = preload_search_info(modptr, MODINFO_ADDR); 656215013Smdf sizeptr = preload_search_info(modptr, MODINFO_SIZE); 657215013Smdf dynptr = preload_search_info(modptr, 658215013Smdf MODINFO_METADATA | MODINFOMD_DYNAMIC); 659215013Smdf if (type == NULL || 660215013Smdf (strcmp(type, "elf" __XSTRING(__ELF_WORD_SIZE) " module") != 0 && 661215013Smdf strcmp(type, "elf module") != 0)) 662215013Smdf return (EFTYPE); 663215013Smdf if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) 664215013Smdf return (EINVAL); 66540156Speter 666215013Smdf lf = linker_make_file(filename, &link_elf_class); 667215013Smdf if (lf == NULL) 668215013Smdf return (ENOMEM); 66959603Sdfr 670215013Smdf ef = (elf_file_t) lf; 671215013Smdf ef->preloaded = 1; 672215013Smdf ef->modptr = modptr; 673215013Smdf ef->address = *(caddr_t *)baseptr; 67440156Speter#ifdef SPARSE_MAPPING 675215013Smdf ef->object = 0; 67640156Speter#endif 677215013Smdf dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; 678215013Smdf ef->dynamic = (Elf_Dyn *)dp; 679215013Smdf lf->address = ef->address; 680215013Smdf lf->size = *(size_t *)sizeptr; 68140156Speter 682215013Smdf error = parse_dynamic(ef); 683215013Smdf if (error == 0) 684215013Smdf error = parse_dpcpu(ef); 685195699Srwatson#ifdef VIMAGE 686215013Smdf if (error == 0) 687215013Smdf error = parse_vnet(ef); 688195699Srwatson#endif 689215013Smdf if (error != 0) { 690215013Smdf linker_file_unload(lf, LINKER_UNLOAD_FORCE); 691215013Smdf return (error); 692215013Smdf } 693215013Smdf link_elf_reloc_local(lf); 694215013Smdf *result = lf; 695215013Smdf return (0); 69659751Speter} 69759751Speter 69859751Speterstatic int 69959751Speterlink_elf_link_preload_finish(linker_file_t lf) 70059751Speter{ 701215013Smdf elf_file_t ef; 702215013Smdf int error; 70359751Speter 704215013Smdf ef = (elf_file_t) lf; 70559751Speter#if 0 /* this will be more trouble than it's worth for now */ 706215013Smdf for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 707215013Smdf if (dp->d_tag != DT_NEEDED) 708215013Smdf continue; 709215013Smdf modname = ef->strtab + dp->d_un.d_val; 710215013Smdf error = linker_load_module(modname, lf); 711215013Smdf if (error != 0) 712215013Smdf goto out; 71340156Speter } 71459751Speter#endif 715215013Smdf error = relocate_file(ef); 716215013Smdf if (error != 0) 717215013Smdf return (error); 718215013Smdf (void)link_elf_preload_parse_symbols(ef); 71959603Sdfr 720215013Smdf return (link_elf_link_common_finish(lf)); 72140156Speter} 72240156Speter 72340156Speterstatic int 724105468Smarcellink_elf_load_file(linker_class_t cls, const char* filename, 725215013Smdf linker_file_t* result) 72638514Sdfr{ 727215013Smdf struct nameidata nd; 728215013Smdf struct thread* td = curthread; /* XXX */ 729215013Smdf Elf_Ehdr *hdr; 730215013Smdf caddr_t firstpage; 731215013Smdf int nbytes, i; 732215013Smdf Elf_Phdr *phdr; 733215013Smdf Elf_Phdr *phlimit; 734215013Smdf Elf_Phdr *segs[MAXSEGS]; 735215013Smdf int nsegs; 736215013Smdf Elf_Phdr *phdyn; 737215013Smdf Elf_Phdr *phphdr; 738215013Smdf caddr_t mapbase; 739215013Smdf size_t mapsize; 740215013Smdf Elf_Off base_offset; 741215013Smdf Elf_Addr base_vaddr; 742215013Smdf Elf_Addr base_vlimit; 743215013Smdf int error = 0; 744233353Skib ssize_t resid; 745233353Skib int flags; 746215013Smdf elf_file_t ef; 747215013Smdf linker_file_t lf; 748215013Smdf Elf_Shdr *shdr; 749215013Smdf int symtabindex; 750215013Smdf int symstrindex; 751215013Smdf int symcnt; 752215013Smdf int strcnt; 753215013Smdf int vfslocked; 75438514Sdfr 755215013Smdf shdr = NULL; 756215013Smdf lf = NULL; 75740292Speter 758215013Smdf NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, filename, td); 759215013Smdf flags = FREAD; 760215013Smdf error = vn_open(&nd, &flags, 0, NULL); 761215013Smdf if (error != 0) 762215013Smdf return (error); 763215013Smdf vfslocked = NDHASGIANT(&nd); 764215013Smdf NDFREE(&nd, NDF_ONLY_PNBUF); 765215013Smdf if (nd.ni_vp->v_type != VREG) { 766215013Smdf error = ENOEXEC; 767215013Smdf firstpage = NULL; 768215013Smdf goto out; 769215013Smdf } 770107089Srwatson#ifdef MAC 771215013Smdf error = mac_kld_check_load(curthread->td_ucred, nd.ni_vp); 772215013Smdf if (error != 0) { 773215013Smdf firstpage = NULL; 774215013Smdf goto out; 775215013Smdf } 776107089Srwatson#endif 77738514Sdfr 778215013Smdf /* 779215013Smdf * Read the elf header from the file. 780215013Smdf */ 781215013Smdf firstpage = malloc(PAGE_SIZE, M_LINKER, M_WAITOK); 782215013Smdf hdr = (Elf_Ehdr *)firstpage; 783215013Smdf error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0, 784215013Smdf UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 785215013Smdf &resid, td); 786215013Smdf nbytes = PAGE_SIZE - resid; 787215013Smdf if (error != 0) 788215013Smdf goto out; 78938514Sdfr 790215013Smdf if (!IS_ELF(*hdr)) { 791215013Smdf error = ENOEXEC; 792215013Smdf goto out; 793215013Smdf } 79438514Sdfr 795215013Smdf if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 796215013Smdf hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { 797215013Smdf link_elf_error(filename, "Unsupported file layout"); 798215013Smdf error = ENOEXEC; 799215013Smdf goto out; 800215013Smdf } 801215013Smdf if (hdr->e_ident[EI_VERSION] != EV_CURRENT || 802215013Smdf hdr->e_version != EV_CURRENT) { 803215013Smdf link_elf_error(filename, "Unsupported file version"); 804215013Smdf error = ENOEXEC; 805215013Smdf goto out; 806215013Smdf } 807215013Smdf if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { 808215013Smdf error = ENOSYS; 809215013Smdf goto out; 810215013Smdf } 811215013Smdf if (hdr->e_machine != ELF_TARG_MACH) { 812215013Smdf link_elf_error(filename, "Unsupported machine"); 813215013Smdf error = ENOEXEC; 814215013Smdf goto out; 815215013Smdf } 81639071Sdfr 817215013Smdf /* 818215013Smdf * We rely on the program header being in the first page. 819215013Smdf * This is not strictly required by the ABI specification, but 820215013Smdf * it seems to always true in practice. And, it simplifies 821215013Smdf * things considerably. 822215013Smdf */ 823215013Smdf if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) && 824215013Smdf (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) && 825215013Smdf (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes))) 826215013Smdf link_elf_error(filename, "Unreadable program headers"); 82739071Sdfr 828215013Smdf /* 829215013Smdf * Scan the program header entries, and save key information. 830215013Smdf * 831215013Smdf * We rely on there being exactly two load segments, text and data, 832215013Smdf * in that order. 833215013Smdf */ 834215013Smdf phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff); 835215013Smdf phlimit = phdr + hdr->e_phnum; 836215013Smdf nsegs = 0; 837215013Smdf phdyn = NULL; 838215013Smdf phphdr = NULL; 839215013Smdf while (phdr < phlimit) { 840215013Smdf switch (phdr->p_type) { 841215013Smdf case PT_LOAD: 842215013Smdf if (nsegs == MAXSEGS) { 843215013Smdf link_elf_error(filename, "Too many sections"); 844215013Smdf error = ENOEXEC; 845215013Smdf goto out; 846215013Smdf } 847215013Smdf /* 848215013Smdf * XXX: We just trust they come in right order ?? 849215013Smdf */ 850215013Smdf segs[nsegs] = phdr; 851215013Smdf ++nsegs; 852215013Smdf break; 85339071Sdfr 854215013Smdf case PT_PHDR: 855215013Smdf phphdr = phdr; 856215013Smdf break; 85739071Sdfr 858215013Smdf case PT_DYNAMIC: 859215013Smdf phdyn = phdr; 860215013Smdf break; 86139071Sdfr 862215013Smdf case PT_INTERP: 863215013Smdf error = ENOSYS; 864215013Smdf goto out; 865215013Smdf } 86665503Sbp 867215013Smdf ++phdr; 86839071Sdfr } 869215013Smdf if (phdyn == NULL) { 870215013Smdf link_elf_error(filename, "Object is not dynamically-linked"); 871215013Smdf error = ENOEXEC; 872215013Smdf goto out; 873215013Smdf } 874215013Smdf if (nsegs == 0) { 875215013Smdf link_elf_error(filename, "No sections"); 876215013Smdf error = ENOEXEC; 877215013Smdf goto out; 878215013Smdf } 87939071Sdfr 880215013Smdf /* 881215013Smdf * Allocate the entire address space of the object, to stake 882215013Smdf * out our contiguous region, and to establish the base 883215013Smdf * address for relocation. 884215013Smdf */ 885215013Smdf base_offset = trunc_page(segs[0]->p_offset); 886215013Smdf base_vaddr = trunc_page(segs[0]->p_vaddr); 887215013Smdf base_vlimit = round_page(segs[nsegs - 1]->p_vaddr + 888215013Smdf segs[nsegs - 1]->p_memsz); 889215013Smdf mapsize = base_vlimit - base_vaddr; 89038514Sdfr 891215013Smdf lf = linker_make_file(filename, &link_elf_class); 892215013Smdf if (lf == NULL) { 893215013Smdf error = ENOMEM; 894215013Smdf goto out; 895215013Smdf } 89639071Sdfr 897215013Smdf ef = (elf_file_t) lf; 89839071Sdfr#ifdef SPARSE_MAPPING 899215013Smdf ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); 900215013Smdf if (ef->object == NULL) { 901215013Smdf error = ENOMEM; 902215013Smdf goto out; 903215013Smdf } 904215013Smdf ef->address = (caddr_t) vm_map_min(kernel_map); 905215013Smdf error = vm_map_find(kernel_map, ef->object, 0, 906215013Smdf (vm_offset_t *) &ef->address, mapsize, 1, 907215013Smdf VM_PROT_ALL, VM_PROT_ALL, 0); 908215013Smdf if (error != 0) { 909215013Smdf vm_object_deallocate(ef->object); 910215013Smdf ef->object = 0; 911215013Smdf goto out; 912215013Smdf } 91339071Sdfr#else 914215013Smdf ef->address = malloc(mapsize, M_LINKER, M_WAITOK); 91539071Sdfr#endif 916215013Smdf mapbase = ef->address; 91738514Sdfr 918215013Smdf /* 919215013Smdf * Read the text and data sections and zero the bss. 920215013Smdf */ 921215013Smdf for (i = 0; i < nsegs; i++) { 922215013Smdf caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; 923215013Smdf error = vn_rdwr(UIO_READ, nd.ni_vp, 924215013Smdf segbase, segs[i]->p_filesz, segs[i]->p_offset, 925215013Smdf UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 926215013Smdf &resid, td); 927215013Smdf if (error != 0) 928215013Smdf goto out; 929215013Smdf bzero(segbase + segs[i]->p_filesz, 930215013Smdf segs[i]->p_memsz - segs[i]->p_filesz); 931149539Salc 932149539Salc#ifdef SPARSE_MAPPING 933215013Smdf /* 934215013Smdf * Wire down the pages 935215013Smdf */ 936215013Smdf error = vm_map_wire(kernel_map, 937149539Salc (vm_offset_t) segbase, 938149539Salc (vm_offset_t) segbase + segs[i]->p_memsz, 939149539Salc VM_MAP_WIRE_SYSTEM|VM_MAP_WIRE_NOHOLES); 940215013Smdf if (error != KERN_SUCCESS) { 941215013Smdf error = ENOMEM; 942215013Smdf goto out; 943215013Smdf } 944215013Smdf#endif 945149544Salc } 94639071Sdfr 94785734Sgreen#ifdef GPROF 948215013Smdf /* Update profiling information with the new text segment. */ 949215013Smdf mtx_lock(&Giant); 950215013Smdf kmupetext((uintfptr_t)(mapbase + segs[0]->p_vaddr - base_vaddr + 951215013Smdf segs[0]->p_memsz)); 952215013Smdf mtx_unlock(&Giant); 95385734Sgreen#endif 95485734Sgreen 955215013Smdf ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); 95639071Sdfr 957215013Smdf lf->address = ef->address; 958215013Smdf lf->size = mapsize; 95938514Sdfr 960215013Smdf error = parse_dynamic(ef); 961215013Smdf if (error != 0) 962215013Smdf goto out; 963215013Smdf error = parse_dpcpu(ef); 964215013Smdf if (error != 0) 965215013Smdf goto out; 966195699Srwatson#ifdef VIMAGE 967215013Smdf error = parse_vnet(ef); 968215013Smdf if (error != 0) 969215013Smdf goto out; 970195699Srwatson#endif 971215013Smdf link_elf_reloc_local(lf); 972109605Sjake 973215013Smdf VOP_UNLOCK(nd.ni_vp, 0); 974215013Smdf error = linker_load_dependencies(lf); 975215013Smdf vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); 976215013Smdf if (error != 0) 977215013Smdf goto out; 97859751Speter#if 0 /* this will be more trouble than it's worth for now */ 979215013Smdf for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 980215013Smdf if (dp->d_tag != DT_NEEDED) 981215013Smdf continue; 982215013Smdf modname = ef->strtab + dp->d_un.d_val; 983215013Smdf error = linker_load_module(modname, lf); 984215013Smdf if (error != 0) 985215013Smdf goto out; 98659751Speter } 98759751Speter#endif 988215013Smdf error = relocate_file(ef); 989215013Smdf if (error != 0) 990215013Smdf goto out; 99140292Speter 992215013Smdf /* 993215013Smdf * Try and load the symbol table if it's present. (you can 994215013Smdf * strip it!) 995215013Smdf */ 996215013Smdf nbytes = hdr->e_shnum * hdr->e_shentsize; 997215013Smdf if (nbytes == 0 || hdr->e_shoff == 0) 998215013Smdf goto nosyms; 999215013Smdf shdr = malloc(nbytes, M_LINKER, M_WAITOK | M_ZERO); 1000215013Smdf error = vn_rdwr(UIO_READ, nd.ni_vp, 1001215013Smdf (caddr_t)shdr, nbytes, hdr->e_shoff, 1002215013Smdf UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 1003215013Smdf &resid, td); 1004215013Smdf if (error != 0) 1005215013Smdf goto out; 1006215013Smdf symtabindex = -1; 1007215013Smdf symstrindex = -1; 1008215013Smdf for (i = 0; i < hdr->e_shnum; i++) { 1009215013Smdf if (shdr[i].sh_type == SHT_SYMTAB) { 1010215013Smdf symtabindex = i; 1011215013Smdf symstrindex = shdr[i].sh_link; 1012215013Smdf } 1013215013Smdf } 1014215013Smdf if (symtabindex < 0 || symstrindex < 0) 1015215013Smdf goto nosyms; 101640156Speter 1017215013Smdf symcnt = shdr[symtabindex].sh_size; 1018215013Smdf ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK); 1019215013Smdf strcnt = shdr[symstrindex].sh_size; 1020215013Smdf ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK); 102140292Speter 1022215013Smdf error = vn_rdwr(UIO_READ, nd.ni_vp, 1023215013Smdf ef->symbase, symcnt, shdr[symtabindex].sh_offset, 1024215013Smdf UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 1025215013Smdf &resid, td); 1026215013Smdf if (error != 0) 1027215013Smdf goto out; 1028215013Smdf error = vn_rdwr(UIO_READ, nd.ni_vp, 1029215013Smdf ef->strbase, strcnt, shdr[symstrindex].sh_offset, 1030215013Smdf UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 1031215013Smdf &resid, td); 1032215013Smdf if (error != 0) 1033215013Smdf goto out; 103440292Speter 1035215013Smdf ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 1036215013Smdf ef->ddbsymtab = (const Elf_Sym *)ef->symbase; 1037215013Smdf ef->ddbstrcnt = strcnt; 1038215013Smdf ef->ddbstrtab = ef->strbase; 103940292Speter 1040223155Smarcelnosyms: 1041215013Smdf error = link_elf_link_common_finish(lf); 1042215013Smdf if (error != 0) 1043215013Smdf goto out; 104459603Sdfr 1045215013Smdf *result = lf; 104640292Speter 104738514Sdfrout: 1048215013Smdf VOP_UNLOCK(nd.ni_vp, 0); 1049215013Smdf vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 1050215013Smdf VFS_UNLOCK_GIANT(vfslocked); 1051215013Smdf if (error != 0 && lf != NULL) 1052215013Smdf linker_file_unload(lf, LINKER_UNLOAD_FORCE); 1053215013Smdf if (shdr != NULL) 1054215013Smdf free(shdr, M_LINKER); 1055215013Smdf if (firstpage != NULL) 1056215013Smdf free(firstpage, M_LINKER); 105738514Sdfr 1058215013Smdf return (error); 105938514Sdfr} 106038514Sdfr 1061194784SjeffElf_Addr 1062194784Sjeffelf_relocaddr(linker_file_t lf, Elf_Addr x) 1063194784Sjeff{ 1064215013Smdf elf_file_t ef; 1065194784Sjeff 1066215013Smdf ef = (elf_file_t)lf; 1067215013Smdf if (x >= ef->pcpu_start && x < ef->pcpu_stop) 1068215013Smdf return ((x - ef->pcpu_start) + ef->pcpu_base); 1069195699Srwatson#ifdef VIMAGE 1070215013Smdf if (x >= ef->vnet_start && x < ef->vnet_stop) 1071215013Smdf return ((x - ef->vnet_start) + ef->vnet_base); 1072195699Srwatson#endif 1073215013Smdf return (x); 1074194784Sjeff} 1075194784Sjeff 1076194784Sjeff 107738514Sdfrstatic void 107840156Speterlink_elf_unload_file(linker_file_t file) 107938514Sdfr{ 1080215013Smdf elf_file_t ef = (elf_file_t) file; 108138514Sdfr 1082215013Smdf if (ef->pcpu_base != 0) { 1083215013Smdf dpcpu_free((void *)ef->pcpu_base, 1084215013Smdf ef->pcpu_stop - ef->pcpu_start); 1085243308Strociny elf_set_delete(&set_pcpu_list, ef->pcpu_start); 1086215013Smdf } 1087195699Srwatson#ifdef VIMAGE 1088215013Smdf if (ef->vnet_base != 0) { 1089215013Smdf vnet_data_free((void *)ef->vnet_base, 1090215013Smdf ef->vnet_stop - ef->vnet_start); 1091243308Strociny elf_set_delete(&set_vnet_list, ef->vnet_start); 1092215013Smdf } 1093195699Srwatson#endif 1094131928Smarcel#ifdef GDB 1095215013Smdf if (ef->gdb.l_ld != NULL) { 1096215013Smdf GDB_STATE(RT_DELETE); 1097215013Smdf free((void *)(uintptr_t)ef->gdb.l_name, M_LINKER); 1098215013Smdf link_elf_delete_gdb(&ef->gdb); 1099215013Smdf GDB_STATE(RT_CONSISTENT); 1100215013Smdf } 110159603Sdfr#endif 110259603Sdfr 1103215013Smdf /* Notify MD code that a module is being unloaded. */ 1104215013Smdf elf_cpu_unload_file(file); 1105105469Smarcel 1106215013Smdf if (ef->preloaded) { 1107215013Smdf link_elf_unload_preload(file); 1108215013Smdf return; 1109215013Smdf } 1110105468Smarcel 111139071Sdfr#ifdef SPARSE_MAPPING 1112215013Smdf if (ef->object != NULL) { 1113215013Smdf vm_map_remove(kernel_map, (vm_offset_t) ef->address, 1114215013Smdf (vm_offset_t) ef->address 1115215013Smdf + (ef->object->size << PAGE_SHIFT)); 1116215013Smdf } 111739071Sdfr#else 1118215013Smdf if (ef->address != NULL) 1119215013Smdf free(ef->address, M_LINKER); 112039071Sdfr#endif 1121215013Smdf if (ef->symbase != NULL) 1122215013Smdf free(ef->symbase, M_LINKER); 1123215013Smdf if (ef->strbase != NULL) 1124215013Smdf free(ef->strbase, M_LINKER); 1125215013Smdf if (ef->ctftab != NULL) 1126215013Smdf free(ef->ctftab, M_LINKER); 1127215013Smdf if (ef->ctfoff != NULL) 1128215013Smdf free(ef->ctfoff, M_LINKER); 1129215013Smdf if (ef->typoff != NULL) 1130215013Smdf free(ef->typoff, M_LINKER); 113138514Sdfr} 113238514Sdfr 113340156Speterstatic void 113459751Speterlink_elf_unload_preload(linker_file_t file) 113540156Speter{ 1136215013Smdf if (file->filename != NULL) 1137215013Smdf preload_delete_name(file->filename); 113840156Speter} 113940156Speter 114039071Sdfrstatic const char * 1141153504Smarcelsymbol_name(elf_file_t ef, Elf_Size r_info) 114238514Sdfr{ 1143215013Smdf const Elf_Sym *ref; 114438514Sdfr 1145215013Smdf if (ELF_R_SYM(r_info)) { 1146215013Smdf ref = ef->symtab + ELF_R_SYM(r_info); 1147215013Smdf return (ef->strtab + ref->st_name); 1148215013Smdf } 1149215013Smdf return (NULL); 115038514Sdfr} 115138514Sdfr 115238514Sdfrstatic int 115359603Sdfrrelocate_file(elf_file_t ef) 115438514Sdfr{ 1155215013Smdf const Elf_Rel *rellim; 1156215013Smdf const Elf_Rel *rel; 1157215013Smdf const Elf_Rela *relalim; 1158215013Smdf const Elf_Rela *rela; 1159215013Smdf const char *symname; 116038514Sdfr 1161215013Smdf /* Perform relocations without addend if there are any: */ 1162215013Smdf rel = ef->rel; 1163215013Smdf if (rel != NULL) { 1164215013Smdf rellim = (const Elf_Rel *) 1165215013Smdf ((const char *)ef->rel + ef->relsize); 1166215013Smdf while (rel < rellim) { 1167215013Smdf if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel, 1168215013Smdf ELF_RELOC_REL, elf_lookup)) { 1169215013Smdf symname = symbol_name(ef, rel->r_info); 1170215013Smdf printf("link_elf: symbol %s undefined\n", symname); 1171215013Smdf return (ENOENT); 1172215013Smdf } 1173215013Smdf rel++; 1174215013Smdf } 117540435Speter } 117638514Sdfr 1177215013Smdf /* Perform relocations with addend if there are any: */ 1178215013Smdf rela = ef->rela; 1179215013Smdf if (rela != NULL) { 1180215013Smdf relalim = (const Elf_Rela *) 1181215013Smdf ((const char *)ef->rela + ef->relasize); 1182215013Smdf while (rela < relalim) { 1183215013Smdf if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela, 1184215013Smdf ELF_RELOC_RELA, elf_lookup)) { 1185215013Smdf symname = symbol_name(ef, rela->r_info); 1186215013Smdf printf("link_elf: symbol %s undefined\n", 1187215013Smdf symname); 1188215013Smdf return (ENOENT); 1189215013Smdf } 1190215013Smdf rela++; 1191215013Smdf } 119240435Speter } 119338514Sdfr 1194215013Smdf /* Perform PLT relocations without addend if there are any: */ 1195215013Smdf rel = ef->pltrel; 1196215013Smdf if (rel != NULL) { 1197215013Smdf rellim = (const Elf_Rel *) 1198215013Smdf ((const char *)ef->pltrel + ef->pltrelsize); 1199215013Smdf while (rel < rellim) { 1200215013Smdf if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel, 1201215013Smdf ELF_RELOC_REL, elf_lookup)) { 1202215013Smdf symname = symbol_name(ef, rel->r_info); 1203215013Smdf printf("link_elf: symbol %s undefined\n", 1204215013Smdf symname); 1205215013Smdf return (ENOENT); 1206215013Smdf } 1207215013Smdf rel++; 1208215013Smdf } 120940435Speter } 121038514Sdfr 1211215013Smdf /* Perform relocations with addend if there are any: */ 1212215013Smdf rela = ef->pltrela; 1213215013Smdf if (rela != NULL) { 1214215013Smdf relalim = (const Elf_Rela *) 1215215013Smdf ((const char *)ef->pltrela + ef->pltrelasize); 1216215013Smdf while (rela < relalim) { 1217215013Smdf if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela, 1218215013Smdf ELF_RELOC_RELA, elf_lookup)) { 1219215013Smdf symname = symbol_name(ef, rela->r_info); 1220215013Smdf printf("link_elf: symbol %s undefined\n", 1221215013Smdf symname); 1222215013Smdf return (ENOENT); 1223215013Smdf } 1224215013Smdf rela++; 1225215013Smdf } 122640435Speter } 122738514Sdfr 1228215013Smdf return (0); 122938514Sdfr} 123038514Sdfr 123139071Sdfr/* 123239071Sdfr * Hash function for symbol table lookup. Don't even think about changing 123339071Sdfr * this. It is specified by the System V ABI. 123439071Sdfr */ 123539071Sdfrstatic unsigned long 123639071Sdfrelf_hash(const char *name) 123738514Sdfr{ 1238215013Smdf const unsigned char *p = (const unsigned char *) name; 1239215013Smdf unsigned long h = 0; 1240215013Smdf unsigned long g; 124138514Sdfr 1242215013Smdf while (*p != '\0') { 1243215013Smdf h = (h << 4) + *p++; 1244215013Smdf if ((g = h & 0xf0000000) != 0) 1245215013Smdf h ^= g >> 24; 1246215013Smdf h &= ~g; 1247215013Smdf } 1248215013Smdf return (h); 124938514Sdfr} 125038514Sdfr 1251104094Sphkstatic int 125243301Sdillonlink_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym) 125338514Sdfr{ 1254215013Smdf elf_file_t ef = (elf_file_t) lf; 1255215013Smdf unsigned long symnum; 1256215013Smdf const Elf_Sym* symp; 1257215013Smdf const char *strp; 1258215013Smdf unsigned long hash; 1259215013Smdf int i; 126038514Sdfr 1261215013Smdf /* If we don't have a hash, bail. */ 1262215013Smdf if (ef->buckets == NULL || ef->nbuckets == 0) { 1263215013Smdf printf("link_elf_lookup_symbol: missing symbol hash table\n"); 1264215013Smdf return (ENOENT); 1265215013Smdf } 1266151902Sjhb 1267215013Smdf /* First, search hashed global symbols */ 1268215013Smdf hash = elf_hash(name); 1269215013Smdf symnum = ef->buckets[hash % ef->nbuckets]; 127039071Sdfr 1271215013Smdf while (symnum != STN_UNDEF) { 1272215013Smdf if (symnum >= ef->nchains) { 1273215013Smdf printf("%s: corrupt symbol table\n", __func__); 1274215013Smdf return (ENOENT); 1275215013Smdf } 127638514Sdfr 1277215013Smdf symp = ef->symtab + symnum; 1278215013Smdf if (symp->st_name == 0) { 1279215013Smdf printf("%s: corrupt symbol table\n", __func__); 1280215013Smdf return (ENOENT); 1281215013Smdf } 128239071Sdfr 1283215013Smdf strp = ef->strtab + symp->st_name; 128439071Sdfr 1285215013Smdf if (strcmp(name, strp) == 0) { 1286215013Smdf if (symp->st_shndx != SHN_UNDEF || 1287215013Smdf (symp->st_value != 0 && 1288215013Smdf ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 1289215013Smdf *sym = (c_linker_sym_t) symp; 1290215013Smdf return (0); 1291215013Smdf } 1292215013Smdf return (ENOENT); 1293215013Smdf } 1294215013Smdf 1295215013Smdf symnum = ef->chains[symnum]; 129639071Sdfr } 129739071Sdfr 1298215013Smdf /* If we have not found it, look at the full table (if loaded) */ 1299215013Smdf if (ef->symtab == ef->ddbsymtab) 1300215013Smdf return (ENOENT); 130139071Sdfr 1302215013Smdf /* Exhaustive search */ 1303215013Smdf for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 1304215013Smdf strp = ef->ddbstrtab + symp->st_name; 1305215013Smdf if (strcmp(name, strp) == 0) { 1306215013Smdf if (symp->st_shndx != SHN_UNDEF || 1307215013Smdf (symp->st_value != 0 && 1308215013Smdf ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 1309215013Smdf *sym = (c_linker_sym_t) symp; 1310215013Smdf return (0); 1311215013Smdf } 1312215013Smdf return (ENOENT); 1313215013Smdf } 131440254Speter } 131540254Speter 1316215013Smdf return (ENOENT); 131738514Sdfr} 131838514Sdfr 131940156Speterstatic int 1320215013Smdflink_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, 1321215013Smdf linker_symval_t *symval) 132238514Sdfr{ 132359603Sdfr elf_file_t ef = (elf_file_t) lf; 132443311Sdillon const Elf_Sym* es = (const Elf_Sym*) sym; 132538514Sdfr 1326102348Smarcel if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) { 1327215013Smdf symval->name = ef->strtab + es->st_name; 1328215013Smdf symval->value = (caddr_t) ef->address + es->st_value; 1329215013Smdf symval->size = es->st_size; 1330215013Smdf return (0); 133140254Speter } 133240254Speter if (ef->symtab == ef->ddbsymtab) 1333215013Smdf return (ENOENT); 1334102348Smarcel if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) { 1335215013Smdf symval->name = ef->ddbstrtab + es->st_name; 1336215013Smdf symval->value = (caddr_t) ef->address + es->st_value; 1337215013Smdf symval->size = es->st_size; 1338215013Smdf return (0); 133940254Speter } 1340215013Smdf return (ENOENT); 134138514Sdfr} 134238514Sdfr 134338514Sdfrstatic int 134438514Sdfrlink_elf_search_symbol(linker_file_t lf, caddr_t value, 1345215013Smdf c_linker_sym_t *sym, long *diffp) 134638514Sdfr{ 134759603Sdfr elf_file_t ef = (elf_file_t) lf; 134855090Sbde u_long off = (uintptr_t) (void *) value; 134938514Sdfr u_long diff = off; 135055090Sbde u_long st_value; 135139071Sdfr const Elf_Sym* es; 135239071Sdfr const Elf_Sym* best = 0; 135338514Sdfr int i; 135438514Sdfr 135540254Speter for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { 135638514Sdfr if (es->st_name == 0) 135738514Sdfr continue; 135855090Sbde st_value = es->st_value + (uintptr_t) (void *) ef->address; 135953820Speter if (off >= st_value) { 136053820Speter if (off - st_value < diff) { 136153820Speter diff = off - st_value; 136238514Sdfr best = es; 136338514Sdfr if (diff == 0) 136438514Sdfr break; 136553820Speter } else if (off - st_value == diff) { 136638514Sdfr best = es; 136738514Sdfr } 136838514Sdfr } 136938514Sdfr } 137038514Sdfr if (best == 0) 137138514Sdfr *diffp = off; 137238514Sdfr else 137338514Sdfr *diffp = diff; 137443301Sdillon *sym = (c_linker_sym_t) best; 137538514Sdfr 1376215013Smdf return (0); 137738514Sdfr} 137878161Speter 137978161Speter/* 138078161Speter * Look up a linker set on an ELF system. 138178161Speter */ 138278161Speterstatic int 138378161Speterlink_elf_lookup_set(linker_file_t lf, const char *name, 1384215013Smdf void ***startp, void ***stopp, int *countp) 138578161Speter{ 138678161Speter c_linker_sym_t sym; 138778161Speter linker_symval_t symval; 138878161Speter char *setsym; 138978161Speter void **start, **stop; 139078161Speter int len, error = 0, count; 139178161Speter 139278161Speter len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */ 1393111119Simp setsym = malloc(len, M_LINKER, M_WAITOK); 139478161Speter 139578161Speter /* get address of first entry */ 139678161Speter snprintf(setsym, len, "%s%s", "__start_set_", name); 139778161Speter error = link_elf_lookup_symbol(lf, setsym, &sym); 1398215013Smdf if (error != 0) 139978161Speter goto out; 140078161Speter link_elf_symbol_values(lf, sym, &symval); 140178161Speter if (symval.value == 0) { 140278161Speter error = ESRCH; 140378161Speter goto out; 140478161Speter } 140578161Speter start = (void **)symval.value; 140678161Speter 140778161Speter /* get address of last entry */ 140878161Speter snprintf(setsym, len, "%s%s", "__stop_set_", name); 140978161Speter error = link_elf_lookup_symbol(lf, setsym, &sym); 1410215013Smdf if (error != 0) 141178161Speter goto out; 141278161Speter link_elf_symbol_values(lf, sym, &symval); 141378161Speter if (symval.value == 0) { 141478161Speter error = ESRCH; 141578161Speter goto out; 141678161Speter } 141778161Speter stop = (void **)symval.value; 141878161Speter 141978161Speter /* and the number of entries */ 142078161Speter count = stop - start; 142178161Speter 142278161Speter /* and copy out */ 1423215013Smdf if (startp != NULL) 142478161Speter *startp = start; 1425215013Smdf if (stopp != NULL) 142678161Speter *stopp = stop; 1427215013Smdf if (countp != NULL) 142878161Speter *countp = count; 142978161Speter 143078161Speterout: 143178161Speter free(setsym, M_LINKER); 1432215013Smdf return (error); 143378161Speter} 143485736Sgreen 143585736Sgreenstatic int 143685736Sgreenlink_elf_each_function_name(linker_file_t file, 1437215013Smdf int (*callback)(const char *, void *), void *opaque) 1438215013Smdf{ 1439215013Smdf elf_file_t ef = (elf_file_t)file; 1440215013Smdf const Elf_Sym *symp; 1441215013Smdf int i, error; 144285736Sgreen 1443215013Smdf /* Exhaustive search */ 1444215013Smdf for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 1445215013Smdf if (symp->st_value != 0 && 1446215013Smdf ELF_ST_TYPE(symp->st_info) == STT_FUNC) { 1447215013Smdf error = callback(ef->ddbstrtab + symp->st_name, opaque); 1448215013Smdf if (error != 0) 1449215013Smdf return (error); 1450215013Smdf } 145185736Sgreen } 1452215013Smdf return (0); 145385736Sgreen} 145495228Smarcel 1455179223Sjbstatic int 1456179223Sjblink_elf_each_function_nameval(linker_file_t file, 1457179223Sjb linker_function_nameval_callback_t callback, void *opaque) 1458179223Sjb{ 1459179223Sjb linker_symval_t symval; 1460179223Sjb elf_file_t ef = (elf_file_t)file; 1461179223Sjb const Elf_Sym* symp; 1462179223Sjb int i, error; 1463179223Sjb 1464179223Sjb /* Exhaustive search */ 1465179223Sjb for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 1466179223Sjb if (symp->st_value != 0 && 1467179223Sjb ELF_ST_TYPE(symp->st_info) == STT_FUNC) { 1468215013Smdf error = link_elf_symbol_values(file, 1469215013Smdf (c_linker_sym_t) symp, &symval); 1470215013Smdf if (error != 0) 1471179223Sjb return (error); 1472179223Sjb error = callback(file, i, &symval, opaque); 1473215013Smdf if (error != 0) 1474179223Sjb return (error); 1475179223Sjb } 1476179223Sjb } 1477179223Sjb return (0); 1478179223Sjb} 1479179223Sjb 148095228Smarcel#ifdef __ia64__ 148195228Smarcel/* 148295228Smarcel * Each KLD has its own GP. The GP value for each load module is given by 148395228Smarcel * DT_PLTGOT on ia64. We need GP to construct function descriptors, but 148495228Smarcel * don't have direct access to the ELF file structure. The link_elf_get_gp() 148595228Smarcel * function returns the GP given a pointer to a generic linker file struct. 148695228Smarcel */ 148795228SmarcelElf_Addr 148895228Smarcellink_elf_get_gp(linker_file_t lf) 148995228Smarcel{ 149095228Smarcel elf_file_t ef = (elf_file_t)lf; 1491215013Smdf return ((Elf_Addr)ef->got); 149295228Smarcel} 149395228Smarcel#endif 149495410Smarcel 1495104072Sjakeconst Elf_Sym * 1496153504Smarcelelf_get_sym(linker_file_t lf, Elf_Size symidx) 1497104072Sjake{ 1498104072Sjake elf_file_t ef = (elf_file_t)lf; 1499104072Sjake 1500104072Sjake if (symidx >= ef->nchains) 1501104072Sjake return (NULL); 1502104072Sjake return (ef->symtab + symidx); 1503104072Sjake} 1504104072Sjake 1505105147Smarcelconst char * 1506153504Smarcelelf_get_symname(linker_file_t lf, Elf_Size symidx) 1507105147Smarcel{ 1508105147Smarcel elf_file_t ef = (elf_file_t)lf; 1509105147Smarcel const Elf_Sym *sym; 1510105147Smarcel 1511105147Smarcel if (symidx >= ef->nchains) 1512105147Smarcel return (NULL); 1513105147Smarcel sym = ef->symtab + symidx; 1514105147Smarcel return (ef->strtab + sym->st_name); 1515105147Smarcel} 1516105147Smarcel 151795410Smarcel/* 151895410Smarcel * Symbol lookup function that can be used when the symbol index is known (ie 151995410Smarcel * in relocations). It uses the symbol index instead of doing a fully fledged 152095410Smarcel * hash table based lookup when such is valid. For example for local symbols. 152195410Smarcel * This is not only more efficient, it's also more correct. It's not always 152295410Smarcel * the case that the symbol can be found through the hash table. 152395410Smarcel */ 1524129282Speterstatic Elf_Addr 1525153504Smarcelelf_lookup(linker_file_t lf, Elf_Size symidx, int deps) 152695410Smarcel{ 152795410Smarcel elf_file_t ef = (elf_file_t)lf; 152895410Smarcel const Elf_Sym *sym; 152995410Smarcel const char *symbol; 1530243308Strociny Elf_Addr addr, start, base; 153195410Smarcel 153295410Smarcel /* Don't even try to lookup the symbol if the index is bogus. */ 153395410Smarcel if (symidx >= ef->nchains) 153495410Smarcel return (0); 153595410Smarcel 153695410Smarcel sym = ef->symtab + symidx; 153795410Smarcel 153895410Smarcel /* 153995410Smarcel * Don't do a full lookup when the symbol is local. It may even 154095410Smarcel * fail because it may not be found through the hash table. 154195410Smarcel */ 154295410Smarcel if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 154395410Smarcel /* Force lookup failure when we have an insanity. */ 154495410Smarcel if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0) 154595410Smarcel return (0); 154695410Smarcel return ((Elf_Addr)ef->address + sym->st_value); 154795410Smarcel } 154895410Smarcel 154995410Smarcel /* 155095410Smarcel * XXX we can avoid doing a hash table based lookup for global 155195410Smarcel * symbols as well. This however is not always valid, so we'll 155295410Smarcel * just do it the hard way for now. Performance tweaks can 155395410Smarcel * always be added. 155495410Smarcel */ 155595410Smarcel 155695410Smarcel symbol = ef->strtab + sym->st_name; 155795410Smarcel 155895410Smarcel /* Force a lookup failure if the symbol name is bogus. */ 155995410Smarcel if (*symbol == 0) 156095410Smarcel return (0); 156195410Smarcel 1562243308Strociny addr = ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps)); 1563243308Strociny 1564243308Strociny if (elf_set_find(&set_pcpu_list, addr, &start, &base)) 1565243308Strociny addr = addr - start + base; 1566243308Strociny#ifdef VIMAGE 1567243308Strociny else if (elf_set_find(&set_vnet_list, addr, &start, &base)) 1568243308Strociny addr = addr - start + base; 1569243308Strociny#endif 1570243308Strociny return addr; 157195410Smarcel} 1572109605Sjake 1573109605Sjakestatic void 1574109605Sjakelink_elf_reloc_local(linker_file_t lf) 1575109605Sjake{ 1576215013Smdf const Elf_Rel *rellim; 1577215013Smdf const Elf_Rel *rel; 1578215013Smdf const Elf_Rela *relalim; 1579215013Smdf const Elf_Rela *rela; 1580215013Smdf elf_file_t ef = (elf_file_t)lf; 1581109605Sjake 1582215013Smdf /* Perform relocations without addend if there are any: */ 1583215013Smdf if ((rel = ef->rel) != NULL) { 1584215013Smdf rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize); 1585215013Smdf while (rel < rellim) { 1586215013Smdf elf_reloc_local(lf, (Elf_Addr)ef->address, rel, 1587215013Smdf ELF_RELOC_REL, elf_lookup); 1588215013Smdf rel++; 1589215013Smdf } 1590109605Sjake } 1591109605Sjake 1592215013Smdf /* Perform relocations with addend if there are any: */ 1593215013Smdf if ((rela = ef->rela) != NULL) { 1594215013Smdf relalim = (const Elf_Rela *) 1595215013Smdf ((const char *)ef->rela + ef->relasize); 1596215013Smdf while (rela < relalim) { 1597215013Smdf elf_reloc_local(lf, (Elf_Addr)ef->address, rela, 1598215013Smdf ELF_RELOC_RELA, elf_lookup); 1599215013Smdf rela++; 1600215013Smdf } 1601109605Sjake } 1602109605Sjake} 1603192859Ssson 1604192859Sssonstatic long 1605192859Sssonlink_elf_symtab_get(linker_file_t lf, const Elf_Sym **symtab) 1606192859Ssson{ 1607215013Smdf elf_file_t ef = (elf_file_t)lf; 1608192859Ssson 1609215013Smdf *symtab = ef->ddbsymtab; 1610215013Smdf 1611215013Smdf if (*symtab == NULL) 1612215013Smdf return (0); 1613215013Smdf 1614215013Smdf return (ef->ddbsymcnt); 1615192859Ssson} 1616192859Ssson 1617192859Sssonstatic long 1618192859Sssonlink_elf_strtab_get(linker_file_t lf, caddr_t *strtab) 1619192859Ssson{ 1620215013Smdf elf_file_t ef = (elf_file_t)lf; 1621192859Ssson 1622215013Smdf *strtab = ef->ddbstrtab; 1623192859Ssson 1624215013Smdf if (*strtab == NULL) 1625215013Smdf return (0); 1626192859Ssson 1627215013Smdf return (ef->ddbstrcnt); 1628192859Ssson} 1629