1 /**********************************************************************
6 created at: Tue Jan 18 17:05:06 JST 1994
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
10 **********************************************************************/
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
19 #define dln_notimplement --->>> dln not implemented <<<---
20 #define dln_memerror abort
22 static void dln_loaderror(const char *format
, ...);
26 #include "internal/compilers.h"
32 #if defined(HAVE_ALLOCA_H)
49 #define free(x) xfree(x)
53 #include "missing/file.h"
55 #include <sys/types.h>
59 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
62 #ifdef HAVE_SYS_PARAM_H
63 # include <sys/param.h>
66 # define MAXPATHLEN 1024
78 # if defined(HAVE_DLOPEN)
79 /* Mac OS X with dlopen (10.3 or later) */
80 # define MACOSX_DLOPEN
88 dln_loaderror(const char *format
, ...)
92 vfprintf(stderr
, format
, ap
);
98 #if defined(HAVE_DLOPEN) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
99 /* dynamic load with dlopen() */
100 # define USE_DLN_DLOPEN
103 #if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(NeXT) || defined(MACOSX_DYLD)
104 # define EXTERNAL_PREFIX "_"
106 # define EXTERNAL_PREFIX ""
108 #define FUNCNAME_PREFIX EXTERNAL_PREFIX"Init_"
110 #if defined __CYGWIN__ || defined DOSISH
111 #define isdirsep(x) ((x) == '/' || (x) == '\\')
113 #define isdirsep(x) ((x) == '/')
117 init_funcname_len(const char **file
)
119 const char *p
= *file
, *base
, *dot
= NULL
;
121 /* Load the file as an object one */
122 for (base
= p
; *p
; p
++) { /* Find position of last '/' */
123 if (*p
== '.' && !dot
) dot
= p
;
124 if (isdirsep(*p
)) base
= p
+1, dot
= NULL
;
127 /* Delete suffix if it exists */
128 return (dot
? dot
: p
) - base
;
131 static const char funcname_prefix
[sizeof(FUNCNAME_PREFIX
) - 1] = FUNCNAME_PREFIX
;
133 #define init_funcname(buf, file) do {\
134 const char *base = (file);\
135 const size_t flen = init_funcname_len(&base);\
136 const size_t plen = sizeof(funcname_prefix);\
137 char *const tmp = ALLOCA_N(char, plen+flen+1);\
141 memcpy(tmp, funcname_prefix, plen);\
142 memcpy(tmp+plen, base, flen);\
143 tmp[plen+flen] = '\0';\
147 #ifdef USE_DLN_DLOPEN
157 #include <ctype.h> /* for isdigit() */
158 #include <errno.h> /* for global errno */
163 #if NS_TARGET_MAJOR < 4
164 #include <mach-o/rld.h>
166 #include <mach-o/dyld.h>
167 #ifndef NSLINKMODULE_OPTION_BINDNOW
168 #define NSLINKMODULE_OPTION_BINDNOW 1
173 #include <mach-o/dyld.h>
179 #include <imagehlp.h>
184 dln_strerror(char *message
, size_t size
)
186 int error
= GetLastError();
188 size_t len
= snprintf(message
, size
, "%d: ", error
);
190 #define format_message(sublang) FormatMessage(\
191 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
192 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
193 message + len, size - len, NULL)
194 if (format_message(SUBLANG_ENGLISH_US
) == 0)
195 format_message(SUBLANG_DEFAULT
);
196 for (p
= message
+ len
; *p
; p
++) {
197 if (*p
== '\n' || *p
== '\r')
202 #define dln_strerror() dln_strerror(message, sizeof message)
203 #elif defined USE_DLN_DLOPEN
207 return (char*)dlerror();
213 aix_loaderror(const char *pathname
)
215 char *message
[1024], errbuf
[1024];
217 #define ERRBUF_APPEND(s) strlcat(errbuf, (s), sizeof(errbuf))
218 snprintf(errbuf
, sizeof(errbuf
), "load failed - %s. ", pathname
);
220 if (loadquery(L_GETMESSAGES
, &message
[0], sizeof(message
)) != -1) {
221 ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t");
222 ERRBUF_APPEND("/usr/sbin/execerror ruby ");
223 for (i
=0; message
[i
]; i
++) {
225 ERRBUF_APPEND(message
[i
]);
226 ERRBUF_APPEND("\" ");
231 ERRBUF_APPEND(strerror(errno
));
232 ERRBUF_APPEND("[loadquery failed]");
234 dln_loaderror("%s", errbuf
);
238 #if defined _WIN32 && defined RUBY_EXPORT
239 HANDLE
rb_libruby_handle(void);
242 rb_w32_check_imported(HMODULE ext
, HMODULE mine
)
245 const IMAGE_IMPORT_DESCRIPTOR
*desc
;
247 desc
= ImageDirectoryEntryToData(ext
, TRUE
, IMAGE_DIRECTORY_ENTRY_IMPORT
, &size
);
250 PIMAGE_THUNK_DATA pint
= (PIMAGE_THUNK_DATA
)((char *)ext
+ desc
->Characteristics
);
251 PIMAGE_THUNK_DATA piat
= (PIMAGE_THUNK_DATA
)((char *)ext
+ desc
->FirstThunk
);
252 for (; piat
->u1
.Function
; piat
++, pint
++) {
253 static const char prefix
[] = "rb_";
254 PIMAGE_IMPORT_BY_NAME pii
;
257 if (IMAGE_SNAP_BY_ORDINAL(pint
->u1
.Ordinal
)) continue;
258 pii
= (PIMAGE_IMPORT_BY_NAME
)((char *)ext
+ (size_t)pint
->u1
.AddressOfData
);
259 name
= (const char *)pii
->Name
;
260 if (strncmp(name
, prefix
, sizeof(prefix
) - 1) == 0) {
261 FARPROC addr
= GetProcAddress(mine
, name
);
262 if (addr
) return (FARPROC
)piat
->u1
.Function
== addr
;
271 #if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
272 #define translit_separator(src) do { \
273 char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
275 *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
280 #define translit_separator(str) (void)(str)
283 #ifdef USE_DLN_DLOPEN
284 # include "ruby/internal/stdbool.h"
285 # include "internal/warnings.h"
286 COMPILER_WARNING_PUSH
287 #if defined(__clang__) || GCC_VERSION_SINCE(4, 2, 0)
288 COMPILER_WARNING_IGNORED(-Wpedantic
)
291 dln_incompatible_library_p(void *handle
)
293 void *ex
= dlsym(handle
, EXTERNAL_PREFIX
"ruby_xmalloc");
294 void *const fp
= (void *)ruby_xmalloc
;
295 return ex
&& ex
!= fp
;
301 dln_load(const char *file
)
303 #if (defined _WIN32 || defined USE_DLN_DLOPEN) && defined RUBY_EXPORT
304 static const char incompatible
[] = "incompatible library version";
306 #if defined _WIN32 || defined USE_DLN_DLOPEN
307 const char *error
= 0;
314 void (*init_fct
)(void);
317 /* Load the file as an object one */
318 init_funcname(&buf
, file
);
320 /* Convert the file path to wide char */
321 winfile
= rb_w32_mbstr_to_wstr(CP_UTF8
, file
, -1, NULL
);
327 handle
= LoadLibraryW(winfile
);
331 error
= dln_strerror();
335 #if defined _WIN32 && defined RUBY_EXPORT
336 if (!rb_w32_check_imported(handle
, rb_libruby_handle())) {
338 error
= incompatible
;
343 if ((init_fct
= (void(*)(void))GetProcAddress(handle
, buf
)) == NULL
) {
344 dln_loaderror("%s - %s\n%s", dln_strerror(), buf
, file
);
347 /* Call the init code */
352 /* Load the file as an object one */
353 init_funcname(&buf
, file
);
354 translit_separator(file
);
356 #ifdef USE_DLN_DLOPEN
360 void (*init_fct
)(void);
369 # define RTLD_GLOBAL 0
373 if ((handle
= (void*)dlopen(file
, RTLD_LAZY
|RTLD_GLOBAL
)) == NULL
) {
374 error
= dln_strerror();
377 # if defined RUBY_EXPORT
379 if (dln_incompatible_library_p(handle
)) {
381 # if defined __APPLE__ && \
382 defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
383 (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11)
384 /* dlclose() segfaults */
385 rb_fatal("%s - %s", incompatible
, file
);
388 error
= incompatible
;
395 init_fct
= (void(*)(void))(VALUE
)dlsym(handle
, buf
);
396 if (init_fct
== NULL
) {
397 const size_t errlen
= strlen(error
= dln_strerror()) + 1;
398 error
= memcpy(ALLOCA_N(char, errlen
), error
, errlen
);
402 /* Call the init code */
407 #endif /* USE_DLN_DLOPEN */
414 void (*init_fct
)(void);
416 flags
= BIND_DEFERRED
;
417 lib
= shl_load(file
, flags
, 0);
420 dln_loaderror("%s - %s", strerror(errno
), file
);
422 shl_findsym(&lib
, buf
, TYPE_PROCEDURE
, (void*)&init_fct
);
423 if (init_fct
== NULL
) {
424 shl_findsym(&lib
, buf
, TYPE_UNDEFINED
, (void*)&init_fct
);
425 if (init_fct
== NULL
) {
427 dln_loaderror("%s - %s", strerror(ENOSYM
), file
);
438 void (*init_fct
)(void);
440 init_fct
= (void(*)(void))load((char*)file
, 1, 0);
441 if (init_fct
== NULL
) {
444 if (loadbind(0, (void*)dln_load
, (void*)init_fct
) == -1) {
448 return (void*)init_fct
;
452 #if defined(MACOSX_DYLD)
454 /*----------------------------------------------------
455 By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
458 Yu tomoak-i@is.aist-nara.ac.jp,
459 Mi hisho@tasihara.nest.or.jp,
460 sunshine@sunshineco.com,
461 and... Miss ARAI Akino(^^;)
462 ----------------------------------------------------*/
465 NSObjectFileImage obj_file
; /* handle, but not use it */
466 /* "file" is module file name .
467 "buf" is pointer to initial function name with "_" . */
469 void (*init_fct
)(void);
472 dyld_result
= NSCreateObjectFileImageFromFile(file
, &obj_file
);
474 if (dyld_result
!= NSObjectFileImageSuccess
) {
475 dln_loaderror("Failed to load %.200s", file
);
478 NSLinkModule(obj_file
, file
, NSLINKMODULE_OPTION_BINDNOW
);
480 /* lookup the initial function */
481 if (!NSIsSymbolNameDefined(buf
)) {
482 dln_loaderror("Failed to lookup Init function %.200s",file
);
484 init_fct
= NSAddressOfSymbol(NSLookupAndBindSymbol(buf
));
487 return (void*)init_fct
;
496 #if defined(_WIN32) || defined(USE_DLN_DLOPEN)
498 dln_loaderror("%s - %s", error
, file
);
501 return 0; /* dummy return */