link_elf.c revision 40906
1/*- 2 * Copyright (c) 1998 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: link_elf.c,v 1.8 1998/10/25 17:44:51 phk Exp $ 27 */ 28 29#include <sys/param.h> 30#include <sys/kernel.h> 31#include <sys/systm.h> 32#include <sys/malloc.h> 33#include <sys/proc.h> 34#include <sys/namei.h> 35#include <sys/fcntl.h> 36#include <sys/vnode.h> 37#include <sys/linker.h> 38#include <machine/elf.h> 39 40#include <vm/vm.h> 41#include <vm/vm_prot.h> 42#include <vm/vm_param.h> 43#include <sys/lock.h> 44#include <vm/vm_object.h> 45#include <vm/vm_kern.h> 46#include <vm/vm_extern.h> 47#include <vm/pmap.h> 48#include <vm/vm_map.h> 49 50static int link_elf_load_module(const char*, linker_file_t*); 51static int link_elf_load_file(const char*, linker_file_t*); 52static int link_elf_lookup_symbol(linker_file_t, const char*, 53 linker_sym_t*); 54static int link_elf_symbol_values(linker_file_t, linker_sym_t, linker_symval_t*); 55static int link_elf_search_symbol(linker_file_t, caddr_t value, 56 linker_sym_t* sym, long* diffp); 57 58static void link_elf_unload_file(linker_file_t); 59static void link_elf_unload_module(linker_file_t); 60 61static struct linker_class_ops link_elf_class_ops = { 62 link_elf_load_module, 63}; 64 65static struct linker_file_ops link_elf_file_ops = { 66 link_elf_lookup_symbol, 67 link_elf_symbol_values, 68 link_elf_search_symbol, 69 link_elf_unload_file, 70}; 71 72static struct linker_file_ops link_elf_module_ops = { 73 link_elf_lookup_symbol, 74 link_elf_symbol_values, 75 link_elf_search_symbol, 76 link_elf_unload_module, 77}; 78typedef struct elf_file { 79 caddr_t address; /* Relocation address */ 80#ifdef SPARSE_MAPPING 81 vm_object_t object; /* VM object to hold file pages */ 82#endif 83 const Elf_Dyn* dynamic; /* Symbol table etc. */ 84 Elf_Off nbuckets; /* DT_HASH info */ 85 Elf_Off nchains; 86 const Elf_Off* buckets; 87 const Elf_Off* chains; 88 caddr_t hash; 89 caddr_t strtab; /* DT_STRTAB */ 90 int strsz; /* DT_STRSZ */ 91 const Elf_Sym* symtab; /* DT_SYMTAB */ 92 Elf_Addr* got; /* DT_PLTGOT */ 93 const Elf_Rel* pltrel; /* DT_JMPREL */ 94 int pltrelsize; /* DT_PLTRELSZ */ 95 const Elf_Rela* pltrela; /* DT_JMPREL */ 96 int pltrelasize; /* DT_PLTRELSZ */ 97 const Elf_Rel* rel; /* DT_REL */ 98 int relsize; /* DT_RELSZ */ 99 const Elf_Rela* rela; /* DT_RELA */ 100 int relasize; /* DT_RELASZ */ 101 caddr_t modptr; 102 const Elf_Sym* ddbsymtab; /* The symbol table we are using */ 103 long ddbsymcnt; /* Number of symbols */ 104 caddr_t ddbstrtab; /* String table */ 105 long ddbstrcnt; /* number of bytes in string table */ 106 caddr_t symbase; /* malloc'ed symbold base */ 107 caddr_t strbase; /* malloc'ed string base */ 108} *elf_file_t; 109 110static int parse_dynamic(linker_file_t lf); 111static int load_dependancies(linker_file_t lf); 112static int relocate_file(linker_file_t lf); 113static int parse_module_symbols(linker_file_t lf); 114 115/* 116 * The kernel symbol table starts here. 117 */ 118extern struct _dynamic _DYNAMIC; 119 120static void 121link_elf_init(void* arg) 122{ 123#ifdef __ELF__ 124 Elf_Dyn *dp; 125 caddr_t modptr, baseptr, sizeptr; 126 elf_file_t ef; 127 char *modname; 128#endif 129 130#if ELF_TARG_CLASS == ELFCLASS32 131 linker_add_class("elf32", NULL, &link_elf_class_ops); 132#else 133 linker_add_class("elf64", NULL, &link_elf_class_ops); 134#endif 135 136#ifdef __ELF__ 137 dp = (Elf_Dyn*) &_DYNAMIC; 138 if (dp) { 139 ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT); 140 if (ef == NULL) 141 panic("link_elf_init: Can't create linker structures for kernel"); 142 bzero(ef, sizeof(*ef)); 143 144 ef->address = 0; 145#ifdef SPARSE_MAPPING 146 ef->object = 0; 147#endif 148 ef->dynamic = dp; 149 modname = NULL; 150 modptr = preload_search_by_type("elf kernel"); 151 if (modptr) 152 modname = (char *)preload_search_info(modptr, MODINFO_NAME); 153 if (modname == NULL) 154 modname = "kernel"; 155 linker_kernel_file = linker_make_file(modname, ef, &link_elf_file_ops); 156 if (linker_kernel_file == NULL) 157 panic("link_elf_init: Can't create linker structures for kernel"); 158 parse_dynamic(linker_kernel_file); 159 /* Sigh, magic constants. */ 160#ifdef __alpha__ 161 linker_kernel_file->address = (caddr_t) 0xfffffc0000300000; 162#else 163 linker_kernel_file->address = (caddr_t) 0xf0100000; 164#endif 165 linker_kernel_file->size = -(long)linker_kernel_file->address; 166 167 if (modptr) { 168 ef->modptr = modptr; 169 baseptr = preload_search_info(modptr, MODINFO_ADDR); 170 if (baseptr) 171 linker_kernel_file->address = *(caddr_t *)baseptr; 172 sizeptr = preload_search_info(modptr, MODINFO_SIZE); 173 if (sizeptr) 174 linker_kernel_file->size = *(size_t *)sizeptr; 175 } 176 (void)parse_module_symbols(linker_kernel_file); 177 linker_current_file = linker_kernel_file; 178 } 179#endif 180} 181 182SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); 183 184static int 185parse_module_symbols(linker_file_t lf) 186{ 187 elf_file_t ef = lf->priv; 188 caddr_t pointer; 189 caddr_t ssym, esym, base; 190 caddr_t strtab; 191 int strcnt; 192 Elf_Sym* symtab; 193 int symcnt; 194 195 if (ef->modptr == NULL) 196 return 0; 197 pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM); 198 if (pointer == NULL) 199 return 0; 200 ssym = *(caddr_t *)pointer; 201 pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM); 202 if (pointer == NULL) 203 return 0; 204 esym = *(caddr_t *)pointer; 205 206 base = ssym; 207 208 symcnt = *(long *)base; 209 base += sizeof(long); 210 symtab = (Elf_Sym *)base; 211 base += roundup(symcnt, sizeof(long)); 212 213 if (base > esym || base < ssym) { 214 printf("Symbols are corrupt!\n"); 215 return EINVAL; 216 } 217 218 strcnt = *(long *)base; 219 base += sizeof(long); 220 strtab = base; 221 base += roundup(strcnt, sizeof(long)); 222 223 if (base > esym || base < ssym) { 224 printf("Symbols are corrupt!\n"); 225 return EINVAL; 226 } 227 228 ef->ddbsymtab = symtab; 229 ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 230 ef->ddbstrtab = strtab; 231 ef->ddbstrcnt = strcnt; 232 233 return 0; 234} 235 236static int 237parse_dynamic(linker_file_t lf) 238{ 239 elf_file_t ef = lf->priv; 240 const Elf_Dyn *dp; 241 int plttype = DT_REL; 242 243 for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 244 switch (dp->d_tag) { 245 case DT_HASH: 246 { 247 /* From src/libexec/rtld-elf/rtld.c */ 248 const Elf_Off *hashtab = (const Elf_Off *) 249 (ef->address + dp->d_un.d_ptr); 250 ef->nbuckets = hashtab[0]; 251 ef->nchains = hashtab[1]; 252 ef->buckets = hashtab + 2; 253 ef->chains = ef->buckets + ef->nbuckets; 254 break; 255 } 256 case DT_STRTAB: 257 ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 258 break; 259 case DT_STRSZ: 260 ef->strsz = dp->d_un.d_val; 261 break; 262 case DT_SYMTAB: 263 ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 264 break; 265 case DT_SYMENT: 266 if (dp->d_un.d_val != sizeof(Elf_Sym)) 267 return ENOEXEC; 268 break; 269 case DT_PLTGOT: 270 ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 271 break; 272 case DT_REL: 273 ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 274 break; 275 case DT_RELSZ: 276 ef->relsize = dp->d_un.d_val; 277 break; 278 case DT_RELENT: 279 if (dp->d_un.d_val != sizeof(Elf_Rel)) 280 return ENOEXEC; 281 break; 282 case DT_JMPREL: 283 ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 284 break; 285 case DT_PLTRELSZ: 286 ef->pltrelsize = dp->d_un.d_val; 287 break; 288 case DT_RELA: 289 ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 290 break; 291 case DT_RELASZ: 292 ef->relasize = dp->d_un.d_val; 293 break; 294 case DT_RELAENT: 295 if (dp->d_un.d_val != sizeof(Elf_Rela)) 296 return ENOEXEC; 297 break; 298 case DT_PLTREL: 299 plttype = dp->d_un.d_val; 300 if (plttype != DT_REL && plttype != DT_RELA) 301 return ENOEXEC; 302 break; 303 } 304 } 305 306 if (plttype == DT_RELA) { 307 ef->pltrela = (const Elf_Rela *) ef->pltrel; 308 ef->pltrel = NULL; 309 ef->pltrelasize = ef->pltrelsize; 310 ef->pltrelsize = 0; 311 } 312 313 ef->ddbsymtab = ef->symtab; 314 ef->ddbsymcnt = ef->nchains; 315 ef->ddbstrtab = ef->strtab; 316 ef->ddbstrcnt = ef->strsz; 317 318 return 0; 319} 320 321static void 322link_elf_error(const char *s) 323{ 324 printf("kldload: %s\n", s); 325} 326 327static int 328link_elf_load_module(const char *filename, linker_file_t *result) 329{ 330 caddr_t modptr, baseptr, sizeptr, dynptr; 331 char *type; 332 elf_file_t ef; 333 linker_file_t lf; 334 int error; 335 vm_offset_t dp; 336 337 /* Look to see if we have the module preloaded */ 338 modptr = preload_search_by_name(filename); 339 if (modptr == NULL) 340 return (link_elf_load_file(filename, result)); 341 342 /* It's preloaded, check we can handle it and collect information */ 343 type = (char *)preload_search_info(modptr, MODINFO_TYPE); 344 baseptr = preload_search_info(modptr, MODINFO_ADDR); 345 sizeptr = preload_search_info(modptr, MODINFO_SIZE); 346 dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC); 347 if (type == NULL || strcmp(type, "elf module") != 0) 348 return (EFTYPE); 349 if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) 350 return (EINVAL); 351 352 ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); 353 if (ef == NULL) 354 return (ENOMEM); 355 bzero(ef, sizeof(*ef)); 356 ef->modptr = modptr; 357 ef->address = *(caddr_t *)baseptr; 358#ifdef SPARSE_MAPPING 359 ef->object = 0; 360#endif 361 dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; 362 ef->dynamic = (Elf_Dyn *)dp; 363 lf = linker_make_file(filename, ef, &link_elf_module_ops); 364 if (lf == NULL) { 365 free(ef, M_LINKER); 366 return ENOMEM; 367 } 368 lf->address = ef->address; 369 lf->size = *(size_t *)sizeptr; 370 371 error = parse_dynamic(lf); 372 if (error) { 373 linker_file_unload(lf); 374 return error; 375 } 376 error = load_dependancies(lf); 377 if (error) { 378 linker_file_unload(lf); 379 return error; 380 } 381 error = relocate_file(lf); 382 if (error) { 383 linker_file_unload(lf); 384 return error; 385 } 386 (void)parse_module_symbols(lf); 387 *result = lf; 388 return (0); 389} 390 391static int 392link_elf_load_file(const char* filename, linker_file_t* result) 393{ 394 struct nameidata nd; 395 struct proc* p = curproc; /* XXX */ 396 union { 397 Elf_Ehdr hdr; 398 char buf[PAGE_SIZE]; 399 } u; 400 int nbytes, i; 401 Elf_Phdr *phdr; 402 Elf_Phdr *phlimit; 403 Elf_Phdr *segs[2]; 404 int nsegs; 405 Elf_Phdr *phdyn; 406 Elf_Phdr *phphdr; 407 caddr_t mapbase; 408 size_t mapsize; 409 Elf_Off base_offset; 410 Elf_Addr base_vaddr; 411 Elf_Addr base_vlimit; 412 int error = 0; 413 int resid; 414 elf_file_t ef; 415 linker_file_t lf; 416 char *pathname; 417 Elf_Shdr *shdr; 418 int symtabindex; 419 int symstrindex; 420 int symcnt; 421 int strcnt; 422 423 shdr = NULL; 424 lf = NULL; 425 426 pathname = linker_search_path(filename); 427 if (pathname == NULL) 428 return ENOENT; 429 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p); 430 error = vn_open(&nd, FREAD, 0); 431 free(pathname, M_LINKER); 432 if (error) 433 return error; 434 435 /* 436 * Read the elf header from the file. 437 */ 438 error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &u, sizeof u, 0, 439 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 440 nbytes = sizeof u - resid; 441 if (error) 442 goto out; 443 444 if (!IS_ELF(u.hdr)) { 445 error = ENOEXEC; 446 goto out; 447 } 448 449 if (u.hdr.e_ident[EI_CLASS] != ELF_TARG_CLASS 450 || u.hdr.e_ident[EI_DATA] != ELF_TARG_DATA) { 451 link_elf_error("Unsupported file layout"); 452 error = ENOEXEC; 453 goto out; 454 } 455 if (u.hdr.e_ident[EI_VERSION] != EV_CURRENT 456 || u.hdr.e_version != EV_CURRENT) { 457 link_elf_error("Unsupported file version"); 458 error = ENOEXEC; 459 goto out; 460 } 461 if (u.hdr.e_type != ET_EXEC && u.hdr.e_type != ET_DYN) { 462 link_elf_error("Unsupported file type"); 463 error = ENOEXEC; 464 goto out; 465 } 466 if (u.hdr.e_machine != ELF_TARG_MACH) { 467 link_elf_error("Unsupported machine"); 468 error = ENOEXEC; 469 goto out; 470 } 471 472 /* 473 * We rely on the program header being in the first page. This is 474 * not strictly required by the ABI specification, but it seems to 475 * always true in practice. And, it simplifies things considerably. 476 */ 477 if (!((u.hdr.e_phentsize == sizeof(Elf_Phdr)) 478 || (u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) 479 || (u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= nbytes))) 480 link_elf_error("Unreadable program headers"); 481 482 /* 483 * Scan the program header entries, and save key information. 484 * 485 * We rely on there being exactly two load segments, text and data, 486 * in that order. 487 */ 488 phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff); 489 phlimit = phdr + u.hdr.e_phnum; 490 nsegs = 0; 491 phdyn = NULL; 492 phphdr = NULL; 493 while (phdr < phlimit) { 494 switch (phdr->p_type) { 495 496 case PT_LOAD: 497 if (nsegs == 2) { 498 link_elf_error("Too many sections"); 499 error = ENOEXEC; 500 goto out; 501 } 502 segs[nsegs] = phdr; 503 ++nsegs; 504 break; 505 506 case PT_PHDR: 507 phphdr = phdr; 508 break; 509 510 case PT_DYNAMIC: 511 phdyn = phdr; 512 break; 513 } 514 515 ++phdr; 516 } 517 if (phdyn == NULL) { 518 link_elf_error("Object is not dynamically-linked"); 519 error = ENOEXEC; 520 goto out; 521 } 522 523 /* 524 * Allocate the entire address space of the object, to stake out our 525 * contiguous region, and to establish the base address for relocation. 526 */ 527 base_offset = trunc_page(segs[0]->p_offset); 528 base_vaddr = trunc_page(segs[0]->p_vaddr); 529 base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); 530 mapsize = base_vlimit - base_vaddr; 531 532 ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); 533 bzero(ef, sizeof(*ef)); 534#ifdef SPARSE_MAPPING 535 ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); 536 if (ef->object == NULL) { 537 free(ef, M_LINKER); 538 error = ENOMEM; 539 goto out; 540 } 541 vm_object_reference(ef->object); 542 ef->address = (caddr_t) vm_map_min(kernel_map); 543 error = vm_map_find(kernel_map, ef->object, 0, 544 (vm_offset_t *) &ef->address, 545 mapsize, 1, 546 VM_PROT_ALL, VM_PROT_ALL, 0); 547 if (error) { 548 vm_object_deallocate(ef->object); 549 free(ef, M_LINKER); 550 goto out; 551 } 552#else 553 ef->address = malloc(mapsize, M_LINKER, M_WAITOK); 554#endif 555 mapbase = ef->address; 556 557 /* 558 * Read the text and data sections and zero the bss. 559 */ 560 for (i = 0; i < 2; i++) { 561 caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; 562 error = vn_rdwr(UIO_READ, nd.ni_vp, 563 segbase, segs[i]->p_filesz, segs[i]->p_offset, 564 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 565 if (error) { 566#ifdef SPARSE_MAPPING 567 vm_map_remove(kernel_map, (vm_offset_t) ef->address, 568 (vm_offset_t) ef->address 569 + (ef->object->size << PAGE_SHIFT)); 570 vm_object_deallocate(ef->object); 571#else 572 free(ef->address, M_LINKER); 573#endif 574 free(ef, M_LINKER); 575 goto out; 576 } 577 bzero(segbase + segs[i]->p_filesz, 578 segs[i]->p_memsz - segs[i]->p_filesz); 579 580#ifdef SPARSE_MAPPING 581 /* 582 * Wire down the pages 583 */ 584 vm_map_pageable(kernel_map, 585 (vm_offset_t) segbase, 586 (vm_offset_t) segbase + segs[i]->p_memsz, 587 FALSE); 588#endif 589 } 590 591 ef->dynamic = (const Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); 592 593 lf = linker_make_file(filename, ef, &link_elf_file_ops); 594 if (lf == NULL) { 595#ifdef SPARSE_MAPPING 596 vm_map_remove(kernel_map, (vm_offset_t) ef->address, 597 (vm_offset_t) ef->address 598 + (ef->object->size << PAGE_SHIFT)); 599 vm_object_deallocate(ef->object); 600#else 601 free(ef->address, M_LINKER); 602#endif 603 free(ef, M_LINKER); 604 error = ENOMEM; 605 goto out; 606 } 607 lf->address = ef->address; 608 lf->size = mapsize; 609 610 error = parse_dynamic(lf); 611 if (error) 612 goto out; 613 error = load_dependancies(lf); 614 if (error) 615 goto out; 616 error = relocate_file(lf); 617 if (error) 618 goto out; 619 620 /* Try and load the symbol table if it's present. (you can strip it!) */ 621 nbytes = u.hdr.e_shnum * u.hdr.e_shentsize; 622 if (nbytes == 0 || u.hdr.e_shoff == 0) 623 goto nosyms; 624 shdr = malloc(nbytes, M_LINKER, M_WAITOK); 625 if (shdr == NULL) { 626 error = ENOMEM; 627 goto out; 628 } 629 bzero(shdr, nbytes); 630 error = vn_rdwr(UIO_READ, nd.ni_vp, 631 (caddr_t)shdr, nbytes, u.hdr.e_shoff, 632 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 633 if (error) 634 goto out; 635 symtabindex = -1; 636 symstrindex = -1; 637 for (i = 0; i < u.hdr.e_shnum; i++) { 638 if (shdr[i].sh_type == SHT_SYMTAB) { 639 symtabindex = i; 640 symstrindex = shdr[i].sh_link; 641 } 642 } 643 if (symtabindex < 0 || symstrindex < 0) 644 goto nosyms; 645 646 symcnt = shdr[symtabindex].sh_size; 647 ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK); 648 strcnt = shdr[symstrindex].sh_size; 649 ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK); 650 651 if (ef->symbase == NULL || ef->strbase == NULL) { 652 error = ENOMEM; 653 goto out; 654 } 655 error = vn_rdwr(UIO_READ, nd.ni_vp, 656 ef->symbase, symcnt, shdr[symtabindex].sh_offset, 657 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 658 if (error) 659 goto out; 660 error = vn_rdwr(UIO_READ, nd.ni_vp, 661 ef->strbase, strcnt, shdr[symstrindex].sh_offset, 662 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 663 if (error) 664 goto out; 665 666 ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 667 ef->ddbsymtab = (const Elf_Sym *)ef->symbase; 668 ef->ddbstrcnt = strcnt; 669 ef->ddbstrtab = ef->strbase; 670 671nosyms: 672 673 *result = lf; 674 675out: 676 if (error && lf) 677 linker_file_unload(lf); 678 if (shdr) 679 free(shdr, M_LINKER); 680 VOP_UNLOCK(nd.ni_vp, 0, p); 681 vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 682 683 return error; 684} 685 686static void 687link_elf_unload_file(linker_file_t file) 688{ 689 elf_file_t ef = file->priv; 690 691 if (ef) { 692#ifdef SPARSE_MAPPING 693 if (ef->object) { 694 vm_map_remove(kernel_map, (vm_offset_t) ef->address, 695 (vm_offset_t) ef->address 696 + (ef->object->size << PAGE_SHIFT)); 697 vm_object_deallocate(ef->object); 698 } 699#else 700 if (ef->address) 701 free(ef->address, M_LINKER); 702#endif 703 if (ef->symbase) 704 free(ef->symbase, M_LINKER); 705 if (ef->strbase) 706 free(ef->strbase, M_LINKER); 707 free(ef, M_LINKER); 708 } 709} 710 711static void 712link_elf_unload_module(linker_file_t file) 713{ 714 elf_file_t ef = file->priv; 715 716 if (ef) 717 free(ef, M_LINKER); 718 if (file->filename) 719 preload_delete_name(file->filename); 720} 721 722static int 723load_dependancies(linker_file_t lf) 724{ 725 elf_file_t ef = lf->priv; 726 linker_file_t lfdep; 727 char* name; 728 const Elf_Dyn *dp; 729 int error = 0; 730 731 /* 732 * All files are dependant on /kernel. 733 */ 734 if (linker_kernel_file) { 735 linker_kernel_file->refs++; 736 linker_file_add_dependancy(lf, linker_kernel_file); 737 } 738 739 for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 740 if (dp->d_tag == DT_NEEDED) { 741 name = ef->strtab + dp->d_un.d_val; 742 743 error = linker_load_file(name, &lfdep); 744 if (error) 745 goto out; 746 error = linker_file_add_dependancy(lf, lfdep); 747 if (error) 748 goto out; 749 } 750 } 751 752out: 753 return error; 754} 755 756static const char * 757symbol_name(elf_file_t ef, Elf_Word r_info) 758{ 759 const Elf_Sym *ref; 760 761 if (ELF_R_SYM(r_info)) { 762 ref = ef->symtab + ELF_R_SYM(r_info); 763 return ef->strtab + ref->st_name; 764 } else 765 return NULL; 766} 767 768static int 769relocate_file(linker_file_t lf) 770{ 771 elf_file_t ef = lf->priv; 772 const Elf_Rel *rellim; 773 const Elf_Rel *rel; 774 const Elf_Rela *relalim; 775 const Elf_Rela *rela; 776 const char *symname; 777 778 /* Perform relocations without addend if there are any: */ 779 rel = ef->rel; 780 if (rel) { 781 rellim = (const Elf_Rel *) ((caddr_t) ef->rel + ef->relsize); 782 while (rel < rellim) { 783 symname = symbol_name(ef, rel->r_info); 784 if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) 785 return ENOENT; 786 rel++; 787 } 788 } 789 790 /* Perform relocations with addend if there are any: */ 791 rela = ef->rela; 792 if (rela) { 793 relalim = (const Elf_Rela *) ((caddr_t) ef->rela + ef->relasize); 794 while (rela < relalim) { 795 symname = symbol_name(ef, rela->r_info); 796 if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) 797 return ENOENT; 798 rela++; 799 } 800 } 801 802 /* Perform PLT relocations without addend if there are any: */ 803 rel = ef->pltrel; 804 if (rel) { 805 rellim = (const Elf_Rel *) ((caddr_t) ef->pltrel + ef->pltrelsize); 806 while (rel < rellim) { 807 symname = symbol_name(ef, rel->r_info); 808 if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) 809 return ENOENT; 810 rel++; 811 } 812 } 813 814 /* Perform relocations with addend if there are any: */ 815 rela = ef->pltrela; 816 if (rela) { 817 relalim = (const Elf_Rela *) ((caddr_t) ef->pltrela + ef->pltrelasize); 818 while (rela < relalim) { 819 symname = symbol_name(ef, rela->r_info); 820 if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) 821 return ENOENT; 822 rela++; 823 } 824 } 825 826 return 0; 827} 828 829/* 830 * Hash function for symbol table lookup. Don't even think about changing 831 * this. It is specified by the System V ABI. 832 */ 833static unsigned long 834elf_hash(const char *name) 835{ 836 const unsigned char *p = (const unsigned char *) name; 837 unsigned long h = 0; 838 unsigned long g; 839 840 while (*p != '\0') { 841 h = (h << 4) + *p++; 842 if ((g = h & 0xf0000000) != 0) 843 h ^= g >> 24; 844 h &= ~g; 845 } 846 return h; 847} 848 849int 850link_elf_lookup_symbol(linker_file_t lf, const char* name, linker_sym_t* sym) 851{ 852 elf_file_t ef = lf->priv; 853 unsigned long symnum; 854 const Elf_Sym* symp; 855 const char *strp; 856 unsigned long hash; 857 int i; 858 859 /* First, search hashed global symbols */ 860 hash = elf_hash(name); 861 symnum = ef->buckets[hash % ef->nbuckets]; 862 863 while (symnum != STN_UNDEF) { 864 if (symnum >= ef->nchains) { 865 printf("link_elf_lookup_symbol: corrupt symbol table\n"); 866 return ENOENT; 867 } 868 869 symp = ef->symtab + symnum; 870 if (symp->st_name == 0) { 871 printf("link_elf_lookup_symbol: corrupt symbol table\n"); 872 return ENOENT; 873 } 874 875 strp = ef->strtab + symp->st_name; 876 877 if (strcmp(name, strp) == 0) { 878 if (symp->st_shndx != SHN_UNDEF || 879 (symp->st_value != 0 && 880 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 881 *sym = (linker_sym_t) symp; 882 return 0; 883 } else 884 return ENOENT; 885 } 886 887 symnum = ef->chains[symnum]; 888 } 889 890 /* If we have not found it, look at the full table (if loaded) */ 891 if (ef->symtab == ef->ddbsymtab) 892 return ENOENT; 893 894 /* Exhaustive search */ 895 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 896 strp = ef->ddbstrtab + symp->st_name; 897 if (strcmp(name, strp) == 0) { 898 if (symp->st_shndx != SHN_UNDEF || 899 (symp->st_value != 0 && 900 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 901 *sym = (linker_sym_t) symp; 902 return 0; 903 } else 904 return ENOENT; 905 } 906 } 907 908 return ENOENT; 909} 910 911static int 912link_elf_symbol_values(linker_file_t lf, linker_sym_t sym, linker_symval_t* symval) 913{ 914 elf_file_t ef = lf->priv; 915 Elf_Sym* es = (Elf_Sym*) sym; 916 917 if (es >= ef->symtab && ((es - ef->symtab) < ef->nchains)) { 918 symval->name = ef->strtab + es->st_name; 919 symval->value = (caddr_t) ef->address + es->st_value; 920 symval->size = es->st_size; 921 return 0; 922 } 923 if (ef->symtab == ef->ddbsymtab) 924 return ENOENT; 925 if (es >= ef->ddbsymtab && ((es - ef->ddbsymtab) < ef->ddbsymcnt)) { 926 symval->name = ef->ddbstrtab + es->st_name; 927 symval->value = (caddr_t) ef->address + es->st_value; 928 symval->size = es->st_size; 929 return 0; 930 } 931 return ENOENT; 932} 933 934static int 935link_elf_search_symbol(linker_file_t lf, caddr_t value, 936 linker_sym_t* sym, long* diffp) 937{ 938 elf_file_t ef = lf->priv; 939 u_long off = (u_long) value; 940 u_long diff = off; 941 const Elf_Sym* es; 942 const Elf_Sym* best = 0; 943 int i; 944 945 for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { 946 if (es->st_name == 0) 947 continue; 948 if (off >= es->st_value) { 949 if (off - es->st_value < diff) { 950 diff = off - es->st_value; 951 best = es; 952 if (diff == 0) 953 break; 954 } else if (off - es->st_value == diff) { 955 best = es; 956 } 957 } 958 } 959 if (best == 0) 960 *diffp = off; 961 else 962 *diffp = diff; 963 *sym = (linker_sym_t) best; 964 965 return 0; 966} 967