dln.c


DEFINITIONS

This source file includes following functions.
  1. S_ISDIR
  2. init_funcname_len
  3. N_MAGIC
  4. load_header
  5. R_RIGHTSHIFT
  6. R_BITSIZE
  7. R_LENGTH
  8. R_PCREL
  9. R_SYMBOL
  10. R_SYMBOL
  11. R_MEMORY_SUB
  12. R_PCREL
  13. R_LENGTH
  14. load_reloc
  15. load_sym
  16. sym_hash
  17. dln_init
  18. load_text_data
  19. undef_print
  20. dln_print_undef
  21. dln_undefined
  22. link_undef
  23. reloc_undef
  24. unlink_undef
  25. reloc_repl
  26. load_1
  27. search_undef
  28. load_lib
  29. load
  30. dln_sym
  31. dln_strerror
  32. aix_loaderror
  33. dln_load
  34. dln_find_exe
  35. dln_find_file
  36. conv_to_posix_path
  37. dln_find_1


   1  /**********************************************************************
   2  
   3    dln.c -
   4  
   5    $Author: michal $
   6    $Date: 2002/09/05 09:17:48 $
   7    created at: Tue Jan 18 17:05:06 JST 1994
   8  
   9    Copyright (C) 1993-2002 Yukihiro Matsumoto
  10  
  11  **********************************************************************/
  12  
  13  #include "ruby.h"
  14  #include "dln.h"
  15  
  16  #ifdef HAVE_STDLIB_H
  17  # include <stdlib.h>
  18  #endif
  19  
  20  #ifdef __CHECKER__
  21  #undef HAVE_DLOPEN
  22  #undef USE_DLN_A_OUT
  23  #undef USE_DLN_DLOPEN
  24  #endif
  25  
  26  #ifdef USE_DLN_A_OUT
  27  char *dln_argv0;
  28  #endif
  29  
  30  #ifdef _AIX
  31  #pragma alloca
  32  #endif
  33  
  34  #if defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
  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
  45  void *xmalloc();
  46  void *xcalloc();
  47  void *xrealloc();
  48  #endif
  49  
  50  #include <stdio.h>
  51  #if defined(NT) || defined(__VMS)
  52  #include "missing/file.h"
  53  #endif
  54  #include <sys/types.h>
  55  #include <sys/stat.h>
  56  
  57  #ifndef S_ISDIR
  58  #   define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
  59  #endif
  60  
  61  #ifdef HAVE_SYS_PARAM_H
  62  # include <sys/param.h>
  63  #else
  64  # define MAXPATHLEN 1024
  65  #endif
  66  
  67  #ifdef HAVE_UNISTD_H
  68  # include <unistd.h>
  69  #endif
  70  
  71  #ifndef NT
  72  char *getenv();
  73  #endif
  74  
  75  #if defined(__VMS)
  76  #pragma builtins
  77  #include <dlfcn.h>
  78  #endif
  79  
  80  #ifdef __MACOS__
  81  # include <TextUtils.h>
  82  # include <CodeFragments.h>
  83  # include <Aliases.h>
  84  # include "macruby_private.h"
  85  #endif
  86  
  87  #ifdef __BEOS__
  88  # include <image.h>
  89  #endif
  90  
  91  int eaccess();
  92  
  93  #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX)
  94  /* dynamic load with dlopen() */
  95  # define USE_DLN_DLOPEN
  96  #endif
  97  
  98  #ifndef FUNCNAME_PATTERN
  99  # if defined(__hp9000s300) ||  (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || defined(__OpenBSD__) || defined(NeXT) || defined(__WATCOMC__) || defined(__APPLE__)
 100  #  define FUNCNAME_PATTERN "_Init_%s"
 101  # else
 102  #  define FUNCNAME_PATTERN "Init_%s"
 103  # endif
 104  #endif
 105  
 106  static int
 107  init_funcname_len(buf, file)
 108      char **buf;
 109      char *file;
 110  {
 111      char *p, *slash;
 112  
 113      /* Load the file as an object one */
 114      for (p = file, slash = p-1; *p; p++) /* Find position of last '/' */
 115  #ifdef __MACOS__
 116          if (*p == ':') slash = p;
 117  #else
 118          if (*p == '/') slash = p;
 119  #endif
 120  
 121  /* This assumes that systems without length limitation for file names
 122     provide asprintf(). This shouldn't be too unlikely. */
 123  #ifdef MAXPATHLEN
 124      *buf = xmalloc(MAXPATHLEN);
 125      snprintf(*buf, MAXPATHLEN, FUNCNAME_PATTERN, slash + 1);
 126  #else
 127      asprintf(buf, FUNCNAME_PATTERN, slash + 1);
 128  #endif
 129      for (p = *buf; *p; p++) {         /* Delete suffix if it exists */
 130          if (*p == '.') {
 131              *p = '\0'; break;
 132          }
 133      }
 134      return p - *buf;
 135  }
 136  
 137  #define init_funcname(buf, file) do {\
 138      int len = init_funcname_len(buf, file);\
 139      char *tmp = ALLOCA_N(char, len+1);\
 140      if (!tmp) {\
 141          free(*buf);\
 142          rb_memerror();\
 143      }\
 144      strcpy(tmp, *buf);\
 145      free(*buf);\
 146      *buf = tmp;\
 147  } while (0)
 148  
 149  #ifdef USE_DLN_A_OUT
 150  
 151  #ifndef LIBC_NAME
 152  # define LIBC_NAME "libc.a"
 153  #endif
 154  
 155  #ifndef DLN_DEFAULT_LIB_PATH
 156  #  define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
 157  #endif
 158  
 159  #include <errno.h>
 160  
 161  static int dln_errno;
 162  
 163  #define DLN_ENOEXEC     ENOEXEC /* Exec format error */
 164  #define DLN_ECONFL      1201    /* Symbol name conflict */
 165  #define DLN_ENOINIT     1202    /* No inititalizer given */
 166  #define DLN_EUNDEF      1203    /* Undefine symbol remains */
 167  #define DLN_ENOTLIB     1204    /* Not a library file */
 168  #define DLN_EBADLIB     1205    /* Malformed library file */
 169  #define DLN_EINIT       1206    /* Not initialized */
 170  
 171  static int dln_init_p = 0;
 172  
 173  #include <ar.h>
 174  #include <a.out.h>
 175  #ifndef N_COMM
 176  # define N_COMM 0x12
 177  #endif
 178  #ifndef N_MAGIC
 179  # define N_MAGIC(x) (x).a_magic
 180  #endif
 181  
 182  #define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC)
 183  
 184  #include "util.h"
 185  #include "st.h"
 186  
 187  static st_table *sym_tbl;
 188  static st_table *undef_tbl;
 189  
 190  static int load_lib();
 191  
 192  static int
 193  load_header(fd, hdrp, disp)
 194      int fd;
 195      struct exec *hdrp;
 196      long disp;
 197  {
 198      int size;
 199  
 200      lseek(fd, disp, 0);
 201      size = read(fd, hdrp, sizeof(struct exec));
 202      if (size == -1) {
 203          dln_errno = errno;
 204          return -1;
 205      }
 206      if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
 207          dln_errno = DLN_ENOEXEC;
 208          return -1;
 209      }
 210      return 0;
 211  }
 212  
 213  #if defined(sequent)
 214  #define RELOC_SYMBOL(r)                 ((r)->r_symbolnum)
 215  #define RELOC_MEMORY_SUB_P(r)           ((r)->r_bsr)
 216  #define RELOC_PCREL_P(r)                ((r)->r_pcrel || (r)->r_bsr)
 217  #define RELOC_TARGET_SIZE(r)            ((r)->r_length)
 218  #endif
 219  
 220  /* Default macros */
 221  #ifndef RELOC_ADDRESS
 222  #define RELOC_ADDRESS(r)                ((r)->r_address)
 223  #define RELOC_EXTERN_P(r)               ((r)->r_extern)
 224  #define RELOC_SYMBOL(r)                 ((r)->r_symbolnum)
 225  #define RELOC_MEMORY_SUB_P(r)           0
 226  #define RELOC_PCREL_P(r)                ((r)->r_pcrel)
 227  #define RELOC_TARGET_SIZE(r)            ((r)->r_length)
 228  #endif
 229  
 230  #if defined(sun) && defined(sparc)
 231  /* Sparc (Sun 4) macros */
 232  #  undef relocation_info
 233  #  define relocation_info reloc_info_sparc
 234  #  define R_RIGHTSHIFT(r)       (reloc_r_rightshift[(r)->r_type])
 235  #  define R_BITSIZE(r)          (reloc_r_bitsize[(r)->r_type])
 236  #  define R_LENGTH(r)           (reloc_r_length[(r)->r_type])
 237  static int reloc_r_rightshift[] = {
 238    0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
 239  };
 240  static int reloc_r_bitsize[] = {
 241    8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
 242  };
 243  static int reloc_r_length[] = {
 244    0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
 245  };
 246  #  define R_PCREL(r) \
 247      ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
 248  #  define R_SYMBOL(r) ((r)->r_index)
 249  #endif
 250  
 251  #if defined(sequent)
 252  #define R_SYMBOL(r)             ((r)->r_symbolnum)
 253  #define R_MEMORY_SUB(r)         ((r)->r_bsr)
 254  #define R_PCREL(r)              ((r)->r_pcrel || (r)->r_bsr)
 255  #define R_LENGTH(r)             ((r)->r_length)
 256  #endif
 257  
 258  #ifndef R_SYMBOL
 259  #  define R_SYMBOL(r)           ((r)->r_symbolnum)
 260  #  define R_MEMORY_SUB(r)       0
 261  #  define R_PCREL(r)            ((r)->r_pcrel)
 262  #  define R_LENGTH(r)           ((r)->r_length)
 263  #endif
 264  
 265  static struct relocation_info *
 266  load_reloc(fd, hdrp, disp)
 267       int fd;
 268       struct exec *hdrp;
 269       long disp;
 270  {
 271      struct relocation_info *reloc;
 272      int size;
 273  
 274      lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
 275      size = hdrp->a_trsize + hdrp->a_drsize;
 276      reloc = (struct relocation_info*)xmalloc(size);
 277      if (reloc == NULL) {
 278          dln_errno = errno;
 279          return NULL;
 280      }
 281  
 282      if (read(fd, reloc, size) !=  size) {
 283          dln_errno = errno;
 284          free(reloc);
 285          return NULL;
 286      }
 287  
 288      return reloc;
 289  }
 290  
 291  static struct nlist *
 292  load_sym(fd, hdrp, disp)
 293      int fd;
 294      struct exec *hdrp;
 295      long disp;
 296  {
 297      struct nlist * buffer;
 298      struct nlist * sym;
 299      struct nlist * end;
 300      long displ;
 301      int size;
 302  
 303      lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0);
 304      if (read(fd, &size, sizeof(int)) != sizeof(int)) {
 305          goto err_noexec;
 306      }
 307  
 308      buffer = (struct nlist*)xmalloc(hdrp->a_syms + size);
 309      if (buffer == NULL) {
 310          dln_errno = errno;
 311          return NULL;
 312      }
 313  
 314      lseek(fd, disp + N_SYMOFF(*hdrp), 0);
 315      if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) {
 316          free(buffer);
 317          goto err_noexec;
 318      }
 319  
 320      sym = buffer;
 321      end = sym + hdrp->a_syms / sizeof(struct nlist);
 322      displ = (long)buffer + (long)(hdrp->a_syms);
 323  
 324      while (sym < end) {
 325          sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
 326          sym++;
 327      }
 328      return buffer;
 329  
 330    err_noexec:
 331      dln_errno = DLN_ENOEXEC;
 332      return NULL;
 333  }
 334  
 335  static st_table *
 336  sym_hash(hdrp, syms)
 337      struct exec *hdrp;
 338      struct nlist *syms;
 339  {
 340      st_table *tbl;
 341      struct nlist *sym = syms;
 342      struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist));
 343  
 344      tbl = st_init_strtable();
 345      if (tbl == NULL) {
 346          dln_errno = errno;
 347          return NULL;
 348      }
 349  
 350      while (sym < end) {
 351          st_insert(tbl, sym->n_un.n_name, sym);
 352          sym++;
 353      }
 354      return tbl;
 355  }
 356  
 357  static int
 358  dln_init(prog)
 359      const char *prog;
 360  {
 361      char *file;
 362      int fd;
 363      struct exec hdr;
 364      struct nlist *syms;
 365  
 366      if (dln_init_p == 1) return 0;
 367  
 368      file = dln_find_exe(prog, NULL);
 369      if (file == NULL || (fd = open(file, O_RDONLY)) < 0) {
 370          dln_errno = errno;
 371          return -1;
 372      }
 373  
 374      if (load_header(fd, &hdr, 0) == -1) return -1;
 375      syms = load_sym(fd, &hdr, 0);
 376      if (syms == NULL) {
 377          close(fd);
 378          return -1;
 379      }
 380      sym_tbl = sym_hash(&hdr, syms);
 381      if (sym_tbl == NULL) {      /* file may be start with #! */
 382          char c = '\0';
 383          char buf[MAXPATHLEN];
 384          char *p;
 385  
 386          free(syms);
 387          lseek(fd, 0L, 0);
 388          if (read(fd, &c, 1) == -1) {
 389              dln_errno = errno;
 390              return -1;
 391          }
 392          if (c != '#') goto err_noexec;
 393          if (read(fd, &c, 1) == -1) {
 394              dln_errno = errno;
 395              return -1;
 396          }
 397          if (c != '!') goto err_noexec;
 398  
 399          p = buf;
 400          /* skip forwading spaces */
 401          while (read(fd, &c, 1) == 1) {
 402              if (c == '\n') goto err_noexec;
 403              if (c != '\t' && c != ' ') {
 404                  *p++ = c;
 405                  break;
 406              }
 407          }
 408          /* read in command name */
 409          while (read(fd, p, 1) == 1) {
 410              if (*p == '\n' || *p == '\t' || *p == ' ') break;
 411              p++;
 412              if (p-buf >= MAXPATHLEN) {
 413                  dln_errno = ENAMETOOLONG;
 414                  return -1;
 415              }
 416          }
 417          *p = '\0';
 418  
 419          return dln_init(buf);
 420      }
 421      dln_init_p = 1;
 422      undef_tbl = st_init_strtable();
 423      close(fd);
 424      return 0;
 425  
 426    err_noexec:
 427      close(fd);
 428      dln_errno = DLN_ENOEXEC;
 429      return -1;
 430  }
 431  
 432  static long
 433  load_text_data(fd, hdrp, bss, disp)
 434      int fd;
 435      struct exec *hdrp;
 436      int bss;
 437      long disp;
 438  {
 439      int size;
 440      unsigned char* addr;
 441  
 442      lseek(fd, disp + N_TXTOFF(*hdrp), 0);
 443      size = hdrp->a_text + hdrp->a_data;
 444  
 445      if (bss == -1) size += hdrp->a_bss;
 446      else if (bss > 1) size += bss;
 447  
 448      addr = (unsigned char*)xmalloc(size);
 449      if (addr == NULL) {
 450          dln_errno = errno;
 451          return 0;
 452      }
 453  
 454      if (read(fd, addr, size) !=  size) {
 455          dln_errno = errno;
 456          free(addr);
 457          return 0;
 458      }
 459  
 460      if (bss == -1) {
 461          memset(addr +  hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss);
 462      }
 463      else if (bss > 0) {
 464          memset(addr +  hdrp->a_text + hdrp->a_data, 0, bss);
 465      }
 466  
 467      return (long)addr;
 468  }
 469  
 470  static int
 471  undef_print(key, value)
 472      char *key, *value;
 473  {
 474      fprintf(stderr, "  %s\n", key);
 475      return ST_CONTINUE;
 476  }
 477  
 478  static void
 479  dln_print_undef()
 480  {
 481      fprintf(stderr, " Undefined symbols:\n");
 482      st_foreach(undef_tbl, undef_print, NULL);
 483  }
 484  
 485  static void
 486  dln_undefined()
 487  {
 488      if (undef_tbl->num_entries > 0) {
 489          fprintf(stderr, "dln: Calling undefined function\n");
 490          dln_print_undef();
 491          rb_exit(1);
 492      }
 493  }
 494  
 495  struct undef {
 496      char *name;
 497      struct relocation_info reloc;
 498      long base;
 499      char *addr;
 500      union {
 501          char c;
 502          short s;
 503          long l;
 504      } u;
 505  };
 506  
 507  static st_table *reloc_tbl = NULL;
 508  static void
 509  link_undef(name, base, reloc)
 510      const char *name;
 511      long base;
 512      struct relocation_info *reloc;
 513  {
 514      static int u_no = 0;
 515      struct undef *obj;
 516      char *addr = (char*)(reloc->r_address + base);
 517  
 518      obj = (struct undef*)xmalloc(sizeof(struct undef));
 519      obj->name = strdup(name);
 520      obj->reloc = *reloc;
 521      obj->base = base;
 522      switch (R_LENGTH(reloc)) {
 523        case 0:           /* byte */
 524          obj->u.c = *addr;
 525          break;
 526        case 1:           /* word */
 527          obj->u.s = *(short*)addr;
 528          break;
 529        case 2:           /* long */
 530          obj->u.l = *(long*)addr;
 531          break;
 532      }
 533      if (reloc_tbl == NULL) {
 534          reloc_tbl = st_init_numtable();
 535      }
 536      st_insert(reloc_tbl, u_no++, obj);
 537  }
 538  
 539  struct reloc_arg {
 540      const char *name;
 541      long value;
 542  };
 543  
 544  static int
 545  reloc_undef(no, undef, arg)
 546      int no;
 547      struct undef *undef;
 548      struct reloc_arg *arg;
 549  {
 550      int datum;
 551      char *address;
 552  #if defined(sun) && defined(sparc)
 553      unsigned int mask = 0;
 554  #endif
 555  
 556      if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE;
 557      address = (char*)(undef->base + undef->reloc.r_address);
 558      datum = arg->value;
 559  
 560      if (R_PCREL(&(undef->reloc))) datum -= undef->base;
 561  #if defined(sun) && defined(sparc)
 562      datum += undef->reloc.r_addend;
 563      datum >>= R_RIGHTSHIFT(&(undef->reloc));
 564      mask = (1 << R_BITSIZE(&(undef->reloc))) - 1;
 565      mask |= mask -1;
 566      datum &= mask;
 567      switch (R_LENGTH(&(undef->reloc))) {
 568        case 0:
 569          *address = undef->u.c;
 570          *address &= ~mask;
 571          *address |= datum;
 572          break;
 573        case 1:
 574          *(short *)address = undef->u.s;
 575          *(short *)address &= ~mask;
 576          *(short *)address |= datum;
 577          break;
 578        case 2:
 579          *(long *)address = undef->u.l;
 580          *(long *)address &= ~mask;
 581          *(long *)address |= datum;
 582          break;
 583      }
 584  #else
 585      switch (R_LENGTH(&(undef->reloc))) {
 586        case 0:           /* byte */
 587          if (R_MEMORY_SUB(&(undef->reloc)))
 588              *address = datum - *address;
 589          else *address = undef->u.c + datum;
 590          break;
 591        case 1:           /* word */
 592          if (R_MEMORY_SUB(&(undef->reloc)))
 593              *(short*)address = datum - *(short*)address;
 594          else *(short*)address = undef->u.s + datum;
 595          break;
 596        case 2:           /* long */
 597          if (R_MEMORY_SUB(&(undef->reloc)))
 598              *(long*)address = datum - *(long*)address;
 599          else *(long*)address = undef->u.l + datum;
 600          break;
 601      }
 602  #endif
 603      free(undef->name);
 604      free(undef);
 605      return ST_DELETE;
 606  }
 607  
 608  static void
 609  unlink_undef(name, value)
 610      const char *name;
 611      long value;
 612  {
 613      struct reloc_arg arg;
 614  
 615      arg.name = name;
 616      arg.value = value;
 617      st_foreach(reloc_tbl, reloc_undef, &arg);
 618  }
 619  
 620  #ifdef N_INDR
 621  struct indr_data {
 622      char *name0, *name1;
 623  };
 624  
 625  static int
 626  reloc_repl(no, undef, data)
 627      int no;
 628      struct undef *undef;
 629      struct indr_data *data;
 630  {
 631      if (strcmp(data->name0, undef->name) == 0) {
 632          free(undef->name);
 633          undef->name = strdup(data->name1);
 634      }
 635      return ST_CONTINUE;
 636  }
 637  #endif
 638  
 639  static int
 640  load_1(fd, disp, need_init)
 641      int fd;
 642      long disp;
 643      const char *need_init;
 644  {
 645      static char *libc = LIBC_NAME;
 646      struct exec hdr;
 647      struct relocation_info *reloc = NULL;
 648      long block = 0;
 649      long new_common = 0; /* Length of new common */
 650      struct nlist *syms = NULL;
 651      struct nlist *sym;
 652      struct nlist *end;
 653      int init_p = 0;
 654  
 655      if (load_header(fd, &hdr, disp) == -1) return -1;
 656      if (INVALID_OBJECT(hdr)) {
 657          dln_errno = DLN_ENOEXEC;
 658          return -1;
 659      }
 660      reloc = load_reloc(fd, &hdr, disp);
 661      if (reloc == NULL) return -1;
 662  
 663      syms = load_sym(fd, &hdr, disp);
 664      if (syms == NULL) {
 665          free(reloc);
 666          return -1;
 667      }
 668  
 669      sym = syms;
 670      end = syms + (hdr.a_syms / sizeof(struct nlist));
 671      while (sym < end) {
 672          struct nlist *old_sym;
 673          int value = sym->n_value;
 674  
 675  #ifdef N_INDR
 676          if (sym->n_type == (N_INDR | N_EXT)) {
 677              char *key = sym->n_un.n_name;
 678  
 679              if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) {
 680                  if (st_delete(undef_tbl, &key, NULL)) {
 681                      unlink_undef(key, old_sym->n_value);
 682                      free(key);
 683                  }
 684              }
 685              else {
 686                  struct indr_data data;
 687  
 688                  data.name0 = sym->n_un.n_name;
 689                  data.name1 = sym[1].n_un.n_name;
 690                  st_foreach(reloc_tbl, reloc_repl, &data);
 691  
 692                  st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL);
 693                  if (st_delete(undef_tbl, &key, NULL)) {
 694                      free(key);
 695                  }
 696              }
 697              sym += 2;
 698              continue;
 699          }
 700  #endif
 701          if (sym->n_type == (N_UNDF | N_EXT)) {
 702              if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) {
 703                  old_sym = NULL;
 704              }
 705  
 706              if (value) {
 707                  if (old_sym) {
 708                      sym->n_type = N_EXT | N_COMM;
 709                      sym->n_value = old_sym->n_value;
 710                  }
 711                  else {
 712                      int rnd =
 713                          value >= sizeof(double) ? sizeof(double) - 1
 714                              : value >= sizeof(long) ? sizeof(long) - 1
 715                                  : sizeof(short) - 1;
 716  
 717                      sym->n_type = N_COMM;
 718                      new_common += rnd;
 719                      new_common &= ~(long)rnd;
 720                      sym->n_value = new_common;
 721                      new_common += value;
 722                  }
 723              }
 724              else {
 725                  if (old_sym) {
 726                      sym->n_type = N_EXT | N_COMM;
 727                      sym->n_value = old_sym->n_value;
 728                  }
 729                  else {
 730                      sym->n_value = (long)dln_undefined;
 731                      st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL);
 732                  }
 733              }
 734          }
 735          sym++;
 736      }
 737  
 738      block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp);
 739      if (block == 0) goto err_exit;
 740  
 741      sym = syms;
 742      while (sym < end) {
 743          struct nlist *new_sym;
 744          char *key;
 745  
 746          switch (sym->n_type) {
 747            case N_COMM:
 748              sym->n_value += hdr.a_text + hdr.a_data;
 749            case N_TEXT|N_EXT:
 750            case N_DATA|N_EXT:
 751  
 752              sym->n_value += block;
 753  
 754              if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0
 755                  && new_sym->n_value != (long)dln_undefined) {
 756                  dln_errno = DLN_ECONFL;
 757                  goto err_exit;
 758              }
 759  
 760              key = sym->n_un.n_name;
 761              if (st_delete(undef_tbl, &key, NULL) != 0) {
 762                  unlink_undef(key, sym->n_value);
 763                  free(key);
 764              }
 765  
 766              new_sym = (struct nlist*)xmalloc(sizeof(struct nlist));
 767              *new_sym = *sym;
 768              new_sym->n_un.n_name = strdup(sym->n_un.n_name);
 769              st_insert(sym_tbl, new_sym->n_un.n_name, new_sym);
 770              break;
 771  
 772            case N_TEXT:
 773            case N_DATA:
 774              sym->n_value += block;
 775              break;
 776          }
 777          sym++;
 778      }
 779  
 780      /*
 781       * First comes the text-relocation
 782       */
 783      {
 784          struct relocation_info * rel = reloc;
 785          struct relocation_info * rel_beg = reloc +
 786              (hdr.a_trsize/sizeof(struct relocation_info));
 787          struct relocation_info * rel_end = reloc +
 788              (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info);
 789  
 790          while (rel < rel_end) {
 791              char *address = (char*)(rel->r_address + block);
 792              long datum = 0;
 793  #if defined(sun) && defined(sparc)
 794              unsigned int mask = 0;
 795  #endif
 796  
 797              if(rel >= rel_beg)
 798                  address += hdr.a_text;
 799  
 800              if (rel->r_extern) { /* Look it up in symbol-table */
 801                  sym = &(syms[R_SYMBOL(rel)]);
 802                  switch (sym->n_type) {
 803                    case N_EXT|N_UNDF:
 804                      link_undef(sym->n_un.n_name, block, rel);
 805                    case N_EXT|N_COMM:
 806                    case N_COMM:
 807                      datum = sym->n_value;
 808                      break;
 809                    default:
 810                      goto err_exit;
 811                  }
 812              } /* end.. look it up */
 813              else { /* is static */
 814                  switch (R_SYMBOL(rel)) { 
 815                    case N_TEXT:
 816                    case N_DATA:
 817                      datum = block;
 818                      break;
 819                    case N_BSS:
 820                      datum = block +  new_common;
 821                      break;
 822                    case N_ABS:
 823                      break;
 824                  }
 825              } /* end .. is static */
 826              if (R_PCREL(rel)) datum -= block;
 827  
 828  #if defined(sun) && defined(sparc)
 829              datum += rel->r_addend;
 830              datum >>= R_RIGHTSHIFT(rel);
 831              mask = (1 << R_BITSIZE(rel)) - 1;
 832              mask |= mask -1;
 833              datum &= mask;
 834  
 835              switch (R_LENGTH(rel)) {
 836                case 0:
 837                  *address &= ~mask;
 838                  *address |= datum;
 839                  break;
 840                case 1:
 841                  *(short *)address &= ~mask;
 842                  *(short *)address |= datum;
 843                  break;
 844                case 2:
 845                  *(long *)address &= ~mask;
 846                  *(long *)address |= datum;
 847                  break;
 848              }
 849  #else
 850              switch (R_LENGTH(rel)) {
 851                case 0:           /* byte */
 852                  if (datum < -128 || datum > 127) goto err_exit;
 853                  *address += datum;
 854                  break;
 855                case 1:           /* word */
 856                  *(short *)address += datum;
 857                  break;
 858                case 2:           /* long */
 859                  *(long *)address += datum;
 860                  break;
 861              }
 862  #endif
 863              rel++;
 864          }
 865      }
 866  
 867      if (need_init) {
 868          int len;
 869          char **libs_to_be_linked = 0;
 870          char *buf;
 871  
 872          if (undef_tbl->num_entries > 0) {
 873              if (load_lib(libc) == -1) goto err_exit;
 874          }
 875  
 876          init_funcname(&buf, need_init);
 877          len = strlen(buf);
 878  
 879          for (sym = syms; sym<end; sym++) {
 880              char *name = sym->n_un.n_name;
 881              if (name[0] == '_' && sym->n_value >= block) {
 882                  if (strcmp(name+1, "dln_libs_to_be_linked") == 0) {
 883                      libs_to_be_linked = (char**)sym->n_value;
 884                  }
 885                  else if (strcmp(name+1, buf) == 0) {
 886                      init_p = 1;
 887                      ((int (*)())sym->n_value)();
 888                  }
 889              }
 890          }
 891          if (libs_to_be_linked && undef_tbl->num_entries > 0) {
 892              while (*libs_to_be_linked) {
 893                  load_lib(*libs_to_be_linked);
 894                  libs_to_be_linked++;
 895              }
 896          }
 897      }
 898      free(reloc);
 899      free(syms);
 900      if (need_init) {
 901          if (init_p == 0) {
 902              dln_errno = DLN_ENOINIT;
 903              return -1;
 904          }
 905          if (undef_tbl->num_entries > 0) {
 906              if (load_lib(libc) == -1) goto err_exit;
 907              if (undef_tbl->num_entries > 0) {
 908                  dln_errno = DLN_EUNDEF;
 909                  return -1;
 910              }
 911          }
 912      }
 913      return 0;
 914  
 915    err_exit:
 916      if (syms) free(syms);
 917      if (reloc) free(reloc);
 918      if (block) free((char*)block);
 919      return -1;
 920  }
 921  
 922  static int target_offset;
 923  static int
 924  search_undef(key, value, lib_tbl)
 925      const char *key;
 926      int value;
 927      st_table *lib_tbl;
 928  {
 929      long offset;
 930  
 931      if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
 932      target_offset = offset;
 933      return ST_STOP;
 934  }
 935  
 936  struct symdef {
 937      int rb_str_index;
 938      int lib_offset;
 939  };
 940  
 941  char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
 942  
 943  static int
 944  load_lib(lib)
 945      const char *lib;
 946  {
 947      char *path, *file;
 948      char armagic[SARMAG];
 949      int fd, size;
 950      struct ar_hdr ahdr;
 951      st_table *lib_tbl = NULL;
 952      int *data, nsym;
 953      struct symdef *base;
 954      char *name_base;
 955  
 956      if (dln_init_p == 0) {
 957          dln_errno = DLN_ENOINIT;
 958          return -1;
 959      }
 960  
 961      if (undef_tbl->num_entries == 0) return 0;
 962      dln_errno = DLN_EBADLIB;
 963  
 964      if (lib[0] == '-' && lib[1] == 'l') {
 965          char *p = alloca(strlen(lib) + 4);
 966          sprintf(p, "lib%s.a", lib+2);
 967          lib = p;
 968      }
 969  
 970      /* library search path: */
 971      /* look for environment variable DLN_LIBRARY_PATH first. */
 972      /* then variable dln_librrb_ary_path. */
 973      /* if path is still NULL, use "." for path. */
 974      path = getenv("DLN_LIBRARY_PATH");
 975      if (path == NULL) path = dln_librrb_ary_path;
 976  
 977      file = dln_find_file(lib, path);
 978      fd = open(file, O_RDONLY);
 979      if (fd == -1) goto syserr;
 980      size = read(fd, armagic, SARMAG);
 981      if (size == -1) goto syserr;
 982  
 983      if (size != SARMAG) {
 984          dln_errno = DLN_ENOTLIB;
 985          goto badlib;
 986      }
 987      size = read(fd, &ahdr, sizeof(ahdr));
 988      if (size == -1) goto syserr;
 989      if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) {
 990          goto badlib;
 991      }
 992  
 993      if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) {
 994          /* make hash table from __.SYMDEF */
 995  
 996          lib_tbl = st_init_strtable();
 997          data = (int*)xmalloc(size);
 998          if (data == NULL) goto syserr;
 999          size = read(fd, data, size);
1000          nsym = *data / sizeof(struct symdef);
1001          base = (struct symdef*)(data + 1);
1002          name_base = (char*)(base + nsym) + sizeof(int);
1003          while (nsym > 0) {
1004              char *name = name_base + base->rb_str_index;
1005  
1006              st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr));
1007              nsym--;
1008              base++;
1009          }
1010          for (;;) {
1011              target_offset = -1;
1012              st_foreach(undef_tbl, search_undef, lib_tbl);
1013              if (target_offset == -1) break;
1014              if (load_1(fd, target_offset, 0) == -1) {
1015                  st_free_table(lib_tbl);
1016                  free(data);
1017                  goto badlib;
1018              }
1019              if (undef_tbl->num_entries == 0) break;
1020          }
1021          free(data);
1022          st_free_table(lib_tbl);
1023      }
1024      else {
1025          /* linear library, need to scan (FUTURE) */
1026  
1027          for (;;) {
1028              int offset = SARMAG;
1029              int found = 0;
1030              struct exec hdr;
1031              struct nlist *syms, *sym, *end;
1032  
1033              while (undef_tbl->num_entries > 0) {
1034                  found = 0;
1035                  lseek(fd, offset, 0);
1036                  size = read(fd, &ahdr, sizeof(ahdr));
1037                  if (size == -1) goto syserr;
1038                  if (size == 0) break;
1039                  if (size != sizeof(ahdr)
1040                      || sscanf(ahdr.ar_size, "%d", &size) != 1) {
1041                      goto badlib;
1042                  }
1043                  offset += sizeof(ahdr);
1044                  if (load_header(fd, &hdr, offset) == -1)
1045                      goto badlib;
1046                  syms = load_sym(fd, &hdr, offset);
1047                  if (syms == NULL) goto badlib;
1048                  sym = syms;
1049                  end = syms + (hdr.a_syms / sizeof(struct nlist));
1050                  while (sym < end) {
1051                      if (sym->n_type == N_EXT|N_TEXT
1052                          && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) {
1053                          break;
1054                      }
1055                      sym++;
1056                  }
1057                  if (sym < end) {
1058                      found++;
1059                      free(syms);
1060                      if (load_1(fd, offset, 0) == -1) {
1061                          goto badlib;
1062                      }
1063                  }
1064                  offset += size;
1065                  if (offset & 1) offset++;
1066              }
1067              if (found) break;
1068          }
1069      }
1070      close(fd);
1071      return 0;
1072  
1073    syserr:
1074      dln_errno = errno;
1075    badlib:
1076      if (fd >= 0) close(fd);
1077      return -1;
1078  }
1079  
1080  static int
1081  load(file)
1082      const char *file;
1083  {
1084      int fd;
1085      int result;
1086  
1087      if (dln_init_p == 0) {
1088          if (dln_init(dln_argv0) == -1) return -1;
1089      }
1090      result = strlen(file);
1091      if (file[result-1] == 'a') {
1092          return load_lib(file);
1093      }
1094  
1095      fd = open(file, O_RDONLY);
1096      if (fd == -1) {
1097          dln_errno = errno;
1098          return -1;
1099      }
1100      result = load_1(fd, 0, file);
1101      close(fd);
1102  
1103      return result;
1104  }
1105  
1106  void*
1107  dln_sym(name)
1108      const char *name;
1109  {
1110      struct nlist *sym;
1111  
1112      if (st_lookup(sym_tbl, name, &sym))
1113          return (void*)sym->n_value;
1114      return NULL;
1115  }
1116  
1117  #endif /* USE_DLN_A_OUT */
1118  
1119  #ifdef USE_DLN_DLOPEN
1120  # ifdef __NetBSD__
1121  #  include <nlist.h>
1122  #  include <link.h>
1123  # else
1124  #  include <dlfcn.h>
1125  # endif
1126  #endif
1127  
1128  #ifdef __hpux
1129  #include <errno.h>
1130  #include "dl.h"
1131  #endif
1132  
1133  #if defined(_AIX)
1134  #include <ctype.h>      /* for isdigit()        */
1135  #include <errno.h>      /* for global errno     */
1136  #include <sys/ldr.h>
1137  #endif
1138  
1139  #ifdef NeXT
1140  #if NS_TARGET_MAJOR < 4
1141  #include <mach-o/rld.h>
1142  #else
1143  #include <mach-o/dyld.h>
1144  #endif
1145  #endif
1146  #ifdef __APPLE__
1147  #include <mach-o/dyld.h>
1148  #endif
1149  
1150  
1151  #if defined _WIN32 && !defined __CYGWIN__
1152  #include <windows.h>
1153  #endif
1154  
1155  static const char *
1156  dln_strerror()
1157  {
1158  #ifdef USE_DLN_A_OUT
1159      char *strerror();
1160  
1161      switch (dln_errno) {
1162        case DLN_ECONFL:
1163          return "Symbol name conflict";
1164        case DLN_ENOINIT:
1165          return "No inititalizer given";
1166        case DLN_EUNDEF:
1167          return "Unresolved symbols";
1168        case DLN_ENOTLIB:
1169          return "Not a library file";
1170        case DLN_EBADLIB:
1171          return "Malformed library file";
1172        case DLN_EINIT:
1173          return "Not initialized";
1174        default:
1175          return strerror(dln_errno);
1176      }
1177  #endif
1178  
1179  #ifdef USE_DLN_DLOPEN
1180      return (char*)dlerror();
1181  #endif
1182  
1183  #if defined _WIN32 && !defined __CYGWIN__
1184      static char message[1024];
1185      int error = GetLastError();
1186      char *p = message;
1187      p += sprintf(message, "%d: ", error);
1188      FormatMessage(
1189          FORMAT_MESSAGE_FROM_SYSTEM       | FORMAT_MESSAGE_IGNORE_INSERTS,
1190          NULL,
1191          error,
1192          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1193          p,
1194          sizeof message - strlen(message),
1195          NULL);
1196  
1197      for (p = message; *p; p++) {
1198          if (*p == '\n' || *p == '\r')
1199              *p = ' ';
1200      }
1201      return message;
1202  #endif
1203  }
1204  
1205  
1206  #if defined(_AIX) && ! defined(_IA64)
1207  static void
1208  aix_loaderror(const char *pathname)
1209  {
1210      char *message[8], errbuf[1024];
1211      int i,j;
1212  
1213      struct errtab { 
1214          int errno;
1215          char *errstr;
1216      } load_errtab[] = {
1217          {L_ERROR_TOOMANY,       "too many errors, rest skipped."},
1218          {L_ERROR_NOLIB,         "can't load library:"},
1219          {L_ERROR_UNDEF,         "can't find symbol in library:"},
1220          {L_ERROR_RLDBAD,
1221               "RLD index out of range or bad relocation type:"},
1222          {L_ERROR_FORMAT,        "not a valid, executable xcoff file:"},
1223          {L_ERROR_MEMBER,
1224               "file not an archive or does not contain requested member:"},
1225          {L_ERROR_TYPE,          "symbol table mismatch:"},
1226          {L_ERROR_ALIGN,         "text allignment in file is wrong."},
1227          {L_ERROR_SYSTEM,        "System error:"},
1228          {L_ERROR_ERRNO,         NULL}
1229      };
1230  
1231  #define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0]))
1232  #define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1)
1233  
1234      snprintf(errbuf, 1024, "load failed - %s ", pathname);
1235  
1236      if (!loadquery(1, &message[0], sizeof(message))) 
1237          ERRBUF_APPEND(strerror(errno));
1238      for(i = 0; message[i] && *message[i]; i++) {
1239          int nerr = atoi(message[i]);
1240          for (j=0; j<LOAD_ERRTAB_LEN; j++) {
1241              if (nerr == load_errtab[i].errno && load_errtab[i].errstr)
1242                  ERRBUF_APPEND(load_errtab[i].errstr);
1243          }
1244          while (isdigit(*message[i])) message[i]++; 
1245          ERRBUF_APPEND(message[i]);
1246          ERRBUF_APPEND("\n");
1247      }
1248      errbuf[strlen(errbuf)-1] = '\0';    /* trim off last newline */
1249      rb_loaderror(errbuf);
1250      return;
1251  }
1252  #endif
1253  
1254  void*
1255  dln_load(file)
1256      const char *file;
1257  {
1258  #if !defined(_AIX) && !defined(NeXT)
1259      const char *error = 0;
1260  #define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
1261  #endif
1262  
1263  #if defined _WIN32 && !defined __CYGWIN__
1264      HINSTANCE handle;
1265      char winfile[MAXPATHLEN];
1266      void (*init_fct)();
1267      char *buf;
1268  
1269      if (strlen(file) >= MAXPATHLEN) rb_loaderror("filename too long");
1270  
1271      /* Load the file as an object one */
1272      init_funcname(&buf, file);
1273  
1274      strcpy(winfile, file);
1275  
1276      /* Load file */
1277      if ((handle = LoadLibrary(winfile)) == NULL) {
1278          error = dln_strerror();
1279          goto failed;
1280      }
1281  
1282      if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
1283          rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
1284      }
1285  
1286      /* Call the init code */
1287      (*init_fct)();
1288      return handle;
1289  #else
1290  #ifdef USE_DLN_A_OUT
1291      if (load(file) == -1) {
1292          error = dln_strerror();
1293          goto failed;
1294      }
1295      return 0;
1296  #else
1297  
1298      char *buf;
1299      /* Load the file as an object one */
1300      init_funcname(&buf, file);
1301  
1302  #ifdef USE_DLN_DLOPEN
1303  #define DLN_DEFINED
1304      {
1305          void *handle;
1306          void (*init_fct)();
1307  
1308  #ifndef RTLD_LAZY
1309  # define RTLD_LAZY 1
1310  #endif
1311  #ifndef RTLD_GLOBAL
1312  # define RTLD_GLOBAL 0
1313  #endif
1314  
1315          /* Load file */
1316          if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
1317              error = dln_strerror();
1318              goto failed;
1319          }
1320  
1321          init_fct = (void(*)())dlsym(handle, buf);
1322          if (init_fct == NULL) {
1323              error = DLN_ERROR();
1324              dlclose(handle);
1325              goto failed;
1326          }
1327          /* Call the init code */
1328          (*init_fct)();
1329  
1330          return handle;
1331      }
1332  #endif /* USE_DLN_DLOPEN */
1333  
1334  #ifdef __hpux
1335  #define DLN_DEFINED
1336      {
1337          shl_t lib = NULL;
1338          int flags;
1339          void (*init_fct)();
1340  
1341          flags = BIND_DEFERRED;
1342          lib = shl_load(file, flags, 0);
1343          if (lib == NULL) {
1344              extern int errno;
1345              rb_loaderror("%s - %s", strerror(errno), file);
1346          }
1347          shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
1348          if (init_fct == NULL) {
1349              shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
1350              if (init_fct == NULL) {
1351                  errno = ENOSYM;
1352                  rb_loaderror("%s - %s", strerror(ENOSYM), file);
1353              }
1354          }
1355          (*init_fct)();
1356          return (void*)lib;
1357      }
1358  #endif /* hpux */
1359  
1360  #if defined(_AIX) && ! defined(_IA64)
1361  #define DLN_DEFINED
1362      {
1363          void (*init_fct)();
1364  
1365          init_fct = (void(*)())load((char*)file, 1, 0);
1366          if (init_fct == NULL) {
1367              aix_loaderror(file);
1368          }
1369          if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
1370              aix_loaderror(file);
1371          }
1372          (*init_fct)();
1373          return (void*)init_fct;
1374      }
1375  #endif /* _AIX */
1376  
1377  #if defined(NeXT) || defined(__APPLE__)
1378  #define DLN_DEFINED
1379  /*----------------------------------------------------
1380     By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
1381   
1382     Special Thanks...
1383      Yu tomoak-i@is.aist-nara.ac.jp,
1384      Mi hisho@tasihara.nest.or.jp,
1385      and... Miss ARAI Akino(^^;)
1386   ----------------------------------------------------*/
1387  #if defined(NeXT) && (NS_TARGET_MAJOR < 4)/* NeXTSTEP rld functions */
1388  
1389      {
1390          unsigned long init_address;
1391          char *object_files[2] = {NULL, NULL};
1392  
1393          void (*init_fct)();
1394          
1395          object_files[0] = file;
1396          
1397          /* Load object file, if return value ==0 ,  load failed*/
1398          if(rld_load(NULL, NULL, object_files, NULL) == 0) {
1399              rb_loaderror("Failed to load %.200s", file);
1400          }
1401  
1402          /* lookup the initial function */
1403          if(rld_lookup(NULL, buf, &init_address) == 0) {
1404              rb_loaderror("Failed to lookup Init function %.200s", file);
1405          }
1406  
1407           /* Cannot call *init_address directory, so copy this value to
1408              funtion pointer */
1409          init_fct = (void(*)())init_address;
1410          (*init_fct)();
1411          return (void*)init_address;
1412      }
1413  #else/* OPENSTEP dyld functions */
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              rb_loaderror("Failed to load %.200s", file);
1427          }
1428  
1429          NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
1430  
1431          /* lookup the initial function */
1432          /*NSIsSymbolNameDefined require function name without "_" */
1433          if(NSIsSymbolNameDefined(buf + 1)) {
1434              rb_loaderror("Failed to lookup Init function %.200s",file);
1435          }
1436  
1437          /* NSLookupAndBindSymbol require function name with "_" !! */
1438          init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
1439          (*init_fct)();
1440  
1441          return (void*)init_fct;
1442      }
1443  #endif /* rld or dyld */
1444  #endif
1445  
1446  #ifdef __BEOS__
1447  # define DLN_DEFINED
1448      {
1449        status_t err_stat;  /* BeOS error status code */
1450        image_id img_id;    /* extention module unique id */
1451        void (*init_fct)(); /* initialize function for extention module */
1452  
1453        /* load extention module */
1454        img_id = load_add_on(file);
1455        if (img_id <= 0) {
1456          rb_loaderror("Failed to load %.200s", file);
1457        }
1458        
1459        /* find symbol for module initialize function. */
1460        /* The Be Book KernelKit Images section described to use
1461           B_SYMBOL_TYPE_TEXT for symbol of function, not
1462           B_SYMBOL_TYPE_CODE. Why ? */
1463        /* strcat(init_fct_symname, "__Fv"); */  /* parameter nothing. */
1464        /* "__Fv" dont need! The Be Book Bug ? */
1465        err_stat = get_image_symbol(img_id, buf,
1466                                    B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
1467  
1468        if (err_stat != B_NO_ERROR) {
1469          char real_name[MAXPATHLEN];
1470  
1471          strcpy(real_name, buf);
1472          strcat(real_name, "__Fv");
1473          err_stat = get_image_symbol(img_id, real_name,
1474                                      B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
1475        }
1476  
1477        if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) {
1478          unload_add_on(img_id);
1479          rb_loaderror("Failed to lookup Init function %.200s", file);
1480        }
1481        else if (B_NO_ERROR != err_stat) {
1482          char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
1483          unload_add_on(img_id);
1484          rb_loaderror(errmsg, strerror(err_stat), buf);
1485        }
1486  
1487        /* call module initialize function. */
1488        (*init_fct)();
1489        return (void*)img_id;
1490      }
1491  #endif /* __BEOS__*/
1492  
1493  #ifdef __MACOS__
1494  # define DLN_DEFINED
1495      {
1496        OSErr err;
1497        FSSpec libspec;
1498        CFragConnectionID connID;
1499        Ptr mainAddr;
1500        char errMessage[1024];
1501        Boolean isfolder, didsomething;
1502        Str63 fragname;
1503        Ptr symAddr;
1504        CFragSymbolClass class;
1505        void (*init_fct)();
1506        char fullpath[MAXPATHLEN];
1507  
1508        strcpy(fullpath, file);
1509  
1510        /* resolve any aliases to find the real file */
1511        c2pstr(fullpath);
1512        (void)FSMakeFSSpec(0, 0, fullpath, &libspec);
1513        err = ResolveAliasFile(&libspec, 1, &isfolder, &didsomething);
1514        if (err) {
1515            rb_loaderror("Unresolved Alias - %s", file);
1516        }
1517  
1518        /* Load the fragment (or return the connID if it is already loaded */
1519        fragname[0] = 0;
1520        err = GetDiskFragment(&libspec, 0, 0, fragname, 
1521                              kLoadCFrag, &connID, &mainAddr,
1522                              errMessage);
1523        if (err) {
1524            p2cstr(errMessage);
1525            rb_loaderror("%s - %s",errMessage , file);
1526        }
1527  
1528        /* Locate the address of the correct init function */
1529        c2pstr(buf);
1530        err = FindSymbol(connID, buf, &symAddr, &class);
1531        if (err) {
1532            rb_loaderror("Unresolved symbols - %s" , file);
1533        }
1534        init_fct = (void (*)())symAddr;
1535        (*init_fct)();
1536        return (void*)init_fct;
1537      }
1538  #endif /* __MACOS__ */
1539  
1540  #if defined(__VMS)
1541  #define DLN_DEFINED
1542      {
1543          void *handle, (*init_fct)();
1544          char *fname, *p1, *p2;
1545  
1546          fname = (char *)__alloca(strlen(file)+1);
1547          strcpy(fname,file);
1548          if (p1 = strrchr(fname,'/'))
1549              fname = p1 + 1;
1550          if (p2 = strrchr(fname,'.'))
1551              *p2 = '\0';
1552  
1553          if ((handle = (void*)dlopen(fname, 0)) == NULL) {
1554              error = dln_strerror();
1555              goto failed;
1556          }
1557  
1558          if ((init_fct = (void (*)())dlsym(handle, buf)) == NULL) {
1559              error = DLN_ERROR();
1560              dlclose(handle);
1561              goto failed;
1562          }
1563          /* Call the init code */
1564          (*init_fct)();
1565          return handle;
1566      }
1567  #endif /* __VMS */
1568  
1569  #ifndef DLN_DEFINED
1570      rb_notimplement();
1571  #endif
1572  
1573  #endif /* USE_DLN_A_OUT */
1574  #endif
1575  #if !defined(_AIX) && !defined(NeXT)
1576    failed:
1577      rb_loaderror("%s - %s", error, file);
1578  #endif
1579      return 0;                   /* dummy return */
1580  }
1581  
1582  static char *dln_find_1();
1583  
1584  char *
1585  dln_find_exe(fname, path)
1586      const char *fname;
1587      const char *path;
1588  {
1589      if (!path) {
1590  #if defined(__human68k__)
1591          path = getenv("path");
1592  #else
1593          path = getenv("PATH");
1594  #endif
1595      }
1596  
1597      if (!path) {
1598  #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__MACOS__)
1599          path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;.";
1600  #else
1601          path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
1602  #endif
1603      }
1604      return dln_find_1(fname, path, 1);
1605  }
1606  
1607  char *
1608  dln_find_file(fname, path)
1609      const char *fname;
1610      const char *path;
1611  {
1612  #ifndef __MACOS__
1613      if (!path) path = ".";
1614      return dln_find_1(fname, path, 0);
1615  #else
1616      if (!path) path = ".";
1617      return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, 0));
1618  #endif
1619  }
1620  
1621  #if defined(__CYGWIN32__)
1622  const char *
1623  conv_to_posix_path(win32, posix, len)
1624      char *win32;
1625      char *posix;
1626      int len;
1627  {
1628      char *first = win32;
1629      char *p = win32;
1630      char *dst = posix;
1631  
1632      for (p = win32; *p; p++)
1633          if (*p == ';') {
1634              *p = 0;
1635              cygwin32_conv_to_posix_path(first, posix);
1636              posix += strlen(posix);
1637              *posix++ = ':';
1638              first = p + 1;
1639              *p = ';';
1640          }
1641      if (len < strlen(first))
1642          fprintf(stderr, "PATH length too long: %s\n", first);
1643      else
1644          cygwin32_conv_to_posix_path(first, posix);
1645      return dst;
1646  }
1647  #endif
1648  
1649  static char fbuf[MAXPATHLEN];
1650  
1651  static char *
1652  dln_find_1(fname, path, exe_flag)
1653      char *fname;
1654      char *path;
1655      int exe_flag;               /* non 0 if looking for executable. */
1656  {
1657      register char *dp;
1658      register char *ep;
1659      register char *bp;
1660      struct stat st;
1661  #ifdef __MACOS__
1662      const char* mac_fullpath;
1663  #endif
1664  
1665      if (fname[0] == '/') return fname;
1666      if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0)
1667        return fname;
1668      if (exe_flag && strchr(fname, '/')) return fname;
1669  #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__EMX__)
1670      if (fname[0] == '\\') return fname;
1671      if (strlen(fname) > 2 && fname[1] == ':') return fname;
1672      if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0)
1673        return fname;
1674      if (exe_flag && strchr(fname, '\\')) return fname;
1675  #endif
1676  
1677      for (dp = path;; dp = ++ep) {
1678          register int l;
1679          int i;
1680          int fspace;
1681  
1682          /* extract a component */
1683          ep = strchr(dp, PATH_SEP[0]);
1684          if (ep == NULL)
1685              ep = dp+strlen(dp);
1686  
1687          /* find the length of that component */
1688          l = ep - dp;
1689          bp = fbuf;
1690          fspace = sizeof fbuf - 2;
1691          if (l > 0) {
1692              /*
1693              **  If the length of the component is zero length,
1694              **  start from the current directory.  If the
1695              **  component begins with "~", start from the
1696              **  user's $HOME environment variable.  Otherwise
1697              **  take the path literally.
1698              */
1699  
1700              if (*dp == '~' && (l == 1 ||
1701  #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__EMX__)
1702                                 dp[1] == '\\' || 
1703  #endif
1704                                 dp[1] == '/')) {
1705                  char *home;
1706  
1707                  home = getenv("HOME");
1708                  if (home != NULL) {
1709                      i = strlen(home);
1710                      if ((fspace -= i) < 0)
1711                          goto toolong;
1712                      memcpy(bp, home, i);
1713                      bp += i;
1714                  }
1715                  dp++;
1716                  l--;
1717              }
1718              if (l > 0) {
1719                  if ((fspace -= l) < 0)
1720                      goto toolong;
1721                  memcpy(bp, dp, l);
1722                  bp += l;
1723              }
1724  
1725              /* add a "/" between directory and filename */
1726              if (ep[-1] != '/')
1727                  *bp++ = '/';
1728          }
1729  
1730          /* now append the file name */
1731          i = strlen(fname);
1732          if ((fspace -= i) < 0) {
1733            toolong:
1734              fprintf(stderr, "openpath: pathname too long (ignored)\n");
1735              *bp = '\0';
1736              fprintf(stderr, "\tDirectory \"%s\"\n", fbuf);
1737              fprintf(stderr, "\tFile \"%s\"\n", fname);
1738              continue;
1739          }
1740          memcpy(bp, fname, i + 1);
1741  
1742  #ifndef __MACOS__
1743          if (stat(fbuf, &st) == 0) {
1744              if (exe_flag == 0) return fbuf;
1745              /* looking for executable */
1746              if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
1747                  return fbuf;
1748          }
1749  #else
1750          if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
1751              if (exe_flag == 0) return mac_fullpath;
1752              /* looking for executable */
1753              if (stat(mac_fullpath, &st) == 0) {
1754                  if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0)
1755                      return mac_fullpath;
1756              }
1757          }
1758  #endif
1759  #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__EMX__)
1760          if (exe_flag) {
1761              static const char *extension[] = {
1762  #if defined(MSDOS)
1763                  ".com", ".exe", ".bat",
1764  #if defined(DJGPP)
1765                  ".btm", ".sh", ".ksh", ".pl", ".sed",
1766  #endif
1767  #elif defined(__EMX__) || defined(NT)
1768                  ".exe", ".com", ".cmd", ".bat",
1769  /* end of __EMX__ or NT*/
1770  #else
1771                  ".r", ".R", ".x", ".X", ".bat", ".BAT",
1772  /* __human68k__ */
1773  #endif
1774                  (char *) NULL
1775              };
1776              int j;
1777  
1778              for (j = 0; extension[j]; j++) {
1779                  if (fspace < strlen(extension[j])) {
1780                      fprintf(stderr, "openpath: pathname too long (ignored)\n");
1781                      fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
1782                      fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]);
1783                      continue;
1784                  }
1785                  strcpy(bp + i, extension[j]);
1786  #ifndef __MACOS__
1787                  if (stat(fbuf, &st) == 0)
1788                      return fbuf;
1789  #else
1790                  if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf))
1791                      return mac_fullpath;
1792  #endif
1793              }
1794          }
1795  #endif /* MSDOS or NT or __human68k__ or __EMX__ */
1796          /* if not, and no other alternatives, life is bleak */
1797          if (*ep == '\0') {
1798              return NULL;
1799          }
1800  
1801          /* otherwise try the next component in the search path */
1802      }
1803  }