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