Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

dln.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 dln.c -
4
5 $Author: nobu $
6 created at: Tue Jan 18 17:05:06 JST 1994
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10 **********************************************************************/
11
12 #ifdef RUBY_EXPORT
13 #include "ruby/ruby.h"
14 #define dln_notimplement rb_notimplement
15 #define dln_memerror rb_memerror
16 #define dln_exit rb_exit
17 #define dln_loaderror rb_loaderror
18 #else
19 #define dln_notimplement --->>> dln not implemented <<<---
20 #define dln_memerror abort
21 #define dln_exit exit
22 static void dln_loaderror(const char *format, ...);
23 #endif
24 #include "dln.h"
25
26 #ifdef HAVE_STDLIB_H
27 # include <stdlib.h>
28 #endif
29
30 #ifdef USE_DLN_A_OUT
31 char *dln_argv0;
32 #endif
33
34 #if defined(HAVE_ALLOCA_H)
35 #include <alloca.h>
36 #endif
37
38 #ifdef HAVE_STRING_H
39 # include <string.h>
40 #else
41 # include <strings.h>
42 #endif
43
44 #ifndef xmalloc
45 void *xmalloc();
46 void *xcalloc();
47 void *xrealloc();
48 #endif
49
50 #define free(x) xfree(x)
51
52 #include <stdio.h>
53 #if defined(_WIN32)
54 #include "missing/file.h"
55 #endif
56 #include <sys/types.h>
57 #include <sys/stat.h>
58
59 #ifndef S_ISDIR
60 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
61 #endif
62
63 #ifdef HAVE_SYS_PARAM_H
64 # include <sys/param.h>
65 #endif
66 #ifndef MAXPATHLEN
67 # define MAXPATHLEN 1024
68 #endif
69
70 #ifdef HAVE_UNISTD_H
71 # include <unistd.h>
72 #endif
73
74 #ifndef _WIN32
75 char *getenv();
76 #endif
77
78 #ifdef __APPLE__
79 # if defined(HAVE_DLOPEN)
80 /* Mac OS X with dlopen (10.3 or later) */
81 # define MACOSX_DLOPEN
82 # else
83 # define MACOSX_DYLD
84 # endif
85 #endif
86
87 #if defined(__BEOS__) || defined(__HAIKU__)
88 # include <image.h>
89 #endif
90
91 #ifndef dln_loaderror
92 static void
93 dln_loaderror(const char *format, ...)
94 {
95 va_list ap;
96 va_start(ap, format);
97 vfprintf(stderr, format, ap);
98 va_end(ap);
99 abort();
100 }
101 #endif
102
103 #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
104 /* dynamic load with dlopen() */
105 # define USE_DLN_DLOPEN
106 #endif
107
108 #ifndef FUNCNAME_PATTERN
109 # if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(__BORLANDC__) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD)
110 # define FUNCNAME_PREFIX "_Init_"
111 # else
112 # define FUNCNAME_PREFIX "Init_"
113 # endif
114 #endif
115
116 #if defined __CYGWIN__ || defined DOSISH
117 #define isdirsep(x) ((x) == '/' || (x) == '\\')
118 #else
119 #define isdirsep(x) ((x) == '/')
120 #endif
121
122 static size_t
123 init_funcname_len(const char **file)
124 {
125 const char *p = *file, *base, *dot = NULL;
126
127 /* Load the file as an object one */
128 for (base = p; *p; p++) { /* Find position of last '/' */
129 if (*p == '.' && !dot) dot = p;
130 if (isdirsep(*p)) base = p+1, dot = NULL;
131 }
132 *file = base;
133 /* Delete suffix if it exists */
134 return (dot ? dot : p) - base;
135 }
136
137 static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX;
138
139 #define init_funcname(buf, file) do {\
140 const char *base = (file);\
141 const size_t flen = init_funcname_len(&base);\
142 const size_t plen = sizeof(funcname_prefix);\
143 char *const tmp = ALLOCA_N(char, plen+flen+1);\
144 if (!tmp) {\
145 dln_memerror();\
146 }\
147 memcpy(tmp, funcname_prefix, plen);\
148 memcpy(tmp+plen, base, flen);\
149 tmp[plen+flen] = '\0';\
150 *(buf) = tmp;\
151 } while (0)
152
153 #ifdef USE_DLN_A_OUT
154
155 #ifndef LIBC_NAME
156 # define LIBC_NAME "libc.a"
157 #endif
158
159 #ifndef DLN_DEFAULT_LIB_PATH
160 # define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
161 #endif
162
163 #include <errno.h>
164
165 static int dln_errno;
166
167 #define DLN_ENOEXEC ENOEXEC /* Exec format error */
168 #define DLN_ECONFL 1201 /* Symbol name conflict */
169 #define DLN_ENOINIT 1202 /* No initializer given */
170 #define DLN_EUNDEF 1203 /* Undefine symbol remains */
171 #define DLN_ENOTLIB 1204 /* Not a library file */
172 #define DLN_EBADLIB 1205 /* Malformed library file */
173 #define DLN_EINIT 1206 /* Not initialized */
174
175 static int dln_init_p = 0;
176
177 #include <ar.h>
178 #include <a.out.h>
179 #ifndef N_COMM
180 # define N_COMM 0x12
181 #endif
182 #ifndef N_MAGIC
183 # define N_MAGIC(x) (x).a_magic
184 #endif
185
186 #define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC)
187
188 #include "ruby/util.h"
189 #include "ruby/st.h"
190
191 static st_table *sym_tbl;
192 static st_table *undef_tbl;
193
194 static int load_lib();
195
196 static int
197 load_header(int fd, struct exec *hdrp, long disp)
198 {
199 int size;
200
201 lseek(fd, disp, 0);
202 size = read(fd, hdrp, sizeof(struct exec));
203 if (size == -1) {
204 dln_errno = errno;
205 return -1;
206 }
207 if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
208 dln_errno = DLN_ENOEXEC;
209 return -1;
210 }
211 return 0;
212 }
213
214 #if defined(sequent)
215 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
216 #define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr)
217 #define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr)
218 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
219 #endif
220
221 /* Default macros */
222 #ifndef RELOC_ADDRESS
223 #define RELOC_ADDRESS(r) ((r)->r_address)
224 #define RELOC_EXTERN_P(r) ((r)->r_extern)
225 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
226 #define RELOC_MEMORY_SUB_P(r) 0
227 #define RELOC_PCREL_P(r) ((r)->r_pcrel)
228 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
229 #endif
230
231 #if defined(__sun) && defined(__sparc)
232 /* Sparc (Sun 4) macros */
233 # undef relocation_info
234 # define relocation_info reloc_info_sparc
235 # define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type])
236 # define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type])
237 # define R_LENGTH(r) (reloc_r_length[(r)->r_type])
238 static int reloc_r_rightshift[] = {
239 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
240 };
241 static int reloc_r_bitsize[] = {
242 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
243 };
244 static int reloc_r_length[] = {
245 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
246 };
247 # define R_PCREL(r) \
248 ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
249 # define R_SYMBOL(r) ((r)->r_index)
250 #endif
251
252 #if defined(sequent)
253 #define R_SYMBOL(r) ((r)->r_symbolnum)
254 #define R_MEMORY_SUB(r) ((r)->r_bsr)
255 #define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr)
256 #define R_LENGTH(r) ((r)->r_length)
257 #endif
258
259 #ifndef R_SYMBOL
260 # define R_SYMBOL(r) ((r)->r_symbolnum)
261 # define R_MEMORY_SUB(r) 0
262 # define R_PCREL(r) ((r)->r_pcrel)
263 # define R_LENGTH(r) ((r)->r_length)
264 #endif
265
266 static struct relocation_info *
267 load_reloc(int fd, struct exec *hdrp, long disp)
268 {
269 struct relocation_info *reloc;
270 int size;
271
272 lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
273 size = hdrp->a_trsize + hdrp->a_drsize;
274 reloc = (struct relocation_info*)xmalloc(size);
275 if (reloc == NULL) {
276 dln_errno = errno;
277 return NULL;
278 }
279
280 if (read(fd, reloc, size) != size) {
281 dln_errno = errno;
282 free(reloc);
283 return NULL;
284 }
285
286 return reloc;
287 }
288
289 static struct nlist *
290 load_sym(int fd, struct exec *hdrp, long disp)
291 {
292 struct nlist * buffer;
293 struct nlist * sym;
294 struct nlist * end;
295 long displ;
296 int size;
297
298 lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0);
299 if (read(fd, &size, sizeof(int)) != sizeof(int)) {
300 goto err_noexec;
301 }
302
303 buffer = (struct nlist*)xmalloc(hdrp->a_syms + size);
304 if (buffer == NULL) {
305 dln_errno = errno;
306 return NULL;
307 }
308
309 lseek(fd, disp + N_SYMOFF(*hdrp), 0);
310 if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) {
311 free(buffer);
312 goto err_noexec;
313 }
314
315 sym = buffer;
316 end = sym + hdrp->a_syms / sizeof(struct nlist);
317 displ = (long)buffer + (long)(hdrp->a_syms);
318
319 while (sym < end) {
320 sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
321 sym++;
322 }
323 return buffer;
324
325 err_noexec:
326 dln_errno = DLN_ENOEXEC;
327 return NULL;
328 }
329
330 static st_table *
331 sym_hash(struct exec *hdrp, struct nlist *syms)
332 {
333 st_table *tbl;
334 struct nlist *sym = syms;
335 struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist));
336
337 tbl = st_init_strtable();
338 if (tbl == NULL) {
339 dln_errno = errno;
340 return NULL;
341 }
342
343 while (sym < end) {
344 st_insert(tbl, sym->n_un.n_name, sym);
345 sym++;
346 }
347 return tbl;
348 }
349
350 static int
351 dln_init(const char *prog)
352 {
353 char *file, fbuf[MAXPATHLEN];
354 int fd;
355 struct exec hdr;
356 struct nlist *syms;
357
358 if (dln_init_p == 1) return 0;
359
360 file = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf));
361 if (file == NULL || (fd = open(file, O_RDONLY)) < 0) {
362 dln_errno = errno;
363 return -1;
364 }
365
366 if (load_header(fd, &hdr, 0) == -1) return -1;
367 syms = load_sym(fd, &hdr, 0);
368 if (syms == NULL) {
369 close(fd);
370 return -1;
371 }
372 sym_tbl = sym_hash(&hdr, syms);
373 if (sym_tbl == NULL) { /* file may be start with #! */
374 char c = '\0';
375 char buf[MAXPATHLEN];
376 char *p;
377
378 free(syms);
379 lseek(fd, 0L, 0);
380 if (read(fd, &c, 1) == -1) {
381 dln_errno = errno;
382 return -1;
383 }
384 if (c != '#') goto err_noexec;
385 if (read(fd, &c, 1) == -1) {
386 dln_errno = errno;
387 return -1;
388 }
389 if (c != '!') goto err_noexec;
390
391 p = buf;
392 /* skip forwarding spaces */
393 while (read(fd, &c, 1) == 1) {
394 if (c == '\n') goto err_noexec;
395 if (c != '\t' && c != ' ') {
396 *p++ = c;
397 break;
398 }
399 }
400 /* read in command name */
401 while (read(fd, p, 1) == 1) {
402 if (*p == '\n' || *p == '\t' || *p == ' ') break;
403 p++;
404 if (p-buf >= MAXPATHLEN) {
405 dln_errno = ENAMETOOLONG;
406 return -1;
407 }
408 }
409 *p = '\0';
410
411 return dln_init(buf);
412 }
413 dln_init_p = 1;
414 undef_tbl = st_init_strtable();
415 close(fd);
416 return 0;
417
418 err_noexec:
419 close(fd);
420 dln_errno = DLN_ENOEXEC;
421 return -1;
422 }
423
424 static long
425 load_text_data(int fd, struct exec *hdrp, int bss, long disp)
426 {
427 int size;
428 unsigned char* addr;
429
430 lseek(fd, disp + N_TXTOFF(*hdrp), 0);
431 size = hdrp->a_text + hdrp->a_data;
432
433 if (bss == -1) size += hdrp->a_bss;
434 else if (bss > 1) size += bss;
435
436 addr = (unsigned char*)xmalloc(size);
437 if (addr == NULL) {
438 dln_errno = errno;
439 return 0;
440 }
441
442 if (read(fd, addr, size) != size) {
443 dln_errno = errno;
444 free(addr);
445 return 0;
446 }
447
448 if (bss == -1) {
449 memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss);
450 }
451 else if (bss > 0) {
452 memset(addr + hdrp->a_text + hdrp->a_data, 0, bss);
453 }
454
455 return (long)addr;
456 }
457
458 static int
459 undef_print(char *key, char *value)
460 {
461 fprintf(stderr, " %s\n", key);
462 return ST_CONTINUE;
463 }
464
465 static void
466 dln_print_undef(void)
467 {
468 fprintf(stderr, " Undefined symbols:\n");
469 st_foreach(undef_tbl, undef_print, NULL);
470 }
471
472 static void
473 dln_undefined(void)
474 {
475 if (undef_tbl->num_entries > 0) {
476 fprintf(stderr, "dln: Calling undefined function\n");
477 dln_print_undef();
478 dln_exit(1);
479 }
480 }
481
482 struct undef {
483 char *name;
484 struct relocation_info reloc;
485 long base;
486 char *addr;
487 union {
488 char c;
489 short s;
490 long l;
491 } u;
492 };
493
494 static st_table *reloc_tbl = NULL;
495 static void
496 link_undef(const char *name, long base, struct relocation_info *reloc)
497 {
498 static int u_no = 0;
499 struct undef *obj;
500 char *addr = (char*)(reloc->r_address + base);
501
502 obj = (struct undef*)xmalloc(sizeof(struct undef));
503 obj->name = strdup(name);
504 obj->reloc = *reloc;
505 obj->base = base;
506 switch (R_LENGTH(reloc)) {
507 case 0: /* byte */
508 obj->u.c = *addr;
509 break;
510 case 1: /* word */
511 obj->u.s = *(short*)addr;
512 break;
513 case 2: /* long */
514 obj->u.l = *(long*)addr;
515 break;
516 }
517 if (reloc_tbl == NULL) {
518 reloc_tbl = st_init_numtable();
519 }
520 st_insert(reloc_tbl, u_no++, obj);
521 }
522
523 struct reloc_arg {
524 const char *name;
525 long value;
526 };
527
528 static int
529 reloc_undef(int no, struct undef *undef, struct reloc_arg *arg)
530 {
531 int datum;
532 char *address;
533 #if defined(__sun) && defined(__sparc)
534 unsigned int mask = 0;
535 #endif
536
537 if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE;
538 address = (char*)(undef->base + undef->reloc.r_address);
539 datum = arg->value;
540
541 if (R_PCREL(&(undef->reloc))) datum -= undef->base;
542 #if defined(__sun) && defined(__sparc)
543 datum += undef->reloc.r_addend;
544 datum >>= R_RIGHTSHIFT(&(undef->reloc));
545 mask = (1 << R_BITSIZE(&(undef->reloc))) - 1;
546 mask |= mask -1;
547 datum &= mask;
548 switch (R_LENGTH(&(undef->reloc))) {
549 case 0:
550 *address = undef->u.c;
551 *address &= ~mask;
552 *address |= datum;
553 break;
554 case 1:
555 *(short *)address = undef->u.s;
556 *(short *)address &= ~mask;
557 *(short *)address |= datum;
558 break;
559 case 2:
560 *(long *)address = undef->u.l;
561 *(long *)address &= ~mask;
562 *(long *)address |= datum;
563 break;
564 }
565 #else
566 switch (R_LENGTH(&(undef->reloc))) {
567 case 0: /* byte */
568 if (R_MEMORY_SUB(&(undef->reloc)))
569 *address = datum - *address;
570 else *address = undef->u.c + datum;
571 break;
572 case 1: /* word */
573 if (R_MEMORY_SUB(&(undef->reloc)))
574 *(short*)address = datum - *(short*)address;
575 else *(short*)address = undef->u.s + datum;
576 break;
577 case 2: /* long */
578 if (R_MEMORY_SUB(&(undef->reloc)))
579 *(long*)address = datum - *(long*)address;
580 else *(long*)address = undef->u.l + datum;
581 break;
582 }
583 #endif
584 free(undef->name);
585 free(undef);
586 return ST_DELETE;
587 }
588
589 static void
590 unlink_undef(const char *name, long value)
591 {
592 struct reloc_arg arg;
593
594 arg.name = name;
595 arg.value = value;
596 st_foreach(reloc_tbl, reloc_undef, &arg);
597 }
598
599 #ifdef N_INDR
600 struct indr_data {
601 char *name0, *name1;
602 };
603
604 static int
605 reloc_repl(int no, struct undef *undef, struct indr_data *data)
606 {
607 if (strcmp(data->name0, undef->name) == 0) {
608 free(undef->name);
609 undef->name = strdup(data->name1);
610 }
611 return ST_CONTINUE;
612 }
613 #endif
614
615 static int
616 load_1(int fd, long disp, const char *need_init)
617 {
618 static const char *libc = LIBC_NAME;
619 struct exec hdr;
620 struct relocation_info *reloc = NULL;
621 long block = 0;
622 long new_common = 0; /* Length of new common */
623 struct nlist *syms = NULL;
624 struct nlist *sym;
625 struct nlist *end;
626 int init_p = 0;
627
628 if (load_header(fd, &hdr, disp) == -1) return -1;
629 if (INVALID_OBJECT(hdr)) {
630 dln_errno = DLN_ENOEXEC;
631 return -1;
632 }
633 reloc = load_reloc(fd, &hdr, disp);
634 if (reloc == NULL) return -1;
635
636 syms = load_sym(fd, &hdr, disp);
637 if (syms == NULL) {
638 free(reloc);
639 return -1;
640 }
641
642 sym = syms;
643 end = syms + (hdr.a_syms / sizeof(struct nlist));
644 while (sym < end) {
645 struct nlist *old_sym;
646 int value = sym->n_value;
647
648 #ifdef N_INDR
649 if (sym->n_type == (N_INDR | N_EXT)) {
650 char *key = sym->n_un.n_name;
651
652 if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) {
653 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
654 unlink_undef(key, old_sym->n_value);
655 free(key);
656 }
657 }
658 else {
659 struct indr_data data;
660
661 data.name0 = sym->n_un.n_name;
662 data.name1 = sym[1].n_un.n_name;
663 st_foreach(reloc_tbl, reloc_repl, &data);
664
665 st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL);
666 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
667 free(key);
668 }
669 }
670 sym += 2;
671 continue;
672 }
673 #endif
674 if (sym->n_type == (N_UNDF | N_EXT)) {
675 if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) {
676 old_sym = NULL;
677 }
678
679 if (value) {
680 if (old_sym) {
681 sym->n_type = N_EXT | N_COMM;
682 sym->n_value = old_sym->n_value;
683 }
684 else {
685 int rnd =
686 value >= sizeof(double) ? sizeof(double) - 1
687 : value >= sizeof(long) ? sizeof(long) - 1
688 : sizeof(short) - 1;
689
690 sym->n_type = N_COMM;
691 new_common += rnd;
692 new_common &= ~(long)rnd;
693 sym->n_value = new_common;
694 new_common += value;
695 }
696 }
697 else {
698 if (old_sym) {
699 sym->n_type = N_EXT | N_COMM;
700 sym->n_value = old_sym->n_value;
701 }
702 else {
703 sym->n_value = (long)dln_undefined;
704 st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL);
705 }
706 }
707 }
708 sym++;
709 }
710
711 block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp);
712 if (block == 0) goto err_exit;
713
714 sym = syms;
715 while (sym < end) {
716 struct nlist *new_sym;
717 char *key;
718
719 switch (sym->n_type) {
720 case N_COMM:
721 sym->n_value += hdr.a_text + hdr.a_data;
722 case N_TEXT|N_EXT:
723 case N_DATA|N_EXT:
724
725 sym->n_value += block;
726
727 if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0
728 && new_sym->n_value != (long)dln_undefined) {
729 dln_errno = DLN_ECONFL;
730 goto err_exit;
731 }
732
733 key = sym->n_un.n_name;
734 if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) {
735 unlink_undef(key, sym->n_value);
736 free(key);
737 }
738
739 new_sym = (struct nlist*)xmalloc(sizeof(struct nlist));
740 *new_sym = *sym;
741 new_sym->n_un.n_name = strdup(sym->n_un.n_name);
742 st_insert(sym_tbl, new_sym->n_un.n_name, new_sym);
743 break;
744
745 case N_TEXT:
746 case N_DATA:
747 sym->n_value += block;
748 break;
749 }
750 sym++;
751 }
752
753 /*
754 * First comes the text-relocation
755 */
756 {
757 struct relocation_info * rel = reloc;
758 struct relocation_info * rel_beg = reloc +
759 (hdr.a_trsize/sizeof(struct relocation_info));
760 struct relocation_info * rel_end = reloc +
761 (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info);
762
763 while (rel < rel_end) {
764 char *address = (char*)(rel->r_address + block);
765 long datum = 0;
766 #if defined(__sun) && defined(__sparc)
767 unsigned int mask = 0;
768 #endif
769
770 if (rel >= rel_beg)
771 address += hdr.a_text;
772
773 if (rel->r_extern) { /* Look it up in symbol-table */
774 sym = &(syms[R_SYMBOL(rel)]);
775 switch (sym->n_type) {
776 case N_EXT|N_UNDF:
777 link_undef(sym->n_un.n_name, block, rel);
778 case N_EXT|N_COMM:
779 case N_COMM:
780 datum = sym->n_value;
781 break;
782 default:
783 goto err_exit;
784 }
785 } /* end.. look it up */
786 else { /* is static */
787 switch (R_SYMBOL(rel)) {
788 case N_TEXT:
789 case N_DATA:
790 datum = block;
791 break;
792 case N_BSS:
793 datum = block + new_common;
794 break;
795 case N_ABS:
796 break;
797 }
798 } /* end .. is static */
799 if (R_PCREL(rel)) datum -= block;
800
801 #if defined(__sun) && defined(__sparc)
802 datum += rel->r_addend;
803 datum >>= R_RIGHTSHIFT(rel);
804 mask = (1 << R_BITSIZE(rel)) - 1;
805 mask |= mask -1;
806 datum &= mask;
807
808 switch (R_LENGTH(rel)) {
809 case 0:
810 *address &= ~mask;
811 *address |= datum;
812 break;
813 case 1:
814 *(short *)address &= ~mask;
815 *(short *)address |= datum;
816 break;
817 case 2:
818 *(long *)address &= ~mask;
819 *(long *)address |= datum;
820 break;
821 }
822 #else
823 switch (R_LENGTH(rel)) {
824 case 0: /* byte */
825 if (datum < -128 || datum > 127) goto err_exit;
826 *address += datum;
827 break;
828 case 1: /* word */
829 *(short *)address += datum;
830 break;
831 case 2: /* long */
832 *(long *)address += datum;
833 break;
834 }
835 #endif
836 rel++;
837 }
838 }
839
840 if (need_init) {
841 int len;
842 char **libs_to_be_linked = 0;
843 char *buf;
844
845 if (undef_tbl->num_entries > 0) {
846 if (load_lib(libc) == -1) goto err_exit;
847 }
848
849 init_funcname(&buf, need_init);
850 len = strlen(buf);
851
852 for (sym = syms; sym<end; sym++) {
853 char *name = sym->n_un.n_name;
854 if (name[0] == '_' && sym->n_value >= block) {
855 if (strcmp(name+1, "dln_libs_to_be_linked") == 0) {
856 libs_to_be_linked = (char**)sym->n_value;
857 }
858 else if (strcmp(name+1, buf) == 0) {
859 init_p = 1;
860 ((int (*)())sym->n_value)();
861 }
862 }
863 }
864 if (libs_to_be_linked && undef_tbl->num_entries > 0) {
865 while (*libs_to_be_linked) {
866 load_lib(*libs_to_be_linked);
867 libs_to_be_linked++;
868 }
869 }
870 }
871 free(reloc);
872 free(syms);
873 if (need_init) {
874 if (init_p == 0) {
875 dln_errno = DLN_ENOINIT;
876 return -1;
877 }
878 if (undef_tbl->num_entries > 0) {
879 if (load_lib(libc) == -1) goto err_exit;
880 if (undef_tbl->num_entries > 0) {
881 dln_errno = DLN_EUNDEF;
882 return -1;
883 }
884 }
885 }
886 return 0;
887
888 err_exit:
889 if (syms) free(syms);
890 if (reloc) free(reloc);
891 if (block) free((char*)block);
892 return -1;
893 }
894
895 static int target_offset;
896 static int
897 search_undef(const char *key, int value, st_table *lib_tbl)
898 {
899 long offset;
900
901 if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
902 target_offset = offset;
903 return ST_STOP;
904 }
905
906 struct symdef {
907 int rb_str_index;
908 int lib_offset;
909 };
910
911 const char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
912
913 static int
914 load_lib(const char *lib)
915 {
916 char *path, *file, fbuf[MAXPATHLEN];
917 char *envpath = 0;
918 char armagic[SARMAG];
919 int fd, size;
920 struct ar_hdr ahdr;
921 st_table *lib_tbl = NULL;
922 int *data, nsym;
923 struct symdef *base;
924 char *name_base;
925
926 if (dln_init_p == 0) {
927 dln_errno = DLN_ENOINIT;
928 return -1;
929 }
930
931 if (undef_tbl->num_entries == 0) return 0;
932 dln_errno = DLN_EBADLIB;
933
934 if (lib[0] == '-' && lib[1] == 'l') {
935 long len = strlen(lib) + 4;
936 char *p = alloca(len);
937 snprintf(p, len, "lib%s.a", lib+2);
938 lib = p;
939 }
940
941 /* library search path: */
942 /* look for environment variable DLN_LIBRARY_PATH first. */
943 /* then variable dln_librrb_ary_path. */
944 /* if path is still NULL, use "." for path. */
945 path = getenv("DLN_LIBRARY_PATH");
946 if (path == NULL) path = dln_librrb_ary_path;
947 else path = envpath = strdup(path);
948
949 file = dln_find_file_r(lib, path, fbuf, sizeof(fbuf));
950 if (envpath) free(envpath);
951 fd = open(file, O_RDONLY);
952 if (fd == -1) goto syserr;
953 size = read(fd, armagic, SARMAG);
954 if (size == -1) goto syserr;
955
956 if (size != SARMAG) {
957 dln_errno = DLN_ENOTLIB;
958 goto badlib;
959 }
960 size = read(fd, &ahdr, sizeof(ahdr));
961 if (size == -1) goto syserr;
962 if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) {
963 goto badlib;
964 }
965
966 if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) {
967 /* make hash table from __.SYMDEF */
968
969 lib_tbl = st_init_strtable();
970 data = (int*)xmalloc(size);
971 if (data == NULL) goto syserr;
972 size = read(fd, data, size);
973 nsym = *data / sizeof(struct symdef);
974 base = (struct symdef*)(data + 1);
975 name_base = (char*)(base + nsym) + sizeof(int);
976 while (nsym > 0) {
977 char *name = name_base + base->rb_str_index;
978
979 st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr));
980 nsym--;
981 base++;
982 }
983 for (;;) {
984 target_offset = -1;
985 st_foreach(undef_tbl, search_undef, lib_tbl);
986 if (target_offset == -1) break;
987 if (load_1(fd, target_offset, 0) == -1) {
988 st_free_table(lib_tbl);
989 free(data);
990 goto badlib;
991 }
992 if (undef_tbl->num_entries == 0) break;
993 }
994 free(data);
995 st_free_table(lib_tbl);
996 }
997 else {
998 /* linear library, need to scan (FUTURE) */
999
1000 for (;;) {
1001 int offset = SARMAG;
1002 int found = 0;
1003 struct exec hdr;
1004 struct nlist *syms, *sym, *end;
1005
1006 while (undef_tbl->num_entries > 0) {
1007 found = 0;
1008 lseek(fd, offset, 0);
1009 size = read(fd, &ahdr, sizeof(ahdr));
1010 if (size == -1) goto syserr;
1011 if (size == 0) break;
1012 if (size != sizeof(ahdr)
1013 || sscanf(ahdr.ar_size, "%d", &size) != 1) {
1014 goto badlib;
1015 }
1016 offset += sizeof(ahdr);
1017 if (load_header(fd, &hdr, offset) == -1)
1018 goto badlib;
1019 syms = load_sym(fd, &hdr, offset);
1020 if (syms == NULL) goto badlib;
1021 sym = syms;
1022 end = syms + (hdr.a_syms / sizeof(struct nlist));
1023 while (sym < end) {
1024 if (sym->n_type == N_EXT|N_TEXT
1025 && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) {
1026 break;
1027 }
1028 sym++;
1029 }
1030 if (sym < end) {
1031 found++;
1032 free(syms);
1033 if (load_1(fd, offset, 0) == -1) {
1034 goto badlib;
1035 }
1036 }
1037 offset += size;
1038 if (offset & 1) offset++;
1039 }
1040 if (found) break;
1041 }
1042 }
1043 close(fd);
1044 return 0;
1045
1046 syserr:
1047 dln_errno = errno;
1048 badlib:
1049 if (fd >= 0) close(fd);
1050 return -1;
1051 }
1052
1053 static int
1054 load(const char *file)
1055 {
1056 int fd;
1057 int result;
1058
1059 if (dln_init_p == 0) {
1060 if (dln_init(dln_argv0) == -1) return -1;
1061 }
1062 result = strlen(file);
1063 if (file[result-1] == 'a') {
1064 return load_lib(file);
1065 }
1066
1067 fd = open(file, O_RDONLY);
1068 if (fd == -1) {
1069 dln_errno = errno;
1070 return -1;
1071 }
1072 result = load_1(fd, 0, file);
1073 close(fd);
1074
1075 return result;
1076 }
1077
1078 void*
1079 dln_sym(const char *name)
1080 {
1081 struct nlist *sym;
1082
1083 if (st_lookup(sym_tbl, name, &sym))
1084 return (void*)sym->n_value;
1085 return NULL;
1086 }
1087
1088 #endif /* USE_DLN_A_OUT */
1089
1090 #ifdef USE_DLN_DLOPEN
1091 # include <dlfcn.h>
1092 #endif
1093
1094 #ifdef __hpux
1095 #include <errno.h>
1096 #include "dl.h"
1097 #endif
1098
1099 #if defined(_AIX)
1100 #include <ctype.h> /* for isdigit() */
1101 #include <errno.h> /* for global errno */
1102 #include <sys/ldr.h>
1103 #endif
1104
1105 #ifdef NeXT
1106 #if NS_TARGET_MAJOR < 4
1107 #include <mach-o/rld.h>
1108 #else
1109 #include <mach-o/dyld.h>
1110 #ifndef NSLINKMODULE_OPTION_BINDNOW
1111 #define NSLINKMODULE_OPTION_BINDNOW 1
1112 #endif
1113 #endif
1114 #else
1115 #ifdef MACOSX_DYLD
1116 #include <mach-o/dyld.h>
1117 #endif
1118 #endif
1119
1120 #if defined _WIN32 && !defined __CYGWIN__
1121 #include <windows.h>
1122 #include <imagehlp.h>
1123 #endif
1124
1125 #if defined _WIN32 && !defined __CYGWIN__
1126 static const char *
1127 dln_strerror(char *message, size_t size)
1128 {
1129 int error = GetLastError();
1130 char *p = message;
1131 size_t len = snprintf(message, size, "%d: ", error);
1132
1133 #define format_message(sublang) FormatMessage(\
1134 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
1135 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
1136 message + len, size - len, NULL)
1137 if (format_message(SUBLANG_ENGLISH_US) == 0)
1138 format_message(SUBLANG_DEFAULT);
1139 for (p = message + len; *p; p++) {
1140 if (*p == '\n' || *p == '\r')
1141 *p = ' ';
1142 }
1143 return message;
1144 }
1145 #define dln_strerror() dln_strerror(message, sizeof message)
1146 #elif ! defined _AIX
1147 static const char *
1148 dln_strerror(void)
1149 {
1150 #ifdef USE_DLN_A_OUT
1151 char *strerror();
1152
1153 switch (dln_errno) {
1154 case DLN_ECONFL:
1155 return "Symbol name conflict";
1156 case DLN_ENOINIT:
1157 return "No initializer given";
1158 case DLN_EUNDEF:
1159 return "Unresolved symbols";
1160 case DLN_ENOTLIB:
1161 return "Not a library file";
1162 case DLN_EBADLIB:
1163 return "Malformed library file";
1164 case DLN_EINIT:
1165 return "Not initialized";
1166 default:
1167 return strerror(dln_errno);
1168 }
1169 #endif
1170
1171 #ifdef USE_DLN_DLOPEN
1172 return (char*)dlerror();
1173 #endif
1174 }
1175 #endif
1176
1177 #if defined(_AIX) && ! defined(_IA64)
1178 static void
1179 aix_loaderror(const char *pathname)
1180 {
1181 char *message[1024], errbuf[1024];
1182 int i;
1183 #define ERRBUF_APPEND(s) strncat(errbuf, (s), sizeof(errbuf)-strlen(errbuf)-1)
1184 snprintf(errbuf, sizeof(errbuf), "load failed - %s. ", pathname);
1185
1186 if (loadquery(L_GETMESSAGES, &message[0], sizeof(message)) != -1) {
1187 ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t");
1188 ERRBUF_APPEND("/usr/sbin/execerror ruby ");
1189 for (i=0; message[i]; i++) {
1190 ERRBUF_APPEND("\"");
1191 ERRBUF_APPEND(message[i]);
1192 ERRBUF_APPEND("\" ");
1193 }
1194 ERRBUF_APPEND("\n");
1195 } else {
1196 ERRBUF_APPEND(strerror(errno));
1197 ERRBUF_APPEND("[loadquery failed]");
1198 }
1199 dln_loaderror("%s", errbuf);
1200 }
1201 #endif
1202
1203 #if defined _WIN32 && defined RUBY_EXPORT
1204 HANDLE rb_libruby_handle(void);
1205
1206 static int
1207 rb_w32_check_imported(HMODULE ext, HMODULE mine)
1208 {
1209 ULONG size;
1210 const IMAGE_IMPORT_DESCRIPTOR *desc;
1211
1212 desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
1213 if (!desc) return 0;
1214 while (desc->Name) {
1215 PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics);
1216 PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk);
1217 for (; piat->u1.Function; piat++, pint++) {
1218 static const char prefix[] = "rb_";
1219 PIMAGE_IMPORT_BY_NAME pii;
1220 const char *name;
1221
1222 if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue;
1223 pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData);
1224 name = (const char *)pii->Name;
1225 if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
1226 FARPROC addr = GetProcAddress(mine, name);
1227 if (addr) return (FARPROC)piat->u1.Function == addr;
1228 }
1229 }
1230 desc++;
1231 }
1232 return 1;
1233 }
1234 #endif
1235
1236 #if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
1237 #define translit_separator(src) do { \
1238 char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
1239 do { \
1240 *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
1241 } while (c); \
1242 (src) = tmp; \
1243 } while (0)
1244 #else
1245 #define translit_separator(str) (void)(str)
1246 #endif
1247
1248 void*
1249 dln_load(const char *file)
1250 {
1251 #if !defined(_AIX) && !defined(NeXT)
1252 const char *error = 0;
1253 #define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
1254 #endif
1255
1256 #if defined _WIN32 && !defined __CYGWIN__
1257 HINSTANCE handle;
1258 char winfile[MAXPATHLEN];
1259 char message[1024];
1260 void (*init_fct)();
1261 char *buf;
1262
1263 if (strlen(file) >= MAXPATHLEN) dln_loaderror("filename too long");
1264
1265 /* Load the file as an object one */
1266 init_funcname(&buf, file);
1267
1268 strlcpy(winfile, file, sizeof(winfile));
1269
1270 /* Load file */
1271 if ((handle = LoadLibrary(winfile)) == NULL) {
1272 error = dln_strerror();
1273 goto failed;
1274 }
1275
1276 #if defined _WIN32 && defined RUBY_EXPORT
1277 if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
1278 FreeLibrary(handle);
1279 error = "incompatible library version";
1280 goto failed;
1281 }
1282 #endif
1283
1284 if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
1285 dln_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
1286 }
1287
1288 /* Call the init code */
1289 (*init_fct)();
1290 return handle;
1291 #else
1292 #ifdef USE_DLN_A_OUT
1293 if (load(file) == -1) {
1294 error = dln_strerror();
1295 goto failed;
1296 }
1297 return 0;
1298 #else
1299
1300 char *buf;
1301 /* Load the file as an object one */
1302 init_funcname(&buf, file);
1303 translit_separator(file);
1304
1305 #ifdef USE_DLN_DLOPEN
1306 #define DLN_DEFINED
1307 {
1308 void *handle;
1309 void (*init_fct)();
1310
1311 #ifndef RTLD_LAZY
1312 # define RTLD_LAZY 1
1313 #endif
1314 #ifdef __INTERIX
1315 # undef RTLD_GLOBAL
1316 #endif
1317 #ifndef RTLD_GLOBAL
1318 # define RTLD_GLOBAL 0
1319 #endif
1320
1321 #ifdef __native_client__
1322 char* p, *orig;
1323 if (file[0] == '.' && file[1] == '/') file+=2;
1324 orig = strdup(file);
1325 for (p = file; *p; ++p) {
1326 if (*p == '/') *p = '_';
1327 }
1328 #endif
1329 /* Load file */
1330 if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
1331 #ifdef __native_client__
1332 free(orig);
1333 #endif
1334 error = dln_strerror();
1335 goto failed;
1336 }
1337
1338 init_fct = (void(*)())(VALUE)dlsym(handle, buf);
1339 #ifdef __native_client__
1340 strcpy(file, orig);
1341 free(orig);
1342 #endif
1343 #if defined __SYMBIAN32__
1344 if (init_fct == NULL) {
1345 init_fct = (void(*)())dlsym(handle, "1"); /* Some Symbian versions do not support symbol table in DLL, ordinal numbers only */
1346 }
1347 #endif
1348 if (init_fct == NULL) {
1349 error = DLN_ERROR();
1350 dlclose(handle);
1351 goto failed;
1352 }
1353 /* Call the init code */
1354 (*init_fct)();
1355
1356 return handle;
1357 }
1358 #endif /* USE_DLN_DLOPEN */
1359
1360 #ifdef __hpux
1361 #define DLN_DEFINED
1362 {
1363 shl_t lib = NULL;
1364 int flags;
1365 void (*init_fct)();
1366
1367 flags = BIND_DEFERRED;
1368 lib = shl_load(file, flags, 0);
1369 if (lib == NULL) {
1370 extern int errno;
1371 dln_loaderror("%s - %s", strerror(errno), file);
1372 }
1373 shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
1374 if (init_fct == NULL) {
1375 shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
1376 if (init_fct == NULL) {
1377 errno = ENOSYM;
1378 dln_loaderror("%s - %s", strerror(ENOSYM), file);
1379 }
1380 }
1381 (*init_fct)();
1382 return (void*)lib;
1383 }
1384 #endif /* hpux */
1385
1386 #if defined(_AIX) && ! defined(_IA64)
1387 #define DLN_DEFINED
1388 {
1389 void (*init_fct)();
1390
1391 init_fct = (void(*)())load((char*)file, 1, 0);
1392 if (init_fct == NULL) {
1393 aix_loaderror(file);
1394 }
1395 if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
1396 aix_loaderror(file);
1397 }
1398 (*init_fct)();
1399 return (void*)init_fct;
1400 }
1401 #endif /* _AIX */
1402
1403 #if defined(MACOSX_DYLD)
1404 #define DLN_DEFINED
1405 /*----------------------------------------------------
1406 By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
1407
1408 Special Thanks...
1409 Yu tomoak-i@is.aist-nara.ac.jp,
1410 Mi hisho@tasihara.nest.or.jp,
1411 sunshine@sunshineco.com,
1412 and... Miss ARAI Akino(^^;)
1413 ----------------------------------------------------*/
1414 {
1415 int dyld_result;
1416 NSObjectFileImage obj_file; /* handle, but not use it */
1417 /* "file" is module file name .
1418 "buf" is pointer to initial function name with "_" . */
1419
1420 void (*init_fct)();
1421
1422
1423 dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
1424
1425 if (dyld_result != NSObjectFileImageSuccess) {
1426 dln_loaderror("Failed to load %.200s", file);
1427 }
1428
1429 NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
1430
1431 /* lookup the initial function */
1432 if (!NSIsSymbolNameDefined(buf)) {
1433 dln_loaderror("Failed to lookup Init function %.200s",file);
1434 }
1435 init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
1436 (*init_fct)();
1437
1438 return (void*)init_fct;
1439 }
1440 #endif
1441
1442 #if defined(__BEOS__) || defined(__HAIKU__)
1443 # define DLN_DEFINED
1444 {
1445 status_t err_stat; /* BeOS error status code */
1446 image_id img_id; /* extension module unique id */
1447 void (*init_fct)(); /* initialize function for extension module */
1448
1449 /* load extension module */
1450 img_id = load_add_on(file);
1451 if (img_id <= 0) {
1452 dln_loaderror("Failed to load add_on %.200s error_code=%x",
1453 file, img_id);
1454 }
1455
1456 /* find symbol for module initialize function. */
1457 /* The Be Book KernelKit Images section described to use
1458 B_SYMBOL_TYPE_TEXT for symbol of function, not
1459 B_SYMBOL_TYPE_CODE. Why ? */
1460 /* strcat(init_fct_symname, "__Fv"); */ /* parameter nothing. */
1461 /* "__Fv" dont need! The Be Book Bug ? */
1462 err_stat = get_image_symbol(img_id, buf,
1463 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
1464
1465 if (err_stat != B_NO_ERROR) {
1466 char real_name[MAXPATHLEN];
1467
1468 strlcpy(real_name, buf, MAXPATHLEN);
1469 strlcat(real_name, "__Fv", MAXPATHLEN);
1470 err_stat = get_image_symbol(img_id, real_name,
1471 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
1472 }
1473
1474 if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) {
1475 unload_add_on(img_id);
1476 dln_loaderror("Failed to lookup Init function %.200s", file);
1477 }
1478 else if (B_NO_ERROR != err_stat) {
1479 char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
1480 unload_add_on(img_id);
1481 dln_loaderror(errmsg, strerror(err_stat), buf);
1482 }
1483
1484 /* call module initialize function. */
1485 (*init_fct)();
1486 return (void*)img_id;
1487 }
1488 #endif /* __BEOS__ || __HAIKU__ */
1489
1490 #ifndef DLN_DEFINED
1491 dln_notimplement();
1492 #endif
1493
1494 #endif /* USE_DLN_A_OUT */
1495 #endif
1496 #if !defined(_AIX) && !defined(NeXT)
1497 failed:
1498 dln_loaderror("%s - %s", error, file);
1499 #endif
1500
1501 return 0; /* dummy return */
1502 }
1503