1/********************************************************************** 2 3 dln.c - 4 5 $Author: nobu $ 6 created at: Tue Jan 18 17:05:06 JST 1994 7 8 Copyright (C) 1993-2007 Yukihiro Matsumoto 9 10**********************************************************************/ 11 12#ifdef RUBY_EXPORT 13#include "ruby/ruby.h" 14#define dln_notimplement rb_notimplement 15#define dln_memerror rb_memerror 16#define dln_exit rb_exit 17#define dln_loaderror rb_loaderror 18#else 19#define dln_notimplement --->>> dln not implemented <<<--- 20#define dln_memerror abort 21#define dln_exit exit 22static void dln_loaderror(const char *format, ...); 23#endif 24#include "dln.h" 25 26#ifdef HAVE_STDLIB_H 27# include <stdlib.h> 28#endif 29 30#ifdef USE_DLN_A_OUT 31char *dln_argv0; 32#endif 33 34#if defined(HAVE_ALLOCA_H) 35#include <alloca.h> 36#endif 37 38#ifdef HAVE_STRING_H 39# include <string.h> 40#else 41# include <strings.h> 42#endif 43 44#ifndef xmalloc 45void *xmalloc(); 46void *xcalloc(); 47void *xrealloc(); 48#endif 49 50#define free(x) xfree(x) 51 52#include <stdio.h> 53#if defined(_WIN32) 54#include "missing/file.h" 55#endif 56#include <sys/types.h> 57#include <sys/stat.h> 58 59#ifndef S_ISDIR 60# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 61#endif 62 63#ifdef HAVE_SYS_PARAM_H 64# include <sys/param.h> 65#endif 66#ifndef MAXPATHLEN 67# define MAXPATHLEN 1024 68#endif 69 70#ifdef HAVE_UNISTD_H 71# include <unistd.h> 72#endif 73 74#ifndef _WIN32 75char *getenv(); 76#endif 77 78#ifdef __APPLE__ 79# if defined(HAVE_DLOPEN) 80 /* Mac OS X with dlopen (10.3 or later) */ 81# define MACOSX_DLOPEN 82# else 83# define MACOSX_DYLD 84# endif 85#endif 86 87#if defined(__BEOS__) || defined(__HAIKU__) 88# include <image.h> 89#endif 90 91#ifndef dln_loaderror 92static void 93dln_loaderror(const char *format, ...) 94{ 95 va_list ap; 96 va_start(ap, format); 97 vfprintf(stderr, format, ap); 98 va_end(ap); 99 abort(); 100} 101#endif 102 103#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP) 104/* dynamic load with dlopen() */ 105# define USE_DLN_DLOPEN 106#endif 107 108#ifndef FUNCNAME_PATTERN 109# if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(__BORLANDC__) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD) 110# define FUNCNAME_PREFIX "_Init_" 111# else 112# define FUNCNAME_PREFIX "Init_" 113# endif 114#endif 115 116#if defined __CYGWIN__ || defined DOSISH 117#define isdirsep(x) ((x) == '/' || (x) == '\\') 118#else 119#define isdirsep(x) ((x) == '/') 120#endif 121 122static size_t 123init_funcname_len(const char **file) 124{ 125 const char *p = *file, *base, *dot = NULL; 126 127 /* Load the file as an object one */ 128 for (base = p; *p; p++) { /* Find position of last '/' */ 129 if (*p == '.' && !dot) dot = p; 130 if (isdirsep(*p)) base = p+1, dot = NULL; 131 } 132 *file = base; 133 /* Delete suffix if it exists */ 134 return (dot ? dot : p) - base; 135} 136 137static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX; 138 139#define init_funcname(buf, file) do {\ 140 const char *base = (file);\ 141 const size_t flen = init_funcname_len(&base);\ 142 const size_t plen = sizeof(funcname_prefix);\ 143 char *const tmp = ALLOCA_N(char, plen+flen+1);\ 144 if (!tmp) {\ 145 dln_memerror();\ 146 }\ 147 memcpy(tmp, funcname_prefix, plen);\ 148 memcpy(tmp+plen, base, flen);\ 149 tmp[plen+flen] = '\0';\ 150 *(buf) = tmp;\ 151} while (0) 152 153#ifdef USE_DLN_A_OUT 154 155#ifndef LIBC_NAME 156# define LIBC_NAME "libc.a" 157#endif 158 159#ifndef DLN_DEFAULT_LIB_PATH 160# define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:." 161#endif 162 163#include <errno.h> 164 165static int dln_errno; 166 167#define DLN_ENOEXEC ENOEXEC /* Exec format error */ 168#define DLN_ECONFL 1201 /* Symbol name conflict */ 169#define DLN_ENOINIT 1202 /* No initializer given */ 170#define DLN_EUNDEF 1203 /* Undefine symbol remains */ 171#define DLN_ENOTLIB 1204 /* Not a library file */ 172#define DLN_EBADLIB 1205 /* Malformed library file */ 173#define DLN_EINIT 1206 /* Not initialized */ 174 175static int dln_init_p = 0; 176 177#include <ar.h> 178#include <a.out.h> 179#ifndef N_COMM 180# define N_COMM 0x12 181#endif 182#ifndef N_MAGIC 183# define N_MAGIC(x) (x).a_magic 184#endif 185 186#define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC) 187 188#include "ruby/util.h" 189#include "ruby/st.h" 190 191static st_table *sym_tbl; 192static st_table *undef_tbl; 193 194static int load_lib(); 195 196static int 197load_header(int fd, struct exec *hdrp, long disp) 198{ 199 int size; 200 201 lseek(fd, disp, 0); 202 size = read(fd, hdrp, sizeof(struct exec)); 203 if (size == -1) { 204 dln_errno = errno; 205 return -1; 206 } 207 if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) { 208 dln_errno = DLN_ENOEXEC; 209 return -1; 210 } 211 return 0; 212} 213 214#if defined(sequent) 215#define RELOC_SYMBOL(r) ((r)->r_symbolnum) 216#define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr) 217#define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr) 218#define RELOC_TARGET_SIZE(r) ((r)->r_length) 219#endif 220 221/* Default macros */ 222#ifndef RELOC_ADDRESS 223#define RELOC_ADDRESS(r) ((r)->r_address) 224#define RELOC_EXTERN_P(r) ((r)->r_extern) 225#define RELOC_SYMBOL(r) ((r)->r_symbolnum) 226#define RELOC_MEMORY_SUB_P(r) 0 227#define RELOC_PCREL_P(r) ((r)->r_pcrel) 228#define RELOC_TARGET_SIZE(r) ((r)->r_length) 229#endif 230 231#if defined(__sun) && defined(__sparc) 232/* Sparc (Sun 4) macros */ 233# undef relocation_info 234# define relocation_info reloc_info_sparc 235# define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type]) 236# define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type]) 237# define R_LENGTH(r) (reloc_r_length[(r)->r_type]) 238static int reloc_r_rightshift[] = { 239 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0, 240}; 241static int reloc_r_bitsize[] = { 242 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16, 243}; 244static int reloc_r_length[] = { 245 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 246}; 247# define R_PCREL(r) \ 248 ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) 249# define R_SYMBOL(r) ((r)->r_index) 250#endif 251 252#if defined(sequent) 253#define R_SYMBOL(r) ((r)->r_symbolnum) 254#define R_MEMORY_SUB(r) ((r)->r_bsr) 255#define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr) 256#define R_LENGTH(r) ((r)->r_length) 257#endif 258 259#ifndef R_SYMBOL 260# define R_SYMBOL(r) ((r)->r_symbolnum) 261# define R_MEMORY_SUB(r) 0 262# define R_PCREL(r) ((r)->r_pcrel) 263# define R_LENGTH(r) ((r)->r_length) 264#endif 265 266static struct relocation_info * 267load_reloc(int fd, struct exec *hdrp, long disp) 268{ 269 struct relocation_info *reloc; 270 int size; 271 272 lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0); 273 size = hdrp->a_trsize + hdrp->a_drsize; 274 reloc = (struct relocation_info*)xmalloc(size); 275 if (reloc == NULL) { 276 dln_errno = errno; 277 return NULL; 278 } 279 280 if (read(fd, reloc, size) != size) { 281 dln_errno = errno; 282 free(reloc); 283 return NULL; 284 } 285 286 return reloc; 287} 288 289static struct nlist * 290load_sym(int fd, struct exec *hdrp, long disp) 291{ 292 struct nlist * buffer; 293 struct nlist * sym; 294 struct nlist * end; 295 long displ; 296 int size; 297 298 lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0); 299 if (read(fd, &size, sizeof(int)) != sizeof(int)) { 300 goto err_noexec; 301 } 302 303 buffer = (struct nlist*)xmalloc(hdrp->a_syms + size); 304 if (buffer == NULL) { 305 dln_errno = errno; 306 return NULL; 307 } 308 309 lseek(fd, disp + N_SYMOFF(*hdrp), 0); 310 if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) { 311 free(buffer); 312 goto err_noexec; 313 } 314 315 sym = buffer; 316 end = sym + hdrp->a_syms / sizeof(struct nlist); 317 displ = (long)buffer + (long)(hdrp->a_syms); 318 319 while (sym < end) { 320 sym->n_un.n_name = (char*)sym->n_un.n_strx + displ; 321 sym++; 322 } 323 return buffer; 324 325 err_noexec: 326 dln_errno = DLN_ENOEXEC; 327 return NULL; 328} 329 330static st_table * 331sym_hash(struct exec *hdrp, struct nlist *syms) 332{ 333 st_table *tbl; 334 struct nlist *sym = syms; 335 struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist)); 336 337 tbl = st_init_strtable(); 338 if (tbl == NULL) { 339 dln_errno = errno; 340 return NULL; 341 } 342 343 while (sym < end) { 344 st_insert(tbl, sym->n_un.n_name, sym); 345 sym++; 346 } 347 return tbl; 348} 349 350static int 351dln_init(const char *prog) 352{ 353 char *file, fbuf[MAXPATHLEN]; 354 int fd; 355 struct exec hdr; 356 struct nlist *syms; 357 358 if (dln_init_p == 1) return 0; 359 360 file = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)); 361 if (file == NULL || (fd = open(file, O_RDONLY)) < 0) { 362 dln_errno = errno; 363 return -1; 364 } 365 366 if (load_header(fd, &hdr, 0) == -1) return -1; 367 syms = load_sym(fd, &hdr, 0); 368 if (syms == NULL) { 369 close(fd); 370 return -1; 371 } 372 sym_tbl = sym_hash(&hdr, syms); 373 if (sym_tbl == NULL) { /* file may be start with #! */ 374 char c = '\0'; 375 char buf[MAXPATHLEN]; 376 char *p; 377 378 free(syms); 379 lseek(fd, 0L, 0); 380 if (read(fd, &c, 1) == -1) { 381 dln_errno = errno; 382 return -1; 383 } 384 if (c != '#') goto err_noexec; 385 if (read(fd, &c, 1) == -1) { 386 dln_errno = errno; 387 return -1; 388 } 389 if (c != '!') goto err_noexec; 390 391 p = buf; 392 /* skip forwarding spaces */ 393 while (read(fd, &c, 1) == 1) { 394 if (c == '\n') goto err_noexec; 395 if (c != '\t' && c != ' ') { 396 *p++ = c; 397 break; 398 } 399 } 400 /* read in command name */ 401 while (read(fd, p, 1) == 1) { 402 if (*p == '\n' || *p == '\t' || *p == ' ') break; 403 p++; 404 if (p-buf >= MAXPATHLEN) { 405 dln_errno = ENAMETOOLONG; 406 return -1; 407 } 408 } 409 *p = '\0'; 410 411 return dln_init(buf); 412 } 413 dln_init_p = 1; 414 undef_tbl = st_init_strtable(); 415 close(fd); 416 return 0; 417 418 err_noexec: 419 close(fd); 420 dln_errno = DLN_ENOEXEC; 421 return -1; 422} 423 424static long 425load_text_data(int fd, struct exec *hdrp, int bss, long disp) 426{ 427 int size; 428 unsigned char* addr; 429 430 lseek(fd, disp + N_TXTOFF(*hdrp), 0); 431 size = hdrp->a_text + hdrp->a_data; 432 433 if (bss == -1) size += hdrp->a_bss; 434 else if (bss > 1) size += bss; 435 436 addr = (unsigned char*)xmalloc(size); 437 if (addr == NULL) { 438 dln_errno = errno; 439 return 0; 440 } 441 442 if (read(fd, addr, size) != size) { 443 dln_errno = errno; 444 free(addr); 445 return 0; 446 } 447 448 if (bss == -1) { 449 memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss); 450 } 451 else if (bss > 0) { 452 memset(addr + hdrp->a_text + hdrp->a_data, 0, bss); 453 } 454 455 return (long)addr; 456} 457 458static int 459undef_print(char *key, char *value) 460{ 461 fprintf(stderr, " %s\n", key); 462 return ST_CONTINUE; 463} 464 465static void 466dln_print_undef(void) 467{ 468 fprintf(stderr, " Undefined symbols:\n"); 469 st_foreach(undef_tbl, undef_print, NULL); 470} 471 472static void 473dln_undefined(void) 474{ 475 if (undef_tbl->num_entries > 0) { 476 fprintf(stderr, "dln: Calling undefined function\n"); 477 dln_print_undef(); 478 dln_exit(1); 479 } 480} 481 482struct undef { 483 char *name; 484 struct relocation_info reloc; 485 long base; 486 char *addr; 487 union { 488 char c; 489 short s; 490 long l; 491 } u; 492}; 493 494static st_table *reloc_tbl = NULL; 495static void 496link_undef(const char *name, long base, struct relocation_info *reloc) 497{ 498 static int u_no = 0; 499 struct undef *obj; 500 char *addr = (char*)(reloc->r_address + base); 501 502 obj = (struct undef*)xmalloc(sizeof(struct undef)); 503 obj->name = strdup(name); 504 obj->reloc = *reloc; 505 obj->base = base; 506 switch (R_LENGTH(reloc)) { 507 case 0: /* byte */ 508 obj->u.c = *addr; 509 break; 510 case 1: /* word */ 511 obj->u.s = *(short*)addr; 512 break; 513 case 2: /* long */ 514 obj->u.l = *(long*)addr; 515 break; 516 } 517 if (reloc_tbl == NULL) { 518 reloc_tbl = st_init_numtable(); 519 } 520 st_insert(reloc_tbl, u_no++, obj); 521} 522 523struct reloc_arg { 524 const char *name; 525 long value; 526}; 527 528static int 529reloc_undef(int no, struct undef *undef, struct reloc_arg *arg) 530{ 531 int datum; 532 char *address; 533#if defined(__sun) && defined(__sparc) 534 unsigned int mask = 0; 535#endif 536 537 if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE; 538 address = (char*)(undef->base + undef->reloc.r_address); 539 datum = arg->value; 540 541 if (R_PCREL(&(undef->reloc))) datum -= undef->base; 542#if defined(__sun) && defined(__sparc) 543 datum += undef->reloc.r_addend; 544 datum >>= R_RIGHTSHIFT(&(undef->reloc)); 545 mask = (1 << R_BITSIZE(&(undef->reloc))) - 1; 546 mask |= mask -1; 547 datum &= mask; 548 switch (R_LENGTH(&(undef->reloc))) { 549 case 0: 550 *address = undef->u.c; 551 *address &= ~mask; 552 *address |= datum; 553 break; 554 case 1: 555 *(short *)address = undef->u.s; 556 *(short *)address &= ~mask; 557 *(short *)address |= datum; 558 break; 559 case 2: 560 *(long *)address = undef->u.l; 561 *(long *)address &= ~mask; 562 *(long *)address |= datum; 563 break; 564 } 565#else 566 switch (R_LENGTH(&(undef->reloc))) { 567 case 0: /* byte */ 568 if (R_MEMORY_SUB(&(undef->reloc))) 569 *address = datum - *address; 570 else *address = undef->u.c + datum; 571 break; 572 case 1: /* word */ 573 if (R_MEMORY_SUB(&(undef->reloc))) 574 *(short*)address = datum - *(short*)address; 575 else *(short*)address = undef->u.s + datum; 576 break; 577 case 2: /* long */ 578 if (R_MEMORY_SUB(&(undef->reloc))) 579 *(long*)address = datum - *(long*)address; 580 else *(long*)address = undef->u.l + datum; 581 break; 582 } 583#endif 584 free(undef->name); 585 free(undef); 586 return ST_DELETE; 587} 588 589static void 590unlink_undef(const char *name, long value) 591{ 592 struct reloc_arg arg; 593 594 arg.name = name; 595 arg.value = value; 596 st_foreach(reloc_tbl, reloc_undef, &arg); 597} 598 599#ifdef N_INDR 600struct indr_data { 601 char *name0, *name1; 602}; 603 604static int 605reloc_repl(int no, struct undef *undef, struct indr_data *data) 606{ 607 if (strcmp(data->name0, undef->name) == 0) { 608 free(undef->name); 609 undef->name = strdup(data->name1); 610 } 611 return ST_CONTINUE; 612} 613#endif 614 615static int 616load_1(int fd, long disp, const char *need_init) 617{ 618 static const char *libc = LIBC_NAME; 619 struct exec hdr; 620 struct relocation_info *reloc = NULL; 621 long block = 0; 622 long new_common = 0; /* Length of new common */ 623 struct nlist *syms = NULL; 624 struct nlist *sym; 625 struct nlist *end; 626 int init_p = 0; 627 628 if (load_header(fd, &hdr, disp) == -1) return -1; 629 if (INVALID_OBJECT(hdr)) { 630 dln_errno = DLN_ENOEXEC; 631 return -1; 632 } 633 reloc = load_reloc(fd, &hdr, disp); 634 if (reloc == NULL) return -1; 635 636 syms = load_sym(fd, &hdr, disp); 637 if (syms == NULL) { 638 free(reloc); 639 return -1; 640 } 641 642 sym = syms; 643 end = syms + (hdr.a_syms / sizeof(struct nlist)); 644 while (sym < end) { 645 struct nlist *old_sym; 646 int value = sym->n_value; 647 648#ifdef N_INDR 649 if (sym->n_type == (N_INDR | N_EXT)) { 650 char *key = sym->n_un.n_name; 651 652 if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) { 653 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { 654 unlink_undef(key, old_sym->n_value); 655 free(key); 656 } 657 } 658 else { 659 struct indr_data data; 660 661 data.name0 = sym->n_un.n_name; 662 data.name1 = sym[1].n_un.n_name; 663 st_foreach(reloc_tbl, reloc_repl, &data); 664 665 st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL); 666 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { 667 free(key); 668 } 669 } 670 sym += 2; 671 continue; 672 } 673#endif 674 if (sym->n_type == (N_UNDF | N_EXT)) { 675 if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) { 676 old_sym = NULL; 677 } 678 679 if (value) { 680 if (old_sym) { 681 sym->n_type = N_EXT | N_COMM; 682 sym->n_value = old_sym->n_value; 683 } 684 else { 685 int rnd = 686 value >= sizeof(double) ? sizeof(double) - 1 687 : value >= sizeof(long) ? sizeof(long) - 1 688 : sizeof(short) - 1; 689 690 sym->n_type = N_COMM; 691 new_common += rnd; 692 new_common &= ~(long)rnd; 693 sym->n_value = new_common; 694 new_common += value; 695 } 696 } 697 else { 698 if (old_sym) { 699 sym->n_type = N_EXT | N_COMM; 700 sym->n_value = old_sym->n_value; 701 } 702 else { 703 sym->n_value = (long)dln_undefined; 704 st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL); 705 } 706 } 707 } 708 sym++; 709 } 710 711 block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp); 712 if (block == 0) goto err_exit; 713 714 sym = syms; 715 while (sym < end) { 716 struct nlist *new_sym; 717 char *key; 718 719 switch (sym->n_type) { 720 case N_COMM: 721 sym->n_value += hdr.a_text + hdr.a_data; 722 case N_TEXT|N_EXT: 723 case N_DATA|N_EXT: 724 725 sym->n_value += block; 726 727 if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0 728 && new_sym->n_value != (long)dln_undefined) { 729 dln_errno = DLN_ECONFL; 730 goto err_exit; 731 } 732 733 key = sym->n_un.n_name; 734 if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) { 735 unlink_undef(key, sym->n_value); 736 free(key); 737 } 738 739 new_sym = (struct nlist*)xmalloc(sizeof(struct nlist)); 740 *new_sym = *sym; 741 new_sym->n_un.n_name = strdup(sym->n_un.n_name); 742 st_insert(sym_tbl, new_sym->n_un.n_name, new_sym); 743 break; 744 745 case N_TEXT: 746 case N_DATA: 747 sym->n_value += block; 748 break; 749 } 750 sym++; 751 } 752 753 /* 754 * First comes the text-relocation 755 */ 756 { 757 struct relocation_info * rel = reloc; 758 struct relocation_info * rel_beg = reloc + 759 (hdr.a_trsize/sizeof(struct relocation_info)); 760 struct relocation_info * rel_end = reloc + 761 (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info); 762 763 while (rel < rel_end) { 764 char *address = (char*)(rel->r_address + block); 765 long datum = 0; 766#if defined(__sun) && defined(__sparc) 767 unsigned int mask = 0; 768#endif 769 770 if (rel >= rel_beg) 771 address += hdr.a_text; 772 773 if (rel->r_extern) { /* Look it up in symbol-table */ 774 sym = &(syms[R_SYMBOL(rel)]); 775 switch (sym->n_type) { 776 case N_EXT|N_UNDF: 777 link_undef(sym->n_un.n_name, block, rel); 778 case N_EXT|N_COMM: 779 case N_COMM: 780 datum = sym->n_value; 781 break; 782 default: 783 goto err_exit; 784 } 785 } /* end.. look it up */ 786 else { /* is static */ 787 switch (R_SYMBOL(rel)) { 788 case N_TEXT: 789 case N_DATA: 790 datum = block; 791 break; 792 case N_BSS: 793 datum = block + new_common; 794 break; 795 case N_ABS: 796 break; 797 } 798 } /* end .. is static */ 799 if (R_PCREL(rel)) datum -= block; 800 801#if defined(__sun) && defined(__sparc) 802 datum += rel->r_addend; 803 datum >>= R_RIGHTSHIFT(rel); 804 mask = (1 << R_BITSIZE(rel)) - 1; 805 mask |= mask -1; 806 datum &= mask; 807 808 switch (R_LENGTH(rel)) { 809 case 0: 810 *address &= ~mask; 811 *address |= datum; 812 break; 813 case 1: 814 *(short *)address &= ~mask; 815 *(short *)address |= datum; 816 break; 817 case 2: 818 *(long *)address &= ~mask; 819 *(long *)address |= datum; 820 break; 821 } 822#else 823 switch (R_LENGTH(rel)) { 824 case 0: /* byte */ 825 if (datum < -128 || datum > 127) goto err_exit; 826 *address += datum; 827 break; 828 case 1: /* word */ 829 *(short *)address += datum; 830 break; 831 case 2: /* long */ 832 *(long *)address += datum; 833 break; 834 } 835#endif 836 rel++; 837 } 838 } 839 840 if (need_init) { 841 int len; 842 char **libs_to_be_linked = 0; 843 char *buf; 844 845 if (undef_tbl->num_entries > 0) { 846 if (load_lib(libc) == -1) goto err_exit; 847 } 848 849 init_funcname(&buf, need_init); 850 len = strlen(buf); 851 852 for (sym = syms; sym<end; sym++) { 853 char *name = sym->n_un.n_name; 854 if (name[0] == '_' && sym->n_value >= block) { 855 if (strcmp(name+1, "dln_libs_to_be_linked") == 0) { 856 libs_to_be_linked = (char**)sym->n_value; 857 } 858 else if (strcmp(name+1, buf) == 0) { 859 init_p = 1; 860 ((int (*)())sym->n_value)(); 861 } 862 } 863 } 864 if (libs_to_be_linked && undef_tbl->num_entries > 0) { 865 while (*libs_to_be_linked) { 866 load_lib(*libs_to_be_linked); 867 libs_to_be_linked++; 868 } 869 } 870 } 871 free(reloc); 872 free(syms); 873 if (need_init) { 874 if (init_p == 0) { 875 dln_errno = DLN_ENOINIT; 876 return -1; 877 } 878 if (undef_tbl->num_entries > 0) { 879 if (load_lib(libc) == -1) goto err_exit; 880 if (undef_tbl->num_entries > 0) { 881 dln_errno = DLN_EUNDEF; 882 return -1; 883 } 884 } 885 } 886 return 0; 887 888 err_exit: 889 if (syms) free(syms); 890 if (reloc) free(reloc); 891 if (block) free((char*)block); 892 return -1; 893} 894 895static int target_offset; 896static int 897search_undef(const char *key, int value, st_table *lib_tbl) 898{ 899 long offset; 900 901 if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE; 902 target_offset = offset; 903 return ST_STOP; 904} 905 906struct symdef { 907 int rb_str_index; 908 int lib_offset; 909}; 910 911const char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH; 912 913static int 914load_lib(const char *lib) 915{ 916 char *path, *file, fbuf[MAXPATHLEN]; 917 char *envpath = 0; 918 char armagic[SARMAG]; 919 int fd, size; 920 struct ar_hdr ahdr; 921 st_table *lib_tbl = NULL; 922 int *data, nsym; 923 struct symdef *base; 924 char *name_base; 925 926 if (dln_init_p == 0) { 927 dln_errno = DLN_ENOINIT; 928 return -1; 929 } 930 931 if (undef_tbl->num_entries == 0) return 0; 932 dln_errno = DLN_EBADLIB; 933 934 if (lib[0] == '-' && lib[1] == 'l') { 935 long len = strlen(lib) + 4; 936 char *p = alloca(len); 937 snprintf(p, len, "lib%s.a", lib+2); 938 lib = p; 939 } 940 941 /* library search path: */ 942 /* look for environment variable DLN_LIBRARY_PATH first. */ 943 /* then variable dln_librrb_ary_path. */ 944 /* if path is still NULL, use "." for path. */ 945 path = getenv("DLN_LIBRARY_PATH"); 946 if (path == NULL) path = dln_librrb_ary_path; 947 else path = envpath = strdup(path); 948 949 file = dln_find_file_r(lib, path, fbuf, sizeof(fbuf)); 950 if (envpath) free(envpath); 951 fd = open(file, O_RDONLY); 952 if (fd == -1) goto syserr; 953 size = read(fd, armagic, SARMAG); 954 if (size == -1) goto syserr; 955 956 if (size != SARMAG) { 957 dln_errno = DLN_ENOTLIB; 958 goto badlib; 959 } 960 size = read(fd, &ahdr, sizeof(ahdr)); 961 if (size == -1) goto syserr; 962 if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) { 963 goto badlib; 964 } 965 966 if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) { 967 /* make hash table from __.SYMDEF */ 968 969 lib_tbl = st_init_strtable(); 970 data = (int*)xmalloc(size); 971 if (data == NULL) goto syserr; 972 size = read(fd, data, size); 973 nsym = *data / sizeof(struct symdef); 974 base = (struct symdef*)(data + 1); 975 name_base = (char*)(base + nsym) + sizeof(int); 976 while (nsym > 0) { 977 char *name = name_base + base->rb_str_index; 978 979 st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr)); 980 nsym--; 981 base++; 982 } 983 for (;;) { 984 target_offset = -1; 985 st_foreach(undef_tbl, search_undef, lib_tbl); 986 if (target_offset == -1) break; 987 if (load_1(fd, target_offset, 0) == -1) { 988 st_free_table(lib_tbl); 989 free(data); 990 goto badlib; 991 } 992 if (undef_tbl->num_entries == 0) break; 993 } 994 free(data); 995 st_free_table(lib_tbl); 996 } 997 else { 998 /* linear library, need to scan (FUTURE) */ 999 1000 for (;;) { 1001 int offset = SARMAG; 1002 int found = 0; 1003 struct exec hdr; 1004 struct nlist *syms, *sym, *end; 1005 1006 while (undef_tbl->num_entries > 0) { 1007 found = 0; 1008 lseek(fd, offset, 0); 1009 size = read(fd, &ahdr, sizeof(ahdr)); 1010 if (size == -1) goto syserr; 1011 if (size == 0) break; 1012 if (size != sizeof(ahdr) 1013 || sscanf(ahdr.ar_size, "%d", &size) != 1) { 1014 goto badlib; 1015 } 1016 offset += sizeof(ahdr); 1017 if (load_header(fd, &hdr, offset) == -1) 1018 goto badlib; 1019 syms = load_sym(fd, &hdr, offset); 1020 if (syms == NULL) goto badlib; 1021 sym = syms; 1022 end = syms + (hdr.a_syms / sizeof(struct nlist)); 1023 while (sym < end) { 1024 if (sym->n_type == N_EXT|N_TEXT 1025 && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) { 1026 break; 1027 } 1028 sym++; 1029 } 1030 if (sym < end) { 1031 found++; 1032 free(syms); 1033 if (load_1(fd, offset, 0) == -1) { 1034 goto badlib; 1035 } 1036 } 1037 offset += size; 1038 if (offset & 1) offset++; 1039 } 1040 if (found) break; 1041 } 1042 } 1043 close(fd); 1044 return 0; 1045 1046 syserr: 1047 dln_errno = errno; 1048 badlib: 1049 if (fd >= 0) close(fd); 1050 return -1; 1051} 1052 1053static int 1054load(const char *file) 1055{ 1056 int fd; 1057 int result; 1058 1059 if (dln_init_p == 0) { 1060 if (dln_init(dln_argv0) == -1) return -1; 1061 } 1062 result = strlen(file); 1063 if (file[result-1] == 'a') { 1064 return load_lib(file); 1065 } 1066 1067 fd = open(file, O_RDONLY); 1068 if (fd == -1) { 1069 dln_errno = errno; 1070 return -1; 1071 } 1072 result = load_1(fd, 0, file); 1073 close(fd); 1074 1075 return result; 1076} 1077 1078void* 1079dln_sym(const char *name) 1080{ 1081 struct nlist *sym; 1082 1083 if (st_lookup(sym_tbl, name, &sym)) 1084 return (void*)sym->n_value; 1085 return NULL; 1086} 1087 1088#endif /* USE_DLN_A_OUT */ 1089 1090#ifdef USE_DLN_DLOPEN 1091# include <dlfcn.h> 1092#endif 1093 1094#ifdef __hpux 1095#include <errno.h> 1096#include "dl.h" 1097#endif 1098 1099#if defined(_AIX) 1100#include <ctype.h> /* for isdigit() */ 1101#include <errno.h> /* for global errno */ 1102#include <sys/ldr.h> 1103#endif 1104 1105#ifdef NeXT 1106#if NS_TARGET_MAJOR < 4 1107#include <mach-o/rld.h> 1108#else 1109#include <mach-o/dyld.h> 1110#ifndef NSLINKMODULE_OPTION_BINDNOW 1111#define NSLINKMODULE_OPTION_BINDNOW 1 1112#endif 1113#endif 1114#else 1115#ifdef MACOSX_DYLD 1116#include <mach-o/dyld.h> 1117#endif 1118#endif 1119 1120#if defined _WIN32 && !defined __CYGWIN__ 1121#include <windows.h> 1122#include <imagehlp.h> 1123#endif 1124 1125#if defined _WIN32 && !defined __CYGWIN__ 1126static const char * 1127dln_strerror(char *message, size_t size) 1128{ 1129 int error = GetLastError(); 1130 char *p = message; 1131 size_t len = snprintf(message, size, "%d: ", error); 1132 1133#define format_message(sublang) FormatMessage(\ 1134 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \ 1135 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \ 1136 message + len, size - len, NULL) 1137 if (format_message(SUBLANG_ENGLISH_US) == 0) 1138 format_message(SUBLANG_DEFAULT); 1139 for (p = message + len; *p; p++) { 1140 if (*p == '\n' || *p == '\r') 1141 *p = ' '; 1142 } 1143 return message; 1144} 1145#define dln_strerror() dln_strerror(message, sizeof message) 1146#elif ! defined _AIX 1147static const char * 1148dln_strerror(void) 1149{ 1150#ifdef USE_DLN_A_OUT 1151 char *strerror(); 1152 1153 switch (dln_errno) { 1154 case DLN_ECONFL: 1155 return "Symbol name conflict"; 1156 case DLN_ENOINIT: 1157 return "No initializer given"; 1158 case DLN_EUNDEF: 1159 return "Unresolved symbols"; 1160 case DLN_ENOTLIB: 1161 return "Not a library file"; 1162 case DLN_EBADLIB: 1163 return "Malformed library file"; 1164 case DLN_EINIT: 1165 return "Not initialized"; 1166 default: 1167 return strerror(dln_errno); 1168 } 1169#endif 1170 1171#ifdef USE_DLN_DLOPEN 1172 return (char*)dlerror(); 1173#endif 1174} 1175#endif 1176 1177#if defined(_AIX) && ! defined(_IA64) 1178static void 1179aix_loaderror(const char *pathname) 1180{ 1181 char *message[1024], errbuf[1024]; 1182 int i; 1183#define ERRBUF_APPEND(s) strncat(errbuf, (s), sizeof(errbuf)-strlen(errbuf)-1) 1184 snprintf(errbuf, sizeof(errbuf), "load failed - %s. ", pathname); 1185 1186 if (loadquery(L_GETMESSAGES, &message[0], sizeof(message)) != -1) { 1187 ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t"); 1188 ERRBUF_APPEND("/usr/sbin/execerror ruby "); 1189 for (i=0; message[i]; i++) { 1190 ERRBUF_APPEND("\""); 1191 ERRBUF_APPEND(message[i]); 1192 ERRBUF_APPEND("\" "); 1193 } 1194 ERRBUF_APPEND("\n"); 1195 } else { 1196 ERRBUF_APPEND(strerror(errno)); 1197 ERRBUF_APPEND("[loadquery failed]"); 1198 } 1199 dln_loaderror("%s", errbuf); 1200} 1201#endif 1202 1203#if defined _WIN32 && defined RUBY_EXPORT 1204HANDLE rb_libruby_handle(void); 1205 1206static int 1207rb_w32_check_imported(HMODULE ext, HMODULE mine) 1208{ 1209 ULONG size; 1210 const IMAGE_IMPORT_DESCRIPTOR *desc; 1211 1212 desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size); 1213 if (!desc) return 0; 1214 while (desc->Name) { 1215 PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics); 1216 PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk); 1217 for (; piat->u1.Function; piat++, pint++) { 1218 static const char prefix[] = "rb_"; 1219 PIMAGE_IMPORT_BY_NAME pii; 1220 const char *name; 1221 1222 if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue; 1223 pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData); 1224 name = (const char *)pii->Name; 1225 if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) { 1226 FARPROC addr = GetProcAddress(mine, name); 1227 if (addr) return (FARPROC)piat->u1.Function == addr; 1228 } 1229 } 1230 desc++; 1231 } 1232 return 1; 1233} 1234#endif 1235 1236#if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR 1237#define translit_separator(src) do { \ 1238 char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \ 1239 do { \ 1240 *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \ 1241 } while (c); \ 1242 (src) = tmp; \ 1243 } while (0) 1244#else 1245#define translit_separator(str) (void)(str) 1246#endif 1247 1248void* 1249dln_load(const char *file) 1250{ 1251#if !defined(_AIX) && !defined(NeXT) 1252 const char *error = 0; 1253#define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error)) 1254#endif 1255 1256#if defined _WIN32 && !defined __CYGWIN__ 1257 HINSTANCE handle; 1258 char winfile[MAXPATHLEN]; 1259 char message[1024]; 1260 void (*init_fct)(); 1261 char *buf; 1262 1263 if (strlen(file) >= MAXPATHLEN) dln_loaderror("filename too long"); 1264 1265 /* Load the file as an object one */ 1266 init_funcname(&buf, file); 1267 1268 strlcpy(winfile, file, sizeof(winfile)); 1269 1270 /* Load file */ 1271 if ((handle = LoadLibrary(winfile)) == NULL) { 1272 error = dln_strerror(); 1273 goto failed; 1274 } 1275 1276#if defined _WIN32 && defined RUBY_EXPORT 1277 if (!rb_w32_check_imported(handle, rb_libruby_handle())) { 1278 FreeLibrary(handle); 1279 error = "incompatible library version"; 1280 goto failed; 1281 } 1282#endif 1283 1284 if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) { 1285 dln_loaderror("%s - %s\n%s", dln_strerror(), buf, file); 1286 } 1287 1288 /* Call the init code */ 1289 (*init_fct)(); 1290 return handle; 1291#else 1292#ifdef USE_DLN_A_OUT 1293 if (load(file) == -1) { 1294 error = dln_strerror(); 1295 goto failed; 1296 } 1297 return 0; 1298#else 1299 1300 char *buf; 1301 /* Load the file as an object one */ 1302 init_funcname(&buf, file); 1303 translit_separator(file); 1304 1305#ifdef USE_DLN_DLOPEN 1306#define DLN_DEFINED 1307 { 1308 void *handle; 1309 void (*init_fct)(); 1310 1311#ifndef RTLD_LAZY 1312# define RTLD_LAZY 1 1313#endif 1314#ifdef __INTERIX 1315# undef RTLD_GLOBAL 1316#endif 1317#ifndef RTLD_GLOBAL 1318# define RTLD_GLOBAL 0 1319#endif 1320 1321#ifdef __native_client__ 1322 char* p, *orig; 1323 if (file[0] == '.' && file[1] == '/') file+=2; 1324 orig = strdup(file); 1325 for (p = file; *p; ++p) { 1326 if (*p == '/') *p = '_'; 1327 } 1328#endif 1329 /* Load file */ 1330 if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) { 1331#ifdef __native_client__ 1332 free(orig); 1333#endif 1334 error = dln_strerror(); 1335 goto failed; 1336 } 1337 1338 init_fct = (void(*)())(VALUE)dlsym(handle, buf); 1339#ifdef __native_client__ 1340 strcpy(file, orig); 1341 free(orig); 1342#endif 1343#if defined __SYMBIAN32__ 1344 if (init_fct == NULL) { 1345 init_fct = (void(*)())dlsym(handle, "1"); /* Some Symbian versions do not support symbol table in DLL, ordinal numbers only */ 1346 } 1347#endif 1348 if (init_fct == NULL) { 1349 error = DLN_ERROR(); 1350 dlclose(handle); 1351 goto failed; 1352 } 1353 /* Call the init code */ 1354 (*init_fct)(); 1355 1356 return handle; 1357 } 1358#endif /* USE_DLN_DLOPEN */ 1359 1360#ifdef __hpux 1361#define DLN_DEFINED 1362 { 1363 shl_t lib = NULL; 1364 int flags; 1365 void (*init_fct)(); 1366 1367 flags = BIND_DEFERRED; 1368 lib = shl_load(file, flags, 0); 1369 if (lib == NULL) { 1370 extern int errno; 1371 dln_loaderror("%s - %s", strerror(errno), file); 1372 } 1373 shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct); 1374 if (init_fct == NULL) { 1375 shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct); 1376 if (init_fct == NULL) { 1377 errno = ENOSYM; 1378 dln_loaderror("%s - %s", strerror(ENOSYM), file); 1379 } 1380 } 1381 (*init_fct)(); 1382 return (void*)lib; 1383 } 1384#endif /* hpux */ 1385 1386#if defined(_AIX) && ! defined(_IA64) 1387#define DLN_DEFINED 1388 { 1389 void (*init_fct)(); 1390 1391 init_fct = (void(*)())load((char*)file, 1, 0); 1392 if (init_fct == NULL) { 1393 aix_loaderror(file); 1394 } 1395 if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) { 1396 aix_loaderror(file); 1397 } 1398 (*init_fct)(); 1399 return (void*)init_fct; 1400 } 1401#endif /* _AIX */ 1402 1403#if defined(MACOSX_DYLD) 1404#define DLN_DEFINED 1405/*---------------------------------------------------- 1406 By SHIROYAMA Takayuki Psi@fortune.nest.or.jp 1407 1408 Special Thanks... 1409 Yu tomoak-i@is.aist-nara.ac.jp, 1410 Mi hisho@tasihara.nest.or.jp, 1411 sunshine@sunshineco.com, 1412 and... Miss ARAI Akino(^^;) 1413 ----------------------------------------------------*/ 1414 { 1415 int dyld_result; 1416 NSObjectFileImage obj_file; /* handle, but not use it */ 1417 /* "file" is module file name . 1418 "buf" is pointer to initial function name with "_" . */ 1419 1420 void (*init_fct)(); 1421 1422 1423 dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file); 1424 1425 if (dyld_result != NSObjectFileImageSuccess) { 1426 dln_loaderror("Failed to load %.200s", file); 1427 } 1428 1429 NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW); 1430 1431 /* lookup the initial function */ 1432 if (!NSIsSymbolNameDefined(buf)) { 1433 dln_loaderror("Failed to lookup Init function %.200s",file); 1434 } 1435 init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf)); 1436 (*init_fct)(); 1437 1438 return (void*)init_fct; 1439 } 1440#endif 1441 1442#if defined(__BEOS__) || defined(__HAIKU__) 1443# define DLN_DEFINED 1444 { 1445 status_t err_stat; /* BeOS error status code */ 1446 image_id img_id; /* extension module unique id */ 1447 void (*init_fct)(); /* initialize function for extension module */ 1448 1449 /* load extension module */ 1450 img_id = load_add_on(file); 1451 if (img_id <= 0) { 1452 dln_loaderror("Failed to load add_on %.200s error_code=%x", 1453 file, img_id); 1454 } 1455 1456 /* find symbol for module initialize function. */ 1457 /* The Be Book KernelKit Images section described to use 1458 B_SYMBOL_TYPE_TEXT for symbol of function, not 1459 B_SYMBOL_TYPE_CODE. Why ? */ 1460 /* strcat(init_fct_symname, "__Fv"); */ /* parameter nothing. */ 1461 /* "__Fv" dont need! The Be Book Bug ? */ 1462 err_stat = get_image_symbol(img_id, buf, 1463 B_SYMBOL_TYPE_TEXT, (void **)&init_fct); 1464 1465 if (err_stat != B_NO_ERROR) { 1466 char real_name[MAXPATHLEN]; 1467 1468 strlcpy(real_name, buf, MAXPATHLEN); 1469 strlcat(real_name, "__Fv", MAXPATHLEN); 1470 err_stat = get_image_symbol(img_id, real_name, 1471 B_SYMBOL_TYPE_TEXT, (void **)&init_fct); 1472 } 1473 1474 if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) { 1475 unload_add_on(img_id); 1476 dln_loaderror("Failed to lookup Init function %.200s", file); 1477 } 1478 else if (B_NO_ERROR != err_stat) { 1479 char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)"; 1480 unload_add_on(img_id); 1481 dln_loaderror(errmsg, strerror(err_stat), buf); 1482 } 1483 1484 /* call module initialize function. */ 1485 (*init_fct)(); 1486 return (void*)img_id; 1487 } 1488#endif /* __BEOS__ || __HAIKU__ */ 1489 1490#ifndef DLN_DEFINED 1491 dln_notimplement(); 1492#endif 1493 1494#endif /* USE_DLN_A_OUT */ 1495#endif 1496#if !defined(_AIX) && !defined(NeXT) 1497 failed: 1498 dln_loaderror("%s - %s", error, file); 1499#endif 1500 1501 return 0; /* dummy return */ 1502} 1503