Ruby  2.0.0p247(2013-06-27revision41674)
dln.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   dln.c -
00004 
00005   $Author: nobu $
00006   created at: Tue Jan 18 17:05:06 JST 1994
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009 
00010 **********************************************************************/
00011 
00012 #ifdef RUBY_EXPORT
00013 #include "ruby/ruby.h"
00014 #define dln_notimplement rb_notimplement
00015 #define dln_memerror rb_memerror
00016 #define dln_exit rb_exit
00017 #define dln_loaderror rb_loaderror
00018 #else
00019 #define dln_notimplement --->>> dln not implemented <<<---
00020 #define dln_memerror abort
00021 #define dln_exit exit
00022 static void dln_loaderror(const char *format, ...);
00023 #endif
00024 #include "dln.h"
00025 
00026 #ifdef HAVE_STDLIB_H
00027 # include <stdlib.h>
00028 #endif
00029 
00030 #ifdef USE_DLN_A_OUT
00031 char *dln_argv0;
00032 #endif
00033 
00034 #if defined(HAVE_ALLOCA_H)
00035 #include <alloca.h>
00036 #endif
00037 
00038 #ifdef HAVE_STRING_H
00039 # include <string.h>
00040 #else
00041 # include <strings.h>
00042 #endif
00043 
00044 #ifndef xmalloc
00045 void *xmalloc();
00046 void *xcalloc();
00047 void *xrealloc();
00048 #endif
00049 
00050 #define free(x) xfree(x)
00051 
00052 #include <stdio.h>
00053 #if defined(_WIN32)
00054 #include "missing/file.h"
00055 #endif
00056 #include <sys/types.h>
00057 #include <sys/stat.h>
00058 
00059 #ifndef S_ISDIR
00060 #   define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
00061 #endif
00062 
00063 #ifdef HAVE_SYS_PARAM_H
00064 # include <sys/param.h>
00065 #endif
00066 #ifndef MAXPATHLEN
00067 # define MAXPATHLEN 1024
00068 #endif
00069 
00070 #ifdef HAVE_UNISTD_H
00071 # include <unistd.h>
00072 #endif
00073 
00074 #ifndef _WIN32
00075 char *getenv();
00076 #endif
00077 
00078 #ifdef __APPLE__
00079 # if defined(HAVE_DLOPEN)
00080    /* Mac OS X with dlopen (10.3 or later) */
00081 #  define MACOSX_DLOPEN
00082 # else
00083 #  define MACOSX_DYLD
00084 # endif
00085 #endif
00086 
00087 #if defined(__BEOS__) || defined(__HAIKU__)
00088 # include <image.h>
00089 #endif
00090 
00091 #ifndef dln_loaderror
00092 static void
00093 dln_loaderror(const char *format, ...)
00094 {
00095     va_list ap;
00096     va_start(ap, format);
00097     vfprintf(stderr, format, ap);
00098     va_end(ap);
00099     abort();
00100 }
00101 #endif
00102 
00103 #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
00104 /* dynamic load with dlopen() */
00105 # define USE_DLN_DLOPEN
00106 #endif
00107 
00108 #ifndef FUNCNAME_PATTERN
00109 # if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(__BORLANDC__) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD)
00110 #  define FUNCNAME_PREFIX "_Init_"
00111 # else
00112 #  define FUNCNAME_PREFIX "Init_"
00113 # endif
00114 #endif
00115 
00116 #if defined __CYGWIN__ || defined DOSISH
00117 #define isdirsep(x) ((x) == '/' || (x) == '\\')
00118 #else
00119 #define isdirsep(x) ((x) == '/')
00120 #endif
00121 
00122 static size_t
00123 init_funcname_len(const char **file)
00124 {
00125     const char *p = *file, *base, *dot = NULL;
00126 
00127     /* Load the file as an object one */
00128     for (base = p; *p; p++) { /* Find position of last '/' */
00129         if (*p == '.' && !dot) dot = p;
00130         if (isdirsep(*p)) base = p+1, dot = NULL;
00131     }
00132     *file = base;
00133     /* Delete suffix if it exists */
00134     return (dot ? dot : p) - base;
00135 }
00136 
00137 static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX;
00138 
00139 #define init_funcname(buf, file) do {\
00140     const char *base = (file);\
00141     const size_t flen = init_funcname_len(&base);\
00142     const size_t plen = sizeof(funcname_prefix);\
00143     char *const tmp = ALLOCA_N(char, plen+flen+1);\
00144     if (!tmp) {\
00145         dln_memerror();\
00146     }\
00147     memcpy(tmp, funcname_prefix, plen);\
00148     memcpy(tmp+plen, base, flen);\
00149     tmp[plen+flen] = '\0';\
00150     *(buf) = tmp;\
00151 } while (0)
00152 
00153 #ifdef USE_DLN_A_OUT
00154 
00155 #ifndef LIBC_NAME
00156 # define LIBC_NAME "libc.a"
00157 #endif
00158 
00159 #ifndef DLN_DEFAULT_LIB_PATH
00160 #  define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
00161 #endif
00162 
00163 #include <errno.h>
00164 
00165 static int dln_errno;
00166 
00167 #define DLN_ENOEXEC     ENOEXEC /* Exec format error */
00168 #define DLN_ECONFL      1201    /* Symbol name conflict */
00169 #define DLN_ENOINIT     1202    /* No initializer given */
00170 #define DLN_EUNDEF      1203    /* Undefine symbol remains */
00171 #define DLN_ENOTLIB     1204    /* Not a library file */
00172 #define DLN_EBADLIB     1205    /* Malformed library file */
00173 #define DLN_EINIT       1206    /* Not initialized */
00174 
00175 static int dln_init_p = 0;
00176 
00177 #include <ar.h>
00178 #include <a.out.h>
00179 #ifndef N_COMM
00180 # define N_COMM 0x12
00181 #endif
00182 #ifndef N_MAGIC
00183 # define N_MAGIC(x) (x).a_magic
00184 #endif
00185 
00186 #define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC)
00187 
00188 #include "ruby/util.h"
00189 #include "ruby/st.h"
00190 
00191 static st_table *sym_tbl;
00192 static st_table *undef_tbl;
00193 
00194 static int load_lib();
00195 
00196 static int
00197 load_header(int fd, struct exec *hdrp, long disp)
00198 {
00199     int size;
00200 
00201     lseek(fd, disp, 0);
00202     size = read(fd, hdrp, sizeof(struct exec));
00203     if (size == -1) {
00204         dln_errno = errno;
00205         return -1;
00206     }
00207     if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
00208         dln_errno = DLN_ENOEXEC;
00209         return -1;
00210     }
00211     return 0;
00212 }
00213 
00214 #if defined(sequent)
00215 #define RELOC_SYMBOL(r)                 ((r)->r_symbolnum)
00216 #define RELOC_MEMORY_SUB_P(r)           ((r)->r_bsr)
00217 #define RELOC_PCREL_P(r)                ((r)->r_pcrel || (r)->r_bsr)
00218 #define RELOC_TARGET_SIZE(r)            ((r)->r_length)
00219 #endif
00220 
00221 /* Default macros */
00222 #ifndef RELOC_ADDRESS
00223 #define RELOC_ADDRESS(r)                ((r)->r_address)
00224 #define RELOC_EXTERN_P(r)               ((r)->r_extern)
00225 #define RELOC_SYMBOL(r)                 ((r)->r_symbolnum)
00226 #define RELOC_MEMORY_SUB_P(r)           0
00227 #define RELOC_PCREL_P(r)                ((r)->r_pcrel)
00228 #define RELOC_TARGET_SIZE(r)            ((r)->r_length)
00229 #endif
00230 
00231 #if defined(__sun) && defined(__sparc)
00232 /* Sparc (Sun 4) macros */
00233 #  undef relocation_info
00234 #  define relocation_info reloc_info_sparc
00235 #  define R_RIGHTSHIFT(r)       (reloc_r_rightshift[(r)->r_type])
00236 #  define R_BITSIZE(r)          (reloc_r_bitsize[(r)->r_type])
00237 #  define R_LENGTH(r)           (reloc_r_length[(r)->r_type])
00238 static int reloc_r_rightshift[] = {
00239   0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
00240 };
00241 static int reloc_r_bitsize[] = {
00242   8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
00243 };
00244 static int reloc_r_length[] = {
00245   0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
00246 };
00247 #  define R_PCREL(r) \
00248     ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
00249 #  define R_SYMBOL(r) ((r)->r_index)
00250 #endif
00251 
00252 #if defined(sequent)
00253 #define R_SYMBOL(r)             ((r)->r_symbolnum)
00254 #define R_MEMORY_SUB(r)         ((r)->r_bsr)
00255 #define R_PCREL(r)              ((r)->r_pcrel || (r)->r_bsr)
00256 #define R_LENGTH(r)             ((r)->r_length)
00257 #endif
00258 
00259 #ifndef R_SYMBOL
00260 #  define R_SYMBOL(r)           ((r)->r_symbolnum)
00261 #  define R_MEMORY_SUB(r)       0
00262 #  define R_PCREL(r)            ((r)->r_pcrel)
00263 #  define R_LENGTH(r)           ((r)->r_length)
00264 #endif
00265 
00266 static struct relocation_info *
00267 load_reloc(int fd, struct exec *hdrp, long disp)
00268 {
00269     struct relocation_info *reloc;
00270     int size;
00271 
00272     lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
00273     size = hdrp->a_trsize + hdrp->a_drsize;
00274     reloc = (struct relocation_info*)xmalloc(size);
00275     if (reloc == NULL) {
00276         dln_errno = errno;
00277         return NULL;
00278     }
00279 
00280     if (read(fd, reloc, size) !=  size) {
00281         dln_errno = errno;
00282         free(reloc);
00283         return NULL;
00284     }
00285 
00286     return reloc;
00287 }
00288 
00289 static struct nlist *
00290 load_sym(int fd, struct exec *hdrp, long disp)
00291 {
00292     struct nlist * buffer;
00293     struct nlist * sym;
00294     struct nlist * end;
00295     long displ;
00296     int size;
00297 
00298     lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0);
00299     if (read(fd, &size, sizeof(int)) != sizeof(int)) {
00300         goto err_noexec;
00301     }
00302 
00303     buffer = (struct nlist*)xmalloc(hdrp->a_syms + size);
00304     if (buffer == NULL) {
00305         dln_errno = errno;
00306         return NULL;
00307     }
00308 
00309     lseek(fd, disp + N_SYMOFF(*hdrp), 0);
00310     if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) {
00311         free(buffer);
00312         goto err_noexec;
00313     }
00314 
00315     sym = buffer;
00316     end = sym + hdrp->a_syms / sizeof(struct nlist);
00317     displ = (long)buffer + (long)(hdrp->a_syms);
00318 
00319     while (sym < end) {
00320         sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
00321         sym++;
00322     }
00323     return buffer;
00324 
00325   err_noexec:
00326     dln_errno = DLN_ENOEXEC;
00327     return NULL;
00328 }
00329 
00330 static st_table *
00331 sym_hash(struct exec *hdrp, struct nlist *syms)
00332 {
00333     st_table *tbl;
00334     struct nlist *sym = syms;
00335     struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist));
00336 
00337     tbl = st_init_strtable();
00338     if (tbl == NULL) {
00339         dln_errno = errno;
00340         return NULL;
00341     }
00342 
00343     while (sym < end) {
00344         st_insert(tbl, sym->n_un.n_name, sym);
00345         sym++;
00346     }
00347     return tbl;
00348 }
00349 
00350 static int
00351 dln_init(const char *prog)
00352 {
00353     char *file, fbuf[MAXPATHLEN];
00354     int fd;
00355     struct exec hdr;
00356     struct nlist *syms;
00357 
00358     if (dln_init_p == 1) return 0;
00359 
00360     file = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf));
00361     if (file == NULL || (fd = open(file, O_RDONLY)) < 0) {
00362         dln_errno = errno;
00363         return -1;
00364     }
00365 
00366     if (load_header(fd, &hdr, 0) == -1) return -1;
00367     syms = load_sym(fd, &hdr, 0);
00368     if (syms == NULL) {
00369         close(fd);
00370         return -1;
00371     }
00372     sym_tbl = sym_hash(&hdr, syms);
00373     if (sym_tbl == NULL) {      /* file may be start with #! */
00374         char c = '\0';
00375         char buf[MAXPATHLEN];
00376         char *p;
00377 
00378         free(syms);
00379         lseek(fd, 0L, 0);
00380         if (read(fd, &c, 1) == -1) {
00381             dln_errno = errno;
00382             return -1;
00383         }
00384         if (c != '#') goto err_noexec;
00385         if (read(fd, &c, 1) == -1) {
00386             dln_errno = errno;
00387             return -1;
00388         }
00389         if (c != '!') goto err_noexec;
00390 
00391         p = buf;
00392         /* skip forwarding spaces */
00393         while (read(fd, &c, 1) == 1) {
00394             if (c == '\n') goto err_noexec;
00395             if (c != '\t' && c != ' ') {
00396                 *p++ = c;
00397                 break;
00398             }
00399         }
00400         /* read in command name */
00401         while (read(fd, p, 1) == 1) {
00402             if (*p == '\n' || *p == '\t' || *p == ' ') break;
00403             p++;
00404             if (p-buf >= MAXPATHLEN) {
00405                 dln_errno = ENAMETOOLONG;
00406                 return -1;
00407             }
00408         }
00409         *p = '\0';
00410 
00411         return dln_init(buf);
00412     }
00413     dln_init_p = 1;
00414     undef_tbl = st_init_strtable();
00415     close(fd);
00416     return 0;
00417 
00418   err_noexec:
00419     close(fd);
00420     dln_errno = DLN_ENOEXEC;
00421     return -1;
00422 }
00423 
00424 static long
00425 load_text_data(int fd, struct exec *hdrp, int bss, long disp)
00426 {
00427     int size;
00428     unsigned char* addr;
00429 
00430     lseek(fd, disp + N_TXTOFF(*hdrp), 0);
00431     size = hdrp->a_text + hdrp->a_data;
00432 
00433     if (bss == -1) size += hdrp->a_bss;
00434     else if (bss > 1) size += bss;
00435 
00436     addr = (unsigned char*)xmalloc(size);
00437     if (addr == NULL) {
00438         dln_errno = errno;
00439         return 0;
00440     }
00441 
00442     if (read(fd, addr, size) !=  size) {
00443         dln_errno = errno;
00444         free(addr);
00445         return 0;
00446     }
00447 
00448     if (bss == -1) {
00449         memset(addr +  hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss);
00450     }
00451     else if (bss > 0) {
00452         memset(addr +  hdrp->a_text + hdrp->a_data, 0, bss);
00453     }
00454 
00455     return (long)addr;
00456 }
00457 
00458 static int
00459 undef_print(char *key, char *value)
00460 {
00461     fprintf(stderr, "  %s\n", key);
00462     return ST_CONTINUE;
00463 }
00464 
00465 static void
00466 dln_print_undef(void)
00467 {
00468     fprintf(stderr, " Undefined symbols:\n");
00469     st_foreach(undef_tbl, undef_print, NULL);
00470 }
00471 
00472 static void
00473 dln_undefined(void)
00474 {
00475     if (undef_tbl->num_entries > 0) {
00476         fprintf(stderr, "dln: Calling undefined function\n");
00477         dln_print_undef();
00478         dln_exit(1);
00479     }
00480 }
00481 
00482 struct undef {
00483     char *name;
00484     struct relocation_info reloc;
00485     long base;
00486     char *addr;
00487     union {
00488         char c;
00489         short s;
00490         long l;
00491     } u;
00492 };
00493 
00494 static st_table *reloc_tbl = NULL;
00495 static void
00496 link_undef(const char *name, long base, struct relocation_info *reloc)
00497 {
00498     static int u_no = 0;
00499     struct undef *obj;
00500     char *addr = (char*)(reloc->r_address + base);
00501 
00502     obj = (struct undef*)xmalloc(sizeof(struct undef));
00503     obj->name = strdup(name);
00504     obj->reloc = *reloc;
00505     obj->base = base;
00506     switch (R_LENGTH(reloc)) {
00507       case 0:           /* byte */
00508         obj->u.c = *addr;
00509         break;
00510       case 1:           /* word */
00511         obj->u.s = *(short*)addr;
00512         break;
00513       case 2:           /* long */
00514         obj->u.l = *(long*)addr;
00515         break;
00516     }
00517     if (reloc_tbl == NULL) {
00518         reloc_tbl = st_init_numtable();
00519     }
00520     st_insert(reloc_tbl, u_no++, obj);
00521 }
00522 
00523 struct reloc_arg {
00524     const char *name;
00525     long value;
00526 };
00527 
00528 static int
00529 reloc_undef(int no, struct undef *undef, struct reloc_arg *arg)
00530 {
00531     int datum;
00532     char *address;
00533 #if defined(__sun) && defined(__sparc)
00534     unsigned int mask = 0;
00535 #endif
00536 
00537     if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE;
00538     address = (char*)(undef->base + undef->reloc.r_address);
00539     datum = arg->value;
00540 
00541     if (R_PCREL(&(undef->reloc))) datum -= undef->base;
00542 #if defined(__sun) && defined(__sparc)
00543     datum += undef->reloc.r_addend;
00544     datum >>= R_RIGHTSHIFT(&(undef->reloc));
00545     mask = (1 << R_BITSIZE(&(undef->reloc))) - 1;
00546     mask |= mask -1;
00547     datum &= mask;
00548     switch (R_LENGTH(&(undef->reloc))) {
00549       case 0:
00550         *address = undef->u.c;
00551         *address &= ~mask;
00552         *address |= datum;
00553         break;
00554       case 1:
00555         *(short *)address = undef->u.s;
00556         *(short *)address &= ~mask;
00557         *(short *)address |= datum;
00558         break;
00559       case 2:
00560         *(long *)address = undef->u.l;
00561         *(long *)address &= ~mask;
00562         *(long *)address |= datum;
00563         break;
00564     }
00565 #else
00566     switch (R_LENGTH(&(undef->reloc))) {
00567       case 0:           /* byte */
00568         if (R_MEMORY_SUB(&(undef->reloc)))
00569             *address = datum - *address;
00570         else *address = undef->u.c + datum;
00571         break;
00572       case 1:           /* word */
00573         if (R_MEMORY_SUB(&(undef->reloc)))
00574             *(short*)address = datum - *(short*)address;
00575         else *(short*)address = undef->u.s + datum;
00576         break;
00577       case 2:           /* long */
00578         if (R_MEMORY_SUB(&(undef->reloc)))
00579             *(long*)address = datum - *(long*)address;
00580         else *(long*)address = undef->u.l + datum;
00581         break;
00582     }
00583 #endif
00584     free(undef->name);
00585     free(undef);
00586     return ST_DELETE;
00587 }
00588 
00589 static void
00590 unlink_undef(const char *name, long value)
00591 {
00592     struct reloc_arg arg;
00593 
00594     arg.name = name;
00595     arg.value = value;
00596     st_foreach(reloc_tbl, reloc_undef, &arg);
00597 }
00598 
00599 #ifdef N_INDR
00600 struct indr_data {
00601     char *name0, *name1;
00602 };
00603 
00604 static int
00605 reloc_repl(int no, struct undef *undef, struct indr_data *data)
00606 {
00607     if (strcmp(data->name0, undef->name) == 0) {
00608         free(undef->name);
00609         undef->name = strdup(data->name1);
00610     }
00611     return ST_CONTINUE;
00612 }
00613 #endif
00614 
00615 static int
00616 load_1(int fd, long disp, const char *need_init)
00617 {
00618     static const char *libc = LIBC_NAME;
00619     struct exec hdr;
00620     struct relocation_info *reloc = NULL;
00621     long block = 0;
00622     long new_common = 0; /* Length of new common */
00623     struct nlist *syms = NULL;
00624     struct nlist *sym;
00625     struct nlist *end;
00626     int init_p = 0;
00627 
00628     if (load_header(fd, &hdr, disp) == -1) return -1;
00629     if (INVALID_OBJECT(hdr)) {
00630         dln_errno = DLN_ENOEXEC;
00631         return -1;
00632     }
00633     reloc = load_reloc(fd, &hdr, disp);
00634     if (reloc == NULL) return -1;
00635 
00636     syms = load_sym(fd, &hdr, disp);
00637     if (syms == NULL) {
00638         free(reloc);
00639         return -1;
00640     }
00641 
00642     sym = syms;
00643     end = syms + (hdr.a_syms / sizeof(struct nlist));
00644     while (sym < end) {
00645         struct nlist *old_sym;
00646         int value = sym->n_value;
00647 
00648 #ifdef N_INDR
00649         if (sym->n_type == (N_INDR | N_EXT)) {
00650             char *key = sym->n_un.n_name;
00651 
00652             if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) {
00653                 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
00654                     unlink_undef(key, old_sym->n_value);
00655                     free(key);
00656                 }
00657             }
00658             else {
00659                 struct indr_data data;
00660 
00661                 data.name0 = sym->n_un.n_name;
00662                 data.name1 = sym[1].n_un.n_name;
00663                 st_foreach(reloc_tbl, reloc_repl, &data);
00664 
00665                 st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL);
00666                 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
00667                     free(key);
00668                 }
00669             }
00670             sym += 2;
00671             continue;
00672         }
00673 #endif
00674         if (sym->n_type == (N_UNDF | N_EXT)) {
00675             if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) {
00676                 old_sym = NULL;
00677             }
00678 
00679             if (value) {
00680                 if (old_sym) {
00681                     sym->n_type = N_EXT | N_COMM;
00682                     sym->n_value = old_sym->n_value;
00683                 }
00684                 else {
00685                     int rnd =
00686                         value >= sizeof(double) ? sizeof(double) - 1
00687                             : value >= sizeof(long) ? sizeof(long) - 1
00688                                 : sizeof(short) - 1;
00689 
00690                     sym->n_type = N_COMM;
00691                     new_common += rnd;
00692                     new_common &= ~(long)rnd;
00693                     sym->n_value = new_common;
00694                     new_common += value;
00695                 }
00696             }
00697             else {
00698                 if (old_sym) {
00699                     sym->n_type = N_EXT | N_COMM;
00700                     sym->n_value = old_sym->n_value;
00701                 }
00702                 else {
00703                     sym->n_value = (long)dln_undefined;
00704                     st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL);
00705                 }
00706             }
00707         }
00708         sym++;
00709     }
00710 
00711     block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp);
00712     if (block == 0) goto err_exit;
00713 
00714     sym = syms;
00715     while (sym < end) {
00716         struct nlist *new_sym;
00717         char *key;
00718 
00719         switch (sym->n_type) {
00720           case N_COMM:
00721             sym->n_value += hdr.a_text + hdr.a_data;
00722           case N_TEXT|N_EXT:
00723           case N_DATA|N_EXT:
00724 
00725             sym->n_value += block;
00726 
00727             if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0
00728                 && new_sym->n_value != (long)dln_undefined) {
00729                 dln_errno = DLN_ECONFL;
00730                 goto err_exit;
00731             }
00732 
00733             key = sym->n_un.n_name;
00734             if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) {
00735                 unlink_undef(key, sym->n_value);
00736                 free(key);
00737             }
00738 
00739             new_sym = (struct nlist*)xmalloc(sizeof(struct nlist));
00740             *new_sym = *sym;
00741             new_sym->n_un.n_name = strdup(sym->n_un.n_name);
00742             st_insert(sym_tbl, new_sym->n_un.n_name, new_sym);
00743             break;
00744 
00745           case N_TEXT:
00746           case N_DATA:
00747             sym->n_value += block;
00748             break;
00749         }
00750         sym++;
00751     }
00752 
00753     /*
00754      * First comes the text-relocation
00755      */
00756     {
00757         struct relocation_info * rel = reloc;
00758         struct relocation_info * rel_beg = reloc +
00759             (hdr.a_trsize/sizeof(struct relocation_info));
00760         struct relocation_info * rel_end = reloc +
00761             (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info);
00762 
00763         while (rel < rel_end) {
00764             char *address = (char*)(rel->r_address + block);
00765             long datum = 0;
00766 #if defined(__sun) && defined(__sparc)
00767             unsigned int mask = 0;
00768 #endif
00769 
00770             if (rel >= rel_beg)
00771                 address += hdr.a_text;
00772 
00773             if (rel->r_extern) { /* Look it up in symbol-table */
00774                 sym = &(syms[R_SYMBOL(rel)]);
00775                 switch (sym->n_type) {
00776                   case N_EXT|N_UNDF:
00777                     link_undef(sym->n_un.n_name, block, rel);
00778                   case N_EXT|N_COMM:
00779                   case N_COMM:
00780                     datum = sym->n_value;
00781                     break;
00782                   default:
00783                     goto err_exit;
00784                 }
00785             } /* end.. look it up */
00786             else { /* is static */
00787                 switch (R_SYMBOL(rel)) {
00788                   case N_TEXT:
00789                   case N_DATA:
00790                     datum = block;
00791                     break;
00792                   case N_BSS:
00793                     datum = block +  new_common;
00794                     break;
00795                   case N_ABS:
00796                     break;
00797                 }
00798             } /* end .. is static */
00799             if (R_PCREL(rel)) datum -= block;
00800 
00801 #if defined(__sun) && defined(__sparc)
00802             datum += rel->r_addend;
00803             datum >>= R_RIGHTSHIFT(rel);
00804             mask = (1 << R_BITSIZE(rel)) - 1;
00805             mask |= mask -1;
00806             datum &= mask;
00807 
00808             switch (R_LENGTH(rel)) {
00809               case 0:
00810                 *address &= ~mask;
00811                 *address |= datum;
00812                 break;
00813               case 1:
00814                 *(short *)address &= ~mask;
00815                 *(short *)address |= datum;
00816                 break;
00817               case 2:
00818                 *(long *)address &= ~mask;
00819                 *(long *)address |= datum;
00820                 break;
00821             }
00822 #else
00823             switch (R_LENGTH(rel)) {
00824               case 0:           /* byte */
00825                 if (datum < -128 || datum > 127) goto err_exit;
00826                 *address += datum;
00827                 break;
00828               case 1:           /* word */
00829                 *(short *)address += datum;
00830                 break;
00831               case 2:           /* long */
00832                 *(long *)address += datum;
00833                 break;
00834             }
00835 #endif
00836             rel++;
00837         }
00838     }
00839 
00840     if (need_init) {
00841         int len;
00842         char **libs_to_be_linked = 0;
00843         char *buf;
00844 
00845         if (undef_tbl->num_entries > 0) {
00846             if (load_lib(libc) == -1) goto err_exit;
00847         }
00848 
00849         init_funcname(&buf, need_init);
00850         len = strlen(buf);
00851 
00852         for (sym = syms; sym<end; sym++) {
00853             char *name = sym->n_un.n_name;
00854             if (name[0] == '_' && sym->n_value >= block) {
00855                 if (strcmp(name+1, "dln_libs_to_be_linked") == 0) {
00856                     libs_to_be_linked = (char**)sym->n_value;
00857                 }
00858                 else if (strcmp(name+1, buf) == 0) {
00859                     init_p = 1;
00860                     ((int (*)())sym->n_value)();
00861                 }
00862             }
00863         }
00864         if (libs_to_be_linked && undef_tbl->num_entries > 0) {
00865             while (*libs_to_be_linked) {
00866                 load_lib(*libs_to_be_linked);
00867                 libs_to_be_linked++;
00868             }
00869         }
00870     }
00871     free(reloc);
00872     free(syms);
00873     if (need_init) {
00874         if (init_p == 0) {
00875             dln_errno = DLN_ENOINIT;
00876             return -1;
00877         }
00878         if (undef_tbl->num_entries > 0) {
00879             if (load_lib(libc) == -1) goto err_exit;
00880             if (undef_tbl->num_entries > 0) {
00881                 dln_errno = DLN_EUNDEF;
00882                 return -1;
00883             }
00884         }
00885     }
00886     return 0;
00887 
00888   err_exit:
00889     if (syms) free(syms);
00890     if (reloc) free(reloc);
00891     if (block) free((char*)block);
00892     return -1;
00893 }
00894 
00895 static int target_offset;
00896 static int
00897 search_undef(const char *key, int value, st_table *lib_tbl)
00898 {
00899     long offset;
00900 
00901     if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
00902     target_offset = offset;
00903     return ST_STOP;
00904 }
00905 
00906 struct symdef {
00907     int rb_str_index;
00908     int lib_offset;
00909 };
00910 
00911 const char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
00912 
00913 static int
00914 load_lib(const char *lib)
00915 {
00916     char *path, *file, fbuf[MAXPATHLEN];
00917     char *envpath = 0;
00918     char armagic[SARMAG];
00919     int fd, size;
00920     struct ar_hdr ahdr;
00921     st_table *lib_tbl = NULL;
00922     int *data, nsym;
00923     struct symdef *base;
00924     char *name_base;
00925 
00926     if (dln_init_p == 0) {
00927         dln_errno = DLN_ENOINIT;
00928         return -1;
00929     }
00930 
00931     if (undef_tbl->num_entries == 0) return 0;
00932     dln_errno = DLN_EBADLIB;
00933 
00934     if (lib[0] == '-' && lib[1] == 'l') {
00935         long len = strlen(lib) + 4;
00936         char *p = alloca(len);
00937         snprintf(p, len, "lib%s.a", lib+2);
00938         lib = p;
00939     }
00940 
00941     /* library search path: */
00942     /* look for environment variable DLN_LIBRARY_PATH first. */
00943     /* then variable dln_librrb_ary_path. */
00944     /* if path is still NULL, use "." for path. */
00945     path = getenv("DLN_LIBRARY_PATH");
00946     if (path == NULL) path = dln_librrb_ary_path;
00947     else path = envpath = strdup(path);
00948 
00949     file = dln_find_file_r(lib, path, fbuf, sizeof(fbuf));
00950     if (envpath) free(envpath);
00951     fd = open(file, O_RDONLY);
00952     if (fd == -1) goto syserr;
00953     size = read(fd, armagic, SARMAG);
00954     if (size == -1) goto syserr;
00955 
00956     if (size != SARMAG) {
00957         dln_errno = DLN_ENOTLIB;
00958         goto badlib;
00959     }
00960     size = read(fd, &ahdr, sizeof(ahdr));
00961     if (size == -1) goto syserr;
00962     if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) {
00963         goto badlib;
00964     }
00965 
00966     if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) {
00967         /* make hash table from __.SYMDEF */
00968 
00969         lib_tbl = st_init_strtable();
00970         data = (int*)xmalloc(size);
00971         if (data == NULL) goto syserr;
00972         size = read(fd, data, size);
00973         nsym = *data / sizeof(struct symdef);
00974         base = (struct symdef*)(data + 1);
00975         name_base = (char*)(base + nsym) + sizeof(int);
00976         while (nsym > 0) {
00977             char *name = name_base + base->rb_str_index;
00978 
00979             st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr));
00980             nsym--;
00981             base++;
00982         }
00983         for (;;) {
00984             target_offset = -1;
00985             st_foreach(undef_tbl, search_undef, lib_tbl);
00986             if (target_offset == -1) break;
00987             if (load_1(fd, target_offset, 0) == -1) {
00988                 st_free_table(lib_tbl);
00989                 free(data);
00990                 goto badlib;
00991             }
00992             if (undef_tbl->num_entries == 0) break;
00993         }
00994         free(data);
00995         st_free_table(lib_tbl);
00996     }
00997     else {
00998         /* linear library, need to scan (FUTURE) */
00999 
01000         for (;;) {
01001             int offset = SARMAG;
01002             int found = 0;
01003             struct exec hdr;
01004             struct nlist *syms, *sym, *end;
01005 
01006             while (undef_tbl->num_entries > 0) {
01007                 found = 0;
01008                 lseek(fd, offset, 0);
01009                 size = read(fd, &ahdr, sizeof(ahdr));
01010                 if (size == -1) goto syserr;
01011                 if (size == 0) break;
01012                 if (size != sizeof(ahdr)
01013                     || sscanf(ahdr.ar_size, "%d", &size) != 1) {
01014                     goto badlib;
01015                 }
01016                 offset += sizeof(ahdr);
01017                 if (load_header(fd, &hdr, offset) == -1)
01018                     goto badlib;
01019                 syms = load_sym(fd, &hdr, offset);
01020                 if (syms == NULL) goto badlib;
01021                 sym = syms;
01022                 end = syms + (hdr.a_syms / sizeof(struct nlist));
01023                 while (sym < end) {
01024                     if (sym->n_type == N_EXT|N_TEXT
01025                         && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) {
01026                         break;
01027                     }
01028                     sym++;
01029                 }
01030                 if (sym < end) {
01031                     found++;
01032                     free(syms);
01033                     if (load_1(fd, offset, 0) == -1) {
01034                         goto badlib;
01035                     }
01036                 }
01037                 offset += size;
01038                 if (offset & 1) offset++;
01039             }
01040             if (found) break;
01041         }
01042     }
01043     close(fd);
01044     return 0;
01045 
01046   syserr:
01047     dln_errno = errno;
01048   badlib:
01049     if (fd >= 0) close(fd);
01050     return -1;
01051 }
01052 
01053 static int
01054 load(const char *file)
01055 {
01056     int fd;
01057     int result;
01058 
01059     if (dln_init_p == 0) {
01060         if (dln_init(dln_argv0) == -1) return -1;
01061     }
01062     result = strlen(file);
01063     if (file[result-1] == 'a') {
01064         return load_lib(file);
01065     }
01066 
01067     fd = open(file, O_RDONLY);
01068     if (fd == -1) {
01069         dln_errno = errno;
01070         return -1;
01071     }
01072     result = load_1(fd, 0, file);
01073     close(fd);
01074 
01075     return result;
01076 }
01077 
01078 void*
01079 dln_sym(const char *name)
01080 {
01081     struct nlist *sym;
01082 
01083     if (st_lookup(sym_tbl, name, &sym))
01084         return (void*)sym->n_value;
01085     return NULL;
01086 }
01087 
01088 #endif /* USE_DLN_A_OUT */
01089 
01090 #ifdef USE_DLN_DLOPEN
01091 # include <dlfcn.h>
01092 #endif
01093 
01094 #ifdef __hpux
01095 #include <errno.h>
01096 #include "dl.h"
01097 #endif
01098 
01099 #if defined(_AIX)
01100 #include <ctype.h>      /* for isdigit()        */
01101 #include <errno.h>      /* for global errno     */
01102 #include <sys/ldr.h>
01103 #endif
01104 
01105 #ifdef NeXT
01106 #if NS_TARGET_MAJOR < 4
01107 #include <mach-o/rld.h>
01108 #else
01109 #include <mach-o/dyld.h>
01110 #ifndef NSLINKMODULE_OPTION_BINDNOW
01111 #define NSLINKMODULE_OPTION_BINDNOW 1
01112 #endif
01113 #endif
01114 #else
01115 #ifdef MACOSX_DYLD
01116 #include <mach-o/dyld.h>
01117 #endif
01118 #endif
01119 
01120 #if defined _WIN32 && !defined __CYGWIN__
01121 #include <windows.h>
01122 #include <imagehlp.h>
01123 #endif
01124 
01125 #if defined _WIN32 && !defined __CYGWIN__
01126 static const char *
01127 dln_strerror(char *message, size_t size)
01128 {
01129     int error = GetLastError();
01130     char *p = message;
01131     size_t len = snprintf(message, size, "%d: ", error);
01132 
01133 #define format_message(sublang) FormatMessage(\
01134         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,     \
01135         NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)),               \
01136         message + len, size - len, NULL)
01137     if (format_message(SUBLANG_ENGLISH_US) == 0)
01138         format_message(SUBLANG_DEFAULT);
01139     for (p = message + len; *p; p++) {
01140         if (*p == '\n' || *p == '\r')
01141             *p = ' ';
01142     }
01143     return message;
01144 }
01145 #define dln_strerror() dln_strerror(message, sizeof message)
01146 #elif ! defined _AIX
01147 static const char *
01148 dln_strerror(void)
01149 {
01150 #ifdef USE_DLN_A_OUT
01151     char *strerror();
01152 
01153     switch (dln_errno) {
01154       case DLN_ECONFL:
01155         return "Symbol name conflict";
01156       case DLN_ENOINIT:
01157         return "No initializer given";
01158       case DLN_EUNDEF:
01159         return "Unresolved symbols";
01160       case DLN_ENOTLIB:
01161         return "Not a library file";
01162       case DLN_EBADLIB:
01163         return "Malformed library file";
01164       case DLN_EINIT:
01165         return "Not initialized";
01166       default:
01167         return strerror(dln_errno);
01168     }
01169 #endif
01170 
01171 #ifdef USE_DLN_DLOPEN
01172     return (char*)dlerror();
01173 #endif
01174 }
01175 #endif
01176 
01177 #if defined(_AIX) && ! defined(_IA64)
01178 static void
01179 aix_loaderror(const char *pathname)
01180 {
01181   char *message[1024], errbuf[1024];
01182   int i;
01183 #define ERRBUF_APPEND(s) strncat(errbuf, (s), sizeof(errbuf)-strlen(errbuf)-1)
01184   snprintf(errbuf, sizeof(errbuf), "load failed - %s. ", pathname);
01185 
01186   if (loadquery(L_GETMESSAGES, &message[0], sizeof(message)) != -1) {
01187     ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t");
01188     ERRBUF_APPEND("/usr/sbin/execerror ruby ");
01189     for (i=0; message[i]; i++) {
01190       ERRBUF_APPEND("\"");
01191       ERRBUF_APPEND(message[i]);
01192       ERRBUF_APPEND("\" ");
01193     }
01194     ERRBUF_APPEND("\n");
01195   } else {
01196     ERRBUF_APPEND(strerror(errno));
01197     ERRBUF_APPEND("[loadquery failed]");
01198   }
01199   dln_loaderror("%s", errbuf);
01200 }
01201 #endif
01202 
01203 #if defined _WIN32 && defined RUBY_EXPORT
01204 HANDLE rb_libruby_handle(void);
01205 
01206 static int
01207 rb_w32_check_imported(HMODULE ext, HMODULE mine)
01208 {
01209     ULONG size;
01210     const IMAGE_IMPORT_DESCRIPTOR *desc;
01211 
01212     desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
01213     if (!desc) return 0;
01214     while (desc->Name) {
01215         PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics);
01216         PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk);
01217         for (; piat->u1.Function; piat++, pint++) {
01218             static const char prefix[] = "rb_";
01219             PIMAGE_IMPORT_BY_NAME pii;
01220             const char *name;
01221 
01222             if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue;
01223             pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData);
01224             name = (const char *)pii->Name;
01225             if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
01226                 FARPROC addr = GetProcAddress(mine, name);
01227                 if (addr) return (FARPROC)piat->u1.Function == addr;
01228             }
01229         }
01230         desc++;
01231     }
01232     return 1;
01233 }
01234 #endif
01235 
01236 #if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
01237 #define translit_separator(src) do { \
01238         char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
01239         do { \
01240             *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
01241         } while (c); \
01242         (src) = tmp; \
01243     } while (0)
01244 #else
01245 #define translit_separator(str) (void)(str)
01246 #endif
01247 
01248 void*
01249 dln_load(const char *file)
01250 {
01251 #if !defined(_AIX) && !defined(NeXT)
01252     const char *error = 0;
01253 #define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
01254 #endif
01255 
01256 #if defined _WIN32 && !defined __CYGWIN__
01257     HINSTANCE handle;
01258     char winfile[MAXPATHLEN];
01259     char message[1024];
01260     void (*init_fct)();
01261     char *buf;
01262 
01263     if (strlen(file) >= MAXPATHLEN) dln_loaderror("filename too long");
01264 
01265     /* Load the file as an object one */
01266     init_funcname(&buf, file);
01267 
01268     strlcpy(winfile, file, sizeof(winfile));
01269 
01270     /* Load file */
01271     if ((handle = LoadLibrary(winfile)) == NULL) {
01272         error = dln_strerror();
01273         goto failed;
01274     }
01275 
01276 #if defined _WIN32 && defined RUBY_EXPORT
01277     if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
01278         FreeLibrary(handle);
01279         error = "incompatible library version";
01280         goto failed;
01281     }
01282 #endif
01283 
01284     if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
01285         dln_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
01286     }
01287 
01288     /* Call the init code */
01289     (*init_fct)();
01290     return handle;
01291 #else
01292 #ifdef USE_DLN_A_OUT
01293     if (load(file) == -1) {
01294         error = dln_strerror();
01295         goto failed;
01296     }
01297     return 0;
01298 #else
01299 
01300     char *buf;
01301     /* Load the file as an object one */
01302     init_funcname(&buf, file);
01303     translit_separator(file);
01304 
01305 #ifdef USE_DLN_DLOPEN
01306 #define DLN_DEFINED
01307     {
01308         void *handle;
01309         void (*init_fct)();
01310 
01311 #ifndef RTLD_LAZY
01312 # define RTLD_LAZY 1
01313 #endif
01314 #ifdef __INTERIX
01315 # undef RTLD_GLOBAL
01316 #endif
01317 #ifndef RTLD_GLOBAL
01318 # define RTLD_GLOBAL 0
01319 #endif
01320 
01321 #ifdef __native_client__
01322         char* p, *orig;
01323         if (file[0] == '.' && file[1] == '/') file+=2;
01324         orig = strdup(file);
01325         for (p = file; *p; ++p) {
01326             if (*p == '/') *p = '_';
01327         }
01328 #endif
01329         /* Load file */
01330         if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
01331 #ifdef __native_client__
01332             free(orig);
01333 #endif
01334             error = dln_strerror();
01335             goto failed;
01336         }
01337 
01338         init_fct = (void(*)())(VALUE)dlsym(handle, buf);
01339 #ifdef __native_client__
01340         strcpy(file, orig);
01341         free(orig);
01342 #endif
01343 #if defined __SYMBIAN32__
01344         if (init_fct == NULL) {
01345             init_fct = (void(*)())dlsym(handle, "1"); /* Some Symbian versions do not support symbol table in DLL, ordinal numbers only */
01346         }
01347 #endif
01348         if (init_fct == NULL) {
01349             error = DLN_ERROR();
01350             dlclose(handle);
01351             goto failed;
01352         }
01353         /* Call the init code */
01354         (*init_fct)();
01355 
01356         return handle;
01357     }
01358 #endif /* USE_DLN_DLOPEN */
01359 
01360 #ifdef __hpux
01361 #define DLN_DEFINED
01362     {
01363         shl_t lib = NULL;
01364         int flags;
01365         void (*init_fct)();
01366 
01367         flags = BIND_DEFERRED;
01368         lib = shl_load(file, flags, 0);
01369         if (lib == NULL) {
01370             extern int errno;
01371             dln_loaderror("%s - %s", strerror(errno), file);
01372         }
01373         shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
01374         if (init_fct == NULL) {
01375             shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
01376             if (init_fct == NULL) {
01377                 errno = ENOSYM;
01378                 dln_loaderror("%s - %s", strerror(ENOSYM), file);
01379             }
01380         }
01381         (*init_fct)();
01382         return (void*)lib;
01383     }
01384 #endif /* hpux */
01385 
01386 #if defined(_AIX) && ! defined(_IA64)
01387 #define DLN_DEFINED
01388     {
01389         void (*init_fct)();
01390 
01391         init_fct = (void(*)())load((char*)file, 1, 0);
01392         if (init_fct == NULL) {
01393             aix_loaderror(file);
01394         }
01395         if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
01396             aix_loaderror(file);
01397         }
01398         (*init_fct)();
01399         return (void*)init_fct;
01400     }
01401 #endif /* _AIX */
01402 
01403 #if defined(MACOSX_DYLD)
01404 #define DLN_DEFINED
01405 /*----------------------------------------------------
01406    By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
01407 
01408    Special Thanks...
01409     Yu tomoak-i@is.aist-nara.ac.jp,
01410     Mi hisho@tasihara.nest.or.jp,
01411     sunshine@sunshineco.com,
01412     and... Miss ARAI Akino(^^;)
01413  ----------------------------------------------------*/
01414     {
01415         int dyld_result;
01416         NSObjectFileImage obj_file; /* handle, but not use it */
01417         /* "file" is module file name .
01418            "buf" is pointer to initial function name with "_" . */
01419 
01420         void (*init_fct)();
01421 
01422 
01423         dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
01424 
01425         if (dyld_result != NSObjectFileImageSuccess) {
01426             dln_loaderror("Failed to load %.200s", file);
01427         }
01428 
01429         NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
01430 
01431         /* lookup the initial function */
01432         if (!NSIsSymbolNameDefined(buf)) {
01433             dln_loaderror("Failed to lookup Init function %.200s",file);
01434         }
01435         init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
01436         (*init_fct)();
01437 
01438         return (void*)init_fct;
01439     }
01440 #endif
01441 
01442 #if defined(__BEOS__) || defined(__HAIKU__)
01443 # define DLN_DEFINED
01444     {
01445       status_t err_stat;  /* BeOS error status code */
01446       image_id img_id;    /* extension module unique id */
01447       void (*init_fct)(); /* initialize function for extension module */
01448 
01449       /* load extension module */
01450       img_id = load_add_on(file);
01451       if (img_id <= 0) {
01452         dln_loaderror("Failed to load add_on %.200s error_code=%x",
01453           file, img_id);
01454       }
01455 
01456       /* find symbol for module initialize function. */
01457       /* The Be Book KernelKit Images section described to use
01458          B_SYMBOL_TYPE_TEXT for symbol of function, not
01459          B_SYMBOL_TYPE_CODE. Why ? */
01460       /* strcat(init_fct_symname, "__Fv"); */  /* parameter nothing. */
01461       /* "__Fv" dont need! The Be Book Bug ? */
01462       err_stat = get_image_symbol(img_id, buf,
01463                                   B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
01464 
01465       if (err_stat != B_NO_ERROR) {
01466         char real_name[MAXPATHLEN];
01467 
01468         strlcpy(real_name, buf, MAXPATHLEN);
01469         strlcat(real_name, "__Fv", MAXPATHLEN);
01470         err_stat = get_image_symbol(img_id, real_name,
01471                                     B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
01472       }
01473 
01474       if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) {
01475         unload_add_on(img_id);
01476         dln_loaderror("Failed to lookup Init function %.200s", file);
01477       }
01478       else if (B_NO_ERROR != err_stat) {
01479         char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
01480         unload_add_on(img_id);
01481         dln_loaderror(errmsg, strerror(err_stat), buf);
01482       }
01483 
01484       /* call module initialize function. */
01485       (*init_fct)();
01486       return (void*)img_id;
01487     }
01488 #endif /* __BEOS__ || __HAIKU__ */
01489 
01490 #ifndef DLN_DEFINED
01491     dln_notimplement();
01492 #endif
01493 
01494 #endif /* USE_DLN_A_OUT */
01495 #endif
01496 #if !defined(_AIX) && !defined(NeXT)
01497   failed:
01498     dln_loaderror("%s - %s", error, file);
01499 #endif
01500 
01501     return 0;                   /* dummy return */
01502 }
01503