1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 2004 Ian Dowse <iedowse@freebsd.org> 3ca987d46SWarner Losh * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 4ca987d46SWarner Losh * Copyright (c) 1998 Peter Wemm <peter@freebsd.org> 5ca987d46SWarner Losh * All rights reserved. 6ca987d46SWarner Losh * 7ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 8ca987d46SWarner Losh * modification, are permitted provided that the following conditions 9ca987d46SWarner Losh * are met: 10ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 11ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 12ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 13ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 14ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 15ca987d46SWarner Losh * 16ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26ca987d46SWarner Losh * SUCH DAMAGE. 27ca987d46SWarner Losh */ 28ca987d46SWarner Losh 29ca987d46SWarner Losh #include <sys/param.h> 30ca987d46SWarner Losh #include <sys/exec.h> 31ca987d46SWarner Losh #include <sys/linker.h> 32ca987d46SWarner Losh #include <sys/module.h> 33f38658e1SWarner Losh #include <stdint.h> 34ca987d46SWarner Losh #include <string.h> 35ca987d46SWarner Losh #include <machine/elf.h> 36ca987d46SWarner Losh #include <stand.h> 37f38658e1SWarner Losh #include <sys/link_elf.h> 38ca987d46SWarner Losh 39ca987d46SWarner Losh #include "bootstrap.h" 40*86077f4fSAhmad Khalifa #include "modinfo.h" 41ca987d46SWarner Losh 42ca987d46SWarner Losh #define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) 43ca987d46SWarner Losh 44ca987d46SWarner Losh #if defined(__i386__) && __ELF_WORD_SIZE == 64 45ca987d46SWarner Losh #undef ELF_TARG_CLASS 46ca987d46SWarner Losh #undef ELF_TARG_MACH 47ca987d46SWarner Losh #define ELF_TARG_CLASS ELFCLASS64 48ca987d46SWarner Losh #define ELF_TARG_MACH EM_X86_64 49ca987d46SWarner Losh #endif 50ca987d46SWarner Losh 51ca987d46SWarner Losh typedef struct elf_file { 52ca987d46SWarner Losh Elf_Ehdr hdr; 53ca987d46SWarner Losh Elf_Shdr *e_shdr; 54ca987d46SWarner Losh 55ca987d46SWarner Losh int symtabindex; /* Index of symbol table */ 56ca987d46SWarner Losh int shstrindex; /* Index of section name string table */ 57ca987d46SWarner Losh 58ca987d46SWarner Losh int fd; 59ca987d46SWarner Losh vm_offset_t off; 60afc571b1SSimon J. Gerraty #ifdef LOADER_VERIEXEC_VECTX 61afc571b1SSimon J. Gerraty struct vectx *vctx; 62afc571b1SSimon J. Gerraty #endif 63ca987d46SWarner Losh } *elf_file_t; 64ca987d46SWarner Losh 65afc571b1SSimon J. Gerraty #ifdef LOADER_VERIEXEC_VECTX 66afc571b1SSimon J. Gerraty #define VECTX_HANDLE(ef) (ef)->vctx 67afc571b1SSimon J. Gerraty #else 68afc571b1SSimon J. Gerraty #define VECTX_HANDLE(ef) (ef)->fd 69afc571b1SSimon J. Gerraty #endif 70afc571b1SSimon J. Gerraty 71ca987d46SWarner Losh static int __elfN(obj_loadimage)(struct preloaded_file *mp, elf_file_t ef, 7256e53cb8SWarner Losh uint64_t loadaddr); 73ca987d46SWarner Losh static int __elfN(obj_lookup_set)(struct preloaded_file *mp, elf_file_t ef, 74ca987d46SWarner Losh const char *name, Elf_Addr *startp, Elf_Addr *stopp, int *countp); 75ca987d46SWarner Losh static int __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, 76ca987d46SWarner Losh Elf_Addr p, void *val, size_t len); 77ca987d46SWarner Losh static int __elfN(obj_parse_modmetadata)(struct preloaded_file *mp, 78ca987d46SWarner Losh elf_file_t ef); 79ca987d46SWarner Losh static Elf_Addr __elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx); 80ca987d46SWarner Losh 81ca987d46SWarner Losh /* 82ca987d46SWarner Losh * Attempt to load the file (file) as an ELF module. It will be stored at 83ca987d46SWarner Losh * (dest), and a pointer to a module structure describing the loaded object 84ca987d46SWarner Losh * will be saved in (result). 85ca987d46SWarner Losh */ 86ca987d46SWarner Losh int 8756e53cb8SWarner Losh __elfN(obj_loadfile)(char *filename, uint64_t dest, 88ca987d46SWarner Losh struct preloaded_file **result) 89ca987d46SWarner Losh { 90ca987d46SWarner Losh struct preloaded_file *fp, *kfp; 91ca987d46SWarner Losh struct elf_file ef; 92ca987d46SWarner Losh Elf_Ehdr *hdr; 93ca987d46SWarner Losh int err; 94ca987d46SWarner Losh ssize_t bytes_read; 95ca987d46SWarner Losh 96ca987d46SWarner Losh fp = NULL; 97ca987d46SWarner Losh bzero(&ef, sizeof(struct elf_file)); 98ca987d46SWarner Losh 99ca987d46SWarner Losh /* 100ca987d46SWarner Losh * Open the image, read and validate the ELF header 101ca987d46SWarner Losh */ 102ca987d46SWarner Losh if (filename == NULL) /* can't handle nameless */ 103ca987d46SWarner Losh return(EFTYPE); 104ca987d46SWarner Losh if ((ef.fd = open(filename, O_RDONLY)) == -1) 105ca987d46SWarner Losh return(errno); 106afc571b1SSimon J. Gerraty #ifdef LOADER_VERIEXEC_VECTX 107afc571b1SSimon J. Gerraty { 108afc571b1SSimon J. Gerraty int verror; 109afc571b1SSimon J. Gerraty 110afc571b1SSimon J. Gerraty ef.vctx = vectx_open(ef.fd, filename, 0L, NULL, &verror, __func__); 111afc571b1SSimon J. Gerraty if (verror) { 112afc571b1SSimon J. Gerraty printf("Unverified %s: %s\n", filename, ve_error_get()); 113afc571b1SSimon J. Gerraty close(ef.fd); 114afc571b1SSimon J. Gerraty free(ef.vctx); 115afc571b1SSimon J. Gerraty return (EAUTH); 116afc571b1SSimon J. Gerraty } 117afc571b1SSimon J. Gerraty } 118afc571b1SSimon J. Gerraty #endif 119ca987d46SWarner Losh 120ca987d46SWarner Losh hdr = &ef.hdr; 121afc571b1SSimon J. Gerraty bytes_read = VECTX_READ(VECTX_HANDLE(&ef), hdr, sizeof(*hdr)); 122ca987d46SWarner Losh if (bytes_read != sizeof(*hdr)) { 123ca987d46SWarner Losh err = EFTYPE; /* could be EIO, but may be small file */ 124ca987d46SWarner Losh goto oerr; 125ca987d46SWarner Losh } 126ca987d46SWarner Losh 127ca987d46SWarner Losh /* Is it ELF? */ 128ca987d46SWarner Losh if (!IS_ELF(*hdr)) { 129ca987d46SWarner Losh err = EFTYPE; 130ca987d46SWarner Losh goto oerr; 131ca987d46SWarner Losh } 132ca987d46SWarner Losh if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ 133ca987d46SWarner Losh hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 134ca987d46SWarner Losh hdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ 135ca987d46SWarner Losh hdr->e_version != EV_CURRENT || 136ca987d46SWarner Losh hdr->e_machine != ELF_TARG_MACH || /* Machine ? */ 137ca987d46SWarner Losh hdr->e_type != ET_REL) { 138ca987d46SWarner Losh err = EFTYPE; 139ca987d46SWarner Losh goto oerr; 140ca987d46SWarner Losh } 141ca987d46SWarner Losh 142ca987d46SWarner Losh if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 || 143ca987d46SWarner Losh hdr->e_shentsize != sizeof(Elf_Shdr)) { 144ca987d46SWarner Losh err = EFTYPE; 145ca987d46SWarner Losh goto oerr; 146ca987d46SWarner Losh } 147ca987d46SWarner Losh 148afc571b1SSimon J. Gerraty #if defined(LOADER_VERIEXEC) && !defined(LOADER_VERIEXEC_VECTX) 149afc571b1SSimon J. Gerraty if (verify_file(ef.fd, filename, bytes_read, VE_MUST, __func__) < 0) { 1508df8b2d3SSimon J. Gerraty err = EAUTH; 1518df8b2d3SSimon J. Gerraty goto oerr; 1528df8b2d3SSimon J. Gerraty } 1538df8b2d3SSimon J. Gerraty #endif 1548df8b2d3SSimon J. Gerraty 155*86077f4fSAhmad Khalifa kfp = file_findfile(NULL, md_kerntype); 156ca987d46SWarner Losh if (kfp == NULL) { 157ca987d46SWarner Losh printf("elf" __XSTRING(__ELF_WORD_SIZE) 158ca987d46SWarner Losh "_obj_loadfile: can't load module before kernel\n"); 159ca987d46SWarner Losh err = EPERM; 160ca987d46SWarner Losh goto oerr; 161ca987d46SWarner Losh } 162ca987d46SWarner Losh 163ca987d46SWarner Losh if (archsw.arch_loadaddr != NULL) 164ca987d46SWarner Losh dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest); 165ca987d46SWarner Losh else 166ca987d46SWarner Losh dest = roundup(dest, PAGE_SIZE); 167ca987d46SWarner Losh 168ca987d46SWarner Losh /* 169ca987d46SWarner Losh * Ok, we think we should handle this. 170ca987d46SWarner Losh */ 171ca987d46SWarner Losh fp = file_alloc(); 172ca987d46SWarner Losh if (fp == NULL) { 173ca987d46SWarner Losh printf("elf" __XSTRING(__ELF_WORD_SIZE) 174ca987d46SWarner Losh "_obj_loadfile: cannot allocate module info\n"); 175ca987d46SWarner Losh err = EPERM; 176ca987d46SWarner Losh goto out; 177ca987d46SWarner Losh } 178ca987d46SWarner Losh fp->f_name = strdup(filename); 179*86077f4fSAhmad Khalifa fp->f_type = strdup(md_modtype_obj); 180ca987d46SWarner Losh 181ec042f46SSimon J. Gerraty if (module_verbose > MODULE_VERBOSE_SILENT) 182ca987d46SWarner Losh printf("%s ", filename); 183ca987d46SWarner Losh 184ca987d46SWarner Losh fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest); 185ca987d46SWarner Losh if (fp->f_size == 0 || fp->f_addr == 0) 186ca987d46SWarner Losh goto ioerr; 187ca987d46SWarner Losh 188ca987d46SWarner Losh /* save exec header as metadata */ 189ca987d46SWarner Losh file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr); 190ca987d46SWarner Losh 191ca987d46SWarner Losh /* Load OK, return module pointer */ 192ca987d46SWarner Losh *result = (struct preloaded_file *)fp; 193ca987d46SWarner Losh err = 0; 194ca987d46SWarner Losh goto out; 195ca987d46SWarner Losh 196ca987d46SWarner Losh ioerr: 197ca987d46SWarner Losh err = EIO; 198ca987d46SWarner Losh oerr: 199ca987d46SWarner Losh file_discard(fp); 200ca987d46SWarner Losh out: 201afc571b1SSimon J. Gerraty #ifdef LOADER_VERIEXEC_VECTX 202afc571b1SSimon J. Gerraty if (!err && ef.vctx) { 203afc571b1SSimon J. Gerraty int verror; 204afc571b1SSimon J. Gerraty 205afc571b1SSimon J. Gerraty verror = vectx_close(ef.vctx, VE_MUST, __func__); 206afc571b1SSimon J. Gerraty if (verror) { 207afc571b1SSimon J. Gerraty err = EAUTH; 208afc571b1SSimon J. Gerraty file_discard(fp); 209afc571b1SSimon J. Gerraty } 210afc571b1SSimon J. Gerraty } 211afc571b1SSimon J. Gerraty #endif 212ca987d46SWarner Losh close(ef.fd); 213ca987d46SWarner Losh if (ef.e_shdr != NULL) 214ca987d46SWarner Losh free(ef.e_shdr); 215ca987d46SWarner Losh 216ca987d46SWarner Losh return(err); 217ca987d46SWarner Losh } 218ca987d46SWarner Losh 219ca987d46SWarner Losh /* 220ca987d46SWarner Losh * With the file (fd) open on the image, and (ehdr) containing 221ca987d46SWarner Losh * the Elf header, load the image at (off) 222ca987d46SWarner Losh */ 223ca987d46SWarner Losh static int 22456e53cb8SWarner Losh __elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, uint64_t off) 225ca987d46SWarner Losh { 226ca987d46SWarner Losh Elf_Ehdr *hdr; 227ca987d46SWarner Losh Elf_Shdr *shdr, *cshdr, *lshdr; 228ca987d46SWarner Losh vm_offset_t firstaddr, lastaddr; 229ca987d46SWarner Losh int i, nsym, res, ret, shdrbytes, symstrindex; 230ca987d46SWarner Losh 231ca987d46SWarner Losh ret = 0; 232ca987d46SWarner Losh firstaddr = lastaddr = (vm_offset_t)off; 233ca987d46SWarner Losh hdr = &ef->hdr; 234ca987d46SWarner Losh ef->off = (vm_offset_t)off; 235ca987d46SWarner Losh 236ca987d46SWarner Losh /* Read in the section headers. */ 237ca987d46SWarner Losh shdrbytes = hdr->e_shnum * hdr->e_shentsize; 238afc571b1SSimon J. Gerraty shdr = alloc_pread(VECTX_HANDLE(ef), (off_t)hdr->e_shoff, shdrbytes); 239ca987d46SWarner Losh if (shdr == NULL) { 240ca987d46SWarner Losh printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 241ca987d46SWarner Losh "_obj_loadimage: read section headers failed\n"); 242ca987d46SWarner Losh goto out; 243ca987d46SWarner Losh } 244ca987d46SWarner Losh ef->e_shdr = shdr; 245ca987d46SWarner Losh 246ca987d46SWarner Losh /* 247ca987d46SWarner Losh * Decide where to load everything, but don't read it yet. 248ca987d46SWarner Losh * We store the load address as a non-zero sh_addr value. 249ca987d46SWarner Losh * Start with the code/data and bss. 250ca987d46SWarner Losh */ 251ca987d46SWarner Losh for (i = 0; i < hdr->e_shnum; i++) 252ca987d46SWarner Losh shdr[i].sh_addr = 0; 253ca987d46SWarner Losh for (i = 0; i < hdr->e_shnum; i++) { 254ca987d46SWarner Losh if (shdr[i].sh_size == 0) 255ca987d46SWarner Losh continue; 256ca987d46SWarner Losh switch (shdr[i].sh_type) { 257ca987d46SWarner Losh case SHT_PROGBITS: 258ca987d46SWarner Losh case SHT_NOBITS: 259ca987d46SWarner Losh #if defined(__i386__) || defined(__amd64__) 260ca987d46SWarner Losh case SHT_X86_64_UNWIND: 261ca987d46SWarner Losh #endif 2627b1b5aadSMark Johnston case SHT_INIT_ARRAY: 2637b1b5aadSMark Johnston case SHT_FINI_ARRAY: 26458c4aee0SJohn Baldwin if ((shdr[i].sh_flags & SHF_ALLOC) == 0) 26558c4aee0SJohn Baldwin break; 266ca987d46SWarner Losh lastaddr = roundup(lastaddr, shdr[i].sh_addralign); 267ca987d46SWarner Losh shdr[i].sh_addr = (Elf_Addr)lastaddr; 268ca987d46SWarner Losh lastaddr += shdr[i].sh_size; 269ca987d46SWarner Losh break; 270ca987d46SWarner Losh } 271ca987d46SWarner Losh } 272ca987d46SWarner Losh 273ca987d46SWarner Losh /* Symbols. */ 274ca987d46SWarner Losh nsym = 0; 275ca987d46SWarner Losh for (i = 0; i < hdr->e_shnum; i++) { 276ca987d46SWarner Losh switch (shdr[i].sh_type) { 277ca987d46SWarner Losh case SHT_SYMTAB: 278ca987d46SWarner Losh nsym++; 279ca987d46SWarner Losh ef->symtabindex = i; 280ca987d46SWarner Losh break; 281ca987d46SWarner Losh } 282ca987d46SWarner Losh } 283ca987d46SWarner Losh if (nsym != 1) { 284ca987d46SWarner Losh printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 285ca987d46SWarner Losh "_obj_loadimage: file has no valid symbol table\n"); 286ca987d46SWarner Losh goto out; 287ca987d46SWarner Losh } 288ca987d46SWarner Losh lastaddr = roundup(lastaddr, shdr[ef->symtabindex].sh_addralign); 289ca987d46SWarner Losh shdr[ef->symtabindex].sh_addr = (Elf_Addr)lastaddr; 290ca987d46SWarner Losh lastaddr += shdr[ef->symtabindex].sh_size; 291ca987d46SWarner Losh 292ca987d46SWarner Losh symstrindex = shdr[ef->symtabindex].sh_link; 293ca987d46SWarner Losh if (symstrindex < 0 || symstrindex >= hdr->e_shnum || 294ca987d46SWarner Losh shdr[symstrindex].sh_type != SHT_STRTAB) { 295ca987d46SWarner Losh printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 296ca987d46SWarner Losh "_obj_loadimage: file has invalid symbol strings\n"); 297ca987d46SWarner Losh goto out; 298ca987d46SWarner Losh } 299ca987d46SWarner Losh lastaddr = roundup(lastaddr, shdr[symstrindex].sh_addralign); 300ca987d46SWarner Losh shdr[symstrindex].sh_addr = (Elf_Addr)lastaddr; 301ca987d46SWarner Losh lastaddr += shdr[symstrindex].sh_size; 302ca987d46SWarner Losh 303ca987d46SWarner Losh /* Section names. */ 304ca987d46SWarner Losh if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum || 305ca987d46SWarner Losh shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) { 306ca987d46SWarner Losh printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 307ca987d46SWarner Losh "_obj_loadimage: file has no section names\n"); 308ca987d46SWarner Losh goto out; 309ca987d46SWarner Losh } 310ca987d46SWarner Losh ef->shstrindex = hdr->e_shstrndx; 311ca987d46SWarner Losh lastaddr = roundup(lastaddr, shdr[ef->shstrindex].sh_addralign); 312ca987d46SWarner Losh shdr[ef->shstrindex].sh_addr = (Elf_Addr)lastaddr; 313ca987d46SWarner Losh lastaddr += shdr[ef->shstrindex].sh_size; 314ca987d46SWarner Losh 315ca987d46SWarner Losh /* Relocation tables. */ 316ca987d46SWarner Losh for (i = 0; i < hdr->e_shnum; i++) { 317ca987d46SWarner Losh switch (shdr[i].sh_type) { 318ca987d46SWarner Losh case SHT_REL: 319ca987d46SWarner Losh case SHT_RELA: 32015746ef4SJohn Baldwin if ((shdr[shdr[i].sh_info].sh_flags & SHF_ALLOC) == 0) 32115746ef4SJohn Baldwin break; 322ca987d46SWarner Losh lastaddr = roundup(lastaddr, shdr[i].sh_addralign); 323ca987d46SWarner Losh shdr[i].sh_addr = (Elf_Addr)lastaddr; 324ca987d46SWarner Losh lastaddr += shdr[i].sh_size; 325ca987d46SWarner Losh break; 326ca987d46SWarner Losh } 327ca987d46SWarner Losh } 328ca987d46SWarner Losh 329ca987d46SWarner Losh /* Clear the whole area, including bss regions. */ 330ca987d46SWarner Losh kern_bzero(firstaddr, lastaddr - firstaddr); 331ca987d46SWarner Losh 332ca987d46SWarner Losh /* Figure section with the lowest file offset we haven't loaded yet. */ 333ca987d46SWarner Losh for (cshdr = NULL; /* none */; /* none */) 334ca987d46SWarner Losh { 335ca987d46SWarner Losh /* 336ca987d46SWarner Losh * Find next section to load. The complexity of this loop is 337ca987d46SWarner Losh * O(n^2), but with the number of sections being typically 338ca987d46SWarner Losh * small, we do not care. 339ca987d46SWarner Losh */ 340ca987d46SWarner Losh lshdr = cshdr; 341ca987d46SWarner Losh 342ca987d46SWarner Losh for (i = 0; i < hdr->e_shnum; i++) { 343ca987d46SWarner Losh if (shdr[i].sh_addr == 0 || 344ca987d46SWarner Losh shdr[i].sh_type == SHT_NOBITS) 345ca987d46SWarner Losh continue; 346ca987d46SWarner Losh /* Skip sections that were loaded already. */ 347ca987d46SWarner Losh if (lshdr != NULL && 348ca987d46SWarner Losh lshdr->sh_offset >= shdr[i].sh_offset) 349ca987d46SWarner Losh continue; 350ca987d46SWarner Losh /* Find section with smallest offset. */ 351ca987d46SWarner Losh if (cshdr == lshdr || 352ca987d46SWarner Losh cshdr->sh_offset > shdr[i].sh_offset) 353ca987d46SWarner Losh cshdr = &shdr[i]; 354ca987d46SWarner Losh } 355ca987d46SWarner Losh 356ca987d46SWarner Losh if (cshdr == lshdr) 357ca987d46SWarner Losh break; 358ca987d46SWarner Losh 359afc571b1SSimon J. Gerraty if (kern_pread(VECTX_HANDLE(ef), (vm_offset_t)cshdr->sh_addr, 360ca987d46SWarner Losh cshdr->sh_size, (off_t)cshdr->sh_offset) != 0) { 361ca987d46SWarner Losh printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 362ca987d46SWarner Losh "_obj_loadimage: read failed\n"); 363ca987d46SWarner Losh goto out; 364ca987d46SWarner Losh } 365ca987d46SWarner Losh } 366ca987d46SWarner Losh 367ca987d46SWarner Losh file_addmetadata(fp, MODINFOMD_SHDR, shdrbytes, shdr); 368ca987d46SWarner Losh 369ca987d46SWarner Losh res = __elfN(obj_parse_modmetadata)(fp, ef); 370ca987d46SWarner Losh if (res != 0) 371ca987d46SWarner Losh goto out; 372ca987d46SWarner Losh 373ca987d46SWarner Losh ret = lastaddr - firstaddr; 374ca987d46SWarner Losh fp->f_addr = firstaddr; 375ca987d46SWarner Losh 376ec042f46SSimon J. Gerraty if (module_verbose > MODULE_VERBOSE_SILENT) 377ca987d46SWarner Losh printf("size 0x%lx at 0x%lx", (u_long)ret, (u_long)firstaddr); 378ca987d46SWarner Losh 379ca987d46SWarner Losh out: 380ec042f46SSimon J. Gerraty if (module_verbose > MODULE_VERBOSE_SILENT) 381ca987d46SWarner Losh printf("\n"); 382ca987d46SWarner Losh return ret; 383ca987d46SWarner Losh } 384ca987d46SWarner Losh 385ca987d46SWarner Losh #if defined(__i386__) && __ELF_WORD_SIZE == 64 386ca987d46SWarner Losh struct mod_metadata64 { 387ca987d46SWarner Losh int md_version; /* structure version MDTV_* */ 388ca987d46SWarner Losh int md_type; /* type of entry MDT_* */ 38956e53cb8SWarner Losh uint64_t md_data; /* specific data */ 39056e53cb8SWarner Losh uint64_t md_cval; /* common string label */ 391ca987d46SWarner Losh }; 392ca987d46SWarner Losh #endif 393ca987d46SWarner Losh 394ca987d46SWarner Losh int 395ca987d46SWarner Losh __elfN(obj_parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef) 396ca987d46SWarner Losh { 397ca987d46SWarner Losh struct mod_metadata md; 398ca987d46SWarner Losh #if defined(__i386__) && __ELF_WORD_SIZE == 64 399ca987d46SWarner Losh struct mod_metadata64 md64; 400ca987d46SWarner Losh #endif 401ca987d46SWarner Losh struct mod_depend *mdepend; 402ca987d46SWarner Losh struct mod_version mver; 403ca987d46SWarner Losh char *s; 404ca987d46SWarner Losh int error, modcnt, minfolen; 405ca987d46SWarner Losh Elf_Addr v, p, p_stop; 406ca987d46SWarner Losh 407ca987d46SWarner Losh if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop, 408ca987d46SWarner Losh &modcnt) != 0) 409ca987d46SWarner Losh return 0; 410ca987d46SWarner Losh 411ca987d46SWarner Losh modcnt = 0; 412ca987d46SWarner Losh while (p < p_stop) { 413ca987d46SWarner Losh COPYOUT(p, &v, sizeof(v)); 414ca987d46SWarner Losh error = __elfN(obj_reloc_ptr)(fp, ef, p, &v, sizeof(v)); 415ca987d46SWarner Losh if (error != 0) 416ca987d46SWarner Losh return (error); 417ca987d46SWarner Losh #if defined(__i386__) && __ELF_WORD_SIZE == 64 418ca987d46SWarner Losh COPYOUT(v, &md64, sizeof(md64)); 419ca987d46SWarner Losh error = __elfN(obj_reloc_ptr)(fp, ef, v, &md64, sizeof(md64)); 420ca987d46SWarner Losh if (error != 0) 421ca987d46SWarner Losh return (error); 422ca987d46SWarner Losh md.md_version = md64.md_version; 423ca987d46SWarner Losh md.md_type = md64.md_type; 424ca987d46SWarner Losh md.md_cval = (const char *)(uintptr_t)md64.md_cval; 425ca987d46SWarner Losh md.md_data = (void *)(uintptr_t)md64.md_data; 426ca987d46SWarner Losh #else 427ca987d46SWarner Losh COPYOUT(v, &md, sizeof(md)); 428ca987d46SWarner Losh error = __elfN(obj_reloc_ptr)(fp, ef, v, &md, sizeof(md)); 429ca987d46SWarner Losh if (error != 0) 430ca987d46SWarner Losh return (error); 431ca987d46SWarner Losh #endif 432ca987d46SWarner Losh p += sizeof(Elf_Addr); 433ca987d46SWarner Losh switch(md.md_type) { 434ca987d46SWarner Losh case MDT_DEPEND: 435ca987d46SWarner Losh s = strdupout((vm_offset_t)md.md_cval); 436ca987d46SWarner Losh minfolen = sizeof(*mdepend) + strlen(s) + 1; 437ca987d46SWarner Losh mdepend = malloc(minfolen); 438ca987d46SWarner Losh if (mdepend == NULL) 439ca987d46SWarner Losh return ENOMEM; 440ca987d46SWarner Losh COPYOUT((vm_offset_t)md.md_data, mdepend, 441ca987d46SWarner Losh sizeof(*mdepend)); 442ca987d46SWarner Losh strcpy((char*)(mdepend + 1), s); 443ca987d46SWarner Losh free(s); 444ca987d46SWarner Losh file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, 445ca987d46SWarner Losh mdepend); 446ca987d46SWarner Losh free(mdepend); 447ca987d46SWarner Losh break; 448ca987d46SWarner Losh case MDT_VERSION: 449ca987d46SWarner Losh s = strdupout((vm_offset_t)md.md_cval); 450ca987d46SWarner Losh COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); 451ca987d46SWarner Losh file_addmodule(fp, s, mver.mv_version, NULL); 452ca987d46SWarner Losh free(s); 453ca987d46SWarner Losh modcnt++; 454ca987d46SWarner Losh break; 455ca987d46SWarner Losh case MDT_MODULE: 456ca987d46SWarner Losh case MDT_PNP_INFO: 457ca987d46SWarner Losh break; 458ca987d46SWarner Losh default: 459ca987d46SWarner Losh printf("unknown type %d\n", md.md_type); 460ca987d46SWarner Losh break; 461ca987d46SWarner Losh } 462ca987d46SWarner Losh } 463ca987d46SWarner Losh return 0; 464ca987d46SWarner Losh } 465ca987d46SWarner Losh 466ca987d46SWarner Losh static int 467ca987d46SWarner Losh __elfN(obj_lookup_set)(struct preloaded_file *fp, elf_file_t ef, 468ca987d46SWarner Losh const char* name, Elf_Addr *startp, Elf_Addr *stopp, int *countp) 469ca987d46SWarner Losh { 470ca987d46SWarner Losh Elf_Ehdr *hdr; 471ca987d46SWarner Losh Elf_Shdr *shdr; 472ca987d46SWarner Losh char *p; 473ca987d46SWarner Losh vm_offset_t shstrtab; 474ca987d46SWarner Losh int i; 475ca987d46SWarner Losh 476ca987d46SWarner Losh hdr = &ef->hdr; 477ca987d46SWarner Losh shdr = ef->e_shdr; 478ca987d46SWarner Losh shstrtab = shdr[ef->shstrindex].sh_addr; 479ca987d46SWarner Losh 480ca987d46SWarner Losh for (i = 0; i < hdr->e_shnum; i++) { 481ca987d46SWarner Losh if (shdr[i].sh_type != SHT_PROGBITS) 482ca987d46SWarner Losh continue; 483ca987d46SWarner Losh if (shdr[i].sh_name == 0) 484ca987d46SWarner Losh continue; 485ca987d46SWarner Losh p = strdupout(shstrtab + shdr[i].sh_name); 486ca987d46SWarner Losh if (strncmp(p, "set_", 4) == 0 && strcmp(p + 4, name) == 0) { 487ca987d46SWarner Losh *startp = shdr[i].sh_addr; 488ca987d46SWarner Losh *stopp = shdr[i].sh_addr + shdr[i].sh_size; 489ca987d46SWarner Losh *countp = (*stopp - *startp) / sizeof(Elf_Addr); 490ca987d46SWarner Losh free(p); 491ca987d46SWarner Losh return (0); 492ca987d46SWarner Losh } 493ca987d46SWarner Losh free(p); 494ca987d46SWarner Losh } 495ca987d46SWarner Losh 496ca987d46SWarner Losh return (ESRCH); 497ca987d46SWarner Losh } 498ca987d46SWarner Losh 499ca987d46SWarner Losh /* 500ca987d46SWarner Losh * Apply any intra-module relocations to the value. p is the load address 501ca987d46SWarner Losh * of the value and val/len is the value to be modified. This does NOT modify 502ca987d46SWarner Losh * the image in-place, because this is done by kern_linker later on. 503ca987d46SWarner Losh */ 504ca987d46SWarner Losh static int 505ca987d46SWarner Losh __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, Elf_Addr p, 506ca987d46SWarner Losh void *val, size_t len) 507ca987d46SWarner Losh { 508ca987d46SWarner Losh Elf_Ehdr *hdr; 509ca987d46SWarner Losh Elf_Shdr *shdr; 510ca987d46SWarner Losh Elf_Addr off = p; 511ca987d46SWarner Losh Elf_Addr base; 512ca987d46SWarner Losh Elf_Rela a, *abase; 513ca987d46SWarner Losh Elf_Rel r, *rbase; 514ca987d46SWarner Losh int error, i, j, nrel, nrela; 515ca987d46SWarner Losh 516ca987d46SWarner Losh hdr = &ef->hdr; 517ca987d46SWarner Losh shdr = ef->e_shdr; 518ca987d46SWarner Losh 519ca987d46SWarner Losh for (i = 0; i < hdr->e_shnum; i++) { 520ca987d46SWarner Losh if (shdr[i].sh_type != SHT_RELA && shdr[i].sh_type != SHT_REL) 521ca987d46SWarner Losh continue; 522ca987d46SWarner Losh base = shdr[shdr[i].sh_info].sh_addr; 523ca987d46SWarner Losh if (base == 0 || shdr[i].sh_addr == 0) 524ca987d46SWarner Losh continue; 525ca987d46SWarner Losh if (off < base || off + len > base + 526ca987d46SWarner Losh shdr[shdr[i].sh_info].sh_size) 527ca987d46SWarner Losh continue; 528ca987d46SWarner Losh 529ca987d46SWarner Losh switch (shdr[i].sh_type) { 530ca987d46SWarner Losh case SHT_RELA: 531ca987d46SWarner Losh abase = (Elf_Rela *)(intptr_t)shdr[i].sh_addr; 532ca987d46SWarner Losh 533ca987d46SWarner Losh nrela = shdr[i].sh_size / sizeof(Elf_Rela); 534ca987d46SWarner Losh for (j = 0; j < nrela; j++) { 535ca987d46SWarner Losh COPYOUT(abase + j, &a, sizeof(a)); 536ca987d46SWarner Losh 537ca987d46SWarner Losh error = __elfN(reloc)(ef, __elfN(obj_symaddr), 538ca987d46SWarner Losh &a, ELF_RELOC_RELA, base, off, val, len); 539ca987d46SWarner Losh if (error != 0) 540ca987d46SWarner Losh return (error); 541ca987d46SWarner Losh } 542ca987d46SWarner Losh break; 543ca987d46SWarner Losh case SHT_REL: 544ca987d46SWarner Losh rbase = (Elf_Rel *)(intptr_t)shdr[i].sh_addr; 545ca987d46SWarner Losh 546ca987d46SWarner Losh nrel = shdr[i].sh_size / sizeof(Elf_Rel); 547ca987d46SWarner Losh for (j = 0; j < nrel; j++) { 548ca987d46SWarner Losh COPYOUT(rbase + j, &r, sizeof(r)); 549ca987d46SWarner Losh 550ca987d46SWarner Losh error = __elfN(reloc)(ef, __elfN(obj_symaddr), 551ca987d46SWarner Losh &r, ELF_RELOC_REL, base, off, val, len); 552ca987d46SWarner Losh if (error != 0) 553ca987d46SWarner Losh return (error); 554ca987d46SWarner Losh } 555ca987d46SWarner Losh break; 556ca987d46SWarner Losh } 557ca987d46SWarner Losh } 558ca987d46SWarner Losh return (0); 559ca987d46SWarner Losh } 560ca987d46SWarner Losh 561ca987d46SWarner Losh /* Look up the address of a specified symbol. */ 562ca987d46SWarner Losh static Elf_Addr 563ca987d46SWarner Losh __elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx) 564ca987d46SWarner Losh { 565ca987d46SWarner Losh Elf_Sym sym; 566ca987d46SWarner Losh Elf_Addr base; 567ca987d46SWarner Losh 568ca987d46SWarner Losh if (symidx >= ef->e_shdr[ef->symtabindex].sh_size / sizeof(Elf_Sym)) 569ca987d46SWarner Losh return (0); 570ca987d46SWarner Losh COPYOUT(ef->e_shdr[ef->symtabindex].sh_addr + symidx * sizeof(Elf_Sym), 571ca987d46SWarner Losh &sym, sizeof(sym)); 572ca987d46SWarner Losh if (sym.st_shndx == SHN_UNDEF || sym.st_shndx >= ef->hdr.e_shnum) 573ca987d46SWarner Losh return (0); 574ca987d46SWarner Losh base = ef->e_shdr[sym.st_shndx].sh_addr; 575ca987d46SWarner Losh if (base == 0) 576ca987d46SWarner Losh return (0); 577ca987d46SWarner Losh return (base + sym.st_value); 578ca987d46SWarner Losh } 579