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