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$"); 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); 79294417Sroygerstatic int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef, 80294417Sroyger Elf_Addr p_start, Elf_Addr p_end); 81134458Siedowsestatic symaddr_fn __elfN(symaddr); 8264187Sjhbstatic char *fake_modname(const char *name); 8359854Sbp 84114379Speterconst char *__elfN(kerneltype) = "elf kernel"; 85114379Speterconst char *__elfN(moduletype) = "elf module"; 8639830Speter 87176484Smarcelu_int64_t __elfN(relocation_offset) = 0; 88176484Smarcel 89294417Sroygerstatic int 90294417Sroyger__elfN(load_elf_header)(char *filename, elf_file_t ef) 91294417Sroyger{ 92294417Sroyger ssize_t bytes_read; 93294417Sroyger Elf_Ehdr *ehdr; 94294417Sroyger int err; 95294417Sroyger 96294417Sroyger /* 97294417Sroyger * Open the image, read and validate the ELF header 98294417Sroyger */ 99294417Sroyger if (filename == NULL) /* can't handle nameless */ 100294417Sroyger return (EFTYPE); 101294417Sroyger if ((ef->fd = open(filename, O_RDONLY)) == -1) 102294417Sroyger return (errno); 103294417Sroyger ef->firstpage = malloc(PAGE_SIZE); 104294417Sroyger if (ef->firstpage == NULL) { 105294417Sroyger close(ef->fd); 106294417Sroyger return (ENOMEM); 107294417Sroyger } 108294417Sroyger bytes_read = read(ef->fd, ef->firstpage, PAGE_SIZE); 109294417Sroyger ef->firstlen = (size_t)bytes_read; 110294417Sroyger if (bytes_read < 0 || ef->firstlen <= sizeof(Elf_Ehdr)) { 111294417Sroyger err = EFTYPE; /* could be EIO, but may be small file */ 112294417Sroyger goto error; 113294417Sroyger } 114294417Sroyger ehdr = ef->ehdr = (Elf_Ehdr *)ef->firstpage; 115294417Sroyger 116294417Sroyger /* Is it ELF? */ 117294417Sroyger if (!IS_ELF(*ehdr)) { 118294417Sroyger err = EFTYPE; 119294417Sroyger goto error; 120294417Sroyger } 121294417Sroyger if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ 122294417Sroyger ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || 123294417Sroyger ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ 124294417Sroyger ehdr->e_version != EV_CURRENT || 125294417Sroyger ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ 126294417Sroyger err = EFTYPE; 127294417Sroyger goto error; 128294417Sroyger } 129294417Sroyger 130294417Sroyger return (0); 131294417Sroyger 132294417Sroygererror: 133294417Sroyger if (ef->firstpage != NULL) { 134294417Sroyger free(ef->firstpage); 135294417Sroyger ef->firstpage = NULL; 136294417Sroyger } 137294417Sroyger if (ef->fd != -1) { 138294417Sroyger close(ef->fd); 139294417Sroyger ef->fd = -1; 140294417Sroyger } 141294417Sroyger return (err); 142294417Sroyger} 143294417Sroyger 14439830Speter/* 14539830Speter * Attempt to load the file (file) as an ELF module. It will be stored at 14639830Speter * (dest), and a pointer to a module structure describing the loaded object 14739830Speter * will be saved in (result). 14839830Speter */ 14939830Speterint 150114379Speter__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) 15139830Speter{ 152294417Sroyger return (__elfN(loadfile_raw)(filename, dest, result, 0)); 153294417Sroyger} 154294417Sroyger 155294417Sroygerint 156294417Sroyger__elfN(loadfile_raw)(char *filename, u_int64_t dest, 157294417Sroyger struct preloaded_file **result, int multiboot) 158294417Sroyger{ 15959854Sbp struct preloaded_file *fp, *kfp; 16059854Sbp struct elf_file ef; 16159854Sbp Elf_Ehdr *ehdr; 16259854Sbp int err; 16339830Speter 16459854Sbp fp = NULL; 16559854Sbp bzero(&ef, sizeof(struct elf_file)); 166294417Sroyger ef.fd = -1; 167176484Smarcel 168294417Sroyger err = __elfN(load_elf_header)(filename, &ef); 169294417Sroyger if (err != 0) 170294417Sroyger return (err); 17139830Speter 172294417Sroyger ehdr = ef.ehdr; 17339830Speter 17439830Speter /* 17539830Speter * Check to see what sort of module we are. 17639830Speter */ 177294417Sroyger kfp = file_findfile(NULL, __elfN(kerneltype)); 178283505Sian#ifdef __powerpc__ 179283505Sian /* 180283505Sian * Kernels can be ET_DYN, so just assume the first loaded object is the 181283505Sian * kernel. This assumption will be checked later. 182283505Sian */ 183283505Sian if (kfp == NULL) 184283505Sian ef.kernel = 1; 185283505Sian#endif 186283505Sian if (ef.kernel || ehdr->e_type == ET_EXEC) { 187283505Sian /* Looks like a kernel */ 188283505Sian if (kfp != NULL) { 189283505Sian printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n"); 190283505Sian err = EPERM; 191283505Sian goto oerr; 192283505Sian } 193283505Sian /* 194283505Sian * Calculate destination address based on kernel entrypoint. 195283505Sian * 196283505Sian * For ARM, the destination address is independent of any values in the 197283505Sian * elf header (an ARM kernel can be loaded at any 2MB boundary), so we 198283505Sian * leave dest set to the value calculated by archsw.arch_loadaddr() and 199283505Sian * passed in to this function. 200283505Sian */ 201283505Sian#ifndef __arm__ 202283505Sian if (ehdr->e_type == ET_EXEC) 203283505Sian dest = (ehdr->e_entry & ~PAGE_MASK); 204283505Sian#endif 205283505Sian if ((ehdr->e_entry & ~PAGE_MASK) == 0) { 206283505Sian printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); 207283505Sian err = EPERM; 208283505Sian goto oerr; 209283505Sian } 210283505Sian ef.kernel = 1; 211283505Sian 212283505Sian } else if (ehdr->e_type == ET_DYN) { 21339830Speter /* Looks like a kld module */ 214294417Sroyger if (multiboot != 0) { 215294417Sroyger printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n"); 216294417Sroyger err = EPERM; 217294417Sroyger goto oerr; 218294417Sroyger } 21959854Sbp if (kfp == NULL) { 220114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n"); 22139830Speter err = EPERM; 22239830Speter goto oerr; 22339830Speter } 224114379Speter if (strcmp(__elfN(kerneltype), kfp->f_type)) { 225114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); 22639830Speter err = EPERM; 22739830Speter goto oerr; 22839830Speter } 22939830Speter /* Looks OK, got ahead */ 23059854Sbp ef.kernel = 0; 23139830Speter 23239830Speter } else { 23339830Speter err = EFTYPE; 23439830Speter goto oerr; 23539830Speter } 23639830Speter 237220311Smarcel if (archsw.arch_loadaddr != NULL) 238220311Smarcel dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); 239220311Smarcel else 240220311Smarcel dest = roundup(dest, PAGE_SIZE); 241220311Smarcel 24239830Speter /* 24339830Speter * Ok, we think we should handle this. 24439830Speter */ 24559854Sbp fp = file_alloc(); 24659854Sbp if (fp == NULL) { 247114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n"); 24840143Speter err = EPERM; 24940143Speter goto out; 25040143Speter } 251294417Sroyger if (ef.kernel == 1 && multiboot == 0) 25240143Speter setenv("kernelname", filename, 1); 25383321Speter fp->f_name = strdup(filename); 254294417Sroyger if (multiboot == 0) 255294417Sroyger fp->f_type = strdup(ef.kernel ? 256294417Sroyger __elfN(kerneltype) : __elfN(moduletype)); 257294417Sroyger else 258294417Sroyger fp->f_type = strdup("elf multiboot kernel"); 25939830Speter 26040291Speter#ifdef ELF_VERBOSE 26159854Sbp if (ef.kernel) 262220311Smarcel printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry); 26340327Speter#else 26440327Speter printf("%s ", filename); 26540291Speter#endif 26639830Speter 267114379Speter fp->f_size = __elfN(loadimage)(fp, &ef, dest); 26859854Sbp if (fp->f_size == 0 || fp->f_addr == 0) 26939830Speter goto ioerr; 27039830Speter 27139830Speter /* save exec header as metadata */ 27259854Sbp file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); 27339830Speter 27439830Speter /* Load OK, return module pointer */ 27559854Sbp *result = (struct preloaded_file *)fp; 27639830Speter err = 0; 27739830Speter goto out; 27839830Speter 27939830Speter ioerr: 28039830Speter err = EIO; 28139830Speter oerr: 28259854Sbp file_discard(fp); 28339830Speter out: 28459854Sbp if (ef.firstpage) 28559854Sbp free(ef.firstpage); 286294417Sroyger if (ef.fd != -1) 287294417Sroyger close(ef.fd); 28839830Speter return(err); 28939830Speter} 29039830Speter 29139830Speter/* 29239830Speter * With the file (fd) open on the image, and (ehdr) containing 29340143Speter * the Elf header, load the image at (off) 29439830Speter */ 29539830Speterstatic int 296114379Speter__elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) 29739830Speter{ 29864187Sjhb int i; 29964187Sjhb u_int j; 30059854Sbp Elf_Ehdr *ehdr; 30159854Sbp Elf_Phdr *phdr, *php; 30239887Speter Elf_Shdr *shdr; 30339830Speter int ret; 30439830Speter vm_offset_t firstaddr; 30539830Speter vm_offset_t lastaddr; 306134441Siedowse size_t chunk; 30764187Sjhb ssize_t result; 308114379Speter Elf_Addr ssym, esym; 30940143Speter Elf_Dyn *dp; 310114379Speter Elf_Addr adp; 31140143Speter int ndp; 31240254Speter int symstrindex; 31340254Speter int symtabindex; 314114379Speter Elf_Size size; 31564187Sjhb u_int fpcopy; 316294417Sroyger Elf_Sym sym; 317294417Sroyger Elf_Addr p_start, p_end; 31839830Speter 31940143Speter dp = NULL; 32040143Speter shdr = NULL; 32139830Speter ret = 0; 32239830Speter firstaddr = lastaddr = 0; 32359854Sbp ehdr = ef->ehdr; 324283505Sian if (ehdr->e_type == ET_EXEC) { 325223695Sdfr#if defined(__i386__) || defined(__amd64__) 326114379Speter#if __ELF_WORD_SIZE == 64 327114379Speter off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */ 328114379Speter#else 329163914Sru off = - (off & 0xff000000u); /* i386 relocates after locore */ 330114379Speter#endif 331176484Smarcel#elif defined(__powerpc__) 332176484Smarcel /* 333176484Smarcel * On the purely virtual memory machines like e500, the kernel is 334176484Smarcel * linked against its final VA range, which is most often not 335176484Smarcel * available at the loader stage, but only after kernel initializes 336176484Smarcel * and completes its VM settings. In such cases we cannot use p_vaddr 337176484Smarcel * field directly to load ELF segments, but put them at some 338176484Smarcel * 'load-time' locations. 339176484Smarcel */ 340176484Smarcel if (off & 0xf0000000u) { 341176484Smarcel off = -(off & 0xf0000000u); 342176484Smarcel /* 343176484Smarcel * XXX the physical load address should not be hardcoded. Note 344176484Smarcel * that the Book-E kernel assumes that it's loaded at a 16MB 345176484Smarcel * boundary for now... 346176484Smarcel */ 347176484Smarcel off += 0x01000000; 348176484Smarcel ehdr->e_entry += off; 349176484Smarcel#ifdef ELF_VERBOSE 350176484Smarcel printf("Converted entry 0x%08x\n", ehdr->e_entry); 351176484Smarcel#endif 352183878Sraj } else 353176484Smarcel off = 0; 354183878Sraj#elif defined(__arm__) 355247301Sian /* 356283505Sian * The elf headers in arm kernels specify virtual addresses in all 357283505Sian * header fields, even the ones that should be physical addresses. 358283505Sian * We assume the entry point is in the first page, and masking the page 359283505Sian * offset will leave us with the virtual address the kernel was linked 360283505Sian * at. We subtract that from the load offset, making 'off' into the 361283505Sian * value which, when added to a virtual address in an elf header, 362283505Sian * translates it to a physical address. We do the va->pa conversion on 363283505Sian * the entry point address in the header now, so that later we can 364283505Sian * launch the kernel by just jumping to that address. 365247301Sian */ 366283505Sian off -= ehdr->e_entry & ~PAGE_MASK; 367283505Sian ehdr->e_entry += off; 368183878Sraj#ifdef ELF_VERBOSE 369247301Sian printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off); 370183878Sraj#endif 37139830Speter#else 372158467Sjhb off = 0; /* other archs use direct mapped kernels */ 37339830Speter#endif 37440143Speter } 37559854Sbp ef->off = off; 37639830Speter 377283505Sian if (ef->kernel) 378283505Sian __elfN(relocation_offset) = off; 379283505Sian 38059854Sbp if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { 381114379Speter printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n"); 38240465Speter goto out; 38340465Speter } 38459854Sbp phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff); 38540465Speter 38639830Speter for (i = 0; i < ehdr->e_phnum; i++) { 38739830Speter /* We want to load PT_LOAD segments only.. */ 38839830Speter if (phdr[i].p_type != PT_LOAD) 38939830Speter continue; 39039830Speter 39140254Speter#ifdef ELF_VERBOSE 39239887Speter printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", 39339830Speter (long)phdr[i].p_filesz, (long)phdr[i].p_offset, 39439830Speter (long)(phdr[i].p_vaddr + off), 39539887Speter (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 39640254Speter#else 39740291Speter if ((phdr[i].p_flags & PF_W) == 0) { 39840291Speter printf("text=0x%lx ", (long)phdr[i].p_filesz); 39940291Speter } else { 40040291Speter printf("data=0x%lx", (long)phdr[i].p_filesz); 40140291Speter if (phdr[i].p_filesz < phdr[i].p_memsz) 40240291Speter printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz)); 40340291Speter printf(" "); 40440291Speter } 40540254Speter#endif 40640465Speter fpcopy = 0; 40759854Sbp if (ef->firstlen > phdr[i].p_offset) { 40859854Sbp fpcopy = ef->firstlen - phdr[i].p_offset; 40959854Sbp archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, 41040465Speter phdr[i].p_vaddr + off, fpcopy); 41139830Speter } 41240465Speter if (phdr[i].p_filesz > fpcopy) { 413134441Siedowse if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy, 414134441Siedowse phdr[i].p_filesz - fpcopy, phdr[i].p_offset + fpcopy) != 0) { 415134441Siedowse printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 416134441Siedowse "_loadimage: read failed\n"); 41740465Speter goto out; 41840465Speter } 41939830Speter } 42039830Speter /* clear space from oversized segments; eg: bss */ 42139830Speter if (phdr[i].p_filesz < phdr[i].p_memsz) { 42240254Speter#ifdef ELF_VERBOSE 42339887Speter printf(" (bss: 0x%lx-0x%lx)", 42439830Speter (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz), 42539830Speter (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 42640254Speter#endif 42739830Speter 428134441Siedowse kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz, 429134441Siedowse phdr[i].p_memsz - phdr[i].p_filesz); 43039830Speter } 43140254Speter#ifdef ELF_VERBOSE 43239887Speter printf("\n"); 43340254Speter#endif 43439830Speter 435220311Smarcel if (archsw.arch_loadseg != NULL) 436220311Smarcel archsw.arch_loadseg(ehdr, phdr + i, off); 437220311Smarcel 43840143Speter if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) 43939830Speter firstaddr = phdr[i].p_vaddr + off; 44040143Speter if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) 44139830Speter lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz; 44239830Speter } 44340254Speter lastaddr = roundup(lastaddr, sizeof(long)); 44439830Speter 44539887Speter /* 44639887Speter * Now grab the symbol tables. This isn't easy if we're reading a 44739887Speter * .gz file. I think the rule is going to have to be that you must 44839887Speter * strip a file to remove symbols before gzipping it so that we do not 44940254Speter * try to lseek() on it. 45039887Speter */ 45139887Speter chunk = ehdr->e_shnum * ehdr->e_shentsize; 45240291Speter if (chunk == 0 || ehdr->e_shoff == 0) 45340291Speter goto nosyms; 454134441Siedowse shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk); 455134441Siedowse if (shdr == NULL) { 456134441Siedowse printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 457134441Siedowse "_loadimage: failed to read section headers"); 45839887Speter goto nosyms; 45939887Speter } 460248121Sian file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr); 461248121Sian 46240254Speter symtabindex = -1; 46340254Speter symstrindex = -1; 46439887Speter for (i = 0; i < ehdr->e_shnum; i++) { 46540254Speter if (shdr[i].sh_type != SHT_SYMTAB) 46640143Speter continue; 46739887Speter for (j = 0; j < ehdr->e_phnum; j++) { 46839887Speter if (phdr[j].p_type != PT_LOAD) 46939887Speter continue; 47039887Speter if (shdr[i].sh_offset >= phdr[j].p_offset && 47139887Speter (shdr[i].sh_offset + shdr[i].sh_size <= 47239887Speter phdr[j].p_offset + phdr[j].p_filesz)) { 47339887Speter shdr[i].sh_offset = 0; 47439887Speter shdr[i].sh_size = 0; 47539887Speter break; 47639887Speter } 47739887Speter } 47839887Speter if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0) 47939887Speter continue; /* alread loaded in a PT_LOAD above */ 48040254Speter /* Save it for loading below */ 48140254Speter symtabindex = i; 48240254Speter symstrindex = shdr[i].sh_link; 48340254Speter } 48440254Speter if (symtabindex < 0 || symstrindex < 0) 48540254Speter goto nosyms; 48639887Speter 48740254Speter /* Ok, committed to a load. */ 48840254Speter#ifndef ELF_VERBOSE 48940291Speter printf("syms=["); 49040254Speter#endif 49140254Speter ssym = lastaddr; 49240254Speter for (i = symtabindex; i >= 0; i = symstrindex) { 49340254Speter#ifdef ELF_VERBOSE 49440254Speter char *secname; 49540254Speter 49640254Speter switch(shdr[i].sh_type) { 49740254Speter case SHT_SYMTAB: /* Symbol table */ 49840254Speter secname = "symtab"; 49940254Speter break; 50040254Speter case SHT_STRTAB: /* String table */ 50140254Speter secname = "strtab"; 50240254Speter break; 50340254Speter default: 50440254Speter secname = "WHOA!!"; 50540254Speter break; 50640254Speter } 50740254Speter#endif 50840254Speter 50940254Speter size = shdr[i].sh_size; 51040254Speter archsw.arch_copyin(&size, lastaddr, sizeof(size)); 511114379Speter lastaddr += sizeof(size); 51240254Speter 51340254Speter#ifdef ELF_VERBOSE 514163917Sru printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname, 515163917Sru (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset, 516163917Sru (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size)); 51740254Speter#else 51840291Speter if (i == symstrindex) 51940291Speter printf("+"); 520114379Speter printf("0x%lx+0x%lx", (long)sizeof(size), (long)size); 52140254Speter#endif 52240254Speter 52364187Sjhb if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { 524114379Speter printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!"); 52540254Speter lastaddr = ssym; 52640254Speter ssym = 0; 52740254Speter goto nosyms; 52839887Speter } 52964187Sjhb result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size); 53064187Sjhb if (result < 0 || (size_t)result != shdr[i].sh_size) { 531215811Semaste printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! (%ju != %ju)", (uintmax_t)result, 532215758Sattilio (uintmax_t)shdr[i].sh_size); 53340254Speter lastaddr = ssym; 53440254Speter ssym = 0; 53540254Speter goto nosyms; 53639887Speter } 53739887Speter /* Reset offsets relative to ssym */ 53839887Speter lastaddr += shdr[i].sh_size; 539114379Speter lastaddr = roundup(lastaddr, sizeof(size)); 54040254Speter if (i == symtabindex) 54140254Speter symtabindex = -1; 54240254Speter else if (i == symstrindex) 54340254Speter symstrindex = -1; 54439887Speter } 54539887Speter esym = lastaddr; 54640254Speter#ifndef ELF_VERBOSE 54742288Speter printf("]"); 54840254Speter#endif 54939887Speter 55059854Sbp file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym); 55159854Sbp file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym); 55239887Speter 55339887Speternosyms: 55442288Speter printf("\n"); 55539887Speter 55639830Speter ret = lastaddr - firstaddr; 55759854Sbp fp->f_addr = firstaddr; 55840143Speter 55959854Sbp php = NULL; 56040143Speter for (i = 0; i < ehdr->e_phnum; i++) { 56140143Speter if (phdr[i].p_type == PT_DYNAMIC) { 56259854Sbp php = phdr + i; 563114379Speter adp = php->p_vaddr; 564114379Speter file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp); 56540143Speter break; 56640143Speter } 56740143Speter } 56840143Speter 56959854Sbp if (php == NULL) /* this is bad, we cannot get to symbols or _DYNAMIC */ 57040143Speter goto out; 57140143Speter 57259854Sbp ndp = php->p_filesz / sizeof(Elf_Dyn); 57359854Sbp if (ndp == 0) 57440143Speter goto out; 57559854Sbp dp = malloc(php->p_filesz); 57659854Sbp if (dp == NULL) 57759854Sbp goto out; 57859854Sbp archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz); 57959854Sbp 58059854Sbp ef->strsz = 0; 58140143Speter for (i = 0; i < ndp; i++) { 582126837Sbde if (dp[i].d_tag == 0) 58340143Speter break; 58440143Speter switch (dp[i].d_tag) { 58559854Sbp case DT_HASH: 586114379Speter ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off); 58759854Sbp break; 58840143Speter case DT_STRTAB: 589114379Speter ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off); 59040143Speter break; 59140143Speter case DT_STRSZ: 59259854Sbp ef->strsz = dp[i].d_un.d_val; 59340143Speter break; 59459854Sbp case DT_SYMTAB: 595114379Speter ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off); 59659854Sbp break; 597134458Siedowse case DT_REL: 598134458Siedowse ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off); 599134458Siedowse break; 600134458Siedowse case DT_RELSZ: 601134458Siedowse ef->relsz = dp[i].d_un.d_val; 602134458Siedowse break; 603109616Sjake case DT_RELA: 604114379Speter ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off); 605109616Sjake break; 606109616Sjake case DT_RELASZ: 607109616Sjake ef->relasz = dp[i].d_un.d_val; 608109616Sjake break; 60940143Speter default: 61040143Speter break; 61140143Speter } 61240143Speter } 61359854Sbp if (ef->hashtab == NULL || ef->symtab == NULL || 61459854Sbp ef->strtab == NULL || ef->strsz == 0) 61540143Speter goto out; 61659854Sbp COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets)); 61759854Sbp COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains)); 61859854Sbp ef->buckets = ef->hashtab + 2; 61959854Sbp ef->chains = ef->buckets + ef->nbuckets; 620294417Sroyger 621294417Sroyger if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0) 622294417Sroyger return 0; 623294417Sroyger p_start = sym.st_value + ef->off; 624294417Sroyger if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0) 625294417Sroyger return ENOENT; 626294417Sroyger p_end = sym.st_value + ef->off; 627294417Sroyger 628294417Sroyger if (__elfN(parse_modmetadata)(fp, ef, p_start, p_end) == 0) 62959854Sbp goto out; 63040143Speter 63159854Sbp if (ef->kernel) /* kernel must not depend on anything */ 63259854Sbp goto out; 63359854Sbp 63439830Speterout: 63540143Speter if (dp) 63640143Speter free(dp); 63740143Speter if (shdr) 63840143Speter free(shdr); 63939830Speter return ret; 64039830Speter} 64159854Sbp 64259854Sbpstatic char invalid_name[] = "bad"; 64383321Speter 64459854Sbpchar * 64578463Speterfake_modname(const char *name) 64678463Speter{ 64778696Sdwmalone const char *sp, *ep; 64878696Sdwmalone char *fp; 64964187Sjhb size_t len; 65059854Sbp 65159854Sbp sp = strrchr(name, '/'); 65259854Sbp if (sp) 65359854Sbp sp++; 65459854Sbp else 65559854Sbp sp = name; 65659854Sbp ep = strrchr(name, '.'); 65759854Sbp if (ep) { 65859854Sbp if (ep == name) { 65959854Sbp sp = invalid_name; 66059854Sbp ep = invalid_name + sizeof(invalid_name) - 1; 66159854Sbp } 66259854Sbp } else 66359854Sbp ep = name + strlen(name); 66459854Sbp len = ep - sp; 66578696Sdwmalone fp = malloc(len + 1); 66678696Sdwmalone if (fp == NULL) 66759854Sbp return NULL; 66878696Sdwmalone memcpy(fp, sp, len); 66978696Sdwmalone fp[len] = '\0'; 67078696Sdwmalone return fp; 67159854Sbp} 67259854Sbp 673240249Sandreast#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 674114937Speterstruct mod_metadata64 { 675114937Speter int md_version; /* structure version MDTV_* */ 676114937Speter int md_type; /* type of entry MDT_* */ 677114937Speter u_int64_t md_data; /* specific data */ 678114937Speter u_int64_t md_cval; /* common string label */ 679114937Speter}; 680114937Speter#endif 681274942Sgrehan#if defined(__amd64__) && __ELF_WORD_SIZE == 32 682274942Sgrehanstruct mod_metadata32 { 683274942Sgrehan int md_version; /* structure version MDTV_* */ 684274942Sgrehan int md_type; /* type of entry MDT_* */ 685274942Sgrehan u_int32_t md_data; /* specific data */ 686274942Sgrehan u_int32_t md_cval; /* common string label */ 687274942Sgrehan}; 688274942Sgrehan#endif 689114937Speter 69059854Sbpint 691294417Sroyger__elfN(load_modmetadata)(struct preloaded_file *fp, u_int64_t dest) 69278463Speter{ 693294417Sroyger struct elf_file ef; 694294417Sroyger int err, i, j; 695294417Sroyger Elf_Shdr *sh_meta, *shdr = NULL; 696294417Sroyger Elf_Shdr *sh_data[2]; 697294417Sroyger char *shstrtab = NULL; 698294417Sroyger size_t size; 699294417Sroyger Elf_Addr p_start, p_end; 700294417Sroyger 701294417Sroyger bzero(&ef, sizeof(struct elf_file)); 702294417Sroyger ef.fd = -1; 703294417Sroyger 704294417Sroyger err = __elfN(load_elf_header)(fp->f_name, &ef); 705294417Sroyger if (err != 0) 706294417Sroyger goto out; 707294417Sroyger 708294417Sroyger if (ef.ehdr->e_type == ET_EXEC) { 709294417Sroyger ef.kernel = 1; 710294417Sroyger } else if (ef.ehdr->e_type != ET_DYN) { 711294417Sroyger err = EFTYPE; 712294417Sroyger goto out; 713294417Sroyger } 714294417Sroyger 715294417Sroyger size = ef.ehdr->e_shnum * ef.ehdr->e_shentsize; 716294417Sroyger shdr = alloc_pread(ef.fd, ef.ehdr->e_shoff, size); 717294417Sroyger if (shdr == NULL) { 718294417Sroyger err = ENOMEM; 719294417Sroyger goto out; 720294417Sroyger } 721294417Sroyger 722294417Sroyger /* Load shstrtab. */ 723294417Sroyger shstrtab = alloc_pread(ef.fd, shdr[ef.ehdr->e_shstrndx].sh_offset, 724294417Sroyger shdr[ef.ehdr->e_shstrndx].sh_size); 725294417Sroyger if (shstrtab == NULL) { 726294417Sroyger printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 727294417Sroyger "load_modmetadata: unable to load shstrtab\n"); 728294417Sroyger err = EFTYPE; 729294417Sroyger goto out; 730294417Sroyger } 731294417Sroyger 732294417Sroyger /* Find set_modmetadata_set and data sections. */ 733294417Sroyger sh_data[0] = sh_data[1] = sh_meta = NULL; 734294417Sroyger for (i = 0, j = 0; i < ef.ehdr->e_shnum; i++) { 735294417Sroyger if (strcmp(&shstrtab[shdr[i].sh_name], 736294417Sroyger "set_modmetadata_set") == 0) { 737294417Sroyger sh_meta = &shdr[i]; 738294417Sroyger } 739294417Sroyger if ((strcmp(&shstrtab[shdr[i].sh_name], ".data") == 0) || 740294417Sroyger (strcmp(&shstrtab[shdr[i].sh_name], ".rodata") == 0)) { 741294417Sroyger sh_data[j++] = &shdr[i]; 742294417Sroyger } 743294417Sroyger } 744294417Sroyger if (sh_meta == NULL || sh_data[0] == NULL || sh_data[1] == NULL) { 745294417Sroyger printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 746294417Sroyger "load_modmetadata: unable to find set_modmetadata_set or data sections\n"); 747294417Sroyger err = EFTYPE; 748294417Sroyger goto out; 749294417Sroyger } 750294417Sroyger 751294417Sroyger /* Load set_modmetadata_set into memory */ 752294417Sroyger err = kern_pread(ef.fd, dest, sh_meta->sh_size, sh_meta->sh_offset); 753294417Sroyger if (err != 0) { 754294417Sroyger printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 755294417Sroyger "load_modmetadata: unable to load set_modmetadata_set: %d\n", err); 756294417Sroyger goto out; 757294417Sroyger } 758294417Sroyger p_start = dest; 759294417Sroyger p_end = dest + sh_meta->sh_size; 760294417Sroyger dest += sh_meta->sh_size; 761294417Sroyger 762294417Sroyger /* Load data sections into memory. */ 763294417Sroyger err = kern_pread(ef.fd, dest, sh_data[0]->sh_size, 764294417Sroyger sh_data[0]->sh_offset); 765294417Sroyger if (err != 0) { 766294417Sroyger printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 767294417Sroyger "load_modmetadata: unable to load data: %d\n", err); 768294417Sroyger goto out; 769294417Sroyger } 770294417Sroyger 771294417Sroyger /* 772294417Sroyger * We have to increment the dest, so that the offset is the same into 773294417Sroyger * both the .rodata and .data sections. 774294417Sroyger */ 775294417Sroyger ef.off = -(sh_data[0]->sh_addr - dest); 776294417Sroyger dest += (sh_data[1]->sh_addr - sh_data[0]->sh_addr); 777294417Sroyger 778294417Sroyger err = kern_pread(ef.fd, dest, sh_data[1]->sh_size, 779294417Sroyger sh_data[1]->sh_offset); 780294417Sroyger if (err != 0) { 781294417Sroyger printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 782294417Sroyger "load_modmetadata: unable to load data: %d\n", err); 783294417Sroyger goto out; 784294417Sroyger } 785294417Sroyger 786294417Sroyger err = __elfN(parse_modmetadata)(fp, &ef, p_start, p_end); 787294417Sroyger if (err != 0) { 788294417Sroyger printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 789294417Sroyger "load_modmetadata: unable to parse metadata: %d\n", err); 790294417Sroyger goto out; 791294417Sroyger } 792294417Sroyger 793294417Sroygerout: 794294417Sroyger if (shstrtab != NULL) 795294417Sroyger free(shstrtab); 796294417Sroyger if (shdr != NULL) 797294417Sroyger free(shdr); 798294417Sroyger if (ef.firstpage != NULL) 799294417Sroyger free(ef.firstpage); 800294417Sroyger if (ef.fd != -1) 801294417Sroyger close(ef.fd); 802294417Sroyger return (err); 803294417Sroyger} 804294417Sroyger 805294417Sroygerint 806294417Sroyger__elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef, 807294417Sroyger Elf_Addr p_start, Elf_Addr p_end) 808294417Sroyger{ 80959854Sbp struct mod_metadata md; 810240249Sandreast#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 811114937Speter struct mod_metadata64 md64; 812274942Sgrehan#elif defined(__amd64__) && __ELF_WORD_SIZE == 32 813274942Sgrehan struct mod_metadata32 md32; 814114937Speter#endif 81583321Speter struct mod_depend *mdepend; 81683321Speter struct mod_version mver; 817114937Speter char *s; 818134458Siedowse int error, modcnt, minfolen; 819294417Sroyger Elf_Addr v, p; 82059854Sbp 82159854Sbp modcnt = 0; 822294417Sroyger p = p_start; 823294417Sroyger while (p < p_end) { 824109616Sjake COPYOUT(p, &v, sizeof(v)); 825134458Siedowse error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v)); 826134458Siedowse if (error == EOPNOTSUPP) 827134458Siedowse v += ef->off; 828134458Siedowse else if (error != 0) 829134458Siedowse return (error); 830240249Sandreast#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 831114937Speter COPYOUT(v, &md64, sizeof(md64)); 832134458Siedowse error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof(md64)); 833134458Siedowse if (error == EOPNOTSUPP) { 834134458Siedowse md64.md_cval += ef->off; 835134458Siedowse md64.md_data += ef->off; 836134458Siedowse } else if (error != 0) 837134458Siedowse return (error); 838114937Speter md.md_version = md64.md_version; 839114937Speter md.md_type = md64.md_type; 840134458Siedowse md.md_cval = (const char *)(uintptr_t)md64.md_cval; 841134458Siedowse md.md_data = (void *)(uintptr_t)md64.md_data; 842274942Sgrehan#elif defined(__amd64__) && __ELF_WORD_SIZE == 32 843274942Sgrehan COPYOUT(v, &md32, sizeof(md32)); 844274942Sgrehan error = __elfN(reloc_ptr)(fp, ef, v, &md32, sizeof(md32)); 845274942Sgrehan if (error == EOPNOTSUPP) { 846274942Sgrehan md32.md_cval += ef->off; 847274942Sgrehan md32.md_data += ef->off; 848274942Sgrehan } else if (error != 0) 849274942Sgrehan return (error); 850274942Sgrehan md.md_version = md32.md_version; 851274942Sgrehan md.md_type = md32.md_type; 852274942Sgrehan md.md_cval = (const char *)(uintptr_t)md32.md_cval; 853274942Sgrehan md.md_data = (void *)(uintptr_t)md32.md_data; 854114937Speter#else 855109616Sjake COPYOUT(v, &md, sizeof(md)); 856134458Siedowse error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md)); 857134458Siedowse if (error == EOPNOTSUPP) { 858134458Siedowse md.md_cval += ef->off; 859295531Ssmh md.md_data = (void *)((uintptr_t)md.md_data + (uintptr_t)ef->off); 860134458Siedowse } else if (error != 0) 861134458Siedowse return (error); 862109616Sjake#endif 863114937Speter p += sizeof(Elf_Addr); 86459854Sbp switch(md.md_type) { 86559854Sbp case MDT_DEPEND: 86659854Sbp if (ef->kernel) /* kernel must not depend on anything */ 86759854Sbp break; 868109616Sjake s = strdupout((vm_offset_t)md.md_cval); 86983321Speter minfolen = sizeof(*mdepend) + strlen(s) + 1; 87083321Speter mdepend = malloc(minfolen); 87183321Speter if (mdepend == NULL) 87283321Speter return ENOMEM; 873109616Sjake COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend)); 87483321Speter strcpy((char*)(mdepend + 1), s); 87559854Sbp free(s); 87683321Speter file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend); 87783321Speter free(mdepend); 87859854Sbp break; 87959854Sbp case MDT_VERSION: 880109616Sjake s = strdupout((vm_offset_t)md.md_cval); 881109616Sjake COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); 88283321Speter file_addmodule(fp, s, mver.mv_version, NULL); 88359854Sbp free(s); 88459854Sbp modcnt++; 88559854Sbp break; 88659854Sbp } 88759854Sbp } 88859854Sbp if (modcnt == 0) { 88959854Sbp s = fake_modname(fp->f_name); 89083321Speter file_addmodule(fp, s, 1, NULL); 89159854Sbp free(s); 89259854Sbp } 89359854Sbp return 0; 89459854Sbp} 89559854Sbp 89659854Sbpstatic unsigned long 89759854Sbpelf_hash(const char *name) 89859854Sbp{ 89959854Sbp const unsigned char *p = (const unsigned char *) name; 90059854Sbp unsigned long h = 0; 90159854Sbp unsigned long g; 90259854Sbp 90359854Sbp while (*p != '\0') { 90459854Sbp h = (h << 4) + *p++; 90559854Sbp if ((g = h & 0xf0000000) != 0) 90659854Sbp h ^= g >> 24; 90759854Sbp h &= ~g; 90859854Sbp } 90959854Sbp return h; 91059854Sbp} 91159854Sbp 912114379Speterstatic const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE) "_lookup_symbol: corrupt symbol table\n"; 91359854Sbpint 914114379Speter__elfN(lookup_symbol)(struct preloaded_file *fp, elf_file_t ef, const char* name, 91559854Sbp Elf_Sym *symp) 91659854Sbp{ 91794248Sjake Elf_Hashelt symnum; 91859854Sbp Elf_Sym sym; 91959854Sbp char *strp; 92059854Sbp unsigned long hash; 92159854Sbp 92259854Sbp hash = elf_hash(name); 92359854Sbp COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum)); 92459854Sbp 92559854Sbp while (symnum != STN_UNDEF) { 92659854Sbp if (symnum >= ef->nchains) { 927114379Speter printf(__elfN(bad_symtable)); 92859854Sbp return ENOENT; 92959854Sbp } 93059854Sbp 93159854Sbp COPYOUT(ef->symtab + symnum, &sym, sizeof(sym)); 93259854Sbp if (sym.st_name == 0) { 933114379Speter printf(__elfN(bad_symtable)); 93459854Sbp return ENOENT; 93559854Sbp } 93659854Sbp 93759854Sbp strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name)); 93859854Sbp if (strcmp(name, strp) == 0) { 93959854Sbp free(strp); 94059854Sbp if (sym.st_shndx != SHN_UNDEF || 94159854Sbp (sym.st_value != 0 && 94259854Sbp ELF_ST_TYPE(sym.st_info) == STT_FUNC)) { 94359854Sbp *symp = sym; 94459854Sbp return 0; 94559854Sbp } 94659854Sbp return ENOENT; 94759854Sbp } 94859854Sbp free(strp); 94959854Sbp COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum)); 95059854Sbp } 95159854Sbp return ENOENT; 95259854Sbp} 953109616Sjake 954109616Sjake/* 955134458Siedowse * Apply any intra-module relocations to the value. p is the load address 956109616Sjake * of the value and val/len is the value to be modified. This does NOT modify 957109616Sjake * the image in-place, because this is done by kern_linker later on. 958134458Siedowse * 959134458Siedowse * Returns EOPNOTSUPP if no relocation method is supplied. 960109616Sjake */ 961134458Siedowsestatic int 962114379Speter__elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, 963134458Siedowse Elf_Addr p, void *val, size_t len) 964109616Sjake{ 965109616Sjake size_t n; 966134458Siedowse Elf_Rela a; 967134458Siedowse Elf_Rel r; 968134458Siedowse int error; 969109616Sjake 970134458Siedowse /* 971134458Siedowse * The kernel is already relocated, but we still want to apply 972134458Siedowse * offset adjustments. 973134458Siedowse */ 974134458Siedowse if (ef->kernel) 975134458Siedowse return (EOPNOTSUPP); 976109616Sjake 977134458Siedowse for (n = 0; n < ef->relsz / sizeof(r); n++) { 978134458Siedowse COPYOUT(ef->rel + n, &r, sizeof(r)); 979134458Siedowse 980134458Siedowse error = __elfN(reloc)(ef, __elfN(symaddr), &r, ELF_RELOC_REL, 981134458Siedowse ef->off, p, val, len); 982134458Siedowse if (error != 0) 983134458Siedowse return (error); 984109616Sjake } 985134458Siedowse for (n = 0; n < ef->relasz / sizeof(a); n++) { 986134458Siedowse COPYOUT(ef->rela + n, &a, sizeof(a)); 987134458Siedowse 988134458Siedowse error = __elfN(reloc)(ef, __elfN(symaddr), &a, ELF_RELOC_RELA, 989134458Siedowse ef->off, p, val, len); 990134458Siedowse if (error != 0) 991134458Siedowse return (error); 992134458Siedowse } 993134458Siedowse 994134458Siedowse return (0); 995109616Sjake} 996134458Siedowse 997134458Siedowsestatic Elf_Addr 998153504Smarcel__elfN(symaddr)(struct elf_file *ef, Elf_Size symidx) 999134458Siedowse{ 1000134458Siedowse 1001134458Siedowse /* Symbol lookup by index not required here. */ 1002134458Siedowse return (0); 1003134458Siedowse} 1004