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