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