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