load_elf.c revision 248121
139830Speter/*- 239830Speter * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 339830Speter * Copyright (c) 1998 Peter Wemm <peter@freebsd.org> 439830Speter * All rights reserved. 539830Speter * 639830Speter * Redistribution and use in source and binary forms, with or without 739830Speter * modification, are permitted provided that the following conditions 839830Speter * are met: 939830Speter * 1. Redistributions of source code must retain the above copyright 1039830Speter * notice, this list of conditions and the following disclaimer. 1139830Speter * 2. Redistributions in binary form must reproduce the above copyright 1239830Speter * notice, this list of conditions and the following disclaimer in the 1339830Speter * documentation and/or other materials provided with the distribution. 1439830Speter * 1539830Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1639830Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1739830Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1839830Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1939830Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2039830Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2139830Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2239830Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2339830Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2439830Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2539830Speter * SUCH DAMAGE. 2639830Speter */ 2739830Speter 28119483Sobrien#include <sys/cdefs.h> 29119483Sobrien__FBSDID("$FreeBSD: head/sys/boot/common/load_elf.c 248121 2013-03-10 00:43:01Z ian $"); 30119483Sobrien 3139830Speter#include <sys/param.h> 3239830Speter#include <sys/exec.h> 3340143Speter#include <sys/linker.h> 3459854Sbp#include <sys/module.h> 35163917Sru#include <sys/stdint.h> 3639830Speter#include <string.h> 3739830Speter#include <machine/elf.h> 3839830Speter#include <stand.h> 3939830Speter#define FREEBSD_ELF 4039830Speter#include <link.h> 4139830Speter 4239830Speter#include "bootstrap.h" 4339830Speter 4459854Sbp#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) 4539830Speter 46114379Speter#if defined(__i386__) && __ELF_WORD_SIZE == 64 47114379Speter#undef ELF_TARG_CLASS 48114379Speter#undef ELF_TARG_MACH 49114379Speter#define ELF_TARG_CLASS ELFCLASS64 50114379Speter#define ELF_TARG_MACH EM_X86_64 51114379Speter#endif 5259854Sbp 5359854Sbptypedef struct elf_file { 5459854Sbp Elf_Phdr *ph; 5559854Sbp Elf_Ehdr *ehdr; 5659854Sbp Elf_Sym *symtab; 5793922Speter Elf_Hashelt *hashtab; 5893922Speter Elf_Hashelt nbuckets; 5993922Speter Elf_Hashelt nchains; 6093922Speter Elf_Hashelt *buckets; 6193922Speter Elf_Hashelt *chains; 62134458Siedowse Elf_Rel *rel; 63134458Siedowse size_t relsz; 64109616Sjake Elf_Rela *rela; 65109616Sjake size_t relasz; 6659854Sbp char *strtab; 6759854Sbp size_t strsz; 6859854Sbp int fd; 6959854Sbp caddr_t firstpage; 7064187Sjhb size_t firstlen; 7159854Sbp int kernel; 72114379Speter u_int64_t off; 7359854Sbp} *elf_file_t; 7459854Sbp 75114379Speterstatic int __elfN(loadimage)(struct preloaded_file *mp, elf_file_t ef, u_int64_t loadaddr); 76114379Speterstatic int __elfN(lookup_symbol)(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym); 77134458Siedowsestatic int __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, 78134458Siedowse Elf_Addr p, void *val, size_t len); 79114379Speterstatic int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef); 80134458Siedowsestatic symaddr_fn __elfN(symaddr); 8164187Sjhbstatic char *fake_modname(const char *name); 8259854Sbp 83114379Speterconst char *__elfN(kerneltype) = "elf kernel"; 84114379Speterconst char *__elfN(moduletype) = "elf module"; 8539830Speter 86176484Smarcelu_int64_t __elfN(relocation_offset) = 0; 87176484Smarcel 8839830Speter/* 8939830Speter * Attempt to load the file (file) as an ELF module. It will be stored at 9039830Speter * (dest), and a pointer to a module structure describing the loaded object 9139830Speter * will be saved in (result). 9239830Speter */ 9339830Speterint 94114379Speter__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) 9539830Speter{ 9659854Sbp struct preloaded_file *fp, *kfp; 9759854Sbp struct elf_file ef; 9859854Sbp Elf_Ehdr *ehdr; 9959854Sbp int err; 10064187Sjhb ssize_t bytes_read; 10139830Speter 10259854Sbp fp = NULL; 10359854Sbp bzero(&ef, sizeof(struct elf_file)); 104176484Smarcel 10539830Speter /* 10639830Speter * Open the image, read and validate the ELF header 10739830Speter */ 10839830Speter if (filename == NULL) /* can't handle nameless */ 10939830Speter return(EFTYPE); 11059854Sbp if ((ef.fd = open(filename, O_RDONLY)) == -1) 11139830Speter return(errno); 11259854Sbp ef.firstpage = malloc(PAGE_SIZE); 11359854Sbp if (ef.firstpage == NULL) { 11459854Sbp close(ef.fd); 11540465Speter return(ENOMEM); 11659854Sbp } 11764187Sjhb bytes_read = read(ef.fd, ef.firstpage, PAGE_SIZE); 11864187Sjhb ef.firstlen = (size_t)bytes_read; 11964187Sjhb if (bytes_read < 0 || ef.firstlen <= sizeof(Elf_Ehdr)) { 12039830Speter err = EFTYPE; /* could be EIO, but may be small file */ 12139830Speter goto oerr; 12239830Speter } 12359854Sbp ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage; 12439830Speter 12539830Speter /* Is it ELF? */ 12640465Speter if (!IS_ELF(*ehdr)) { 12739830Speter err = EFTYPE; 12839830Speter goto oerr; 12939830Speter } 13040465Speter if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ 13140465Speter ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || 13240465Speter ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ 13340465Speter ehdr->e_version != EV_CURRENT || 13440465Speter ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ 13539830Speter err = EFTYPE; 13639830Speter goto oerr; 13739830Speter } 13839830Speter 13939830Speter 14039830Speter /* 14139830Speter * Check to see what sort of module we are. 14239830Speter */ 14359854Sbp kfp = file_findfile(NULL, NULL); 14440465Speter if (ehdr->e_type == ET_DYN) { 14539830Speter /* Looks like a kld module */ 14659854Sbp if (kfp == NULL) { 147114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n"); 14839830Speter err = EPERM; 14939830Speter goto oerr; 15039830Speter } 151114379Speter if (strcmp(__elfN(kerneltype), kfp->f_type)) { 152114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); 15339830Speter err = EPERM; 15439830Speter goto oerr; 15539830Speter } 15639830Speter /* Looks OK, got ahead */ 15759854Sbp ef.kernel = 0; 15839830Speter 15940465Speter } else if (ehdr->e_type == ET_EXEC) { 16039830Speter /* Looks like a kernel */ 16159854Sbp if (kfp != NULL) { 162114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n"); 16339830Speter err = EPERM; 16439830Speter goto oerr; 16539830Speter } 16639830Speter /* 16739830Speter * Calculate destination address based on kernel entrypoint 16839830Speter */ 169220311Smarcel dest = (ehdr->e_entry & ~PAGE_MASK); 17039830Speter if (dest == 0) { 171114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); 17239830Speter err = EPERM; 17339830Speter goto oerr; 17439830Speter } 17559854Sbp ef.kernel = 1; 17639830Speter 17739830Speter } else { 17839830Speter err = EFTYPE; 17939830Speter goto oerr; 18039830Speter } 18139830Speter 182220311Smarcel if (archsw.arch_loadaddr != NULL) 183220311Smarcel dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); 184220311Smarcel else 185220311Smarcel dest = roundup(dest, PAGE_SIZE); 186220311Smarcel 18739830Speter /* 18839830Speter * Ok, we think we should handle this. 18939830Speter */ 19059854Sbp fp = file_alloc(); 19159854Sbp if (fp == NULL) { 192114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n"); 19340143Speter err = EPERM; 19440143Speter goto out; 19540143Speter } 19659854Sbp if (ef.kernel) 19740143Speter setenv("kernelname", filename, 1); 19883321Speter fp->f_name = strdup(filename); 199114379Speter fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype)); 20039830Speter 20140291Speter#ifdef ELF_VERBOSE 20259854Sbp if (ef.kernel) 203220311Smarcel printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry); 20440327Speter#else 20540327Speter printf("%s ", filename); 20640291Speter#endif 20739830Speter 208114379Speter fp->f_size = __elfN(loadimage)(fp, &ef, dest); 20959854Sbp if (fp->f_size == 0 || fp->f_addr == 0) 21039830Speter goto ioerr; 21139830Speter 21239830Speter /* save exec header as metadata */ 21359854Sbp file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); 21439830Speter 21539830Speter /* Load OK, return module pointer */ 21659854Sbp *result = (struct preloaded_file *)fp; 21739830Speter err = 0; 21839830Speter goto out; 21939830Speter 22039830Speter ioerr: 22139830Speter err = EIO; 22239830Speter oerr: 22359854Sbp file_discard(fp); 22439830Speter out: 22559854Sbp if (ef.firstpage) 22659854Sbp free(ef.firstpage); 22759854Sbp close(ef.fd); 22839830Speter return(err); 22939830Speter} 23039830Speter 23139830Speter/* 23239830Speter * With the file (fd) open on the image, and (ehdr) containing 23340143Speter * the Elf header, load the image at (off) 23439830Speter */ 23539830Speterstatic int 236114379Speter__elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) 23739830Speter{ 23864187Sjhb int i; 23964187Sjhb u_int j; 24059854Sbp Elf_Ehdr *ehdr; 24159854Sbp Elf_Phdr *phdr, *php; 24239887Speter Elf_Shdr *shdr; 24339830Speter int ret; 24439830Speter vm_offset_t firstaddr; 24539830Speter vm_offset_t lastaddr; 246134441Siedowse size_t chunk; 24764187Sjhb ssize_t result; 248114379Speter Elf_Addr ssym, esym; 24940143Speter Elf_Dyn *dp; 250114379Speter Elf_Addr adp; 25140143Speter int ndp; 25240254Speter int symstrindex; 25340254Speter int symtabindex; 254114379Speter Elf_Size size; 25564187Sjhb u_int fpcopy; 25639830Speter 25740143Speter dp = NULL; 25840143Speter shdr = NULL; 25939830Speter ret = 0; 26039830Speter firstaddr = lastaddr = 0; 26159854Sbp ehdr = ef->ehdr; 26259854Sbp if (ef->kernel) { 263223695Sdfr#if defined(__i386__) || defined(__amd64__) 264114379Speter#if __ELF_WORD_SIZE == 64 265114379Speter off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */ 266114379Speter#else 267163914Sru off = - (off & 0xff000000u); /* i386 relocates after locore */ 268114379Speter#endif 269176484Smarcel#elif defined(__powerpc__) 270176484Smarcel /* 271176484Smarcel * On the purely virtual memory machines like e500, the kernel is 272176484Smarcel * linked against its final VA range, which is most often not 273176484Smarcel * available at the loader stage, but only after kernel initializes 274176484Smarcel * and completes its VM settings. In such cases we cannot use p_vaddr 275176484Smarcel * field directly to load ELF segments, but put them at some 276176484Smarcel * 'load-time' locations. 277176484Smarcel */ 278176484Smarcel if (off & 0xf0000000u) { 279176484Smarcel off = -(off & 0xf0000000u); 280176484Smarcel /* 281176484Smarcel * XXX the physical load address should not be hardcoded. Note 282176484Smarcel * that the Book-E kernel assumes that it's loaded at a 16MB 283176484Smarcel * boundary for now... 284176484Smarcel */ 285176484Smarcel off += 0x01000000; 286176484Smarcel ehdr->e_entry += off; 287176484Smarcel#ifdef ELF_VERBOSE 288176484Smarcel printf("Converted entry 0x%08x\n", ehdr->e_entry); 289176484Smarcel#endif 290183878Sraj } else 291176484Smarcel off = 0; 292183878Sraj#elif defined(__arm__) 293247301Sian /* 294247301Sian * The elf headers in some kernels specify virtual addresses in all 295247301Sian * header fields. More recently, the e_entry and p_paddr fields are the 296247301Sian * proper physical addresses. Even when the p_paddr fields are correct, 297247301Sian * the MI code below uses the p_vaddr fields with an offset added for 298247301Sian * loading (doing so is arguably wrong). To make loading work, we need 299247301Sian * an offset that represents the difference between physical and virtual 300248118Sian * addressing. ARM kernels are always linked at 0xCnnnnnnn. Depending 301247301Sian * on the headers, the offset value passed in may be physical or virtual 302247301Sian * (because it typically comes from e_entry), but we always replace 303247301Sian * whatever is passed in with the va<->pa offset. On the other hand, we 304248118Sian * always remove the high-order part of the entry address whether it's 305248118Sian * physical or virtual, because it will be adjusted later for the actual 306248118Sian * physical entry point based on where the image gets loaded. 307247301Sian */ 308248118Sian off = -0xc0000000; 309248118Sian ehdr->e_entry &= ~0xf0000000; 310183878Sraj#ifdef ELF_VERBOSE 311247301Sian printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off); 312183878Sraj#endif 31339830Speter#else 314158467Sjhb off = 0; /* other archs use direct mapped kernels */ 31539830Speter#endif 316176484Smarcel __elfN(relocation_offset) = off; 31740143Speter } 31859854Sbp ef->off = off; 31939830Speter 32059854Sbp if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { 321114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n"); 32240465Speter goto out; 32340465Speter } 32459854Sbp phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff); 32540465Speter 32639830Speter for (i = 0; i < ehdr->e_phnum; i++) { 32739830Speter /* We want to load PT_LOAD segments only.. */ 32839830Speter if (phdr[i].p_type != PT_LOAD) 32939830Speter continue; 33039830Speter 33140254Speter#ifdef ELF_VERBOSE 33239887Speter printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", 33339830Speter (long)phdr[i].p_filesz, (long)phdr[i].p_offset, 33439830Speter (long)(phdr[i].p_vaddr + off), 33539887Speter (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 33640254Speter#else 33740291Speter if ((phdr[i].p_flags & PF_W) == 0) { 33840291Speter printf("text=0x%lx ", (long)phdr[i].p_filesz); 33940291Speter } else { 34040291Speter printf("data=0x%lx", (long)phdr[i].p_filesz); 34140291Speter if (phdr[i].p_filesz < phdr[i].p_memsz) 34240291Speter printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz)); 34340291Speter printf(" "); 34440291Speter } 34540254Speter#endif 34640465Speter fpcopy = 0; 34759854Sbp if (ef->firstlen > phdr[i].p_offset) { 34859854Sbp fpcopy = ef->firstlen - phdr[i].p_offset; 34959854Sbp archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, 35040465Speter phdr[i].p_vaddr + off, fpcopy); 35139830Speter } 35240465Speter if (phdr[i].p_filesz > fpcopy) { 353134441Siedowse if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy, 354134441Siedowse phdr[i].p_filesz - fpcopy, phdr[i].p_offset + fpcopy) != 0) { 355134441Siedowse printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 356134441Siedowse "_loadimage: read failed\n"); 35740465Speter goto out; 35840465Speter } 35939830Speter } 36039830Speter /* clear space from oversized segments; eg: bss */ 36139830Speter if (phdr[i].p_filesz < phdr[i].p_memsz) { 36240254Speter#ifdef ELF_VERBOSE 36339887Speter printf(" (bss: 0x%lx-0x%lx)", 36439830Speter (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz), 36539830Speter (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 36640254Speter#endif 36739830Speter 368134441Siedowse kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz, 369134441Siedowse phdr[i].p_memsz - phdr[i].p_filesz); 37039830Speter } 37140254Speter#ifdef ELF_VERBOSE 37239887Speter printf("\n"); 37340254Speter#endif 37439830Speter 375220311Smarcel if (archsw.arch_loadseg != NULL) 376220311Smarcel archsw.arch_loadseg(ehdr, phdr + i, off); 377220311Smarcel 37840143Speter if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) 37939830Speter firstaddr = phdr[i].p_vaddr + off; 38040143Speter if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) 38139830Speter lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz; 38239830Speter } 38340254Speter lastaddr = roundup(lastaddr, sizeof(long)); 38439830Speter 38539887Speter /* 38639887Speter * Now grab the symbol tables. This isn't easy if we're reading a 38739887Speter * .gz file. I think the rule is going to have to be that you must 38839887Speter * strip a file to remove symbols before gzipping it so that we do not 38940254Speter * try to lseek() on it. 39039887Speter */ 39139887Speter chunk = ehdr->e_shnum * ehdr->e_shentsize; 39240291Speter if (chunk == 0 || ehdr->e_shoff == 0) 39340291Speter goto nosyms; 394134441Siedowse shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk); 395134441Siedowse if (shdr == NULL) { 396134441Siedowse printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 397134441Siedowse "_loadimage: failed to read section headers"); 39839887Speter goto nosyms; 39939887Speter } 400248121Sian file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr); 401248121Sian 40240254Speter symtabindex = -1; 40340254Speter symstrindex = -1; 40439887Speter for (i = 0; i < ehdr->e_shnum; i++) { 40540254Speter if (shdr[i].sh_type != SHT_SYMTAB) 40640143Speter continue; 40739887Speter for (j = 0; j < ehdr->e_phnum; j++) { 40839887Speter if (phdr[j].p_type != PT_LOAD) 40939887Speter continue; 41039887Speter if (shdr[i].sh_offset >= phdr[j].p_offset && 41139887Speter (shdr[i].sh_offset + shdr[i].sh_size <= 41239887Speter phdr[j].p_offset + phdr[j].p_filesz)) { 41339887Speter shdr[i].sh_offset = 0; 41439887Speter shdr[i].sh_size = 0; 41539887Speter break; 41639887Speter } 41739887Speter } 41839887Speter if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0) 41939887Speter continue; /* alread loaded in a PT_LOAD above */ 42040254Speter /* Save it for loading below */ 42140254Speter symtabindex = i; 42240254Speter symstrindex = shdr[i].sh_link; 42340254Speter } 42440254Speter if (symtabindex < 0 || symstrindex < 0) 42540254Speter goto nosyms; 42639887Speter 42740254Speter /* Ok, committed to a load. */ 42840254Speter#ifndef ELF_VERBOSE 42940291Speter printf("syms=["); 43040254Speter#endif 43140254Speter ssym = lastaddr; 43240254Speter for (i = symtabindex; i >= 0; i = symstrindex) { 43340254Speter#ifdef ELF_VERBOSE 43440254Speter char *secname; 43540254Speter 43640254Speter switch(shdr[i].sh_type) { 43740254Speter case SHT_SYMTAB: /* Symbol table */ 43840254Speter secname = "symtab"; 43940254Speter break; 44040254Speter case SHT_STRTAB: /* String table */ 44140254Speter secname = "strtab"; 44240254Speter break; 44340254Speter default: 44440254Speter secname = "WHOA!!"; 44540254Speter break; 44640254Speter } 44740254Speter#endif 44840254Speter 44940254Speter size = shdr[i].sh_size; 45040254Speter archsw.arch_copyin(&size, lastaddr, sizeof(size)); 451114379Speter lastaddr += sizeof(size); 45240254Speter 45340254Speter#ifdef ELF_VERBOSE 454163917Sru printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname, 455163917Sru (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset, 456163917Sru (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size)); 45740254Speter#else 45840291Speter if (i == symstrindex) 45940291Speter printf("+"); 460114379Speter printf("0x%lx+0x%lx", (long)sizeof(size), (long)size); 46140254Speter#endif 46240254Speter 46364187Sjhb if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { 464114379Speter printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!"); 46540254Speter lastaddr = ssym; 46640254Speter ssym = 0; 46740254Speter goto nosyms; 46839887Speter } 46964187Sjhb result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size); 47064187Sjhb if (result < 0 || (size_t)result != shdr[i].sh_size) { 471215811Semaste printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! (%ju != %ju)", (uintmax_t)result, 472215758Sattilio (uintmax_t)shdr[i].sh_size); 47340254Speter lastaddr = ssym; 47440254Speter ssym = 0; 47540254Speter goto nosyms; 47639887Speter } 47739887Speter /* Reset offsets relative to ssym */ 47839887Speter lastaddr += shdr[i].sh_size; 479114379Speter lastaddr = roundup(lastaddr, sizeof(size)); 48040254Speter if (i == symtabindex) 48140254Speter symtabindex = -1; 48240254Speter else if (i == symstrindex) 48340254Speter symstrindex = -1; 48439887Speter } 48539887Speter esym = lastaddr; 48640254Speter#ifndef ELF_VERBOSE 48742288Speter printf("]"); 48840254Speter#endif 48939887Speter 49059854Sbp file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym); 49159854Sbp file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym); 49239887Speter 49339887Speternosyms: 49442288Speter printf("\n"); 49539887Speter 49639830Speter ret = lastaddr - firstaddr; 49759854Sbp fp->f_addr = firstaddr; 49840143Speter 49959854Sbp php = NULL; 50040143Speter for (i = 0; i < ehdr->e_phnum; i++) { 50140143Speter if (phdr[i].p_type == PT_DYNAMIC) { 50259854Sbp php = phdr + i; 503114379Speter adp = php->p_vaddr; 504114379Speter file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp); 50540143Speter break; 50640143Speter } 50740143Speter } 50840143Speter 50959854Sbp if (php == NULL) /* this is bad, we cannot get to symbols or _DYNAMIC */ 51040143Speter goto out; 51140143Speter 51259854Sbp ndp = php->p_filesz / sizeof(Elf_Dyn); 51359854Sbp if (ndp == 0) 51440143Speter goto out; 51559854Sbp dp = malloc(php->p_filesz); 51659854Sbp if (dp == NULL) 51759854Sbp goto out; 51859854Sbp archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz); 51959854Sbp 52059854Sbp ef->strsz = 0; 52140143Speter for (i = 0; i < ndp; i++) { 522126837Sbde if (dp[i].d_tag == 0) 52340143Speter break; 52440143Speter switch (dp[i].d_tag) { 52559854Sbp case DT_HASH: 526114379Speter ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off); 52759854Sbp break; 52840143Speter case DT_STRTAB: 529114379Speter ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off); 53040143Speter break; 53140143Speter case DT_STRSZ: 53259854Sbp ef->strsz = dp[i].d_un.d_val; 53340143Speter break; 53459854Sbp case DT_SYMTAB: 535114379Speter ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off); 53659854Sbp break; 537134458Siedowse case DT_REL: 538134458Siedowse ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off); 539134458Siedowse break; 540134458Siedowse case DT_RELSZ: 541134458Siedowse ef->relsz = dp[i].d_un.d_val; 542134458Siedowse break; 543109616Sjake case DT_RELA: 544114379Speter ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off); 545109616Sjake break; 546109616Sjake case DT_RELASZ: 547109616Sjake ef->relasz = dp[i].d_un.d_val; 548109616Sjake break; 54940143Speter default: 55040143Speter break; 55140143Speter } 55240143Speter } 55359854Sbp if (ef->hashtab == NULL || ef->symtab == NULL || 55459854Sbp ef->strtab == NULL || ef->strsz == 0) 55540143Speter goto out; 55659854Sbp COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets)); 55759854Sbp COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains)); 55859854Sbp ef->buckets = ef->hashtab + 2; 55959854Sbp ef->chains = ef->buckets + ef->nbuckets; 560114379Speter if (__elfN(parse_modmetadata)(fp, ef) == 0) 56159854Sbp goto out; 56240143Speter 56359854Sbp if (ef->kernel) /* kernel must not depend on anything */ 56459854Sbp goto out; 56559854Sbp 56639830Speterout: 56740143Speter if (dp) 56840143Speter free(dp); 56940143Speter if (shdr) 57040143Speter free(shdr); 57139830Speter return ret; 57239830Speter} 57359854Sbp 57459854Sbpstatic char invalid_name[] = "bad"; 57583321Speter 57659854Sbpchar * 57778463Speterfake_modname(const char *name) 57878463Speter{ 57978696Sdwmalone const char *sp, *ep; 58078696Sdwmalone char *fp; 58164187Sjhb size_t len; 58259854Sbp 58359854Sbp sp = strrchr(name, '/'); 58459854Sbp if (sp) 58559854Sbp sp++; 58659854Sbp else 58759854Sbp sp = name; 58859854Sbp ep = strrchr(name, '.'); 58959854Sbp if (ep) { 59059854Sbp if (ep == name) { 59159854Sbp sp = invalid_name; 59259854Sbp ep = invalid_name + sizeof(invalid_name) - 1; 59359854Sbp } 59459854Sbp } else 59559854Sbp ep = name + strlen(name); 59659854Sbp len = ep - sp; 59778696Sdwmalone fp = malloc(len + 1); 59878696Sdwmalone if (fp == NULL) 59959854Sbp return NULL; 60078696Sdwmalone memcpy(fp, sp, len); 60178696Sdwmalone fp[len] = '\0'; 60278696Sdwmalone return fp; 60359854Sbp} 60459854Sbp 605240249Sandreast#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 606114937Speterstruct mod_metadata64 { 607114937Speter int md_version; /* structure version MDTV_* */ 608114937Speter int md_type; /* type of entry MDT_* */ 609114937Speter u_int64_t md_data; /* specific data */ 610114937Speter u_int64_t md_cval; /* common string label */ 611114937Speter}; 612114937Speter#endif 613114937Speter 61459854Sbpint 615114379Speter__elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef) 61678463Speter{ 61759854Sbp struct mod_metadata md; 618240249Sandreast#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 619114937Speter struct mod_metadata64 md64; 620114937Speter#endif 62183321Speter struct mod_depend *mdepend; 62283321Speter struct mod_version mver; 62359854Sbp Elf_Sym sym; 624114937Speter char *s; 625134458Siedowse int error, modcnt, minfolen; 626114937Speter Elf_Addr v, p, p_stop; 62759854Sbp 628114379Speter if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0) 629237338Sjhb return 0; 630114937Speter p = sym.st_value + ef->off; 631114379Speter if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0) 63278465Speter return ENOENT; 633114937Speter p_stop = sym.st_value + ef->off; 63459854Sbp 63559854Sbp modcnt = 0; 63678465Speter while (p < p_stop) { 637109616Sjake COPYOUT(p, &v, sizeof(v)); 638134458Siedowse error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v)); 639134458Siedowse if (error == EOPNOTSUPP) 640134458Siedowse v += ef->off; 641134458Siedowse else if (error != 0) 642134458Siedowse return (error); 643240249Sandreast#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 644114937Speter COPYOUT(v, &md64, sizeof(md64)); 645134458Siedowse error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof(md64)); 646134458Siedowse if (error == EOPNOTSUPP) { 647134458Siedowse md64.md_cval += ef->off; 648134458Siedowse md64.md_data += ef->off; 649134458Siedowse } else if (error != 0) 650134458Siedowse return (error); 651114937Speter md.md_version = md64.md_version; 652114937Speter md.md_type = md64.md_type; 653134458Siedowse md.md_cval = (const char *)(uintptr_t)md64.md_cval; 654134458Siedowse md.md_data = (void *)(uintptr_t)md64.md_data; 655114937Speter#else 656109616Sjake COPYOUT(v, &md, sizeof(md)); 657134458Siedowse error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md)); 658134458Siedowse if (error == EOPNOTSUPP) { 659134458Siedowse md.md_cval += ef->off; 660134458Siedowse md.md_data += ef->off; 661134458Siedowse } else if (error != 0) 662134458Siedowse return (error); 663109616Sjake#endif 664114937Speter p += sizeof(Elf_Addr); 66559854Sbp switch(md.md_type) { 66659854Sbp case MDT_DEPEND: 66759854Sbp if (ef->kernel) /* kernel must not depend on anything */ 66859854Sbp break; 669109616Sjake s = strdupout((vm_offset_t)md.md_cval); 67083321Speter minfolen = sizeof(*mdepend) + strlen(s) + 1; 67183321Speter mdepend = malloc(minfolen); 67283321Speter if (mdepend == NULL) 67383321Speter return ENOMEM; 674109616Sjake COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend)); 67583321Speter strcpy((char*)(mdepend + 1), s); 67659854Sbp free(s); 67783321Speter file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend); 67883321Speter free(mdepend); 67959854Sbp break; 68059854Sbp case MDT_VERSION: 681109616Sjake s = strdupout((vm_offset_t)md.md_cval); 682109616Sjake COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); 68383321Speter file_addmodule(fp, s, mver.mv_version, NULL); 68459854Sbp free(s); 68559854Sbp modcnt++; 68659854Sbp break; 68759854Sbp } 68859854Sbp } 68959854Sbp if (modcnt == 0) { 69059854Sbp s = fake_modname(fp->f_name); 69183321Speter file_addmodule(fp, s, 1, NULL); 69259854Sbp free(s); 69359854Sbp } 69459854Sbp return 0; 69559854Sbp} 69659854Sbp 69759854Sbpstatic unsigned long 69859854Sbpelf_hash(const char *name) 69959854Sbp{ 70059854Sbp const unsigned char *p = (const unsigned char *) name; 70159854Sbp unsigned long h = 0; 70259854Sbp unsigned long g; 70359854Sbp 70459854Sbp while (*p != '\0') { 70559854Sbp h = (h << 4) + *p++; 70659854Sbp if ((g = h & 0xf0000000) != 0) 70759854Sbp h ^= g >> 24; 70859854Sbp h &= ~g; 70959854Sbp } 71059854Sbp return h; 71159854Sbp} 71259854Sbp 713114379Speterstatic const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE) "_lookup_symbol: corrupt symbol table\n"; 71459854Sbpint 715114379Speter__elfN(lookup_symbol)(struct preloaded_file *fp, elf_file_t ef, const char* name, 71659854Sbp Elf_Sym *symp) 71759854Sbp{ 71894248Sjake Elf_Hashelt symnum; 71959854Sbp Elf_Sym sym; 72059854Sbp char *strp; 72159854Sbp unsigned long hash; 72259854Sbp 72359854Sbp hash = elf_hash(name); 72459854Sbp COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum)); 72559854Sbp 72659854Sbp while (symnum != STN_UNDEF) { 72759854Sbp if (symnum >= ef->nchains) { 728114379Speter printf(__elfN(bad_symtable)); 72959854Sbp return ENOENT; 73059854Sbp } 73159854Sbp 73259854Sbp COPYOUT(ef->symtab + symnum, &sym, sizeof(sym)); 73359854Sbp if (sym.st_name == 0) { 734114379Speter printf(__elfN(bad_symtable)); 73559854Sbp return ENOENT; 73659854Sbp } 73759854Sbp 73859854Sbp strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name)); 73959854Sbp if (strcmp(name, strp) == 0) { 74059854Sbp free(strp); 74159854Sbp if (sym.st_shndx != SHN_UNDEF || 74259854Sbp (sym.st_value != 0 && 74359854Sbp ELF_ST_TYPE(sym.st_info) == STT_FUNC)) { 74459854Sbp *symp = sym; 74559854Sbp return 0; 74659854Sbp } 74759854Sbp return ENOENT; 74859854Sbp } 74959854Sbp free(strp); 75059854Sbp COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum)); 75159854Sbp } 75259854Sbp return ENOENT; 75359854Sbp} 754109616Sjake 755109616Sjake/* 756134458Siedowse * Apply any intra-module relocations to the value. p is the load address 757109616Sjake * of the value and val/len is the value to be modified. This does NOT modify 758109616Sjake * the image in-place, because this is done by kern_linker later on. 759134458Siedowse * 760134458Siedowse * Returns EOPNOTSUPP if no relocation method is supplied. 761109616Sjake */ 762134458Siedowsestatic int 763114379Speter__elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, 764134458Siedowse Elf_Addr p, void *val, size_t len) 765109616Sjake{ 766109616Sjake size_t n; 767134458Siedowse Elf_Rela a; 768134458Siedowse Elf_Rel r; 769134458Siedowse int error; 770109616Sjake 771134458Siedowse /* 772134458Siedowse * The kernel is already relocated, but we still want to apply 773134458Siedowse * offset adjustments. 774134458Siedowse */ 775134458Siedowse if (ef->kernel) 776134458Siedowse return (EOPNOTSUPP); 777109616Sjake 778134458Siedowse for (n = 0; n < ef->relsz / sizeof(r); n++) { 779134458Siedowse COPYOUT(ef->rel + n, &r, sizeof(r)); 780134458Siedowse 781134458Siedowse error = __elfN(reloc)(ef, __elfN(symaddr), &r, ELF_RELOC_REL, 782134458Siedowse ef->off, p, val, len); 783134458Siedowse if (error != 0) 784134458Siedowse return (error); 785109616Sjake } 786134458Siedowse for (n = 0; n < ef->relasz / sizeof(a); n++) { 787134458Siedowse COPYOUT(ef->rela + n, &a, sizeof(a)); 788134458Siedowse 789134458Siedowse error = __elfN(reloc)(ef, __elfN(symaddr), &a, ELF_RELOC_RELA, 790134458Siedowse ef->off, p, val, len); 791134458Siedowse if (error != 0) 792134458Siedowse return (error); 793134458Siedowse } 794134458Siedowse 795134458Siedowse return (0); 796109616Sjake} 797134458Siedowse 798134458Siedowsestatic Elf_Addr 799153504Smarcel__elfN(symaddr)(struct elf_file *ef, Elf_Size symidx) 800134458Siedowse{ 801134458Siedowse 802134458Siedowse /* Symbol lookup by index not required here. */ 803134458Siedowse return (0); 804134458Siedowse} 805