link_elf.c revision 40254
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.3 1998/10/09 23:55:31 peter 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 61/* 62 * The file representing the currently running kernel. This contains 63 * the global symbol table. 64 */ 65 66linker_file_t linker_kernel_file; 67 68static struct linker_class_ops link_elf_class_ops = { 69 link_elf_load_module, 70}; 71 72static struct linker_file_ops link_elf_file_ops = { 73 link_elf_lookup_symbol, 74 link_elf_symbol_values, 75 link_elf_search_symbol, 76 link_elf_unload_file, 77}; 78 79static struct linker_file_ops link_elf_module_ops = { 80 link_elf_lookup_symbol, 81 link_elf_symbol_values, 82 link_elf_search_symbol, 83 link_elf_unload_module, 84}; 85typedef struct elf_file { 86 caddr_t address; /* Relocation address */ 87#ifdef SPARSE_MAPPING 88 vm_object_t object; /* VM object to hold file pages */ 89#endif 90 const Elf_Dyn* dynamic; /* Symbol table etc. */ 91 Elf_Off nbuckets; /* DT_HASH info */ 92 Elf_Off nchains; 93 const Elf_Off* buckets; 94 const Elf_Off* chains; 95 caddr_t hash; 96 caddr_t strtab; /* DT_STRTAB */ 97 int strsz; /* DT_STRSZ */ 98 const Elf_Sym* symtab; /* DT_SYMTAB */ 99 Elf_Addr* got; /* DT_PLTGOT */ 100 const Elf_Rel* pltrel; /* DT_JMPREL */ 101 int pltrelsize; /* DT_PLTRELSZ */ 102 const Elf_Rela* pltrela; /* DT_JMPREL */ 103 int pltrelasize; /* DT_PLTRELSZ */ 104 const Elf_Rel* rel; /* DT_REL */ 105 int relsize; /* DT_RELSZ */ 106 const Elf_Rela* rela; /* DT_RELA */ 107 int relasize; /* DT_RELASZ */ 108 caddr_t modptr; 109 const Elf_Sym* ddbsymtab; /* The symbol table we are using */ 110 long ddbsymcnt; /* Number of symbols */ 111 caddr_t ddbstrtab; /* String table */ 112 long ddbstrcnt; /* number of bytes in string table */ 113} *elf_file_t; 114 115static int parse_dynamic(linker_file_t lf); 116static int load_dependancies(linker_file_t lf); 117static int relocate_file(linker_file_t lf); 118static int parse_module_symbols(linker_file_t lf); 119 120/* 121 * The kernel symbol table starts here. 122 */ 123extern struct _dynamic _DYNAMIC; 124 125static void 126link_elf_init(void* arg) 127{ 128#ifdef __ELF__ 129 Elf_Dyn *dp; 130 caddr_t modptr, baseptr, sizeptr; 131 elf_file_t ef; 132 char *modname; 133#endif 134 135#if ELF_TARG_CLASS == ELFCLASS32 136 linker_add_class("elf32", NULL, &link_elf_class_ops); 137#else 138 linker_add_class("elf64", NULL, &link_elf_class_ops); 139#endif 140 141#ifdef __ELF__ 142 dp = (Elf_Dyn*) &_DYNAMIC; 143 if (dp) { 144 ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT); 145 if (ef == NULL) 146 panic("link_elf_init: Can't create linker structures for kernel"); 147 148 ef->address = 0; 149#ifdef SPARSE_MAPPING 150 ef->object = 0; 151#endif 152 ef->dynamic = dp; 153 modname = NULL; 154 modptr = preload_search_by_type("elf kernel"); 155 if (modptr) 156 modname = (char *)preload_search_info(modptr, MODINFO_NAME); 157 if (modname == NULL) 158 modname = "kernel"; 159 linker_kernel_file = linker_make_file(modname, ef, &link_elf_file_ops); 160 if (linker_kernel_file == NULL) 161 panic("link_elf_init: Can't create linker structures for kernel"); 162 parse_dynamic(linker_kernel_file); 163 /* Sigh, magic constants. */ 164#ifdef __alpha__ 165 linker_kernel_file->address = (caddr_t) 0xfffffc0000300000; 166#else 167 linker_kernel_file->address = (caddr_t) 0xf0100000; 168#endif 169 linker_kernel_file->size = -(long)linker_kernel_file->address; 170 171 if (modptr) { 172 ef->modptr = modptr; 173 baseptr = preload_search_info(modptr, MODINFO_ADDR); 174 if (baseptr) 175 linker_kernel_file->address = *(caddr_t *)baseptr; 176 sizeptr = preload_search_info(modptr, MODINFO_SIZE); 177 if (sizeptr) 178 linker_kernel_file->size = *(size_t *)sizeptr; 179 } 180 (void)parse_module_symbols(linker_kernel_file); 181 linker_current_file = linker_kernel_file; 182 } 183#endif 184} 185 186SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); 187 188static int 189parse_module_symbols(linker_file_t lf) 190{ 191 elf_file_t ef = lf->priv; 192 caddr_t pointer; 193 caddr_t ssym, esym, base; 194 caddr_t strtab; 195 int strcnt; 196 Elf_Sym* symtab; 197 int symcnt; 198 199 pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM); 200 if (pointer == NULL) 201 return 0; 202 ssym = *(caddr_t *)pointer; 203 pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM); 204 if (pointer == NULL) 205 return 0; 206 esym = *(caddr_t *)pointer; 207 208 base = ssym; 209 210 symcnt = *(long *)base; 211 base += sizeof(long); 212 symtab = (Elf_Sym *)base; 213 base += roundup(symcnt, sizeof(long)); 214 215 if (base > esym || base < ssym) { 216 printf("Symbols are corrupt!\n"); 217 return EINVAL; 218 } 219 220 strcnt = *(long *)base; 221 base += sizeof(long); 222 strtab = base; 223 base += roundup(strcnt, sizeof(long)); 224 225 if (base > esym || base < ssym) { 226 printf("Symbols are corrupt!\n"); 227 return EINVAL; 228 } 229 230 ef->ddbsymtab = symtab; 231 ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 232 ef->ddbstrtab = strtab; 233 ef->ddbstrcnt = strcnt; 234 235 return 0; 236} 237 238static int 239parse_dynamic(linker_file_t lf) 240{ 241 elf_file_t ef = lf->priv; 242 const Elf_Dyn *dp; 243 int plttype = DT_REL; 244 245 for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 246 switch (dp->d_tag) { 247 case DT_HASH: 248 { 249 /* From src/libexec/rtld-elf/rtld.c */ 250 const Elf_Off *hashtab = (const Elf_Off *) 251 (ef->address + dp->d_un.d_ptr); 252 ef->nbuckets = hashtab[0]; 253 ef->nchains = hashtab[1]; 254 ef->buckets = hashtab + 2; 255 ef->chains = ef->buckets + ef->nbuckets; 256 break; 257 } 258 case DT_STRTAB: 259 ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 260 break; 261 case DT_STRSZ: 262 ef->strsz = dp->d_un.d_val; 263 break; 264 case DT_SYMTAB: 265 ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 266 break; 267 case DT_SYMENT: 268 if (dp->d_un.d_val != sizeof(Elf_Sym)) 269 return ENOEXEC; 270 break; 271 case DT_PLTGOT: 272 ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 273 break; 274 case DT_REL: 275 ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 276 break; 277 case DT_RELSZ: 278 ef->relsize = dp->d_un.d_val; 279 break; 280 case DT_RELENT: 281 if (dp->d_un.d_val != sizeof(Elf_Rel)) 282 return ENOEXEC; 283 break; 284 case DT_JMPREL: 285 ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 286 break; 287 case DT_PLTRELSZ: 288 ef->pltrelsize = dp->d_un.d_val; 289 break; 290 case DT_RELA: 291 ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 292 break; 293 case DT_RELASZ: 294 ef->relasize = dp->d_un.d_val; 295 break; 296 case DT_RELAENT: 297 if (dp->d_un.d_val != sizeof(Elf_Rela)) 298 return ENOEXEC; 299 break; 300 case DT_PLTREL: 301 plttype = dp->d_un.d_val; 302 if (plttype != DT_REL && plttype != DT_RELA) 303 return ENOEXEC; 304 break; 305 } 306 } 307 308 if (plttype == DT_RELA) { 309 ef->pltrela = (const Elf_Rela *) ef->pltrel; 310 ef->pltrel = NULL; 311 ef->pltrelasize = ef->pltrelsize; 312 ef->pltrelsize = 0; 313 } 314 315 ef->ddbsymtab = ef->symtab; 316 ef->ddbsymcnt = ef->nchains; 317 ef->ddbstrtab = ef->strtab; 318 ef->ddbstrcnt = ef->strsz; 319 320 return 0; 321} 322 323static void 324link_elf_error(const char *s) 325{ 326 printf("kldload: %s\n", s); 327} 328 329static int 330link_elf_load_module(const char *filename, linker_file_t *result) 331{ 332 caddr_t modptr, baseptr, sizeptr, dynptr; 333 char *type; 334 elf_file_t ef; 335 linker_file_t lf; 336 int error; 337 vm_offset_t dp; 338 339 /* Look to see if we have the module preloaded */ 340 modptr = preload_search_by_name(filename); 341 if (modptr == NULL) 342 return (link_elf_load_file(filename, result)); 343 344 /* It's preloaded, check we can handle it and collect information */ 345 type = (char *)preload_search_info(modptr, MODINFO_TYPE); 346 baseptr = preload_search_info(modptr, MODINFO_ADDR); 347 sizeptr = preload_search_info(modptr, MODINFO_SIZE); 348 dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC); 349 if (type == NULL || strcmp(type, "elf module") != 0) 350 return (EFTYPE); 351 if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) 352 return (EINVAL); 353 354 ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); 355 if (ef == NULL) 356 return (ENOMEM); 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 caddr_t base_addr; 413 Elf_Off data_offset; 414 Elf_Addr data_vaddr; 415 Elf_Addr data_vlimit; 416 caddr_t data_addr; 417 Elf_Addr clear_vaddr; 418 caddr_t clear_addr; 419 size_t nclear; 420 Elf_Addr bss_vaddr; 421 Elf_Addr bss_vlimit; 422 caddr_t bss_addr; 423 int error = 0; 424 int resid; 425 elf_file_t ef; 426 linker_file_t lf; 427 char *pathname; 428 429 pathname = linker_search_path(filename); 430 if (pathname == NULL) 431 return ENOENT; 432 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p); 433 error = vn_open(&nd, FREAD, 0); 434 free(pathname, M_LINKER); 435 if (error) 436 return error; 437 438 /* 439 * Read the elf header from the file. 440 */ 441 error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &u, sizeof u, 0, 442 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 443 nbytes = sizeof u - resid; 444 if (error) 445 goto out; 446 447 if (!IS_ELF(u.hdr)) { 448 error = ENOEXEC; 449 goto out; 450 } 451 452 if (u.hdr.e_ident[EI_CLASS] != ELF_TARG_CLASS 453 || u.hdr.e_ident[EI_DATA] != ELF_TARG_DATA) { 454 link_elf_error("Unsupported file layout"); 455 error = ENOEXEC; 456 goto out; 457 } 458 if (u.hdr.e_ident[EI_VERSION] != EV_CURRENT 459 || u.hdr.e_version != EV_CURRENT) { 460 link_elf_error("Unsupported file version"); 461 error = ENOEXEC; 462 goto out; 463 } 464 if (u.hdr.e_type != ET_EXEC && u.hdr.e_type != ET_DYN) { 465 link_elf_error("Unsupported file type"); 466 error = ENOEXEC; 467 goto out; 468 } 469 if (u.hdr.e_machine != ELF_TARG_MACH) { 470 link_elf_error("Unsupported machine"); 471 error = ENOEXEC; 472 goto out; 473 } 474 475 /* 476 * We rely on the program header being in the first page. This is 477 * not strictly required by the ABI specification, but it seems to 478 * always true in practice. And, it simplifies things considerably. 479 */ 480 if (!((u.hdr.e_phentsize == sizeof(Elf_Phdr)) 481 || (u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) 482 || (u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= nbytes))) 483 link_elf_error("Unreadable program headers"); 484 485 /* 486 * Scan the program header entries, and save key information. 487 * 488 * We rely on there being exactly two load segments, text and data, 489 * in that order. 490 */ 491 phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff); 492 phlimit = phdr + u.hdr.e_phnum; 493 nsegs = 0; 494 phdyn = NULL; 495 phphdr = NULL; 496 while (phdr < phlimit) { 497 switch (phdr->p_type) { 498 499 case PT_LOAD: 500 if (nsegs == 2) { 501 link_elf_error("Too many sections"); 502 error = ENOEXEC; 503 goto out; 504 } 505 segs[nsegs] = phdr; 506 ++nsegs; 507 break; 508 509 case PT_PHDR: 510 phphdr = phdr; 511 break; 512 513 case PT_DYNAMIC: 514 phdyn = phdr; 515 break; 516 } 517 518 ++phdr; 519 } 520 if (phdyn == NULL) { 521 link_elf_error("Object is not dynamically-linked"); 522 error = ENOEXEC; 523 goto out; 524 } 525 526 /* 527 * Allocate the entire address space of the object, to stake out our 528 * contiguous region, and to establish the base address for relocation. 529 */ 530 base_offset = trunc_page(segs[0]->p_offset); 531 base_vaddr = trunc_page(segs[0]->p_vaddr); 532 base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); 533 mapsize = base_vlimit - base_vaddr; 534 535 ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); 536#ifdef SPARSE_MAPPING 537 ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); 538 if (ef->object == NULL) { 539 free(ef, M_LINKER); 540 error = ENOMEM; 541 goto out; 542 } 543 vm_object_reference(ef->object); 544 ef->address = (caddr_t) vm_map_min(kernel_map); 545 error = vm_map_find(kernel_map, ef->object, 0, 546 (vm_offset_t *) &ef->address, 547 mapsize, 1, 548 VM_PROT_ALL, VM_PROT_ALL, 0); 549 if (error) { 550 vm_object_deallocate(ef->object); 551 free(ef, M_LINKER); 552 goto out; 553 } 554#else 555 ef->address = malloc(mapsize, M_LINKER, M_WAITOK); 556#endif 557 mapbase = ef->address; 558 559 /* 560 * Read the text and data sections and zero the bss. 561 */ 562 for (i = 0; i < 2; i++) { 563 caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; 564 error = vn_rdwr(UIO_READ, nd.ni_vp, 565 segbase, segs[i]->p_filesz, segs[i]->p_offset, 566 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 567 if (error) { 568#ifdef SPARSE_MAPPING 569 vm_map_remove(kernel_map, (vm_offset_t) ef->address, 570 (vm_offset_t) ef->address 571 + (ef->object->size << PAGE_SHIFT)); 572 vm_object_deallocate(ef->object); 573#else 574 free(ef->address, M_LINKER); 575#endif 576 free(ef, M_LINKER); 577 goto out; 578 } 579 bzero(segbase + segs[i]->p_filesz, 580 segs[i]->p_memsz - segs[i]->p_filesz); 581 582#ifdef SPARSE_MAPPING 583 /* 584 * Wire down the pages 585 */ 586 vm_map_pageable(kernel_map, 587 (vm_offset_t) segbase, 588 (vm_offset_t) segbase + segs[i]->p_memsz, 589 FALSE); 590#endif 591 } 592 593 ef->dynamic = (const Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); 594 595 lf = linker_make_file(filename, ef, &link_elf_file_ops); 596 if (lf == NULL) { 597#ifdef SPARSE_MAPPING 598 vm_map_remove(kernel_map, (vm_offset_t) ef->address, 599 (vm_offset_t) ef->address 600 + (ef->object->size << PAGE_SHIFT)); 601 vm_object_deallocate(ef->object); 602#else 603 free(ef->address, M_LINKER); 604#endif 605 free(ef, M_LINKER); 606 error = ENOMEM; 607 goto out; 608 } 609 lf->address = ef->address; 610 lf->size = mapsize; 611 612 error = parse_dynamic(lf); 613 if (error) { 614 linker_file_unload(lf); 615 goto out; 616 } 617 error = load_dependancies(lf); 618 if (error) { 619 linker_file_unload(lf); 620 goto out; 621 } 622 error = relocate_file(lf); 623 if (error) { 624 linker_file_unload(lf); 625 goto out; 626 } 627 628 *result = lf; 629 630out: 631 VOP_UNLOCK(nd.ni_vp, 0, p); 632 vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 633 634 return error; 635} 636 637static void 638link_elf_unload_file(linker_file_t file) 639{ 640 elf_file_t ef = file->priv; 641 642 if (ef) { 643#ifdef SPARSE_MAPPING 644 if (ef->object) { 645 vm_map_remove(kernel_map, (vm_offset_t) ef->address, 646 (vm_offset_t) ef->address 647 + (ef->object->size << PAGE_SHIFT)); 648 vm_object_deallocate(ef->object); 649 } 650#else 651 free(ef->address, M_LINKER); 652#endif 653 free(ef, M_LINKER); 654 } 655} 656 657static void 658link_elf_unload_module(linker_file_t file) 659{ 660 elf_file_t ef = file->priv; 661 662 if (ef) 663 free(ef, M_LINKER); 664 if (file->filename) 665 preload_delete_name(file->filename); 666} 667 668static int 669load_dependancies(linker_file_t lf) 670{ 671 elf_file_t ef = lf->priv; 672 linker_file_t lfdep; 673 char* name; 674 char* filename = 0; 675 const Elf_Dyn *dp; 676 int error = 0; 677 678 /* 679 * All files are dependant on /kernel. 680 */ 681 linker_kernel_file->refs++; 682 linker_file_add_dependancy(lf, linker_kernel_file); 683 684 685 for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 686 if (dp->d_tag == DT_NEEDED) { 687 name = ef->strtab + dp->d_un.d_val; 688 689 error = linker_load_file(name, &lfdep); 690 if (error) 691 goto out; 692 error = linker_file_add_dependancy(lf, lfdep); 693 if (error) 694 goto out; 695 } 696 } 697 698out: 699 if (filename) 700 free(filename, M_TEMP); 701 return error; 702} 703 704static const char * 705symbol_name(elf_file_t ef, const Elf_Rela *rela) 706{ 707 const Elf_Sym *ref; 708 709 if (ELF_R_SYM(rela->r_info)) { 710 ref = ef->ddbsymtab + ELF_R_SYM(rela->r_info); 711 return ef->ddbstrtab + ref->st_name; 712 } else 713 return NULL; 714} 715 716static int 717relocate_file(linker_file_t lf) 718{ 719 elf_file_t ef = lf->priv; 720 const Elf_Rel *rellim; 721 const Elf_Rel *rel; 722 const Elf_Rela *relalim; 723 const Elf_Rela *rela; 724 725 /* Perform relocations without addend if there are any: */ 726 rellim = (const Elf_Rel *) ((caddr_t) ef->rel + ef->relsize); 727 for (rel = ef->rel; ef->rel != NULL && rel < rellim; rel++) { 728 Elf_Rela locrela; 729 730 locrela.r_info = rel->r_info; 731 locrela.r_offset = rel->r_offset; 732 locrela.r_addend = 0; 733 if (elf_reloc(lf, &locrela, symbol_name(ef, &locrela))) 734 return ENOENT; 735 } 736 737 /* Perform relocations with addend if there are any: */ 738 relalim = (const Elf_Rela *) ((caddr_t) ef->rela + ef->relasize); 739 for (rela = ef->rela; ef->rela != NULL && rela < relalim; rela++) { 740 if (elf_reloc(lf, rela, symbol_name(ef, rela))) 741 return ENOENT; 742 } 743 744 /* Perform PLT relocations without addend if there are any: */ 745 rellim = (const Elf_Rel *) ((caddr_t) ef->pltrel + ef->pltrelsize); 746 for (rel = ef->pltrel; ef->pltrel != NULL && rel < rellim; rel++) { 747 Elf_Rela locrela; 748 749 locrela.r_info = rel->r_info; 750 locrela.r_offset = rel->r_offset; 751 locrela.r_addend = 0; 752 if (elf_reloc(lf, &locrela, symbol_name(ef, &locrela))) 753 return ENOENT; 754 } 755 756 /* Perform relocations with addend if there are any: */ 757 relalim = (const Elf_Rela *) ((caddr_t) ef->pltrela + ef->pltrelasize); 758 for (rela = ef->pltrela; ef->pltrela != NULL && rela < relalim; rela++) { 759 if (elf_reloc(lf, rela, symbol_name(ef, rela))) 760 return ENOENT; 761 } 762 763 return 0; 764} 765 766/* 767 * Hash function for symbol table lookup. Don't even think about changing 768 * this. It is specified by the System V ABI. 769 */ 770static unsigned long 771elf_hash(const char *name) 772{ 773 const unsigned char *p = (const unsigned char *) name; 774 unsigned long h = 0; 775 unsigned long g; 776 777 while (*p != '\0') { 778 h = (h << 4) + *p++; 779 if ((g = h & 0xf0000000) != 0) 780 h ^= g >> 24; 781 h &= ~g; 782 } 783 return h; 784} 785 786int 787link_elf_lookup_symbol(linker_file_t lf, const char* name, linker_sym_t* sym) 788{ 789 elf_file_t ef = lf->priv; 790 unsigned long symnum; 791 const Elf_Sym* symp; 792 const char *strp; 793 unsigned long hash; 794 int i; 795 796 /* First, search hashed global symbols */ 797 hash = elf_hash(name); 798 symnum = ef->buckets[hash % ef->nbuckets]; 799 800 while (symnum != STN_UNDEF) { 801 if (symnum >= ef->nchains) { 802 printf("link_elf_lookup_symbol: corrupt symbol table\n"); 803 return ENOENT; 804 } 805 806 symp = ef->symtab + symnum; 807 if (symp->st_name == 0) { 808 printf("link_elf_lookup_symbol: corrupt symbol table\n"); 809 return ENOENT; 810 } 811 812 strp = ef->strtab + symp->st_name; 813 814 if (strcmp(name, strp) == 0) { 815 if (symp->st_shndx != SHN_UNDEF || 816 (symp->st_value != 0 && 817 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 818 *sym = (linker_sym_t) symp; 819 return 0; 820 } else 821 return ENOENT; 822 } 823 824 symnum = ef->chains[symnum]; 825 } 826 827 /* If we have not found it, look at the full table (if loaded) */ 828 if (ef->symtab == ef->ddbsymtab) 829 return ENOENT; 830 831 /* Exhaustive search */ 832 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 833 strp = ef->ddbstrtab + symp->st_name; 834 if (strcmp(name, strp) == 0) { 835 if (symp->st_shndx != SHN_UNDEF || 836 (symp->st_value != 0 && 837 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 838 *sym = (linker_sym_t) symp; 839 return 0; 840 } else 841 return ENOENT; 842 } 843 } 844 845 return ENOENT; 846} 847 848static int 849link_elf_symbol_values(linker_file_t lf, linker_sym_t sym, linker_symval_t* symval) 850{ 851 elf_file_t ef = lf->priv; 852 Elf_Sym* es = (Elf_Sym*) sym; 853 854 if (es >= ef->symtab && ((es - ef->symtab) < ef->nchains)) { 855 symval->name = ef->strtab + es->st_name; 856 symval->value = (caddr_t) ef->address + es->st_value; 857 symval->size = es->st_size; 858 return 0; 859 } 860 if (ef->symtab == ef->ddbsymtab) 861 return ENOENT; 862 if (es >= ef->ddbsymtab && ((es - ef->ddbsymtab) < ef->ddbsymcnt)) { 863 symval->name = ef->ddbstrtab + es->st_name; 864 symval->value = (caddr_t) ef->address + es->st_value; 865 symval->size = es->st_size; 866 return 0; 867 } 868 return ENOENT; 869} 870 871static int 872link_elf_search_symbol(linker_file_t lf, caddr_t value, 873 linker_sym_t* sym, long* diffp) 874{ 875 elf_file_t ef = lf->priv; 876 u_long off = (u_long) value; 877 u_long diff = off; 878 const Elf_Sym* es; 879 const Elf_Sym* best = 0; 880 int i; 881 882 for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { 883 if (es->st_name == 0) 884 continue; 885 if (off >= es->st_value) { 886 if (off - es->st_value < diff) { 887 diff = off - es->st_value; 888 best = es; 889 if (diff == 0) 890 break; 891 } else if (off - es->st_value == diff) { 892 best = es; 893 } 894 } 895 } 896 if (best == 0) 897 *diffp = off; 898 else 899 *diffp = diff; 900 *sym = (linker_sym_t) best; 901 902 return 0; 903} 904