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 * 26fe3db7c7SDoug Rabson * $Id: link_elf.c,v 1.1 1998/08/24 08:25:26 dfr 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 50fe3db7c7SDoug Rabson extern int elf_reloc(linker_file_t lf, const Elf_Rela *rela, 51fe3db7c7SDoug Rabson const char *sym); 52fe3db7c7SDoug Rabson 53a4f67738SDoug Rabson static int link_elf_load_file(const char*, linker_file_t*); 54a4f67738SDoug Rabson static int link_elf_lookup_symbol(linker_file_t, const char*, 55a4f67738SDoug Rabson linker_sym_t*); 56a4f67738SDoug Rabson static void link_elf_symbol_values(linker_file_t, linker_sym_t, linker_symval_t*); 57a4f67738SDoug Rabson static int link_elf_search_symbol(linker_file_t, caddr_t value, 58a4f67738SDoug Rabson linker_sym_t* sym, long* diffp); 59a4f67738SDoug Rabson 60a4f67738SDoug Rabson static void link_elf_unload(linker_file_t); 61a4f67738SDoug Rabson 62a4f67738SDoug Rabson /* 63a4f67738SDoug Rabson * The file representing the currently running kernel. This contains 64a4f67738SDoug Rabson * the global symbol table. 65a4f67738SDoug Rabson */ 66a4f67738SDoug Rabson 67a4f67738SDoug Rabson linker_file_t linker_kernel_file; 68a4f67738SDoug Rabson 69a4f67738SDoug Rabson static struct linker_class_ops link_elf_class_ops = { 70a4f67738SDoug Rabson link_elf_load_file, 71a4f67738SDoug Rabson }; 72a4f67738SDoug Rabson 73a4f67738SDoug Rabson static struct linker_file_ops link_elf_file_ops = { 74a4f67738SDoug Rabson link_elf_lookup_symbol, 75a4f67738SDoug Rabson link_elf_symbol_values, 76a4f67738SDoug Rabson link_elf_search_symbol, 77a4f67738SDoug Rabson link_elf_unload, 78a4f67738SDoug Rabson }; 79a4f67738SDoug Rabson 80a4f67738SDoug Rabson typedef struct elf_file { 81fe3db7c7SDoug Rabson caddr_t address; /* Relocation address */ 82fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 83fe3db7c7SDoug Rabson vm_object_t object; /* VM object to hold file pages */ 84fe3db7c7SDoug Rabson #endif 85fe3db7c7SDoug Rabson const Elf_Dyn* dynamic; /* Symbol table etc. */ 86a4f67738SDoug Rabson Elf_Off nbuckets; /* DT_HASH info */ 87a4f67738SDoug Rabson Elf_Off nchains; 88a4f67738SDoug Rabson const Elf_Off* buckets; 89a4f67738SDoug Rabson const Elf_Off* chains; 90a4f67738SDoug Rabson caddr_t hash; 91a4f67738SDoug Rabson caddr_t strtab; /* DT_STRTAB */ 92fe3db7c7SDoug Rabson const Elf_Sym* symtab; /* DT_SYMTAB */ 93fe3db7c7SDoug Rabson Elf_Addr* got; /* DT_PLTGOT */ 94fe3db7c7SDoug Rabson const Elf_Rel* pltrel; /* DT_JMPREL */ 95fe3db7c7SDoug Rabson int pltrelsize; /* DT_PLTRELSZ */ 96fe3db7c7SDoug Rabson const Elf_Rela* pltrela; /* DT_JMPREL */ 97fe3db7c7SDoug Rabson int pltrelasize; /* DT_PLTRELSZ */ 98fe3db7c7SDoug Rabson const Elf_Rel* rel; /* DT_REL */ 99fe3db7c7SDoug Rabson int relsize; /* DT_RELSZ */ 100fe3db7c7SDoug Rabson const Elf_Rela* rela; /* DT_RELA */ 101fe3db7c7SDoug Rabson int relasize; /* DT_RELASZ */ 102a4f67738SDoug Rabson } *elf_file_t; 103a4f67738SDoug Rabson 104a4f67738SDoug Rabson static int parse_dynamic(linker_file_t lf); 105a4f67738SDoug Rabson static int load_dependancies(linker_file_t lf); 106a4f67738SDoug Rabson static int relocate_file(linker_file_t lf); 107a4f67738SDoug Rabson 108a4f67738SDoug Rabson /* 109a4f67738SDoug Rabson * The kernel symbol table starts here. 110a4f67738SDoug Rabson */ 111a4f67738SDoug Rabson extern struct _dynamic _DYNAMIC; 112a4f67738SDoug Rabson 113a4f67738SDoug Rabson static void 114a4f67738SDoug Rabson link_elf_init(void* arg) 115a4f67738SDoug Rabson { 116a4f67738SDoug Rabson Elf_Dyn* dp = (Elf_Dyn*) &_DYNAMIC; 117a4f67738SDoug Rabson 118a4f67738SDoug Rabson #if ELF_TARG_CLASS == ELFCLASS32 119a4f67738SDoug Rabson linker_add_class("elf32", NULL, &link_elf_class_ops); 120a4f67738SDoug Rabson #else 121a4f67738SDoug Rabson linker_add_class("elf64", NULL, &link_elf_class_ops); 122a4f67738SDoug Rabson #endif 123a4f67738SDoug Rabson 124a4f67738SDoug Rabson if (dp) { 125a4f67738SDoug Rabson elf_file_t ef; 126a4f67738SDoug Rabson 127a4f67738SDoug Rabson ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT); 128a4f67738SDoug Rabson if (ef == NULL) 129a4f67738SDoug Rabson panic("link_elf_init: Can't create linker structures for kernel"); 130a4f67738SDoug Rabson 131a4f67738SDoug Rabson ef->address = 0; 132fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 133fe3db7c7SDoug Rabson ef->object = 0; 134fe3db7c7SDoug Rabson #endif 135a4f67738SDoug Rabson ef->dynamic = dp; 136a4f67738SDoug Rabson linker_kernel_file = 137a4f67738SDoug Rabson linker_make_file(kernelname, ef, &link_elf_file_ops); 138a4f67738SDoug Rabson if (linker_kernel_file == NULL) 139a4f67738SDoug Rabson panic("link_elf_init: Can't create linker structures for kernel"); 140a4f67738SDoug Rabson parse_dynamic(linker_kernel_file); 141a4f67738SDoug Rabson /* 142a4f67738SDoug Rabson * XXX there must be a better way of getting these constants. 143a4f67738SDoug Rabson */ 144a4f67738SDoug Rabson #ifdef __alpha__ 145a4f67738SDoug Rabson linker_kernel_file->address = (caddr_t) 0xfffffc0000300000; 146a4f67738SDoug Rabson #else 147a4f67738SDoug Rabson linker_kernel_file->address = (caddr_t) 0xf0100000; 148a4f67738SDoug Rabson #endif 149a4f67738SDoug Rabson linker_kernel_file->size = -(long)linker_kernel_file->address; 150a4f67738SDoug Rabson linker_current_file = linker_kernel_file; 151a4f67738SDoug Rabson } 152a4f67738SDoug Rabson } 153a4f67738SDoug Rabson 154a4f67738SDoug Rabson SYSINIT(link_elf, SI_SUB_KMEM, SI_ORDER_THIRD, link_elf_init, 0); 155a4f67738SDoug Rabson 156a4f67738SDoug Rabson static int 157a4f67738SDoug Rabson parse_dynamic(linker_file_t lf) 158a4f67738SDoug Rabson { 159a4f67738SDoug Rabson elf_file_t ef = lf->priv; 160fe3db7c7SDoug Rabson const Elf_Dyn *dp; 161fe3db7c7SDoug Rabson int plttype = DT_REL; 162a4f67738SDoug Rabson 163a4f67738SDoug Rabson for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 164a4f67738SDoug Rabson switch (dp->d_tag) { 165a4f67738SDoug Rabson case DT_HASH: 166a4f67738SDoug Rabson { 167a4f67738SDoug Rabson /* From src/libexec/rtld-elf/rtld.c */ 168a4f67738SDoug Rabson const Elf_Off *hashtab = (const Elf_Off *) 169a4f67738SDoug Rabson (ef->address + dp->d_un.d_ptr); 170a4f67738SDoug Rabson ef->nbuckets = hashtab[0]; 171a4f67738SDoug Rabson ef->nchains = hashtab[1]; 172a4f67738SDoug Rabson ef->buckets = hashtab + 2; 173a4f67738SDoug Rabson ef->chains = ef->buckets + ef->nbuckets; 174a4f67738SDoug Rabson break; 175a4f67738SDoug Rabson } 176a4f67738SDoug Rabson case DT_STRTAB: 177fe3db7c7SDoug Rabson ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 178a4f67738SDoug Rabson break; 179a4f67738SDoug Rabson case DT_SYMTAB: 180fe3db7c7SDoug Rabson ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 181a4f67738SDoug Rabson break; 182a4f67738SDoug Rabson case DT_SYMENT: 183a4f67738SDoug Rabson if (dp->d_un.d_val != sizeof(Elf_Sym)) 184a4f67738SDoug Rabson return ENOEXEC; 185fe3db7c7SDoug Rabson break; 186fe3db7c7SDoug Rabson case DT_PLTGOT: 187fe3db7c7SDoug Rabson ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 188fe3db7c7SDoug Rabson break; 189fe3db7c7SDoug Rabson case DT_REL: 190fe3db7c7SDoug Rabson ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 191fe3db7c7SDoug Rabson break; 192fe3db7c7SDoug Rabson case DT_RELSZ: 193fe3db7c7SDoug Rabson ef->relsize = dp->d_un.d_val; 194fe3db7c7SDoug Rabson break; 195fe3db7c7SDoug Rabson case DT_RELENT: 196fe3db7c7SDoug Rabson if (dp->d_un.d_val != sizeof(Elf_Rel)) 197fe3db7c7SDoug Rabson return ENOEXEC; 198fe3db7c7SDoug Rabson break; 199fe3db7c7SDoug Rabson case DT_JMPREL: 200fe3db7c7SDoug Rabson ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 201fe3db7c7SDoug Rabson break; 202fe3db7c7SDoug Rabson case DT_PLTRELSZ: 203fe3db7c7SDoug Rabson ef->pltrelsize = dp->d_un.d_val; 204fe3db7c7SDoug Rabson break; 205fe3db7c7SDoug Rabson case DT_RELA: 206fe3db7c7SDoug Rabson ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 207fe3db7c7SDoug Rabson break; 208fe3db7c7SDoug Rabson case DT_RELASZ: 209fe3db7c7SDoug Rabson ef->relasize = dp->d_un.d_val; 210fe3db7c7SDoug Rabson break; 211fe3db7c7SDoug Rabson case DT_RELAENT: 212fe3db7c7SDoug Rabson if (dp->d_un.d_val != sizeof(Elf_Rela)) 213fe3db7c7SDoug Rabson return ENOEXEC; 214fe3db7c7SDoug Rabson break; 215fe3db7c7SDoug Rabson case DT_PLTREL: 216fe3db7c7SDoug Rabson plttype = dp->d_un.d_val; 217fe3db7c7SDoug Rabson if (plttype != DT_REL && plttype != DT_RELA) 218fe3db7c7SDoug Rabson return ENOEXEC; 219fe3db7c7SDoug Rabson break; 220a4f67738SDoug Rabson } 221a4f67738SDoug Rabson } 222fe3db7c7SDoug Rabson 223fe3db7c7SDoug Rabson if (plttype == DT_RELA) { 224fe3db7c7SDoug Rabson ef->pltrela = (const Elf_Rela *) ef->pltrel; 225fe3db7c7SDoug Rabson ef->pltrel = NULL; 226fe3db7c7SDoug Rabson ef->pltrelasize = ef->pltrelsize; 227fe3db7c7SDoug Rabson ef->pltrelsize = 0; 228fe3db7c7SDoug Rabson } 229fe3db7c7SDoug Rabson 230a4f67738SDoug Rabson return 0; 231a4f67738SDoug Rabson } 232a4f67738SDoug Rabson 233fe3db7c7SDoug Rabson static void 234fe3db7c7SDoug Rabson link_elf_error(const char *s) 235fe3db7c7SDoug Rabson { 236fe3db7c7SDoug Rabson printf("kldload: %s\n", s); 237fe3db7c7SDoug Rabson } 238fe3db7c7SDoug Rabson 239a4f67738SDoug Rabson static int 240a4f67738SDoug Rabson link_elf_load_file(const char* filename, linker_file_t* result) 241a4f67738SDoug Rabson { 242a4f67738SDoug Rabson struct nameidata nd; 243a4f67738SDoug Rabson struct proc* p = curproc; /* XXX */ 244fe3db7c7SDoug Rabson union { 245fe3db7c7SDoug Rabson Elf_Ehdr hdr; 246fe3db7c7SDoug Rabson char buf[PAGE_SIZE]; 247fe3db7c7SDoug Rabson } u; 248fe3db7c7SDoug Rabson int nbytes, i; 249fe3db7c7SDoug Rabson Elf_Phdr *phdr; 250fe3db7c7SDoug Rabson Elf_Phdr *phlimit; 251fe3db7c7SDoug Rabson Elf_Phdr *segs[2]; 252fe3db7c7SDoug Rabson int nsegs; 253fe3db7c7SDoug Rabson Elf_Phdr *phdyn; 254fe3db7c7SDoug Rabson Elf_Phdr *phphdr; 255fe3db7c7SDoug Rabson caddr_t mapbase; 256fe3db7c7SDoug Rabson size_t mapsize; 257fe3db7c7SDoug Rabson Elf_Off base_offset; 258fe3db7c7SDoug Rabson Elf_Addr base_vaddr; 259fe3db7c7SDoug Rabson Elf_Addr base_vlimit; 260fe3db7c7SDoug Rabson caddr_t base_addr; 261fe3db7c7SDoug Rabson Elf_Off data_offset; 262fe3db7c7SDoug Rabson Elf_Addr data_vaddr; 263fe3db7c7SDoug Rabson Elf_Addr data_vlimit; 264fe3db7c7SDoug Rabson caddr_t data_addr; 265fe3db7c7SDoug Rabson Elf_Addr clear_vaddr; 266fe3db7c7SDoug Rabson caddr_t clear_addr; 267fe3db7c7SDoug Rabson size_t nclear; 268fe3db7c7SDoug Rabson Elf_Addr bss_vaddr; 269fe3db7c7SDoug Rabson Elf_Addr bss_vlimit; 270fe3db7c7SDoug Rabson caddr_t bss_addr; 271a4f67738SDoug Rabson int error = 0; 272a4f67738SDoug Rabson int resid; 273a4f67738SDoug Rabson elf_file_t ef; 274a4f67738SDoug Rabson linker_file_t lf; 275a4f67738SDoug Rabson 276a4f67738SDoug Rabson NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); 277a4f67738SDoug Rabson error = vn_open(&nd, FREAD, 0); 278a4f67738SDoug Rabson if (error) 279a4f67738SDoug Rabson return error; 280a4f67738SDoug Rabson 281a4f67738SDoug Rabson /* 282fe3db7c7SDoug Rabson * Read the elf header from the file. 283a4f67738SDoug Rabson */ 284fe3db7c7SDoug Rabson error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &u, sizeof u, 0, 285a4f67738SDoug Rabson UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 286fe3db7c7SDoug Rabson nbytes = sizeof u - resid; 287a4f67738SDoug Rabson if (error) 288a4f67738SDoug Rabson goto out; 289a4f67738SDoug Rabson 290fe3db7c7SDoug Rabson if (!IS_ELF(u.hdr)) { 291fe3db7c7SDoug Rabson error = ENOEXEC; 292a4f67738SDoug Rabson goto out; 293fe3db7c7SDoug Rabson } 294fe3db7c7SDoug Rabson 295fe3db7c7SDoug Rabson if (u.hdr.e_ident[EI_CLASS] != ELF_TARG_CLASS 296fe3db7c7SDoug Rabson || u.hdr.e_ident[EI_DATA] != ELF_TARG_DATA) { 297fe3db7c7SDoug Rabson link_elf_error("Unsupported file layout"); 298fe3db7c7SDoug Rabson error = ENOEXEC; 299fe3db7c7SDoug Rabson goto out; 300fe3db7c7SDoug Rabson } 301fe3db7c7SDoug Rabson if (u.hdr.e_ident[EI_VERSION] != EV_CURRENT 302fe3db7c7SDoug Rabson || u.hdr.e_version != EV_CURRENT) { 303fe3db7c7SDoug Rabson link_elf_error("Unsupported file version"); 304fe3db7c7SDoug Rabson error = ENOEXEC; 305fe3db7c7SDoug Rabson goto out; 306fe3db7c7SDoug Rabson } 307fe3db7c7SDoug Rabson if (u.hdr.e_type != ET_EXEC && u.hdr.e_type != ET_DYN) { 308fe3db7c7SDoug Rabson link_elf_error("Unsupported file type"); 309fe3db7c7SDoug Rabson error = ENOEXEC; 310fe3db7c7SDoug Rabson goto out; 311fe3db7c7SDoug Rabson } 312fe3db7c7SDoug Rabson if (u.hdr.e_machine != ELF_TARG_MACH) { 313fe3db7c7SDoug Rabson link_elf_error("Unsupported machine"); 314fe3db7c7SDoug Rabson error = ENOEXEC; 315fe3db7c7SDoug Rabson goto out; 316fe3db7c7SDoug Rabson } 317fe3db7c7SDoug Rabson if (!ELF_MACHINE_OK(u.hdr.e_machine)) { 318fe3db7c7SDoug Rabson link_elf_error("Incompatibile elf machine type"); 319fe3db7c7SDoug Rabson error = ENOEXEC; 320fe3db7c7SDoug Rabson goto out; 321fe3db7c7SDoug Rabson } 322a4f67738SDoug Rabson 323a4f67738SDoug Rabson /* 324fe3db7c7SDoug Rabson * We rely on the program header being in the first page. This is 325fe3db7c7SDoug Rabson * not strictly required by the ABI specification, but it seems to 326fe3db7c7SDoug Rabson * always true in practice. And, it simplifies things considerably. 327a4f67738SDoug Rabson */ 328fe3db7c7SDoug Rabson if (!((u.hdr.e_phentsize == sizeof(Elf_Phdr)) 329fe3db7c7SDoug Rabson || (u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) 330fe3db7c7SDoug Rabson || (u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= nbytes))) 331fe3db7c7SDoug Rabson link_elf_error("Unreadable program headers"); 332fe3db7c7SDoug Rabson 333fe3db7c7SDoug Rabson /* 334fe3db7c7SDoug Rabson * Scan the program header entries, and save key information. 335fe3db7c7SDoug Rabson * 336fe3db7c7SDoug Rabson * We rely on there being exactly two load segments, text and data, 337fe3db7c7SDoug Rabson * in that order. 338fe3db7c7SDoug Rabson */ 339fe3db7c7SDoug Rabson phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff); 340fe3db7c7SDoug Rabson phlimit = phdr + u.hdr.e_phnum; 341fe3db7c7SDoug Rabson nsegs = 0; 342fe3db7c7SDoug Rabson phdyn = NULL; 343fe3db7c7SDoug Rabson phphdr = NULL; 344fe3db7c7SDoug Rabson while (phdr < phlimit) { 345fe3db7c7SDoug Rabson switch (phdr->p_type) { 346fe3db7c7SDoug Rabson 347fe3db7c7SDoug Rabson case PT_LOAD: 348fe3db7c7SDoug Rabson if (nsegs == 2) { 349fe3db7c7SDoug Rabson link_elf_error("Too many sections"); 350fe3db7c7SDoug Rabson error = ENOEXEC; 351fe3db7c7SDoug Rabson goto out; 352fe3db7c7SDoug Rabson } 353fe3db7c7SDoug Rabson segs[nsegs] = phdr; 354fe3db7c7SDoug Rabson ++nsegs; 355fe3db7c7SDoug Rabson break; 356fe3db7c7SDoug Rabson 357fe3db7c7SDoug Rabson case PT_PHDR: 358fe3db7c7SDoug Rabson phphdr = phdr; 359fe3db7c7SDoug Rabson break; 360fe3db7c7SDoug Rabson 361fe3db7c7SDoug Rabson case PT_DYNAMIC: 362fe3db7c7SDoug Rabson phdyn = phdr; 363fe3db7c7SDoug Rabson break; 364fe3db7c7SDoug Rabson } 365fe3db7c7SDoug Rabson 366fe3db7c7SDoug Rabson ++phdr; 367fe3db7c7SDoug Rabson } 368fe3db7c7SDoug Rabson if (phdyn == NULL) { 369fe3db7c7SDoug Rabson link_elf_error("Object is not dynamically-linked"); 370fe3db7c7SDoug Rabson error = ENOEXEC; 371fe3db7c7SDoug Rabson goto out; 372fe3db7c7SDoug Rabson } 373fe3db7c7SDoug Rabson 374fe3db7c7SDoug Rabson /* 375fe3db7c7SDoug Rabson * Allocate the entire address space of the object, to stake out our 376fe3db7c7SDoug Rabson * contiguous region, and to establish the base address for relocation. 377fe3db7c7SDoug Rabson */ 378fe3db7c7SDoug Rabson base_offset = trunc_page(segs[0]->p_offset); 379fe3db7c7SDoug Rabson base_vaddr = trunc_page(segs[0]->p_vaddr); 380fe3db7c7SDoug Rabson base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); 381fe3db7c7SDoug Rabson mapsize = base_vlimit - base_vaddr; 382fe3db7c7SDoug Rabson 383a4f67738SDoug Rabson ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); 384fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 385fe3db7c7SDoug Rabson ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); 386fe3db7c7SDoug Rabson if (ef->object == NULL) { 387fe3db7c7SDoug Rabson free(ef, M_LINKER); 388fe3db7c7SDoug Rabson error = ENOMEM; 389fe3db7c7SDoug Rabson goto out; 390fe3db7c7SDoug Rabson } 391fe3db7c7SDoug Rabson vm_object_reference(ef->object); 392fe3db7c7SDoug Rabson ef->address = (caddr_t) vm_map_min(kernel_map); 393fe3db7c7SDoug Rabson error = vm_map_find(kernel_map, ef->object, 0, 394fe3db7c7SDoug Rabson (vm_offset_t *) &ef->address, 395fe3db7c7SDoug Rabson mapsize, 1, 396fe3db7c7SDoug Rabson VM_PROT_ALL, VM_PROT_ALL, 0); 397fe3db7c7SDoug Rabson if (error) { 398fe3db7c7SDoug Rabson vm_object_deallocate(ef->object); 399fe3db7c7SDoug Rabson free(ef, M_LINKER); 400fe3db7c7SDoug Rabson goto out; 401fe3db7c7SDoug Rabson } 402fe3db7c7SDoug Rabson #else 403fe3db7c7SDoug Rabson ef->address = malloc(mapsize, M_LINKER, M_WAITOK); 404fe3db7c7SDoug Rabson #endif 405fe3db7c7SDoug Rabson mapbase = ef->address; 406a4f67738SDoug Rabson 407a4f67738SDoug Rabson /* 408a4f67738SDoug Rabson * Read the text and data sections and zero the bss. 409a4f67738SDoug Rabson */ 410fe3db7c7SDoug Rabson for (i = 0; i < 2; i++) { 411fe3db7c7SDoug Rabson caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; 412fe3db7c7SDoug Rabson error = vn_rdwr(UIO_READ, nd.ni_vp, 413fe3db7c7SDoug Rabson segbase, segs[i]->p_filesz, segs[i]->p_offset, 414a4f67738SDoug Rabson UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 415fe3db7c7SDoug Rabson if (error) { 416fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 417fe3db7c7SDoug Rabson vm_map_remove(kernel_map, (vm_offset_t) ef->address, 418fe3db7c7SDoug Rabson (vm_offset_t) ef->address 419fe3db7c7SDoug Rabson + (ef->object->size << PAGE_SHIFT)); 420fe3db7c7SDoug Rabson vm_object_deallocate(ef->object); 421fe3db7c7SDoug Rabson #else 422a4f67738SDoug Rabson free(ef->address, M_LINKER); 423fe3db7c7SDoug Rabson #endif 424a4f67738SDoug Rabson free(ef, M_LINKER); 425a4f67738SDoug Rabson goto out; 426a4f67738SDoug Rabson } 427fe3db7c7SDoug Rabson bzero(segbase + segs[i]->p_filesz, 428fe3db7c7SDoug Rabson segs[i]->p_memsz - segs[i]->p_filesz); 429fe3db7c7SDoug Rabson 430fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 431fe3db7c7SDoug Rabson /* 432fe3db7c7SDoug Rabson * Wire down the pages 433fe3db7c7SDoug Rabson */ 434fe3db7c7SDoug Rabson vm_map_pageable(kernel_map, 435fe3db7c7SDoug Rabson (vm_offset_t) segbase, 436fe3db7c7SDoug Rabson (vm_offset_t) segbase + segs[i]->p_memsz, 437fe3db7c7SDoug Rabson FALSE); 438fe3db7c7SDoug Rabson #endif 439fe3db7c7SDoug Rabson } 440fe3db7c7SDoug Rabson 441fe3db7c7SDoug Rabson ef->dynamic = (const Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); 442a4f67738SDoug Rabson 443a4f67738SDoug Rabson lf = linker_make_file(filename, ef, &link_elf_file_ops); 444a4f67738SDoug Rabson if (lf == NULL) { 445fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 446fe3db7c7SDoug Rabson vm_map_remove(kernel_map, (vm_offset_t) ef->address, 447fe3db7c7SDoug Rabson (vm_offset_t) ef->address 448fe3db7c7SDoug Rabson + (ef->object->size << PAGE_SHIFT)); 449fe3db7c7SDoug Rabson vm_object_deallocate(ef->object); 450fe3db7c7SDoug Rabson #else 451a4f67738SDoug Rabson free(ef->address, M_LINKER); 452fe3db7c7SDoug Rabson #endif 453a4f67738SDoug Rabson free(ef, M_LINKER); 454a4f67738SDoug Rabson error = ENOMEM; 455a4f67738SDoug Rabson goto out; 456a4f67738SDoug Rabson } 457a4f67738SDoug Rabson lf->address = ef->address; 458fe3db7c7SDoug Rabson lf->size = mapsize; 459a4f67738SDoug Rabson 460fe3db7c7SDoug Rabson if ((error = parse_dynamic(lf)) != 0 461fe3db7c7SDoug Rabson || (error = load_dependancies(lf)) != 0 462a4f67738SDoug Rabson || (error = relocate_file(lf)) != 0) { 463a4f67738SDoug Rabson linker_file_unload(lf); 464a4f67738SDoug Rabson goto out; 465a4f67738SDoug Rabson } 466a4f67738SDoug Rabson 467a4f67738SDoug Rabson *result = lf; 468a4f67738SDoug Rabson 469a4f67738SDoug Rabson out: 470a4f67738SDoug Rabson VOP_UNLOCK(nd.ni_vp, 0, p); 471a4f67738SDoug Rabson vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 472a4f67738SDoug Rabson 473a4f67738SDoug Rabson return error; 474a4f67738SDoug Rabson } 475a4f67738SDoug Rabson 476a4f67738SDoug Rabson static void 477a4f67738SDoug Rabson link_elf_unload(linker_file_t file) 478a4f67738SDoug Rabson { 479a4f67738SDoug Rabson elf_file_t ef = file->priv; 480a4f67738SDoug Rabson 481a4f67738SDoug Rabson if (ef) { 482fe3db7c7SDoug Rabson #ifdef SPARSE_MAPPING 483fe3db7c7SDoug Rabson if (ef->object) { 484fe3db7c7SDoug Rabson vm_map_remove(kernel_map, (vm_offset_t) ef->address, 485fe3db7c7SDoug Rabson (vm_offset_t) ef->address 486fe3db7c7SDoug Rabson + (ef->object->size << PAGE_SHIFT)); 487fe3db7c7SDoug Rabson vm_object_deallocate(ef->object); 488fe3db7c7SDoug Rabson } 489fe3db7c7SDoug Rabson #else 490a4f67738SDoug Rabson free(ef->address, M_LINKER); 491fe3db7c7SDoug Rabson #endif 492a4f67738SDoug Rabson free(ef, M_LINKER); 493a4f67738SDoug Rabson } 494a4f67738SDoug Rabson } 495a4f67738SDoug Rabson 496a4f67738SDoug Rabson static int 497a4f67738SDoug Rabson load_dependancies(linker_file_t lf) 498a4f67738SDoug Rabson { 499a4f67738SDoug Rabson elf_file_t ef = lf->priv; 500a4f67738SDoug Rabson linker_file_t lfdep; 501a4f67738SDoug Rabson char* name; 502a4f67738SDoug Rabson char* filename = 0; 503fe3db7c7SDoug Rabson const Elf_Dyn *dp; 504a4f67738SDoug Rabson int error = 0; 505a4f67738SDoug Rabson 506a4f67738SDoug Rabson /* 507a4f67738SDoug Rabson * All files are dependant on /kernel. 508a4f67738SDoug Rabson */ 509a4f67738SDoug Rabson linker_kernel_file->refs++; 510a4f67738SDoug Rabson linker_file_add_dependancy(lf, linker_kernel_file); 511a4f67738SDoug Rabson 512a4f67738SDoug Rabson 513fe3db7c7SDoug Rabson for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 514fe3db7c7SDoug Rabson if (dp->d_tag == DT_NEEDED) { 515fe3db7c7SDoug Rabson name = ef->strtab + dp->d_un.d_val; 516a4f67738SDoug Rabson 517a4f67738SDoug Rabson /* 518a4f67738SDoug Rabson * Prepend pathname if dep is not an absolute filename. 519a4f67738SDoug Rabson */ 520a4f67738SDoug Rabson if (name[0] != '/') { 521a4f67738SDoug Rabson char* p; 522fe3db7c7SDoug Rabson if (!filename) { 523a4f67738SDoug Rabson filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 524fe3db7c7SDoug Rabson if (!filename) { 525fe3db7c7SDoug Rabson error = ENOMEM; 526fe3db7c7SDoug Rabson goto out; 527fe3db7c7SDoug Rabson } 528fe3db7c7SDoug Rabson } 529a4f67738SDoug Rabson p = lf->filename + strlen(lf->filename) - 1; 530a4f67738SDoug Rabson while (p >= lf->filename && *p != '/') 531a4f67738SDoug Rabson p--; 532a4f67738SDoug Rabson if (p >= lf->filename) { 533a4f67738SDoug Rabson strncpy(filename, lf->filename, p - lf->filename); 534a4f67738SDoug Rabson filename[p - lf->filename] = '\0'; 535a4f67738SDoug Rabson strcat(filename, "/"); 536a4f67738SDoug Rabson strcat(filename, name); 537a4f67738SDoug Rabson name = filename; 538a4f67738SDoug Rabson } 539a4f67738SDoug Rabson } 540a4f67738SDoug Rabson error = linker_load_file(name, &lfdep); 541a4f67738SDoug Rabson if (error) 542a4f67738SDoug Rabson goto out; 543a4f67738SDoug Rabson error = linker_file_add_dependancy(lf, lfdep); 544a4f67738SDoug Rabson if (error) 545a4f67738SDoug Rabson goto out; 546fe3db7c7SDoug Rabson } 547a4f67738SDoug Rabson } 548a4f67738SDoug Rabson 549a4f67738SDoug Rabson out: 550a4f67738SDoug Rabson if (filename) 551a4f67738SDoug Rabson free(filename, M_TEMP); 552a4f67738SDoug Rabson return error; 553a4f67738SDoug Rabson } 554a4f67738SDoug Rabson 555fe3db7c7SDoug Rabson static const char * 556fe3db7c7SDoug Rabson symbol_name(elf_file_t ef, const Elf_Rela *rela) 557a4f67738SDoug Rabson { 558fe3db7c7SDoug Rabson const Elf_Sym *ref; 559a4f67738SDoug Rabson 560fe3db7c7SDoug Rabson if (ELF_R_SYM(rela->r_info)) { 561fe3db7c7SDoug Rabson ref = ef->symtab + ELF_R_SYM(rela->r_info); 562fe3db7c7SDoug Rabson return ef->strtab + ref->st_name; 563fe3db7c7SDoug Rabson } else 564fe3db7c7SDoug Rabson return NULL; 565a4f67738SDoug Rabson } 566a4f67738SDoug Rabson 567a4f67738SDoug Rabson static int 568a4f67738SDoug Rabson relocate_file(linker_file_t lf) 569a4f67738SDoug Rabson { 570a4f67738SDoug Rabson elf_file_t ef = lf->priv; 571fe3db7c7SDoug Rabson const Elf_Rel *rellim; 572fe3db7c7SDoug Rabson const Elf_Rel *rel; 573fe3db7c7SDoug Rabson const Elf_Rela *relalim; 574fe3db7c7SDoug Rabson const Elf_Rela *rela; 575a4f67738SDoug Rabson 576fe3db7c7SDoug Rabson /* Perform relocations without addend if there are any: */ 577fe3db7c7SDoug Rabson rellim = (const Elf_Rel *) ((caddr_t) ef->rel + ef->relsize); 578fe3db7c7SDoug Rabson for (rel = ef->rel; ef->rel != NULL && rel < rellim; rel++) { 579fe3db7c7SDoug Rabson Elf_Rela locrela; 580a4f67738SDoug Rabson 581fe3db7c7SDoug Rabson locrela.r_info = rel->r_info; 582fe3db7c7SDoug Rabson locrela.r_offset = rel->r_offset; 583fe3db7c7SDoug Rabson locrela.r_addend = 0; 584fe3db7c7SDoug Rabson if (elf_reloc(lf, &locrela, symbol_name(ef, &locrela))) 585a4f67738SDoug Rabson return ENOENT; 586a4f67738SDoug Rabson } 587a4f67738SDoug Rabson 588fe3db7c7SDoug Rabson /* Perform relocations with addend if there are any: */ 589fe3db7c7SDoug Rabson relalim = (const Elf_Rela *) ((caddr_t) ef->rela + ef->relasize); 590fe3db7c7SDoug Rabson for (rela = ef->rela; ef->rela != NULL && rela < relalim; rela++) { 591fe3db7c7SDoug Rabson if (elf_reloc(lf, rela, symbol_name(ef, rela))) 592fe3db7c7SDoug Rabson return ENOENT; 593a4f67738SDoug Rabson } 594a4f67738SDoug Rabson 595fe3db7c7SDoug Rabson /* Perform PLT relocations without addend if there are any: */ 596fe3db7c7SDoug Rabson rellim = (const Elf_Rel *) ((caddr_t) ef->pltrel + ef->pltrelsize); 597fe3db7c7SDoug Rabson for (rel = ef->pltrel; ef->pltrel != NULL && rel < rellim; rel++) { 598fe3db7c7SDoug Rabson Elf_Rela locrela; 599a4f67738SDoug Rabson 600fe3db7c7SDoug Rabson locrela.r_info = rel->r_info; 601fe3db7c7SDoug Rabson locrela.r_offset = rel->r_offset; 602fe3db7c7SDoug Rabson locrela.r_addend = 0; 603fe3db7c7SDoug Rabson if (elf_reloc(lf, &locrela, symbol_name(ef, &locrela))) 604fe3db7c7SDoug Rabson return ENOENT; 605a4f67738SDoug Rabson } 606a4f67738SDoug Rabson 607fe3db7c7SDoug Rabson /* Perform relocations with addend if there are any: */ 608fe3db7c7SDoug Rabson relalim = (const Elf_Rela *) ((caddr_t) ef->pltrela + ef->pltrelasize); 609fe3db7c7SDoug Rabson for (rela = ef->pltrela; ef->pltrela != NULL && rela < relalim; rela++) { 610fe3db7c7SDoug Rabson if (elf_reloc(lf, rela, symbol_name(ef, rela))) 611fe3db7c7SDoug Rabson return ENOENT; 612a4f67738SDoug Rabson } 613a4f67738SDoug Rabson 614a4f67738SDoug Rabson return 0; 615a4f67738SDoug Rabson } 616a4f67738SDoug Rabson 617fe3db7c7SDoug Rabson /* 618fe3db7c7SDoug Rabson * Hash function for symbol table lookup. Don't even think about changing 619fe3db7c7SDoug Rabson * this. It is specified by the System V ABI. 620fe3db7c7SDoug Rabson */ 621fe3db7c7SDoug Rabson static unsigned long 622fe3db7c7SDoug Rabson elf_hash(const char *name) 623a4f67738SDoug Rabson { 624fe3db7c7SDoug Rabson const unsigned char *p = (const unsigned char *) name; 625fe3db7c7SDoug Rabson unsigned long h = 0; 626fe3db7c7SDoug Rabson unsigned long g; 627a4f67738SDoug Rabson 628fe3db7c7SDoug Rabson while (*p != '\0') { 629fe3db7c7SDoug Rabson h = (h << 4) + *p++; 630fe3db7c7SDoug Rabson if ((g = h & 0xf0000000) != 0) 631fe3db7c7SDoug Rabson h ^= g >> 24; 632fe3db7c7SDoug Rabson h &= ~g; 633a4f67738SDoug Rabson } 634fe3db7c7SDoug Rabson return h; 635fe3db7c7SDoug Rabson } 636a4f67738SDoug Rabson 637a4f67738SDoug Rabson int 638a4f67738SDoug Rabson link_elf_lookup_symbol(linker_file_t lf, const char* name, linker_sym_t* sym) 639a4f67738SDoug Rabson { 640a4f67738SDoug Rabson elf_file_t ef = lf->priv; 641fe3db7c7SDoug Rabson unsigned long symnum; 642fe3db7c7SDoug Rabson const Elf_Sym* es; 643fe3db7c7SDoug Rabson unsigned long hash; 644a4f67738SDoug Rabson int i; 645a4f67738SDoug Rabson 646fe3db7c7SDoug Rabson hash = elf_hash(name); 647fe3db7c7SDoug Rabson symnum = ef->buckets[hash % ef->nbuckets]; 648fe3db7c7SDoug Rabson 649fe3db7c7SDoug Rabson while (symnum != STN_UNDEF) { 650fe3db7c7SDoug Rabson const Elf_Sym *symp; 651fe3db7c7SDoug Rabson const char *strp; 652fe3db7c7SDoug Rabson 653fe3db7c7SDoug Rabson if (symnum >= ef->nchains) { 654fe3db7c7SDoug Rabson printf("link_elf_lookup_symbol: corrupt symbol table\n"); 655fe3db7c7SDoug Rabson return ENOENT; 656a4f67738SDoug Rabson } 657fe3db7c7SDoug Rabson 658fe3db7c7SDoug Rabson symp = ef->symtab + symnum; 659fe3db7c7SDoug Rabson if (symp->st_name == 0) { 660fe3db7c7SDoug Rabson printf("link_elf_lookup_symbol: corrupt symbol table\n"); 661fe3db7c7SDoug Rabson return ENOENT; 662fe3db7c7SDoug Rabson } 663fe3db7c7SDoug Rabson 664fe3db7c7SDoug Rabson strp = ef->strtab + symp->st_name; 665fe3db7c7SDoug Rabson 666fe3db7c7SDoug Rabson if (strcmp(name, strp) == 0) { 667fe3db7c7SDoug Rabson if (symp->st_shndx != SHN_UNDEF || 668fe3db7c7SDoug Rabson (symp->st_value != 0 && 669fe3db7c7SDoug Rabson ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 670fe3db7c7SDoug Rabson *sym = (linker_sym_t) symp; 671fe3db7c7SDoug Rabson return 0; 672fe3db7c7SDoug Rabson } else 673fe3db7c7SDoug Rabson return ENOENT; 674fe3db7c7SDoug Rabson } 675fe3db7c7SDoug Rabson 676fe3db7c7SDoug Rabson symnum = ef->chains[symnum]; 677a4f67738SDoug Rabson } 678a4f67738SDoug Rabson 679a4f67738SDoug Rabson return ENOENT; 680a4f67738SDoug Rabson } 681a4f67738SDoug Rabson 682a4f67738SDoug Rabson static void 683a4f67738SDoug Rabson link_elf_symbol_values(linker_file_t lf, linker_sym_t sym, linker_symval_t* symval) 684a4f67738SDoug Rabson { 685a4f67738SDoug Rabson elf_file_t ef = lf->priv; 686a4f67738SDoug Rabson Elf_Sym* es = (Elf_Sym*) sym; 687a4f67738SDoug Rabson 688a4f67738SDoug Rabson symval->name = ef->strtab + es->st_name; 689fe3db7c7SDoug Rabson symval->value = (caddr_t) ef->address + es->st_value; 690a4f67738SDoug Rabson symval->size = es->st_size; 691a4f67738SDoug Rabson } 692a4f67738SDoug Rabson 693a4f67738SDoug Rabson static int 694a4f67738SDoug Rabson link_elf_search_symbol(linker_file_t lf, caddr_t value, 695a4f67738SDoug Rabson linker_sym_t* sym, long* diffp) 696a4f67738SDoug Rabson { 697a4f67738SDoug Rabson elf_file_t ef = lf->priv; 698a4f67738SDoug Rabson u_long off = (u_long) value; 699a4f67738SDoug Rabson u_long diff = off; 700a4f67738SDoug Rabson int symcount = ef->nchains; 701fe3db7c7SDoug Rabson const Elf_Sym* es; 702fe3db7c7SDoug Rabson const Elf_Sym* best = 0; 703a4f67738SDoug Rabson int i; 704a4f67738SDoug Rabson 705a4f67738SDoug Rabson for (i = 0, es = ef->symtab; i < ef->nchains; i++, es++) { 706a4f67738SDoug Rabson if (es->st_name == 0) 707a4f67738SDoug Rabson continue; 708a4f67738SDoug Rabson if (off >= es->st_value) { 709a4f67738SDoug Rabson if (off - es->st_value < diff) { 710a4f67738SDoug Rabson diff = off - es->st_value; 711a4f67738SDoug Rabson best = es; 712a4f67738SDoug Rabson if (diff == 0) 713a4f67738SDoug Rabson break; 714a4f67738SDoug Rabson } else if (off - es->st_value == diff) { 715a4f67738SDoug Rabson best = es; 716a4f67738SDoug Rabson } 717a4f67738SDoug Rabson } 718a4f67738SDoug Rabson } 719a4f67738SDoug Rabson if (best == 0) 720a4f67738SDoug Rabson *diffp = off; 721a4f67738SDoug Rabson else 722a4f67738SDoug Rabson *diffp = diff; 723a4f67738SDoug Rabson *sym = (linker_sym_t) best; 724a4f67738SDoug Rabson 725a4f67738SDoug Rabson return 0; 726a4f67738SDoug Rabson } 727a4f67738SDoug Rabson 728