1*479ab7f0SSascha Wildner /*- 2*479ab7f0SSascha Wildner * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3*479ab7f0SSascha Wildner * Copyright (c) 1998 Peter Wemm <peter@freebsd.org> 4*479ab7f0SSascha Wildner * All rights reserved. 5*479ab7f0SSascha Wildner * 6*479ab7f0SSascha Wildner * Redistribution and use in source and binary forms, with or without 7*479ab7f0SSascha Wildner * modification, are permitted provided that the following conditions 8*479ab7f0SSascha Wildner * are met: 9*479ab7f0SSascha Wildner * 1. Redistributions of source code must retain the above copyright 10*479ab7f0SSascha Wildner * notice, this list of conditions and the following disclaimer. 11*479ab7f0SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 12*479ab7f0SSascha Wildner * notice, this list of conditions and the following disclaimer in the 13*479ab7f0SSascha Wildner * documentation and/or other materials provided with the distribution. 14*479ab7f0SSascha Wildner * 15*479ab7f0SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*479ab7f0SSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*479ab7f0SSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*479ab7f0SSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*479ab7f0SSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*479ab7f0SSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*479ab7f0SSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*479ab7f0SSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*479ab7f0SSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*479ab7f0SSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*479ab7f0SSascha Wildner * SUCH DAMAGE. 26*479ab7f0SSascha Wildner * 27*479ab7f0SSascha Wildner * $FreeBSD: src/sys/boot/common/load_elf.c,v 1.39 2008/10/14 10:11:14 raj Exp $ 28*479ab7f0SSascha Wildner */ 29*479ab7f0SSascha Wildner 30*479ab7f0SSascha Wildner #include <sys/param.h> 31*479ab7f0SSascha Wildner #include <sys/exec.h> 32*479ab7f0SSascha Wildner #include <sys/linker.h> 33*479ab7f0SSascha Wildner #include <sys/module.h> 34*479ab7f0SSascha Wildner #include <sys/stdint.h> 35*479ab7f0SSascha Wildner #include <string.h> 36*479ab7f0SSascha Wildner #include <machine/elf.h> 37*479ab7f0SSascha Wildner #include <stand.h> 38*479ab7f0SSascha Wildner #define FREEBSD_ELF 39*479ab7f0SSascha Wildner #include <link.h> 40*479ab7f0SSascha Wildner 41*479ab7f0SSascha Wildner #include "bootstrap.h" 42*479ab7f0SSascha Wildner 43*479ab7f0SSascha Wildner #define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) 44*479ab7f0SSascha Wildner 45*479ab7f0SSascha Wildner #if defined(__i386__) && __ELF_WORD_SIZE == 64 46*479ab7f0SSascha Wildner #undef ELF_TARG_CLASS 47*479ab7f0SSascha Wildner #undef ELF_TARG_MACH 48*479ab7f0SSascha Wildner #define ELF_TARG_CLASS ELFCLASS64 49*479ab7f0SSascha Wildner #define ELF_TARG_MACH EM_X86_64 50*479ab7f0SSascha Wildner #endif 51*479ab7f0SSascha Wildner 52*479ab7f0SSascha Wildner typedef struct elf_file { 53*479ab7f0SSascha Wildner Elf_Phdr *ph; 54*479ab7f0SSascha Wildner Elf_Ehdr *ehdr; 55*479ab7f0SSascha Wildner Elf_Sym *symtab; 56*479ab7f0SSascha Wildner Elf_Hashelt *hashtab; 57*479ab7f0SSascha Wildner Elf_Hashelt nbuckets; 58*479ab7f0SSascha Wildner Elf_Hashelt nchains; 59*479ab7f0SSascha Wildner Elf_Hashelt *buckets; 60*479ab7f0SSascha Wildner Elf_Hashelt *chains; 61*479ab7f0SSascha Wildner Elf_Rel *rel; 62*479ab7f0SSascha Wildner size_t relsz; 63*479ab7f0SSascha Wildner Elf_Rela *rela; 64*479ab7f0SSascha Wildner size_t relasz; 65*479ab7f0SSascha Wildner char *strtab; 66*479ab7f0SSascha Wildner size_t strsz; 67*479ab7f0SSascha Wildner int fd; 68*479ab7f0SSascha Wildner caddr_t firstpage; 69*479ab7f0SSascha Wildner size_t firstlen; 70*479ab7f0SSascha Wildner int kernel; 71*479ab7f0SSascha Wildner u_int64_t off; 72*479ab7f0SSascha Wildner } *elf_file_t; 73*479ab7f0SSascha Wildner 74*479ab7f0SSascha Wildner static int __elfN(loadimage)(struct preloaded_file *mp, elf_file_t ef, u_int64_t loadaddr); 75*479ab7f0SSascha Wildner static int __elfN(lookup_symbol)(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym); 76*479ab7f0SSascha Wildner static int __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, 77*479ab7f0SSascha Wildner Elf_Addr p, void *val, size_t len); 78*479ab7f0SSascha Wildner static int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef); 79*479ab7f0SSascha Wildner static symaddr_fn __elfN(symaddr); 80*479ab7f0SSascha Wildner static char *fake_modname(const char *name); 81*479ab7f0SSascha Wildner 82*479ab7f0SSascha Wildner const char *__elfN(kerneltype) = "elf kernel"; 83*479ab7f0SSascha Wildner const char *__elfN(moduletype) = "elf module"; 84*479ab7f0SSascha Wildner 85*479ab7f0SSascha Wildner u_int64_t __elfN(relocation_offset) = 0; 86*479ab7f0SSascha Wildner 87*479ab7f0SSascha Wildner /* 88*479ab7f0SSascha Wildner * Attempt to load the file (file) as an ELF module. It will be stored at 89*479ab7f0SSascha Wildner * (dest), and a pointer to a module structure describing the loaded object 90*479ab7f0SSascha Wildner * will be saved in (result). 91*479ab7f0SSascha Wildner */ 92*479ab7f0SSascha Wildner int 93*479ab7f0SSascha Wildner __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) 94*479ab7f0SSascha Wildner { 95*479ab7f0SSascha Wildner struct preloaded_file *fp, *kfp; 96*479ab7f0SSascha Wildner struct elf_file ef; 97*479ab7f0SSascha Wildner Elf_Ehdr *ehdr; 98*479ab7f0SSascha Wildner int err; 99*479ab7f0SSascha Wildner u_int pad; 100*479ab7f0SSascha Wildner ssize_t bytes_read; 101*479ab7f0SSascha Wildner char *fullpath; 102*479ab7f0SSascha Wildner 103*479ab7f0SSascha Wildner fp = NULL; 104*479ab7f0SSascha Wildner bzero(&ef, sizeof(struct elf_file)); 105*479ab7f0SSascha Wildner 106*479ab7f0SSascha Wildner /* 107*479ab7f0SSascha Wildner * Open the image, read and validate the ELF header 108*479ab7f0SSascha Wildner */ 109*479ab7f0SSascha Wildner if (filename == NULL) /* can't handle nameless */ 110*479ab7f0SSascha Wildner return(EFTYPE); 111*479ab7f0SSascha Wildner if ((ef.fd = rel_open(filename, &fullpath, O_RDONLY)) == -1) 112*479ab7f0SSascha Wildner return(errno); 113*479ab7f0SSascha Wildner ef.firstpage = malloc(PAGE_SIZE); 114*479ab7f0SSascha Wildner if (ef.firstpage == NULL) { 115*479ab7f0SSascha Wildner close(ef.fd); 116*479ab7f0SSascha Wildner free(fullpath); 117*479ab7f0SSascha Wildner return(ENOMEM); 118*479ab7f0SSascha Wildner } 119*479ab7f0SSascha Wildner bytes_read = read(ef.fd, ef.firstpage, PAGE_SIZE); 120*479ab7f0SSascha Wildner ef.firstlen = (size_t)bytes_read; 121*479ab7f0SSascha Wildner if (bytes_read < 0 || ef.firstlen <= sizeof(Elf_Ehdr)) { 122*479ab7f0SSascha Wildner err = EFTYPE; /* could be EIO, but may be small file */ 123*479ab7f0SSascha Wildner goto oerr; 124*479ab7f0SSascha Wildner } 125*479ab7f0SSascha Wildner ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage; 126*479ab7f0SSascha Wildner 127*479ab7f0SSascha Wildner /* Is it ELF? */ 128*479ab7f0SSascha Wildner if (!IS_ELF(*ehdr)) { 129*479ab7f0SSascha Wildner err = EFTYPE; 130*479ab7f0SSascha Wildner goto oerr; 131*479ab7f0SSascha Wildner } 132*479ab7f0SSascha Wildner if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ 133*479ab7f0SSascha Wildner ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || 134*479ab7f0SSascha Wildner ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ 135*479ab7f0SSascha Wildner ehdr->e_version != EV_CURRENT || 136*479ab7f0SSascha Wildner ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ 137*479ab7f0SSascha Wildner err = EFTYPE; 138*479ab7f0SSascha Wildner goto oerr; 139*479ab7f0SSascha Wildner } 140*479ab7f0SSascha Wildner 141*479ab7f0SSascha Wildner 142*479ab7f0SSascha Wildner /* 143*479ab7f0SSascha Wildner * Check to see what sort of module we are. 144*479ab7f0SSascha Wildner */ 145*479ab7f0SSascha Wildner kfp = file_findfile(NULL, NULL); 146*479ab7f0SSascha Wildner if (ehdr->e_type == ET_DYN) { 147*479ab7f0SSascha Wildner /* Looks like a kld module */ 148*479ab7f0SSascha Wildner if (kfp == NULL) { 149*479ab7f0SSascha Wildner printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n"); 150*479ab7f0SSascha Wildner err = EPERM; 151*479ab7f0SSascha Wildner goto oerr; 152*479ab7f0SSascha Wildner } 153*479ab7f0SSascha Wildner if (strcmp(__elfN(kerneltype), kfp->f_type)) { 154*479ab7f0SSascha Wildner printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); 155*479ab7f0SSascha Wildner err = EPERM; 156*479ab7f0SSascha Wildner goto oerr; 157*479ab7f0SSascha Wildner } 158*479ab7f0SSascha Wildner /* Looks OK, got ahead */ 159*479ab7f0SSascha Wildner ef.kernel = 0; 160*479ab7f0SSascha Wildner 161*479ab7f0SSascha Wildner /* Page-align the load address */ 162*479ab7f0SSascha Wildner pad = (u_int)dest & PAGE_MASK; 163*479ab7f0SSascha Wildner if (pad != 0) { 164*479ab7f0SSascha Wildner pad = PAGE_SIZE - pad; 165*479ab7f0SSascha Wildner dest += pad; 166*479ab7f0SSascha Wildner } 167*479ab7f0SSascha Wildner } else if (ehdr->e_type == ET_EXEC) { 168*479ab7f0SSascha Wildner /* Looks like a kernel */ 169*479ab7f0SSascha Wildner if (kfp != NULL) { 170*479ab7f0SSascha Wildner printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n"); 171*479ab7f0SSascha Wildner err = EPERM; 172*479ab7f0SSascha Wildner goto oerr; 173*479ab7f0SSascha Wildner } 174*479ab7f0SSascha Wildner /* 175*479ab7f0SSascha Wildner * Calculate destination address based on kernel entrypoint 176*479ab7f0SSascha Wildner */ 177*479ab7f0SSascha Wildner dest = ehdr->e_entry; 178*479ab7f0SSascha Wildner if (dest == 0) { 179*479ab7f0SSascha Wildner printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); 180*479ab7f0SSascha Wildner err = EPERM; 181*479ab7f0SSascha Wildner goto oerr; 182*479ab7f0SSascha Wildner } 183*479ab7f0SSascha Wildner ef.kernel = 1; 184*479ab7f0SSascha Wildner 185*479ab7f0SSascha Wildner } else { 186*479ab7f0SSascha Wildner err = EFTYPE; 187*479ab7f0SSascha Wildner goto oerr; 188*479ab7f0SSascha Wildner } 189*479ab7f0SSascha Wildner 190*479ab7f0SSascha Wildner /* 191*479ab7f0SSascha Wildner * Ok, we think we should handle this. 192*479ab7f0SSascha Wildner */ 193*479ab7f0SSascha Wildner fp = file_alloc(); 194*479ab7f0SSascha Wildner if (fp == NULL) { 195*479ab7f0SSascha Wildner printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n"); 196*479ab7f0SSascha Wildner err = EPERM; 197*479ab7f0SSascha Wildner goto out; 198*479ab7f0SSascha Wildner } 199*479ab7f0SSascha Wildner 200*479ab7f0SSascha Wildner /* 201*479ab7f0SSascha Wildner * Set the kernel name and module path correctly for the kernel's 202*479ab7f0SSascha Wildner * consumption. Always prepend a /boot if we don't have one. 203*479ab7f0SSascha Wildner */ 204*479ab7f0SSascha Wildner if (ef.kernel) { 205*479ab7f0SSascha Wildner char *mptr; 206*479ab7f0SSascha Wildner char *fpend; 207*479ab7f0SSascha Wildner char *modlocal; 208*479ab7f0SSascha Wildner const char *prefix = ""; 209*479ab7f0SSascha Wildner 210*479ab7f0SSascha Wildner mptr = malloc(256); 211*479ab7f0SSascha Wildner if (strncmp(fullpath, "/boot/", 6) != 0) 212*479ab7f0SSascha Wildner prefix = "/boot"; 213*479ab7f0SSascha Wildner snprintf(mptr, 256, "%s%s", prefix, fullpath); 214*479ab7f0SSascha Wildner setenv("kernelname", mptr, 1); 215*479ab7f0SSascha Wildner 216*479ab7f0SSascha Wildner fpend = strrchr(mptr, '/'); 217*479ab7f0SSascha Wildner *fpend = 0; 218*479ab7f0SSascha Wildner if (strcmp(mptr, "/boot") == 0) 219*479ab7f0SSascha Wildner snprintf(mptr, 256, "/boot/modules"); 220*479ab7f0SSascha Wildner 221*479ab7f0SSascha Wildner /* Append modules.local for kernel if requested */ 222*479ab7f0SSascha Wildner modlocal = getenv("local_modules"); 223*479ab7f0SSascha Wildner if (modlocal != NULL && strcmp(modlocal, "YES") == 0) 224*479ab7f0SSascha Wildner strncat(mptr, ";/boot/modules.local", 255); 225*479ab7f0SSascha Wildner 226*479ab7f0SSascha Wildner /* this will be moved to "module_path" on boot */ 227*479ab7f0SSascha Wildner setenv("exported_module_path", mptr, 1); 228*479ab7f0SSascha Wildner free(mptr); 229*479ab7f0SSascha Wildner } 230*479ab7f0SSascha Wildner fp->f_name = strdup(filename); 231*479ab7f0SSascha Wildner fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype)); 232*479ab7f0SSascha Wildner 233*479ab7f0SSascha Wildner #ifdef ELF_VERBOSE 234*479ab7f0SSascha Wildner if (ef.kernel) 235*479ab7f0SSascha Wildner printf("%s entry at 0x%jx\n", filename, (uintmax_t)dest); 236*479ab7f0SSascha Wildner #else 237*479ab7f0SSascha Wildner printf("%s ", filename); 238*479ab7f0SSascha Wildner #endif 239*479ab7f0SSascha Wildner 240*479ab7f0SSascha Wildner fp->f_size = __elfN(loadimage)(fp, &ef, dest); 241*479ab7f0SSascha Wildner if (fp->f_size == 0 || fp->f_addr == 0) 242*479ab7f0SSascha Wildner goto ioerr; 243*479ab7f0SSascha Wildner 244*479ab7f0SSascha Wildner /* save exec header as metadata */ 245*479ab7f0SSascha Wildner file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); 246*479ab7f0SSascha Wildner 247*479ab7f0SSascha Wildner /* Load OK, return module pointer */ 248*479ab7f0SSascha Wildner *result = (struct preloaded_file *)fp; 249*479ab7f0SSascha Wildner err = 0; 250*479ab7f0SSascha Wildner goto out; 251*479ab7f0SSascha Wildner 252*479ab7f0SSascha Wildner ioerr: 253*479ab7f0SSascha Wildner err = EIO; 254*479ab7f0SSascha Wildner oerr: 255*479ab7f0SSascha Wildner file_discard(fp); 256*479ab7f0SSascha Wildner out: 257*479ab7f0SSascha Wildner if (ef.firstpage) 258*479ab7f0SSascha Wildner free(ef.firstpage); 259*479ab7f0SSascha Wildner close(ef.fd); 260*479ab7f0SSascha Wildner if (fullpath) 261*479ab7f0SSascha Wildner free(fullpath); 262*479ab7f0SSascha Wildner return(err); 263*479ab7f0SSascha Wildner } 264*479ab7f0SSascha Wildner 265*479ab7f0SSascha Wildner /* 266*479ab7f0SSascha Wildner * With the file (fd) open on the image, and (ehdr) containing 267*479ab7f0SSascha Wildner * the Elf header, load the image at (off) 268*479ab7f0SSascha Wildner */ 269*479ab7f0SSascha Wildner static int 270*479ab7f0SSascha Wildner __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) 271*479ab7f0SSascha Wildner { 272*479ab7f0SSascha Wildner int i; 273*479ab7f0SSascha Wildner u_int j; 274*479ab7f0SSascha Wildner Elf_Ehdr *ehdr; 275*479ab7f0SSascha Wildner Elf_Phdr *phdr, *php; 276*479ab7f0SSascha Wildner Elf_Shdr *shdr; 277*479ab7f0SSascha Wildner int ret; 278*479ab7f0SSascha Wildner vm_offset_t firstaddr; 279*479ab7f0SSascha Wildner vm_offset_t lastaddr; 280*479ab7f0SSascha Wildner size_t chunk; 281*479ab7f0SSascha Wildner ssize_t result; 282*479ab7f0SSascha Wildner Elf_Addr ssym, esym; 283*479ab7f0SSascha Wildner Elf_Dyn *dp; 284*479ab7f0SSascha Wildner Elf_Addr adp; 285*479ab7f0SSascha Wildner int ndp; 286*479ab7f0SSascha Wildner int symstrindex; 287*479ab7f0SSascha Wildner int symtabindex; 288*479ab7f0SSascha Wildner Elf_Size size; 289*479ab7f0SSascha Wildner u_int fpcopy; 290*479ab7f0SSascha Wildner 291*479ab7f0SSascha Wildner dp = NULL; 292*479ab7f0SSascha Wildner shdr = NULL; 293*479ab7f0SSascha Wildner ret = 0; 294*479ab7f0SSascha Wildner firstaddr = lastaddr = 0; 295*479ab7f0SSascha Wildner ehdr = ef->ehdr; 296*479ab7f0SSascha Wildner if (ef->kernel) { 297*479ab7f0SSascha Wildner #if defined(__x86_64__) || defined(__i386__) 298*479ab7f0SSascha Wildner #if __ELF_WORD_SIZE == 64 299*479ab7f0SSascha Wildner off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */ 300*479ab7f0SSascha Wildner #else 301*479ab7f0SSascha Wildner off = - (off & 0xff000000u); /* i386 relocates after locore */ 302*479ab7f0SSascha Wildner #endif 303*479ab7f0SSascha Wildner #else 304*479ab7f0SSascha Wildner off = 0; /* other archs use direct mapped kernels */ 305*479ab7f0SSascha Wildner #endif 306*479ab7f0SSascha Wildner __elfN(relocation_offset) = off; 307*479ab7f0SSascha Wildner } 308*479ab7f0SSascha Wildner ef->off = off; 309*479ab7f0SSascha Wildner 310*479ab7f0SSascha Wildner if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { 311*479ab7f0SSascha Wildner printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n"); 312*479ab7f0SSascha Wildner goto out; 313*479ab7f0SSascha Wildner } 314*479ab7f0SSascha Wildner phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff); 315*479ab7f0SSascha Wildner 316*479ab7f0SSascha Wildner for (i = 0; i < ehdr->e_phnum; i++) { 317*479ab7f0SSascha Wildner /* We want to load PT_LOAD segments only.. */ 318*479ab7f0SSascha Wildner if (phdr[i].p_type != PT_LOAD) 319*479ab7f0SSascha Wildner continue; 320*479ab7f0SSascha Wildner 321*479ab7f0SSascha Wildner #ifdef ELF_VERBOSE 322*479ab7f0SSascha Wildner printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", 323*479ab7f0SSascha Wildner (long)phdr[i].p_filesz, (long)phdr[i].p_offset, 324*479ab7f0SSascha Wildner (long)(phdr[i].p_vaddr + off), 325*479ab7f0SSascha Wildner (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 326*479ab7f0SSascha Wildner #else 327*479ab7f0SSascha Wildner if ((phdr[i].p_flags & PF_W) == 0) { 328*479ab7f0SSascha Wildner printf("text=0x%lx ", (long)phdr[i].p_filesz); 329*479ab7f0SSascha Wildner } else { 330*479ab7f0SSascha Wildner printf("data=0x%lx", (long)phdr[i].p_filesz); 331*479ab7f0SSascha Wildner if (phdr[i].p_filesz < phdr[i].p_memsz) 332*479ab7f0SSascha Wildner printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz)); 333*479ab7f0SSascha Wildner printf(" "); 334*479ab7f0SSascha Wildner } 335*479ab7f0SSascha Wildner #endif 336*479ab7f0SSascha Wildner fpcopy = 0; 337*479ab7f0SSascha Wildner if (ef->firstlen > phdr[i].p_offset) { 338*479ab7f0SSascha Wildner fpcopy = ef->firstlen - phdr[i].p_offset; 339*479ab7f0SSascha Wildner archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, 340*479ab7f0SSascha Wildner phdr[i].p_vaddr + off, fpcopy); 341*479ab7f0SSascha Wildner } 342*479ab7f0SSascha Wildner if (phdr[i].p_filesz > fpcopy) { 343*479ab7f0SSascha Wildner if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy, 344*479ab7f0SSascha Wildner phdr[i].p_filesz - fpcopy, phdr[i].p_offset + fpcopy) != 0) { 345*479ab7f0SSascha Wildner printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 346*479ab7f0SSascha Wildner "_loadimage: read failed\n"); 347*479ab7f0SSascha Wildner goto out; 348*479ab7f0SSascha Wildner } 349*479ab7f0SSascha Wildner } 350*479ab7f0SSascha Wildner /* clear space from oversized segments; eg: bss */ 351*479ab7f0SSascha Wildner if (phdr[i].p_filesz < phdr[i].p_memsz) { 352*479ab7f0SSascha Wildner #ifdef ELF_VERBOSE 353*479ab7f0SSascha Wildner printf(" (bss: 0x%lx-0x%lx)", 354*479ab7f0SSascha Wildner (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz), 355*479ab7f0SSascha Wildner (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 356*479ab7f0SSascha Wildner #endif 357*479ab7f0SSascha Wildner 358*479ab7f0SSascha Wildner kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz, 359*479ab7f0SSascha Wildner phdr[i].p_memsz - phdr[i].p_filesz); 360*479ab7f0SSascha Wildner } 361*479ab7f0SSascha Wildner #ifdef ELF_VERBOSE 362*479ab7f0SSascha Wildner printf("\n"); 363*479ab7f0SSascha Wildner #endif 364*479ab7f0SSascha Wildner 365*479ab7f0SSascha Wildner if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) 366*479ab7f0SSascha Wildner firstaddr = phdr[i].p_vaddr + off; 367*479ab7f0SSascha Wildner if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) 368*479ab7f0SSascha Wildner lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz; 369*479ab7f0SSascha Wildner } 370*479ab7f0SSascha Wildner lastaddr = roundup(lastaddr, sizeof(long)); 371*479ab7f0SSascha Wildner 372*479ab7f0SSascha Wildner /* 373*479ab7f0SSascha Wildner * Now grab the symbol tables. This isn't easy if we're reading a 374*479ab7f0SSascha Wildner * .gz file. I think the rule is going to have to be that you must 375*479ab7f0SSascha Wildner * strip a file to remove symbols before gzipping it so that we do not 376*479ab7f0SSascha Wildner * try to lseek() on it. 377*479ab7f0SSascha Wildner */ 378*479ab7f0SSascha Wildner chunk = ehdr->e_shnum * ehdr->e_shentsize; 379*479ab7f0SSascha Wildner if (chunk == 0 || ehdr->e_shoff == 0) 380*479ab7f0SSascha Wildner goto nosyms; 381*479ab7f0SSascha Wildner shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk); 382*479ab7f0SSascha Wildner if (shdr == NULL) { 383*479ab7f0SSascha Wildner printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 384*479ab7f0SSascha Wildner "_loadimage: failed to read section headers"); 385*479ab7f0SSascha Wildner goto nosyms; 386*479ab7f0SSascha Wildner } 387*479ab7f0SSascha Wildner symtabindex = -1; 388*479ab7f0SSascha Wildner symstrindex = -1; 389*479ab7f0SSascha Wildner for (i = 0; i < ehdr->e_shnum; i++) { 390*479ab7f0SSascha Wildner if (shdr[i].sh_type != SHT_SYMTAB) 391*479ab7f0SSascha Wildner continue; 392*479ab7f0SSascha Wildner for (j = 0; j < ehdr->e_phnum; j++) { 393*479ab7f0SSascha Wildner if (phdr[j].p_type != PT_LOAD) 394*479ab7f0SSascha Wildner continue; 395*479ab7f0SSascha Wildner if (shdr[i].sh_offset >= phdr[j].p_offset && 396*479ab7f0SSascha Wildner (shdr[i].sh_offset + shdr[i].sh_size <= 397*479ab7f0SSascha Wildner phdr[j].p_offset + phdr[j].p_filesz)) { 398*479ab7f0SSascha Wildner shdr[i].sh_offset = 0; 399*479ab7f0SSascha Wildner shdr[i].sh_size = 0; 400*479ab7f0SSascha Wildner break; 401*479ab7f0SSascha Wildner } 402*479ab7f0SSascha Wildner } 403*479ab7f0SSascha Wildner if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0) 404*479ab7f0SSascha Wildner continue; /* alread loaded in a PT_LOAD above */ 405*479ab7f0SSascha Wildner /* Save it for loading below */ 406*479ab7f0SSascha Wildner symtabindex = i; 407*479ab7f0SSascha Wildner symstrindex = shdr[i].sh_link; 408*479ab7f0SSascha Wildner } 409*479ab7f0SSascha Wildner if (symtabindex < 0 || symstrindex < 0) 410*479ab7f0SSascha Wildner goto nosyms; 411*479ab7f0SSascha Wildner 412*479ab7f0SSascha Wildner /* Ok, committed to a load. */ 413*479ab7f0SSascha Wildner #ifndef ELF_VERBOSE 414*479ab7f0SSascha Wildner printf("syms=["); 415*479ab7f0SSascha Wildner #endif 416*479ab7f0SSascha Wildner ssym = lastaddr; 417*479ab7f0SSascha Wildner for (i = symtabindex; i >= 0; i = symstrindex) { 418*479ab7f0SSascha Wildner #ifdef ELF_VERBOSE 419*479ab7f0SSascha Wildner char *secname; 420*479ab7f0SSascha Wildner 421*479ab7f0SSascha Wildner switch(shdr[i].sh_type) { 422*479ab7f0SSascha Wildner case SHT_SYMTAB: /* Symbol table */ 423*479ab7f0SSascha Wildner secname = "symtab"; 424*479ab7f0SSascha Wildner break; 425*479ab7f0SSascha Wildner case SHT_STRTAB: /* String table */ 426*479ab7f0SSascha Wildner secname = "strtab"; 427*479ab7f0SSascha Wildner break; 428*479ab7f0SSascha Wildner default: 429*479ab7f0SSascha Wildner secname = "WHOA!!"; 430*479ab7f0SSascha Wildner break; 431*479ab7f0SSascha Wildner } 432*479ab7f0SSascha Wildner #endif 433*479ab7f0SSascha Wildner 434*479ab7f0SSascha Wildner size = shdr[i].sh_size; 435*479ab7f0SSascha Wildner archsw.arch_copyin(&size, lastaddr, sizeof(size)); 436*479ab7f0SSascha Wildner lastaddr += sizeof(size); 437*479ab7f0SSascha Wildner 438*479ab7f0SSascha Wildner #ifdef ELF_VERBOSE 439*479ab7f0SSascha Wildner printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname, 440*479ab7f0SSascha Wildner (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset, 441*479ab7f0SSascha Wildner (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size)); 442*479ab7f0SSascha Wildner #else 443*479ab7f0SSascha Wildner if (i == symstrindex) 444*479ab7f0SSascha Wildner printf("+"); 445*479ab7f0SSascha Wildner printf("0x%lx+0x%lx", (long)sizeof(size), (long)size); 446*479ab7f0SSascha Wildner #endif 447*479ab7f0SSascha Wildner 448*479ab7f0SSascha Wildner if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { 449*479ab7f0SSascha Wildner printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!"); 450*479ab7f0SSascha Wildner lastaddr = ssym; 451*479ab7f0SSascha Wildner ssym = 0; 452*479ab7f0SSascha Wildner goto nosyms; 453*479ab7f0SSascha Wildner } 454*479ab7f0SSascha Wildner result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size); 455*479ab7f0SSascha Wildner if (result < 0 || (size_t)result != shdr[i].sh_size) { 456*479ab7f0SSascha Wildner printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped!"); 457*479ab7f0SSascha Wildner lastaddr = ssym; 458*479ab7f0SSascha Wildner ssym = 0; 459*479ab7f0SSascha Wildner goto nosyms; 460*479ab7f0SSascha Wildner } 461*479ab7f0SSascha Wildner /* Reset offsets relative to ssym */ 462*479ab7f0SSascha Wildner lastaddr += shdr[i].sh_size; 463*479ab7f0SSascha Wildner lastaddr = roundup(lastaddr, sizeof(size)); 464*479ab7f0SSascha Wildner if (i == symtabindex) 465*479ab7f0SSascha Wildner symtabindex = -1; 466*479ab7f0SSascha Wildner else if (i == symstrindex) 467*479ab7f0SSascha Wildner symstrindex = -1; 468*479ab7f0SSascha Wildner } 469*479ab7f0SSascha Wildner esym = lastaddr; 470*479ab7f0SSascha Wildner #ifndef ELF_VERBOSE 471*479ab7f0SSascha Wildner printf("]"); 472*479ab7f0SSascha Wildner #endif 473*479ab7f0SSascha Wildner 474*479ab7f0SSascha Wildner file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym); 475*479ab7f0SSascha Wildner file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym); 476*479ab7f0SSascha Wildner 477*479ab7f0SSascha Wildner nosyms: 478*479ab7f0SSascha Wildner printf("\n"); 479*479ab7f0SSascha Wildner 480*479ab7f0SSascha Wildner ret = lastaddr - firstaddr; 481*479ab7f0SSascha Wildner fp->f_addr = firstaddr; 482*479ab7f0SSascha Wildner 483*479ab7f0SSascha Wildner php = NULL; 484*479ab7f0SSascha Wildner for (i = 0; i < ehdr->e_phnum; i++) { 485*479ab7f0SSascha Wildner if (phdr[i].p_type == PT_DYNAMIC) { 486*479ab7f0SSascha Wildner php = phdr + i; 487*479ab7f0SSascha Wildner adp = php->p_vaddr; 488*479ab7f0SSascha Wildner file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp); 489*479ab7f0SSascha Wildner break; 490*479ab7f0SSascha Wildner } 491*479ab7f0SSascha Wildner } 492*479ab7f0SSascha Wildner 493*479ab7f0SSascha Wildner if (php == NULL) /* this is bad, we cannot get to symbols or _DYNAMIC */ 494*479ab7f0SSascha Wildner goto out; 495*479ab7f0SSascha Wildner 496*479ab7f0SSascha Wildner ndp = php->p_filesz / sizeof(Elf_Dyn); 497*479ab7f0SSascha Wildner if (ndp == 0) 498*479ab7f0SSascha Wildner goto out; 499*479ab7f0SSascha Wildner dp = malloc(php->p_filesz); 500*479ab7f0SSascha Wildner if (dp == NULL) 501*479ab7f0SSascha Wildner goto out; 502*479ab7f0SSascha Wildner archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz); 503*479ab7f0SSascha Wildner 504*479ab7f0SSascha Wildner ef->strsz = 0; 505*479ab7f0SSascha Wildner for (i = 0; i < ndp; i++) { 506*479ab7f0SSascha Wildner if (dp[i].d_tag == 0) 507*479ab7f0SSascha Wildner break; 508*479ab7f0SSascha Wildner switch (dp[i].d_tag) { 509*479ab7f0SSascha Wildner case DT_HASH: 510*479ab7f0SSascha Wildner ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off); 511*479ab7f0SSascha Wildner break; 512*479ab7f0SSascha Wildner case DT_STRTAB: 513*479ab7f0SSascha Wildner ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off); 514*479ab7f0SSascha Wildner break; 515*479ab7f0SSascha Wildner case DT_STRSZ: 516*479ab7f0SSascha Wildner ef->strsz = dp[i].d_un.d_val; 517*479ab7f0SSascha Wildner break; 518*479ab7f0SSascha Wildner case DT_SYMTAB: 519*479ab7f0SSascha Wildner ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off); 520*479ab7f0SSascha Wildner break; 521*479ab7f0SSascha Wildner case DT_REL: 522*479ab7f0SSascha Wildner ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off); 523*479ab7f0SSascha Wildner break; 524*479ab7f0SSascha Wildner case DT_RELSZ: 525*479ab7f0SSascha Wildner ef->relsz = dp[i].d_un.d_val; 526*479ab7f0SSascha Wildner break; 527*479ab7f0SSascha Wildner case DT_RELA: 528*479ab7f0SSascha Wildner ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off); 529*479ab7f0SSascha Wildner break; 530*479ab7f0SSascha Wildner case DT_RELASZ: 531*479ab7f0SSascha Wildner ef->relasz = dp[i].d_un.d_val; 532*479ab7f0SSascha Wildner break; 533*479ab7f0SSascha Wildner default: 534*479ab7f0SSascha Wildner break; 535*479ab7f0SSascha Wildner } 536*479ab7f0SSascha Wildner } 537*479ab7f0SSascha Wildner if (ef->hashtab == NULL || ef->symtab == NULL || 538*479ab7f0SSascha Wildner ef->strtab == NULL || ef->strsz == 0) 539*479ab7f0SSascha Wildner goto out; 540*479ab7f0SSascha Wildner COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets)); 541*479ab7f0SSascha Wildner COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains)); 542*479ab7f0SSascha Wildner ef->buckets = ef->hashtab + 2; 543*479ab7f0SSascha Wildner ef->chains = ef->buckets + ef->nbuckets; 544*479ab7f0SSascha Wildner if (__elfN(parse_modmetadata)(fp, ef) == 0) 545*479ab7f0SSascha Wildner goto out; 546*479ab7f0SSascha Wildner 547*479ab7f0SSascha Wildner if (ef->kernel) /* kernel must not depend on anything */ 548*479ab7f0SSascha Wildner goto out; 549*479ab7f0SSascha Wildner 550*479ab7f0SSascha Wildner out: 551*479ab7f0SSascha Wildner if (dp) 552*479ab7f0SSascha Wildner free(dp); 553*479ab7f0SSascha Wildner if (shdr) 554*479ab7f0SSascha Wildner free(shdr); 555*479ab7f0SSascha Wildner return ret; 556*479ab7f0SSascha Wildner } 557*479ab7f0SSascha Wildner 558*479ab7f0SSascha Wildner static char invalid_name[] = "bad"; 559*479ab7f0SSascha Wildner 560*479ab7f0SSascha Wildner char * 561*479ab7f0SSascha Wildner fake_modname(const char *name) 562*479ab7f0SSascha Wildner { 563*479ab7f0SSascha Wildner const char *sp, *ep; 564*479ab7f0SSascha Wildner char *fp; 565*479ab7f0SSascha Wildner size_t len; 566*479ab7f0SSascha Wildner 567*479ab7f0SSascha Wildner sp = strrchr(name, '/'); 568*479ab7f0SSascha Wildner if (sp) 569*479ab7f0SSascha Wildner sp++; 570*479ab7f0SSascha Wildner else 571*479ab7f0SSascha Wildner sp = name; 572*479ab7f0SSascha Wildner ep = strrchr(name, '.'); 573*479ab7f0SSascha Wildner if (ep) { 574*479ab7f0SSascha Wildner if (ep == name) { 575*479ab7f0SSascha Wildner sp = invalid_name; 576*479ab7f0SSascha Wildner ep = invalid_name + sizeof(invalid_name) - 1; 577*479ab7f0SSascha Wildner } 578*479ab7f0SSascha Wildner } else 579*479ab7f0SSascha Wildner ep = name + strlen(name); 580*479ab7f0SSascha Wildner len = ep - sp; 581*479ab7f0SSascha Wildner fp = malloc(len + 1); 582*479ab7f0SSascha Wildner if (fp == NULL) 583*479ab7f0SSascha Wildner return NULL; 584*479ab7f0SSascha Wildner memcpy(fp, sp, len); 585*479ab7f0SSascha Wildner fp[len] = '\0'; 586*479ab7f0SSascha Wildner return fp; 587*479ab7f0SSascha Wildner } 588*479ab7f0SSascha Wildner 589*479ab7f0SSascha Wildner #if defined(__i386__) && __ELF_WORD_SIZE == 64 590*479ab7f0SSascha Wildner struct mod_metadata64 { 591*479ab7f0SSascha Wildner int md_version; /* structure version MDTV_* */ 592*479ab7f0SSascha Wildner int md_type; /* type of entry MDT_* */ 593*479ab7f0SSascha Wildner u_int64_t md_data; /* specific data */ 594*479ab7f0SSascha Wildner u_int64_t md_cval; /* common string label */ 595*479ab7f0SSascha Wildner }; 596*479ab7f0SSascha Wildner #endif 597*479ab7f0SSascha Wildner 598*479ab7f0SSascha Wildner int 599*479ab7f0SSascha Wildner __elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef) 600*479ab7f0SSascha Wildner { 601*479ab7f0SSascha Wildner struct mod_metadata md; 602*479ab7f0SSascha Wildner #if defined(__i386__) && __ELF_WORD_SIZE == 64 603*479ab7f0SSascha Wildner struct mod_metadata64 md64; 604*479ab7f0SSascha Wildner #endif 605*479ab7f0SSascha Wildner struct mod_depend *mdepend; 606*479ab7f0SSascha Wildner struct mod_version mver; 607*479ab7f0SSascha Wildner Elf_Sym sym; 608*479ab7f0SSascha Wildner char *s; 609*479ab7f0SSascha Wildner int error, modcnt, minfolen; 610*479ab7f0SSascha Wildner Elf_Addr v, p, p_stop; 611*479ab7f0SSascha Wildner 612*479ab7f0SSascha Wildner if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0) 613*479ab7f0SSascha Wildner return ENOENT; 614*479ab7f0SSascha Wildner p = sym.st_value + ef->off; 615*479ab7f0SSascha Wildner if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0) 616*479ab7f0SSascha Wildner return ENOENT; 617*479ab7f0SSascha Wildner p_stop = sym.st_value + ef->off; 618*479ab7f0SSascha Wildner 619*479ab7f0SSascha Wildner modcnt = 0; 620*479ab7f0SSascha Wildner while (p < p_stop) { 621*479ab7f0SSascha Wildner COPYOUT(p, &v, sizeof(v)); 622*479ab7f0SSascha Wildner error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v)); 623*479ab7f0SSascha Wildner if (error == EOPNOTSUPP) 624*479ab7f0SSascha Wildner v += ef->off; 625*479ab7f0SSascha Wildner else if (error != 0) 626*479ab7f0SSascha Wildner return (error); 627*479ab7f0SSascha Wildner #if defined(__i386__) && __ELF_WORD_SIZE == 64 628*479ab7f0SSascha Wildner COPYOUT(v, &md64, sizeof(md64)); 629*479ab7f0SSascha Wildner error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof(md64)); 630*479ab7f0SSascha Wildner if (error == EOPNOTSUPP) { 631*479ab7f0SSascha Wildner md64.md_cval += ef->off; 632*479ab7f0SSascha Wildner md64.md_data += ef->off; 633*479ab7f0SSascha Wildner } else if (error != 0) 634*479ab7f0SSascha Wildner return (error); 635*479ab7f0SSascha Wildner md.md_version = md64.md_version; 636*479ab7f0SSascha Wildner md.md_type = md64.md_type; 637*479ab7f0SSascha Wildner md.md_cval = (const char *)(uintptr_t)md64.md_cval; 638*479ab7f0SSascha Wildner md.md_data = (void *)(uintptr_t)md64.md_data; 639*479ab7f0SSascha Wildner #else 640*479ab7f0SSascha Wildner COPYOUT(v, &md, sizeof(md)); 641*479ab7f0SSascha Wildner error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md)); 642*479ab7f0SSascha Wildner if (error == EOPNOTSUPP) { 643*479ab7f0SSascha Wildner md.md_cval += ef->off; 644*479ab7f0SSascha Wildner md.md_data = (char *)md.md_data + ef->off; 645*479ab7f0SSascha Wildner } else if (error != 0) 646*479ab7f0SSascha Wildner return (error); 647*479ab7f0SSascha Wildner #endif 648*479ab7f0SSascha Wildner p += sizeof(Elf_Addr); 649*479ab7f0SSascha Wildner switch(md.md_type) { 650*479ab7f0SSascha Wildner case MDT_DEPEND: 651*479ab7f0SSascha Wildner if (ef->kernel) /* kernel must not depend on anything */ 652*479ab7f0SSascha Wildner break; 653*479ab7f0SSascha Wildner s = strdupout((vm_offset_t)md.md_cval); 654*479ab7f0SSascha Wildner minfolen = sizeof(*mdepend) + strlen(s) + 1; 655*479ab7f0SSascha Wildner mdepend = malloc(minfolen); 656*479ab7f0SSascha Wildner if (mdepend == NULL) 657*479ab7f0SSascha Wildner return ENOMEM; 658*479ab7f0SSascha Wildner COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend)); 659*479ab7f0SSascha Wildner strcpy((char*)(mdepend + 1), s); 660*479ab7f0SSascha Wildner free(s); 661*479ab7f0SSascha Wildner file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend); 662*479ab7f0SSascha Wildner free(mdepend); 663*479ab7f0SSascha Wildner break; 664*479ab7f0SSascha Wildner case MDT_VERSION: 665*479ab7f0SSascha Wildner s = strdupout((vm_offset_t)md.md_cval); 666*479ab7f0SSascha Wildner COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); 667*479ab7f0SSascha Wildner file_addmodule(fp, s, mver.mv_version, NULL); 668*479ab7f0SSascha Wildner free(s); 669*479ab7f0SSascha Wildner modcnt++; 670*479ab7f0SSascha Wildner break; 671*479ab7f0SSascha Wildner } 672*479ab7f0SSascha Wildner } 673*479ab7f0SSascha Wildner if (modcnt == 0) { 674*479ab7f0SSascha Wildner s = fake_modname(fp->f_name); 675*479ab7f0SSascha Wildner file_addmodule(fp, s, 1, NULL); 676*479ab7f0SSascha Wildner free(s); 677*479ab7f0SSascha Wildner } 678*479ab7f0SSascha Wildner return 0; 679*479ab7f0SSascha Wildner } 680*479ab7f0SSascha Wildner 681*479ab7f0SSascha Wildner static unsigned long 682*479ab7f0SSascha Wildner elf_hash(const char *name) 683*479ab7f0SSascha Wildner { 684*479ab7f0SSascha Wildner const unsigned char *p = (const unsigned char *) name; 685*479ab7f0SSascha Wildner unsigned long h = 0; 686*479ab7f0SSascha Wildner unsigned long g; 687*479ab7f0SSascha Wildner 688*479ab7f0SSascha Wildner while (*p != '\0') { 689*479ab7f0SSascha Wildner h = (h << 4) + *p++; 690*479ab7f0SSascha Wildner if ((g = h & 0xf0000000) != 0) 691*479ab7f0SSascha Wildner h ^= g >> 24; 692*479ab7f0SSascha Wildner h &= ~g; 693*479ab7f0SSascha Wildner } 694*479ab7f0SSascha Wildner return h; 695*479ab7f0SSascha Wildner } 696*479ab7f0SSascha Wildner 697*479ab7f0SSascha Wildner static const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE) "_lookup_symbol: corrupt symbol table\n"; 698*479ab7f0SSascha Wildner int 699*479ab7f0SSascha Wildner __elfN(lookup_symbol)(struct preloaded_file *fp, elf_file_t ef, const char* name, 700*479ab7f0SSascha Wildner Elf_Sym *symp) 701*479ab7f0SSascha Wildner { 702*479ab7f0SSascha Wildner Elf_Hashelt symnum; 703*479ab7f0SSascha Wildner Elf_Sym sym; 704*479ab7f0SSascha Wildner char *strp; 705*479ab7f0SSascha Wildner unsigned long hash; 706*479ab7f0SSascha Wildner 707*479ab7f0SSascha Wildner hash = elf_hash(name); 708*479ab7f0SSascha Wildner COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum)); 709*479ab7f0SSascha Wildner 710*479ab7f0SSascha Wildner while (symnum != STN_UNDEF) { 711*479ab7f0SSascha Wildner if (symnum >= ef->nchains) { 712*479ab7f0SSascha Wildner printf(__elfN(bad_symtable)); 713*479ab7f0SSascha Wildner return ENOENT; 714*479ab7f0SSascha Wildner } 715*479ab7f0SSascha Wildner 716*479ab7f0SSascha Wildner COPYOUT(ef->symtab + symnum, &sym, sizeof(sym)); 717*479ab7f0SSascha Wildner if (sym.st_name == 0) { 718*479ab7f0SSascha Wildner printf(__elfN(bad_symtable)); 719*479ab7f0SSascha Wildner return ENOENT; 720*479ab7f0SSascha Wildner } 721*479ab7f0SSascha Wildner 722*479ab7f0SSascha Wildner strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name)); 723*479ab7f0SSascha Wildner if (strcmp(name, strp) == 0) { 724*479ab7f0SSascha Wildner free(strp); 725*479ab7f0SSascha Wildner if (sym.st_shndx != SHN_UNDEF || 726*479ab7f0SSascha Wildner (sym.st_value != 0 && 727*479ab7f0SSascha Wildner ELF_ST_TYPE(sym.st_info) == STT_FUNC)) { 728*479ab7f0SSascha Wildner *symp = sym; 729*479ab7f0SSascha Wildner return 0; 730*479ab7f0SSascha Wildner } 731*479ab7f0SSascha Wildner return ENOENT; 732*479ab7f0SSascha Wildner } 733*479ab7f0SSascha Wildner free(strp); 734*479ab7f0SSascha Wildner COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum)); 735*479ab7f0SSascha Wildner } 736*479ab7f0SSascha Wildner return ENOENT; 737*479ab7f0SSascha Wildner } 738*479ab7f0SSascha Wildner 739*479ab7f0SSascha Wildner /* 740*479ab7f0SSascha Wildner * Apply any intra-module relocations to the value. p is the load address 741*479ab7f0SSascha Wildner * of the value and val/len is the value to be modified. This does NOT modify 742*479ab7f0SSascha Wildner * the image in-place, because this is done by kern_linker later on. 743*479ab7f0SSascha Wildner * 744*479ab7f0SSascha Wildner * Returns EOPNOTSUPP if no relocation method is supplied. 745*479ab7f0SSascha Wildner */ 746*479ab7f0SSascha Wildner static int 747*479ab7f0SSascha Wildner __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, 748*479ab7f0SSascha Wildner Elf_Addr p, void *val, size_t len) 749*479ab7f0SSascha Wildner { 750*479ab7f0SSascha Wildner size_t n; 751*479ab7f0SSascha Wildner Elf_Rela a; 752*479ab7f0SSascha Wildner Elf_Rel r; 753*479ab7f0SSascha Wildner int error; 754*479ab7f0SSascha Wildner 755*479ab7f0SSascha Wildner /* 756*479ab7f0SSascha Wildner * The kernel is already relocated, but we still want to apply 757*479ab7f0SSascha Wildner * offset adjustments. 758*479ab7f0SSascha Wildner */ 759*479ab7f0SSascha Wildner if (ef->kernel) 760*479ab7f0SSascha Wildner return (EOPNOTSUPP); 761*479ab7f0SSascha Wildner 762*479ab7f0SSascha Wildner for (n = 0; n < ef->relsz / sizeof(r); n++) { 763*479ab7f0SSascha Wildner COPYOUT(ef->rel + n, &r, sizeof(r)); 764*479ab7f0SSascha Wildner 765*479ab7f0SSascha Wildner error = __elfN(reloc)(ef, __elfN(symaddr), &r, ELF_RELOC_REL, 766*479ab7f0SSascha Wildner ef->off, p, val, len); 767*479ab7f0SSascha Wildner if (error != 0) 768*479ab7f0SSascha Wildner return (error); 769*479ab7f0SSascha Wildner } 770*479ab7f0SSascha Wildner for (n = 0; n < ef->relasz / sizeof(a); n++) { 771*479ab7f0SSascha Wildner COPYOUT(ef->rela + n, &a, sizeof(a)); 772*479ab7f0SSascha Wildner 773*479ab7f0SSascha Wildner error = __elfN(reloc)(ef, __elfN(symaddr), &a, ELF_RELOC_RELA, 774*479ab7f0SSascha Wildner ef->off, p, val, len); 775*479ab7f0SSascha Wildner if (error != 0) 776*479ab7f0SSascha Wildner return (error); 777*479ab7f0SSascha Wildner } 778*479ab7f0SSascha Wildner 779*479ab7f0SSascha Wildner return (0); 780*479ab7f0SSascha Wildner } 781*479ab7f0SSascha Wildner 782*479ab7f0SSascha Wildner static Elf_Addr 783*479ab7f0SSascha Wildner __elfN(symaddr)(struct elf_file *ef, Elf_Size symidx) 784*479ab7f0SSascha Wildner { 785*479ab7f0SSascha Wildner 786*479ab7f0SSascha Wildner /* Symbol lookup by index not required here. */ 787*479ab7f0SSascha Wildner return (0); 788*479ab7f0SSascha Wildner } 789