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 #if defined(__APPLE__) && defined(__MACH__)
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 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
00128 for (base = p; *p; p++) {
00129 if (*p == '.' && !dot) dot = p;
00130 if (isdirsep(*p)) base = p+1, dot = NULL;
00131 }
00132 *file = base;
00133
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
00168 #define DLN_ECONFL 1201
00169 #define DLN_ENOINIT 1202
00170 #define DLN_EUNDEF 1203
00171 #define DLN_ENOTLIB 1204
00172 #define DLN_EBADLIB 1205
00173 #define DLN_EINIT 1206
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
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
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) {
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
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
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:
00508 obj->u.c = *addr;
00509 break;
00510 case 1:
00511 obj->u.s = *(short*)addr;
00512 break;
00513 case 2:
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:
00568 if (R_MEMORY_SUB(&(undef->reloc)))
00569 *address = datum - *address;
00570 else *address = undef->u.c + datum;
00571 break;
00572 case 1:
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:
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;
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
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) {
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 }
00786 else {
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 }
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:
00825 if (datum < -128 || datum > 127) goto err_exit;
00826 *address += datum;
00827 break;
00828 case 1:
00829 *(short *)address += datum;
00830 break;
00831 case 2:
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
00942
00943
00944
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
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
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
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>
01101 #include <errno.h>
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
01266 init_funcname(&buf, file);
01267
01268 strlcpy(winfile, file, sizeof(winfile));
01269
01270
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
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
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
01322 if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
01323 error = dln_strerror();
01324 goto failed;
01325 }
01326
01327 init_fct = (void(*)())(VALUE)dlsym(handle, buf);
01328 #if defined __SYMBIAN32__
01329 if (init_fct == NULL) {
01330 init_fct = (void(*)())dlsym(handle, "1");
01331 }
01332 #endif
01333 if (init_fct == NULL) {
01334 error = DLN_ERROR();
01335 dlclose(handle);
01336 goto failed;
01337 }
01338
01339 (*init_fct)();
01340
01341 return handle;
01342 }
01343 #endif
01344
01345 #ifdef __hpux
01346 #define DLN_DEFINED
01347 {
01348 shl_t lib = NULL;
01349 int flags;
01350 void (*init_fct)();
01351
01352 flags = BIND_DEFERRED;
01353 lib = shl_load(file, flags, 0);
01354 if (lib == NULL) {
01355 extern int errno;
01356 dln_loaderror("%s - %s", strerror(errno), file);
01357 }
01358 shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
01359 if (init_fct == NULL) {
01360 shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
01361 if (init_fct == NULL) {
01362 errno = ENOSYM;
01363 dln_loaderror("%s - %s", strerror(ENOSYM), file);
01364 }
01365 }
01366 (*init_fct)();
01367 return (void*)lib;
01368 }
01369 #endif
01370
01371 #if defined(_AIX) && ! defined(_IA64)
01372 #define DLN_DEFINED
01373 {
01374 void (*init_fct)();
01375
01376 init_fct = (void(*)())load((char*)file, 1, 0);
01377 if (init_fct == NULL) {
01378 aix_loaderror(file);
01379 }
01380 if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
01381 aix_loaderror(file);
01382 }
01383 (*init_fct)();
01384 return (void*)init_fct;
01385 }
01386 #endif
01387
01388 #if defined(NeXT) || defined(MACOSX_DYLD)
01389 #define DLN_DEFINED
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399 #if defined(NeXT) && (NS_TARGET_MAJOR < 4)
01400
01401 {
01402 NXStream* s;
01403 unsigned long init_address;
01404 char *object_files[2] = {NULL, NULL};
01405
01406 void (*init_fct)();
01407
01408 object_files[0] = (char*)file;
01409
01410 s = NXOpenFile(2,NX_WRITEONLY);
01411
01412
01413 if(rld_load(s, NULL, object_files, NULL) == 0) {
01414 NXFlush(s);
01415 NXClose(s);
01416 dln_loaderror("Failed to load %.200s", file);
01417 }
01418
01419
01420 if(rld_lookup(s, buf, &init_address) == 0) {
01421 NXFlush(s);
01422 NXClose(s);
01423 dln_loaderror("Failed to lookup Init function %.200s", file);
01424 }
01425
01426 NXFlush(s);
01427 NXClose(s);
01428
01429
01430
01431 init_fct = (void(*)())init_address;
01432 (*init_fct)();
01433 return (void*)init_address;
01434 }
01435 #else
01436 {
01437 int dyld_result;
01438 NSObjectFileImage obj_file;
01439
01440
01441
01442 void (*init_fct)();
01443
01444
01445 dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
01446
01447 if (dyld_result != NSObjectFileImageSuccess) {
01448 dln_loaderror("Failed to load %.200s", file);
01449 }
01450
01451 NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
01452
01453
01454 if(!NSIsSymbolNameDefined(buf)) {
01455 dln_loaderror("Failed to lookup Init function %.200s",file);
01456 }
01457 init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
01458 (*init_fct)();
01459
01460 return (void*)init_fct;
01461 }
01462 #endif
01463 #endif
01464
01465 #if defined(__BEOS__) || defined(__HAIKU__)
01466 # define DLN_DEFINED
01467 {
01468 status_t err_stat;
01469 image_id img_id;
01470 void (*init_fct)();
01471
01472
01473 img_id = load_add_on(file);
01474 if (img_id <= 0) {
01475 dln_loaderror("Failed to load add_on %.200s error_code=%x",
01476 file, img_id);
01477 }
01478
01479
01480
01481
01482
01483
01484
01485 err_stat = get_image_symbol(img_id, buf,
01486 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
01487
01488 if (err_stat != B_NO_ERROR) {
01489 char real_name[MAXPATHLEN];
01490
01491 strlcpy(real_name, buf, MAXPATHLEN);
01492 strlcat(real_name, "__Fv", MAXPATHLEN);
01493 err_stat = get_image_symbol(img_id, real_name,
01494 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
01495 }
01496
01497 if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) {
01498 unload_add_on(img_id);
01499 dln_loaderror("Failed to lookup Init function %.200s", file);
01500 }
01501 else if (B_NO_ERROR != err_stat) {
01502 char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
01503 unload_add_on(img_id);
01504 dln_loaderror(errmsg, strerror(err_stat), buf);
01505 }
01506
01507
01508 (*init_fct)();
01509 return (void*)img_id;
01510 }
01511 #endif
01512
01513 #ifndef DLN_DEFINED
01514 dln_notimplement();
01515 #endif
01516
01517 #endif
01518 #endif
01519 #if !defined(_AIX) && !defined(NeXT)
01520 failed:
01521 dln_loaderror("%s - %s", error, file);
01522 #endif
01523
01524 return 0;
01525 }
01526