1 /**********************************************************************
6 created at: Tue Jan 18 17:05:06 JST 1994
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
10 **********************************************************************/
12 #include "ruby/ruby.h"
29 #if defined(HAVE_ALLOCA_H)
45 #define free(x) xfree(x)
48 #if defined(_WIN32) || defined(__VMS)
49 #include "missing/file.h"
51 #include <sys/types.h>
55 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
58 #ifdef HAVE_SYS_PARAM_H
59 # include <sys/param.h>
62 # define MAXPATHLEN 1024
79 # include <TextUtils.h>
80 # include <CodeFragments.h>
82 # include "macruby_private.h"
85 #if defined(__APPLE__) && defined(__MACH__) /* Mac OS X */
86 # if defined(HAVE_DLOPEN)
87 /* Mac OS X with dlopen (10.3 or later) */
88 # define MACOSX_DLOPEN
100 #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
101 /* dynamic load with dlopen() */
102 # define USE_DLN_DLOPEN
105 #ifndef FUNCNAME_PATTERN
106 # if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD)
107 # define FUNCNAME_PATTERN "_Init_%s"
109 # define FUNCNAME_PATTERN "Init_%s"
114 init_funcname_len(char **buf
, const char *file
)
120 /* Load the file as an object one */
121 for (slash
= file
-1; *file
; file
++) /* Find position of last '/' */
123 if (*file
== ':') slash
= file
;
125 if (*file
== '/') slash
= file
;
128 len
= strlen(FUNCNAME_PATTERN
) + strlen(slash
+ 1);
130 snprintf(*buf
, len
, FUNCNAME_PATTERN
, slash
+ 1);
131 for (p
= *buf
; *p
; p
++) { /* Delete suffix if it exists */
139 #define init_funcname(buf, file) do {\
140 int len = init_funcname_len(buf, file);\
141 char *tmp = ALLOCA_N(char, len+1);\
154 # define LIBC_NAME "libc.a"
157 #ifndef DLN_DEFAULT_LIB_PATH
158 # define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
163 static int dln_errno
;
165 #define DLN_ENOEXEC ENOEXEC /* Exec format error */
166 #define DLN_ECONFL 1201 /* Symbol name conflict */
167 #define DLN_ENOINIT 1202 /* No initializer given */
168 #define DLN_EUNDEF 1203 /* Undefine symbol remains */
169 #define DLN_ENOTLIB 1204 /* Not a library file */
170 #define DLN_EBADLIB 1205 /* Malformed library file */
171 #define DLN_EINIT 1206 /* Not initialized */
173 static int dln_init_p
= 0;
181 # define N_MAGIC(x) (x).a_magic
184 #define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC)
186 #include "ruby/util.h"
189 static st_table
*sym_tbl
;
190 static st_table
*undef_tbl
;
192 static int load_lib();
195 load_header(int fd
, struct exec
*hdrp
, long disp
)
200 size
= read(fd
, hdrp
, sizeof(struct exec
));
205 if (size
!= sizeof(struct exec
) || N_BADMAG(*hdrp
)) {
206 dln_errno
= DLN_ENOEXEC
;
213 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
214 #define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr)
215 #define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr)
216 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
220 #ifndef RELOC_ADDRESS
221 #define RELOC_ADDRESS(r) ((r)->r_address)
222 #define RELOC_EXTERN_P(r) ((r)->r_extern)
223 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
224 #define RELOC_MEMORY_SUB_P(r) 0
225 #define RELOC_PCREL_P(r) ((r)->r_pcrel)
226 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
229 #if defined(sun) && defined(sparc)
230 /* Sparc (Sun 4) macros */
231 # undef relocation_info
232 # define relocation_info reloc_info_sparc
233 # define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type])
234 # define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type])
235 # define R_LENGTH(r) (reloc_r_length[(r)->r_type])
236 static int reloc_r_rightshift
[] = {
237 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
239 static int reloc_r_bitsize
[] = {
240 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
242 static int reloc_r_length
[] = {
243 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
245 # define R_PCREL(r) \
246 ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
247 # define R_SYMBOL(r) ((r)->r_index)
251 #define R_SYMBOL(r) ((r)->r_symbolnum)
252 #define R_MEMORY_SUB(r) ((r)->r_bsr)
253 #define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr)
254 #define R_LENGTH(r) ((r)->r_length)
258 # define R_SYMBOL(r) ((r)->r_symbolnum)
259 # define R_MEMORY_SUB(r) 0
260 # define R_PCREL(r) ((r)->r_pcrel)
261 # define R_LENGTH(r) ((r)->r_length)
264 static struct relocation_info
*
265 load_reloc(int fd
, struct exec
*hdrp
, long disp
)
267 struct relocation_info
*reloc
;
270 lseek(fd
, disp
+ N_TXTOFF(*hdrp
) + hdrp
->a_text
+ hdrp
->a_data
, 0);
271 size
= hdrp
->a_trsize
+ hdrp
->a_drsize
;
272 reloc
= (struct relocation_info
*)xmalloc(size
);
278 if (read(fd
, reloc
, size
) != size
) {
287 static struct nlist
*
288 load_sym(int fd
, struct exec
*hdrp
, long disp
)
290 struct nlist
* buffer
;
296 lseek(fd
, N_SYMOFF(*hdrp
) + hdrp
->a_syms
+ disp
, 0);
297 if (read(fd
, &size
, sizeof(int)) != sizeof(int)) {
301 buffer
= (struct nlist
*)xmalloc(hdrp
->a_syms
+ size
);
302 if (buffer
== NULL
) {
307 lseek(fd
, disp
+ N_SYMOFF(*hdrp
), 0);
308 if (read(fd
, buffer
, hdrp
->a_syms
+ size
) != hdrp
->a_syms
+ size
) {
314 end
= sym
+ hdrp
->a_syms
/ sizeof(struct nlist
);
315 displ
= (long)buffer
+ (long)(hdrp
->a_syms
);
318 sym
->n_un
.n_name
= (char*)sym
->n_un
.n_strx
+ displ
;
324 dln_errno
= DLN_ENOEXEC
;
329 sym_hash(struct exec
*hdrp
, struct nlist
*syms
)
332 struct nlist
*sym
= syms
;
333 struct nlist
*end
= syms
+ (hdrp
->a_syms
/ sizeof(struct nlist
));
335 tbl
= st_init_strtable();
342 st_insert(tbl
, sym
->n_un
.n_name
, sym
);
349 dln_init(const char *prog
)
351 char *file
, fbuf
[MAXPATHLEN
];
356 if (dln_init_p
== 1) return 0;
358 file
= dln_find_exe_r(prog
, NULL
, fbuf
, sizeof(fbuf
));
359 if (file
== NULL
|| (fd
= open(file
, O_RDONLY
)) < 0) {
364 if (load_header(fd
, &hdr
, 0) == -1) return -1;
365 syms
= load_sym(fd
, &hdr
, 0);
370 sym_tbl
= sym_hash(&hdr
, syms
);
371 if (sym_tbl
== NULL
) { /* file may be start with #! */
373 char buf
[MAXPATHLEN
];
378 if (read(fd
, &c
, 1) == -1) {
382 if (c
!= '#') goto err_noexec
;
383 if (read(fd
, &c
, 1) == -1) {
387 if (c
!= '!') goto err_noexec
;
390 /* skip forwarding spaces */
391 while (read(fd
, &c
, 1) == 1) {
392 if (c
== '\n') goto err_noexec
;
393 if (c
!= '\t' && c
!= ' ') {
398 /* read in command name */
399 while (read(fd
, p
, 1) == 1) {
400 if (*p
== '\n' || *p
== '\t' || *p
== ' ') break;
402 if (p
-buf
>= MAXPATHLEN
) {
403 dln_errno
= ENAMETOOLONG
;
409 return dln_init(buf
);
412 undef_tbl
= st_init_strtable();
418 dln_errno
= DLN_ENOEXEC
;
423 load_text_data(int fd
, struct exec
*hdrp
, int bss
, long disp
)
428 lseek(fd
, disp
+ N_TXTOFF(*hdrp
), 0);
429 size
= hdrp
->a_text
+ hdrp
->a_data
;
431 if (bss
== -1) size
+= hdrp
->a_bss
;
432 else if (bss
> 1) size
+= bss
;
434 addr
= (unsigned char*)xmalloc(size
);
440 if (read(fd
, addr
, size
) != size
) {
447 memset(addr
+ hdrp
->a_text
+ hdrp
->a_data
, 0, hdrp
->a_bss
);
450 memset(addr
+ hdrp
->a_text
+ hdrp
->a_data
, 0, bss
);
457 undef_print(char *key
, char *value
)
459 fprintf(stderr
, " %s\n", key
);
466 fprintf(stderr
, " Undefined symbols:\n");
467 st_foreach(undef_tbl
, undef_print
, NULL
);
473 if (undef_tbl
->num_entries
> 0) {
474 fprintf(stderr
, "dln: Calling undefined function\n");
482 struct relocation_info reloc
;
492 static st_table
*reloc_tbl
= NULL
;
494 link_undef(const char *name
, long base
, struct relocation_info
*reloc
)
498 char *addr
= (char*)(reloc
->r_address
+ base
);
500 obj
= (struct undef
*)xmalloc(sizeof(struct undef
));
501 obj
->name
= strdup(name
);
504 switch (R_LENGTH(reloc
)) {
509 obj
->u
.s
= *(short*)addr
;
512 obj
->u
.l
= *(long*)addr
;
515 if (reloc_tbl
== NULL
) {
516 reloc_tbl
= st_init_numtable();
518 st_insert(reloc_tbl
, u_no
++, obj
);
527 reloc_undef(int no
, struct undef
*undef
, struct reloc_arg
*arg
)
531 #if defined(sun) && defined(sparc)
532 unsigned int mask
= 0;
535 if (strcmp(arg
->name
, undef
->name
) != 0) return ST_CONTINUE
;
536 address
= (char*)(undef
->base
+ undef
->reloc
.r_address
);
539 if (R_PCREL(&(undef
->reloc
))) datum
-= undef
->base
;
540 #if defined(sun) && defined(sparc)
541 datum
+= undef
->reloc
.r_addend
;
542 datum
>>= R_RIGHTSHIFT(&(undef
->reloc
));
543 mask
= (1 << R_BITSIZE(&(undef
->reloc
))) - 1;
546 switch (R_LENGTH(&(undef
->reloc
))) {
548 *address
= undef
->u
.c
;
553 *(short *)address
= undef
->u
.s
;
554 *(short *)address
&= ~mask
;
555 *(short *)address
|= datum
;
558 *(long *)address
= undef
->u
.l
;
559 *(long *)address
&= ~mask
;
560 *(long *)address
|= datum
;
564 switch (R_LENGTH(&(undef
->reloc
))) {
566 if (R_MEMORY_SUB(&(undef
->reloc
)))
567 *address
= datum
- *address
;
568 else *address
= undef
->u
.c
+ datum
;
571 if (R_MEMORY_SUB(&(undef
->reloc
)))
572 *(short*)address
= datum
- *(short*)address
;
573 else *(short*)address
= undef
->u
.s
+ datum
;
576 if (R_MEMORY_SUB(&(undef
->reloc
)))
577 *(long*)address
= datum
- *(long*)address
;
578 else *(long*)address
= undef
->u
.l
+ datum
;
588 unlink_undef(const char *name
, long value
)
590 struct reloc_arg arg
;
594 st_foreach(reloc_tbl
, reloc_undef
, &arg
);
603 reloc_repl(int no
, struct undef
*undef
, struct indr_data
*data
)
605 if (strcmp(data
->name0
, undef
->name
) == 0) {
607 undef
->name
= strdup(data
->name1
);
614 load_1(int fd
, long disp
, const char *need_init
)
616 static const char *libc
= LIBC_NAME
;
618 struct relocation_info
*reloc
= NULL
;
620 long new_common
= 0; /* Length of new common */
621 struct nlist
*syms
= NULL
;
626 if (load_header(fd
, &hdr
, disp
) == -1) return -1;
627 if (INVALID_OBJECT(hdr
)) {
628 dln_errno
= DLN_ENOEXEC
;
631 reloc
= load_reloc(fd
, &hdr
, disp
);
632 if (reloc
== NULL
) return -1;
634 syms
= load_sym(fd
, &hdr
, disp
);
641 end
= syms
+ (hdr
.a_syms
/ sizeof(struct nlist
));
643 struct nlist
*old_sym
;
644 int value
= sym
->n_value
;
647 if (sym
->n_type
== (N_INDR
| N_EXT
)) {
648 char *key
= sym
->n_un
.n_name
;
650 if (st_lookup(sym_tbl
, sym
[1].n_un
.n_name
, &old_sym
)) {
651 if (st_delete(undef_tbl
, (st_data_t
*)&key
, NULL
)) {
652 unlink_undef(key
, old_sym
->n_value
);
657 struct indr_data data
;
659 data
.name0
= sym
->n_un
.n_name
;
660 data
.name1
= sym
[1].n_un
.n_name
;
661 st_foreach(reloc_tbl
, reloc_repl
, &data
);
663 st_insert(undef_tbl
, strdup(sym
[1].n_un
.n_name
), NULL
);
664 if (st_delete(undef_tbl
, (st_data_t
*)&key
, NULL
)) {
672 if (sym
->n_type
== (N_UNDF
| N_EXT
)) {
673 if (st_lookup(sym_tbl
, sym
->n_un
.n_name
, &old_sym
) == 0) {
679 sym
->n_type
= N_EXT
| N_COMM
;
680 sym
->n_value
= old_sym
->n_value
;
684 value
>= sizeof(double) ? sizeof(double) - 1
685 : value
>= sizeof(long) ? sizeof(long) - 1
688 sym
->n_type
= N_COMM
;
690 new_common
&= ~(long)rnd
;
691 sym
->n_value
= new_common
;
697 sym
->n_type
= N_EXT
| N_COMM
;
698 sym
->n_value
= old_sym
->n_value
;
701 sym
->n_value
= (long)dln_undefined
;
702 st_insert(undef_tbl
, strdup(sym
->n_un
.n_name
), NULL
);
709 block
= load_text_data(fd
, &hdr
, hdr
.a_bss
+ new_common
, disp
);
710 if (block
== 0) goto err_exit
;
714 struct nlist
*new_sym
;
717 switch (sym
->n_type
) {
719 sym
->n_value
+= hdr
.a_text
+ hdr
.a_data
;
723 sym
->n_value
+= block
;
725 if (st_lookup(sym_tbl
, sym
->n_un
.n_name
, &new_sym
) != 0
726 && new_sym
->n_value
!= (long)dln_undefined
) {
727 dln_errno
= DLN_ECONFL
;
731 key
= sym
->n_un
.n_name
;
732 if (st_delete(undef_tbl
, (st_data_t
*)&key
, NULL
) != 0) {
733 unlink_undef(key
, sym
->n_value
);
737 new_sym
= (struct nlist
*)xmalloc(sizeof(struct nlist
));
739 new_sym
->n_un
.n_name
= strdup(sym
->n_un
.n_name
);
740 st_insert(sym_tbl
, new_sym
->n_un
.n_name
, new_sym
);
745 sym
->n_value
+= block
;
752 * First comes the text-relocation
755 struct relocation_info
* rel
= reloc
;
756 struct relocation_info
* rel_beg
= reloc
+
757 (hdr
.a_trsize
/sizeof(struct relocation_info
));
758 struct relocation_info
* rel_end
= reloc
+
759 (hdr
.a_trsize
+hdr
.a_drsize
)/sizeof(struct relocation_info
);
761 while (rel
< rel_end
) {
762 char *address
= (char*)(rel
->r_address
+ block
);
764 #if defined(sun) && defined(sparc)
765 unsigned int mask
= 0;
769 address
+= hdr
.a_text
;
771 if (rel
->r_extern
) { /* Look it up in symbol-table */
772 sym
= &(syms
[R_SYMBOL(rel
)]);
773 switch (sym
->n_type
) {
775 link_undef(sym
->n_un
.n_name
, block
, rel
);
778 datum
= sym
->n_value
;
783 } /* end.. look it up */
784 else { /* is static */
785 switch (R_SYMBOL(rel
)) {
791 datum
= block
+ new_common
;
796 } /* end .. is static */
797 if (R_PCREL(rel
)) datum
-= block
;
799 #if defined(sun) && defined(sparc)
800 datum
+= rel
->r_addend
;
801 datum
>>= R_RIGHTSHIFT(rel
);
802 mask
= (1 << R_BITSIZE(rel
)) - 1;
806 switch (R_LENGTH(rel
)) {
812 *(short *)address
&= ~mask
;
813 *(short *)address
|= datum
;
816 *(long *)address
&= ~mask
;
817 *(long *)address
|= datum
;
821 switch (R_LENGTH(rel
)) {
823 if (datum
< -128 || datum
> 127) goto err_exit
;
827 *(short *)address
+= datum
;
830 *(long *)address
+= datum
;
840 char **libs_to_be_linked
= 0;
843 if (undef_tbl
->num_entries
> 0) {
844 if (load_lib(libc
) == -1) goto err_exit
;
847 init_funcname(&buf
, need_init
);
850 for (sym
= syms
; sym
<end
; sym
++) {
851 char *name
= sym
->n_un
.n_name
;
852 if (name
[0] == '_' && sym
->n_value
>= block
) {
853 if (strcmp(name
+1, "dln_libs_to_be_linked") == 0) {
854 libs_to_be_linked
= (char**)sym
->n_value
;
856 else if (strcmp(name
+1, buf
) == 0) {
858 ((int (*)())sym
->n_value
)();
862 if (libs_to_be_linked
&& undef_tbl
->num_entries
> 0) {
863 while (*libs_to_be_linked
) {
864 load_lib(*libs_to_be_linked
);
873 dln_errno
= DLN_ENOINIT
;
876 if (undef_tbl
->num_entries
> 0) {
877 if (load_lib(libc
) == -1) goto err_exit
;
878 if (undef_tbl
->num_entries
> 0) {
879 dln_errno
= DLN_EUNDEF
;
887 if (syms
) free(syms
);
888 if (reloc
) free(reloc
);
889 if (block
) free((char*)block
);
893 static int target_offset
;
895 search_undef(const char *key
, int value
, st_table
*lib_tbl
)
899 if (st_lookup(lib_tbl
, key
, &offset
) == 0) return ST_CONTINUE
;
900 target_offset
= offset
;
909 char *dln_librrb_ary_path
= DLN_DEFAULT_LIB_PATH
;
912 load_lib(const char *lib
)
914 char *path
, *file
, fbuf
[MAXPATHLEN
];
915 char armagic
[SARMAG
];
918 st_table
*lib_tbl
= NULL
;
923 if (dln_init_p
== 0) {
924 dln_errno
= DLN_ENOINIT
;
928 if (undef_tbl
->num_entries
== 0) return 0;
929 dln_errno
= DLN_EBADLIB
;
931 if (lib
[0] == '-' && lib
[1] == 'l') {
932 long len
= strlen(lib
) + 4;
933 char *p
= alloca(len
);
934 snprintf(p
, len
, "lib%s.a", lib
+2);
938 /* library search path: */
939 /* look for environment variable DLN_LIBRARY_PATH first. */
940 /* then variable dln_librrb_ary_path. */
941 /* if path is still NULL, use "." for path. */
942 path
= getenv("DLN_LIBRARY_PATH");
943 if (path
== NULL
) path
= dln_librrb_ary_path
;
945 file
= dln_find_file_r(lib
, path
, fbuf
, sizeof(fbuf
));
946 fd
= open(file
, O_RDONLY
);
947 if (fd
== -1) goto syserr
;
948 size
= read(fd
, armagic
, SARMAG
);
949 if (size
== -1) goto syserr
;
951 if (size
!= SARMAG
) {
952 dln_errno
= DLN_ENOTLIB
;
955 size
= read(fd
, &ahdr
, sizeof(ahdr
));
956 if (size
== -1) goto syserr
;
957 if (size
!= sizeof(ahdr
) || sscanf(ahdr
.ar_size
, "%d", &size
) != 1) {
961 if (strncmp(ahdr
.ar_name
, "__.SYMDEF", 9) == 0) {
962 /* make hash table from __.SYMDEF */
964 lib_tbl
= st_init_strtable();
965 data
= (int*)xmalloc(size
);
966 if (data
== NULL
) goto syserr
;
967 size
= read(fd
, data
, size
);
968 nsym
= *data
/ sizeof(struct symdef
);
969 base
= (struct symdef
*)(data
+ 1);
970 name_base
= (char*)(base
+ nsym
) + sizeof(int);
972 char *name
= name_base
+ base
->rb_str_index
;
974 st_insert(lib_tbl
, name
, base
->lib_offset
+ sizeof(ahdr
));
980 st_foreach(undef_tbl
, search_undef
, lib_tbl
);
981 if (target_offset
== -1) break;
982 if (load_1(fd
, target_offset
, 0) == -1) {
983 st_free_table(lib_tbl
);
987 if (undef_tbl
->num_entries
== 0) break;
990 st_free_table(lib_tbl
);
993 /* linear library, need to scan (FUTURE) */
999 struct nlist
*syms
, *sym
, *end
;
1001 while (undef_tbl
->num_entries
> 0) {
1003 lseek(fd
, offset
, 0);
1004 size
= read(fd
, &ahdr
, sizeof(ahdr
));
1005 if (size
== -1) goto syserr
;
1006 if (size
== 0) break;
1007 if (size
!= sizeof(ahdr
)
1008 || sscanf(ahdr
.ar_size
, "%d", &size
) != 1) {
1011 offset
+= sizeof(ahdr
);
1012 if (load_header(fd
, &hdr
, offset
) == -1)
1014 syms
= load_sym(fd
, &hdr
, offset
);
1015 if (syms
== NULL
) goto badlib
;
1017 end
= syms
+ (hdr
.a_syms
/ sizeof(struct nlist
));
1019 if (sym
->n_type
== N_EXT
|N_TEXT
1020 && st_lookup(undef_tbl
, sym
->n_un
.n_name
, NULL
)) {
1028 if (load_1(fd
, offset
, 0) == -1) {
1033 if (offset
& 1) offset
++;
1044 if (fd
>= 0) close(fd
);
1049 load(const char *file
)
1054 if (dln_init_p
== 0) {
1055 if (dln_init(dln_argv0
) == -1) return -1;
1057 result
= strlen(file
);
1058 if (file
[result
-1] == 'a') {
1059 return load_lib(file
);
1062 fd
= open(file
, O_RDONLY
);
1067 result
= load_1(fd
, 0, file
);
1074 dln_sym(const char *name
)
1078 if (st_lookup(sym_tbl
, name
, &sym
))
1079 return (void*)sym
->n_value
;
1083 #endif /* USE_DLN_A_OUT */
1085 #ifdef USE_DLN_DLOPEN
1095 #include <ctype.h> /* for isdigit() */
1096 #include <errno.h> /* for global errno */
1097 #include <sys/ldr.h>
1101 #if NS_TARGET_MAJOR < 4
1102 #include <mach-o/rld.h>
1104 #include <mach-o/dyld.h>
1105 #ifndef NSLINKMODULE_OPTION_BINDNOW
1106 #define NSLINKMODULE_OPTION_BINDNOW 1
1111 #include <mach-o/dyld.h>
1115 #if defined _WIN32 && !defined __CYGWIN__
1116 #include <windows.h>
1120 #undef FormatMessage
1121 #define FormatMessage FormatMessageA
1123 #define LoadLibrary LoadLibraryA
1124 #undef GetProcAddress
1125 #define GetProcAddress GetProcAddressA
1131 #ifdef USE_DLN_A_OUT
1134 switch (dln_errno
) {
1136 return "Symbol name conflict";
1138 return "No initializer given";
1140 return "Unresolved symbols";
1142 return "Not a library file";
1144 return "Malformed library file";
1146 return "Not initialized";
1148 return strerror(dln_errno
);
1152 #ifdef USE_DLN_DLOPEN
1153 return (char*)dlerror();
1156 #if defined _WIN32 && !defined __CYGWIN__
1157 static char message
[1024];
1158 int error
= GetLastError();
1160 p
+= sprintf(message
, "%d: ", error
);
1162 FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
,
1165 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
1167 sizeof message
- strlen(message
),
1170 for (p
= message
; *p
; p
++) {
1171 if (*p
== '\n' || *p
== '\r')
1179 #if defined(_AIX) && ! defined(_IA64)
1181 aix_loaderror(const char *pathname
)
1183 char *message
[8], errbuf
[1024];
1190 {L_ERROR_TOOMANY
, "too many errors, rest skipped."},
1191 {L_ERROR_NOLIB
, "can't load library:"},
1192 {L_ERROR_UNDEF
, "can't find symbol in library:"},
1194 "RLD index out of range or bad relocation type:"},
1195 {L_ERROR_FORMAT
, "not a valid, executable xcoff file:"},
1197 "file not an archive or does not contain requested member:"},
1198 {L_ERROR_TYPE
, "symbol table mismatch:"},
1199 {L_ERROR_ALIGN
, "text alignment in file is wrong."},
1200 {L_ERROR_SYSTEM
, "System error:"},
1201 {L_ERROR_ERRNO
, NULL
}
1204 #define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0]))
1205 #define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1)
1207 snprintf(errbuf
, 1024, "load failed - %s ", pathname
);
1209 if (!loadquery(1, &message
[0], sizeof(message
)))
1210 ERRBUF_APPEND(strerror(errno
));
1211 for(i
= 0; message
[i
] && *message
[i
]; i
++) {
1212 int nerr
= atoi(message
[i
]);
1213 for (j
=0; j
<LOAD_ERRTAB_LEN
; j
++) {
1214 if (nerr
== load_errtab
[i
].errnum
&& load_errtab
[i
].errstr
)
1215 ERRBUF_APPEND(load_errtab
[i
].errstr
);
1217 while (isdigit(*message
[i
])) message
[i
]++;
1218 ERRBUF_APPEND(message
[i
]);
1219 ERRBUF_APPEND("\n");
1221 errbuf
[strlen(errbuf
)-1] = '\0'; /* trim off last newline */
1222 rb_loaderror(errbuf
);
1227 #endif /* NO_DLN_LOAD */
1230 dln_load(const char *file
)
1233 rb_raise(rb_eLoadError
, "this executable file can't load extension libraries");
1236 #if !defined(_AIX) && !defined(NeXT)
1237 const char *error
= 0;
1238 #define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
1241 #if defined _WIN32 && !defined __CYGWIN__
1243 char winfile
[MAXPATHLEN
];
1247 if (strlen(file
) >= MAXPATHLEN
) rb_loaderror("filename too long");
1249 /* Load the file as an object one */
1250 init_funcname(&buf
, file
);
1252 strcpy(winfile
, file
);
1255 if ((handle
= LoadLibrary(winfile
)) == NULL
) {
1256 error
= dln_strerror();
1260 if ((init_fct
= (void(*)())GetProcAddress(handle
, buf
)) == NULL
) {
1261 rb_loaderror("%s - %s\n%s", dln_strerror(), buf
, file
);
1264 /* Call the init code */
1268 #ifdef USE_DLN_A_OUT
1269 if (load(file
) == -1) {
1270 error
= dln_strerror();
1277 /* Load the file as an object one */
1278 init_funcname(&buf
, file
);
1280 #ifdef USE_DLN_DLOPEN
1287 # define RTLD_LAZY 1
1293 # define RTLD_GLOBAL 0
1297 if ((handle
= (void*)dlopen(file
, RTLD_LAZY
|RTLD_GLOBAL
)) == NULL
) {
1298 error
= dln_strerror();
1302 init_fct
= (void(*)())dlsym(handle
, buf
);
1303 if (init_fct
== NULL
) {
1304 error
= DLN_ERROR();
1308 /* Call the init code */
1313 #endif /* USE_DLN_DLOPEN */
1322 flags
= BIND_DEFERRED
;
1323 lib
= shl_load(file
, flags
, 0);
1326 rb_loaderror("%s - %s", strerror(errno
), file
);
1328 shl_findsym(&lib
, buf
, TYPE_PROCEDURE
, (void*)&init_fct
);
1329 if (init_fct
== NULL
) {
1330 shl_findsym(&lib
, buf
, TYPE_UNDEFINED
, (void*)&init_fct
);
1331 if (init_fct
== NULL
) {
1333 rb_loaderror("%s - %s", strerror(ENOSYM
), file
);
1341 #if defined(_AIX) && ! defined(_IA64)
1346 init_fct
= (void(*)())load((char*)file
, 1, 0);
1347 if (init_fct
== NULL
) {
1348 aix_loaderror(file
);
1350 if (loadbind(0, (void*)dln_load
, (void*)init_fct
) == -1) {
1351 aix_loaderror(file
);
1354 return (void*)init_fct
;
1358 #if defined(NeXT) || defined(MACOSX_DYLD)
1360 /*----------------------------------------------------
1361 By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
1364 Yu tomoak-i@is.aist-nara.ac.jp,
1365 Mi hisho@tasihara.nest.or.jp,
1366 sunshine@sunshineco.com,
1367 and... Miss ARAI Akino(^^;)
1368 ----------------------------------------------------*/
1369 #if defined(NeXT) && (NS_TARGET_MAJOR < 4)/* NeXTSTEP rld functions */
1373 unsigned long init_address
;
1374 char *object_files
[2] = {NULL
, NULL
};
1378 object_files
[0] = (char*)file
;
1380 s
= NXOpenFile(2,NX_WRITEONLY
);
1382 /* Load object file, if return value ==0 , load failed*/
1383 if(rld_load(s
, NULL
, object_files
, NULL
) == 0) {
1386 rb_loaderror("Failed to load %.200s", file
);
1389 /* lookup the initial function */
1390 if(rld_lookup(s
, buf
, &init_address
) == 0) {
1393 rb_loaderror("Failed to lookup Init function %.200s", file
);
1399 /* Cannot call *init_address directory, so copy this value to
1401 init_fct
= (void(*)())init_address
;
1403 return (void*)init_address
;
1405 #else/* OPENSTEP dyld functions */
1408 NSObjectFileImage obj_file
; /* handle, but not use it */
1409 /* "file" is module file name .
1410 "buf" is pointer to initial function name with "_" . */
1415 dyld_result
= NSCreateObjectFileImageFromFile(file
, &obj_file
);
1417 if (dyld_result
!= NSObjectFileImageSuccess
) {
1418 rb_loaderror("Failed to load %.200s", file
);
1421 NSLinkModule(obj_file
, file
, NSLINKMODULE_OPTION_BINDNOW
);
1423 /* lookup the initial function */
1424 if(!NSIsSymbolNameDefined(buf
)) {
1425 rb_loaderror("Failed to lookup Init function %.200s",file
);
1427 init_fct
= NSAddressOfSymbol(NSLookupAndBindSymbol(buf
));
1430 return (void*)init_fct
;
1432 #endif /* rld or dyld */
1436 # define DLN_DEFINED
1438 status_t err_stat
; /* BeOS error status code */
1439 image_id img_id
; /* extention module unique id */
1440 void (*init_fct
)(); /* initialize function for extention module */
1442 /* load extention module */
1443 img_id
= load_add_on(file
);
1445 rb_loaderror("Failed to load %.200s", file
);
1448 /* find symbol for module initialize function. */
1449 /* The Be Book KernelKit Images section described to use
1450 B_SYMBOL_TYPE_TEXT for symbol of function, not
1451 B_SYMBOL_TYPE_CODE. Why ? */
1452 /* strcat(init_fct_symname, "__Fv"); */ /* parameter nothing. */
1453 /* "__Fv" dont need! The Be Book Bug ? */
1454 err_stat
= get_image_symbol(img_id
, buf
,
1455 B_SYMBOL_TYPE_TEXT
, (void **)&init_fct
);
1457 if (err_stat
!= B_NO_ERROR
) {
1458 char real_name
[MAXPATHLEN
];
1460 strcpy(real_name
, buf
);
1461 strcat(real_name
, "__Fv");
1462 err_stat
= get_image_symbol(img_id
, real_name
,
1463 B_SYMBOL_TYPE_TEXT
, (void **)&init_fct
);
1466 if ((B_BAD_IMAGE_ID
== err_stat
) || (B_BAD_INDEX
== err_stat
)) {
1467 unload_add_on(img_id
);
1468 rb_loaderror("Failed to lookup Init function %.200s", file
);
1470 else if (B_NO_ERROR
!= err_stat
) {
1471 char errmsg
[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
1472 unload_add_on(img_id
);
1473 rb_loaderror(errmsg
, strerror(err_stat
), buf
);
1476 /* call module initialize function. */
1478 return (void*)img_id
;
1480 #endif /* __BEOS__*/
1482 #ifdef __MACOS__ /* Mac OS 9 or before */
1483 # define DLN_DEFINED
1487 CFragConnectionID connID
;
1489 char errMessage
[1024];
1490 Boolean isfolder
, didsomething
;
1493 CFragSymbolClass
class;
1495 char fullpath
[MAXPATHLEN
];
1497 strcpy(fullpath
, file
);
1499 /* resolve any aliases to find the real file */
1501 (void)FSMakeFSSpec(0, 0, fullpath
, &libspec
);
1502 err
= ResolveAliasFile(&libspec
, 1, &isfolder
, &didsomething
);
1504 rb_loaderror("Unresolved Alias - %s", file
);
1507 /* Load the fragment (or return the connID if it is already loaded */
1509 err
= GetDiskFragment(&libspec
, 0, 0, fragname
,
1510 kLoadCFrag
, &connID
, &mainAddr
,
1514 rb_loaderror("%s - %s",errMessage
, file
);
1517 /* Locate the address of the correct init function */
1519 err
= FindSymbol(connID
, buf
, &symAddr
, &class);
1521 rb_loaderror("Unresolved symbols - %s" , file
);
1523 init_fct
= (void (*)())symAddr
;
1525 return (void*)init_fct
;
1527 #endif /* __MACOS__ */
1532 void *handle
, (*init_fct
)();
1533 char *fname
, *p1
, *p2
;
1535 fname
= (char *)__alloca(strlen(file
)+1);
1537 if (p1
= strrchr(fname
,'/'))
1539 if (p2
= strrchr(fname
,'.'))
1542 if ((handle
= (void*)dlopen(fname
, 0)) == NULL
) {
1543 error
= dln_strerror();
1547 if ((init_fct
= (void (*)())dlsym(handle
, buf
)) == NULL
) {
1548 error
= DLN_ERROR();
1552 /* Call the init code */
1562 #endif /* USE_DLN_A_OUT */
1564 #if !defined(_AIX) && !defined(NeXT)
1566 rb_loaderror("%s - %s", error
, file
);
1569 #endif /* NO_DLN_LOAD */
1570 return 0; /* dummy return */
1573 static char *dln_find_1(const char *fname
, const char *path
, char *buf
, int size
, int exe_flag
);
1576 dln_find_exe_r(const char *fname
, const char *path
, char *buf
, int size
)
1579 path
= getenv(PATH_ENV
);
1583 #if defined(MSDOS) || defined(_WIN32) || defined(__human68k__) || defined(__MACOS__)
1584 path
= "/usr/local/bin;/usr/ucb;/usr/bin;/bin;.";
1586 path
= "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
1589 return dln_find_1(fname
, path
, buf
, size
, 1);
1593 dln_find_file_r(const char *fname
, const char *path
, char *buf
, int size
)
1596 if (!path
) path
= ".";
1597 return dln_find_1(fname
, path
, buf
, size
, 0);
1599 if (!path
) path
= ".";
1600 return _macruby_path_conv_posix_to_macos(dln_find_1(fname
, path
, buf
, size
, 0));
1604 static char fbuf
[MAXPATHLEN
];
1607 dln_find_exe(const char *fname
, const char *path
)
1609 return dln_find_exe_r(fname
, path
, fbuf
, sizeof(fbuf
));
1613 dln_find_file(const char *fname
, const char *path
)
1615 return dln_find_file_r(fname
, path
, fbuf
, sizeof(fbuf
));
1619 dln_find_1(const char *fname
, const char *path
, char *fbuf
, int size
,
1620 int exe_flag
/* non 0 if looking for executable. */)
1622 register const char *dp
;
1623 register const char *ep
;
1627 const char* mac_fullpath
;
1630 #define RETURN_IF(expr) if (expr) return (char *)fname;
1633 RETURN_IF(fname
[0] == '/');
1634 RETURN_IF(strncmp("./", fname
, 2) == 0 || strncmp("../", fname
, 3) == 0);
1635 RETURN_IF(exe_flag
&& strchr(fname
, '/'));
1637 RETURN_IF(fname
[0] == '\\');
1638 # ifdef DOSISH_DRIVE_LETTER
1639 RETURN_IF(strlen(fname
) > 2 && fname
[1] == ':');
1641 RETURN_IF(strncmp(".\\", fname
, 2) == 0 || strncmp("..\\", fname
, 3) == 0);
1642 RETURN_IF(exe_flag
&& strchr(fname
, '\\'));
1647 for (dp
= path
;; dp
= ++ep
) {
1652 /* extract a component */
1653 ep
= strchr(dp
, PATH_SEP
[0]);
1657 /* find the length of that component */
1663 ** If the length of the component is zero length,
1664 ** start from the current directory. If the
1665 ** component begins with "~", start from the
1666 ** user's $HOME environment variable. Otherwise
1667 ** take the path literally.
1670 if (*dp
== '~' && (l
== 1 ||
1677 home
= getenv("HOME");
1680 if ((fspace
-= i
) < 0)
1682 memcpy(bp
, home
, i
);
1689 if ((fspace
-= l
) < 0)
1695 /* add a "/" between directory and filename */
1700 /* now append the file name */
1702 if ((fspace
-= i
) < 0) {
1704 fprintf(stderr
, "openpath: pathname too long (ignored)\n");
1706 fprintf(stderr
, "\tDirectory \"%s\"\n", fbuf
);
1707 fprintf(stderr
, "\tFile \"%s\"\n", fname
);
1710 memcpy(bp
, fname
, i
+ 1);
1714 static const char extension
[][5] = {
1716 ".com", ".exe", ".bat",
1718 ".btm", ".sh", ".ksh", ".pl", ".sed",
1720 #elif defined(__EMX__) || defined(_WIN32)
1721 ".exe", ".com", ".cmd", ".bat",
1722 /* end of __EMX__ or _WIN32 */
1724 ".r", ".R", ".x", ".X", ".bat", ".BAT",
1730 for (j
= 0; j
< sizeof(extension
) / sizeof(extension
[0]); j
++) {
1731 if (fspace
< strlen(extension
[j
])) {
1732 fprintf(stderr
, "openpath: pathname too long (ignored)\n");
1733 fprintf(stderr
, "\tDirectory \"%.*s\"\n", (int) (bp
- fbuf
), fbuf
);
1734 fprintf(stderr
, "\tFile \"%s%s\"\n", fname
, extension
[j
]);
1737 strcpy(bp
+ i
, extension
[j
]);
1739 if (stat(fbuf
, &st
) == 0)
1742 if (mac_fullpath
= _macruby_exist_file_in_libdir_as_posix_name(fbuf
))
1743 return mac_fullpath
;
1749 #endif /* MSDOS or _WIN32 or __human68k__ or __EMX__ */
1752 if (stat(fbuf
, &st
) == 0) {
1753 if (exe_flag
== 0) return fbuf
;
1754 /* looking for executable */
1755 if (!S_ISDIR(st
.st_mode
) && eaccess(fbuf
, X_OK
) == 0)
1759 if (mac_fullpath
= _macruby_exist_file_in_libdir_as_posix_name(fbuf
)) {
1760 if (exe_flag
== 0) return mac_fullpath
;
1761 /* looking for executable */
1762 if (stat(mac_fullpath
, &st
) == 0) {
1763 if (!S_ISDIR(st
.st_mode
) && eaccess(mac_fullpath
, X_OK
) == 0)
1764 return mac_fullpath
;
1770 /* if not, and no other alternatives, life is bleak */
1775 /* otherwise try the next component in the search path */