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#define dln_fatalerror rb_fatal
20#define dln_notimplement --->>> dln not implemented <<<---
21#define dln_memerror abort
23static void dln_loaderror(
const char *format, ...);
24#define dln_fatalerror dln_loaderror
28#include "internal/compilers.h"
34#if defined(HAVE_ALLOCA_H)
45# include <AvailabilityMacros.h>
55#define free(x) xfree(x)
59#include "missing/file.h"
65# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
68#ifdef HAVE_SYS_PARAM_H
69# include <sys/param.h>
72# define MAXPATHLEN 1024
81dln_loaderror(
const char *format, ...)
85 vfprintf(stderr, format, ap);
91#if defined(HAVE_DLOPEN) && !defined(_AIX) && !defined(_UNICOSMP)
93# define USE_DLN_DLOPEN
96#if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(NeXT)
97# define EXTERNAL_PREFIX "_"
99# define EXTERNAL_PREFIX ""
101#define FUNCNAME_PREFIX EXTERNAL_PREFIX"Init_"
103#if defined __CYGWIN__ || defined DOSISH
104#define isdirsep(x) ((x) == '/' || (x) == '\\')
106#define isdirsep(x) ((x) == '/')
109#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
111init_funcname_len(
const char **file)
113 const char *p = *file, *base, *dot = NULL;
116 for (base = p; *p; p++) {
117 if (*p ==
'.' && !dot) dot = p;
118 if (isdirsep(*p)) base = p+1, dot = NULL;
122 return (dot ? dot : p) - base;
125static const char funcname_prefix[
sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX;
127#define init_funcname(buf, file) do {\
128 const char *base = (file);\
129 const size_t flen = init_funcname_len(&base);\
130 const size_t plen = sizeof(funcname_prefix);\
131 char *const tmp = ALLOCA_N(char, plen+flen+1);\
135 memcpy(tmp, funcname_prefix, plen);\
136 memcpy(tmp+plen, base, flen);\
137 tmp[plen+flen] = '\0';\
153#if NS_TARGET_MAJOR < 4
154#include <mach-o/rld.h>
156#include <mach-o/dyld.h>
157#ifndef NSLINKMODULE_OPTION_BINDNOW
158#define NSLINKMODULE_OPTION_BINDNOW 1
170dln_strerror(
char *message,
size_t size)
172 int error = GetLastError();
174 size_t len = snprintf(message, size,
"%d: ", error);
176#define format_message(sublang) FormatMessage(\
177 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
178 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
179 message + len, size - len, NULL)
180 if (format_message(SUBLANG_ENGLISH_US) == 0)
181 format_message(SUBLANG_DEFAULT);
182 for (p = message + len; *p; p++) {
183 if (*p ==
'\n' || *p ==
'\r')
188#define dln_strerror() dln_strerror(message, sizeof message)
189#elif defined USE_DLN_DLOPEN
193 return (
char*)dlerror();
199aix_loaderror(
const char *pathname)
201 char *message[1024], errbuf[1024];
203#define ERRBUF_APPEND(s) strlcat(errbuf, (s), sizeof(errbuf))
204 snprintf(errbuf,
sizeof(errbuf),
"load failed - %s. ", pathname);
206 if (loadquery(L_GETMESSAGES, &message[0],
sizeof(message)) != -1) {
207 ERRBUF_APPEND(
"Please issue below command for detailed reasons:\n\t");
208 ERRBUF_APPEND(
"/usr/sbin/execerror ruby ");
209 for (i=0; message[i]; i++) {
211 ERRBUF_APPEND(message[i]);
212 ERRBUF_APPEND(
"\" ");
217 ERRBUF_APPEND(strerror(errno));
218 ERRBUF_APPEND(
"[loadquery failed]");
220 dln_loaderror(
"%s", errbuf);
224#if defined _WIN32 && defined RUBY_EXPORT
225HANDLE rb_libruby_handle(
void);
228rb_w32_check_imported(HMODULE ext, HMODULE mine)
231 const IMAGE_IMPORT_DESCRIPTOR *desc;
233 desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
236 PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((
char *)ext + desc->Characteristics);
237 PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((
char *)ext + desc->FirstThunk);
238 for (; piat->u1.Function; piat++, pint++) {
239 static const char prefix[] =
"rb_";
240 PIMAGE_IMPORT_BY_NAME pii;
243 if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal))
continue;
244 pii = (PIMAGE_IMPORT_BY_NAME)((
char *)ext + (size_t)pint->u1.AddressOfData);
245 name = (
const char *)pii->Name;
246 if (strncmp(name, prefix,
sizeof(prefix) - 1) == 0) {
247 FARPROC addr = GetProcAddress(mine, name);
248 if (addr)
return (FARPROC)piat->u1.Function == addr;
257#if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
258#define translit_separator(src) do { \
259 char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
261 *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
266#define translit_separator(str) (void)(str)
271# include "internal/warnings.h"
273dln_incompatible_func(
void *handle,
const char *funcname,
void *
const fp,
const char **libname)
276 void *ex = dlsym(handle, funcname);
277 if (!ex)
return false;
278 if (ex == fp)
return false;
279 if (dladdr(ex, &dli)) {
280 *libname = dli.dli_fname;
286#if defined(__clang__) || GCC_VERSION_SINCE(4, 2, 0)
287COMPILER_WARNING_IGNORED(-Wpedantic)
290dln_incompatible_library_p(
void *handle,
const char **libname)
292#define check_func(func) \
293 if (dln_incompatible_func(handle, EXTERNAL_PREFIX #func, (void *)&func, libname)) \
295 check_func(ruby_xmalloc);
301#if !defined(MAC_OS_X_VERSION_MIN_REQUIRED)
303# define dln_disable_dlclose() false
305#elif !defined(MAC_OS_X_VERSION_10_11) || \
306 (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11)
308# define dln_disable_dlclose() true
310#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
312# define dln_disable_dlclose() false
316# include <sys/sysctl.h>
319dln_disable_dlclose(
void)
321 int mib[] = {CTL_KERN, KERN_OSREV};
323 size_t size =
sizeof(rev);
324 if (sysctl(mib, numberof(mib), &rev, &size, NULL, 0))
return true;
325 if (rev < MAC_OS_X_VERSION_10_11)
return true;
330#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
332dln_open(
const char *file)
334 static const char incompatible[] =
"incompatible library version";
335 const char *error = NULL;
342 WCHAR *winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL);
348 handle = LoadLibraryW(winfile);
352 error = dln_strerror();
356# if defined(RUBY_EXPORT)
357 if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
359 error = incompatible;
364#elif defined(USE_DLN_DLOPEN)
373# define RTLD_GLOBAL 0
377 handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL);
378 if (handle == NULL) {
379 error = dln_strerror();
383# if defined(RUBY_EXPORT)
385 const char *libruby_name = NULL;
386 if (dln_incompatible_library_p(handle, &libruby_name)) {
387 if (dln_disable_dlclose()) {
390 dln_fatalerror(
"linked to incompatible %s - %s", libruby_name, file);
392 dln_fatalerror(
"%s - %s", incompatible, file);
397 dln_loaderror(
"linked to incompatible %s - %s", libruby_name, file);
399 error = incompatible;
410 dln_loaderror(
"%s - %s", error, file);
414dln_sym(
void *handle,
const char *symbol)
422 func = GetProcAddress(handle, symbol);
424 error = dln_strerror();
428#elif defined(USE_DLN_DLOPEN)
429 func = dlsym(handle, symbol);
431 const size_t errlen = strlen(error = dln_strerror()) + 1;
432 error = memcpy(
ALLOCA_N(
char, errlen), error, errlen);
440 dln_loaderror(
"%s - %s", error, symbol);
444#if defined(RUBY_DLN_CHECK_ABI) && defined(USE_DLN_DLOPEN)
446abi_check_enabled_p(
void)
448 const char *val = getenv(
"RUBY_ABI_CHECK");
449 return val == NULL || !(val[0] ==
'0' && val[1] ==
'\0');
454dln_load(
const char *file)
456#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
457 void *handle = dln_open(file);
459#ifdef RUBY_DLN_CHECK_ABI
460 unsigned long long (*abi_version_fct)(void) = (
unsigned long long(*)(void))dln_sym(handle,
"ruby_abi_version");
461 unsigned long long binary_abi_version = (*abi_version_fct)();
462 if (binary_abi_version != ruby_abi_version() && abi_check_enabled_p()) {
463 dln_loaderror(
"incompatible ABI version of binary - %s", file);
468 init_funcname(&init_fct_name, file);
469 void (*init_fct)(void) = (
void(*)(void))dln_sym(handle, init_fct_name);
478 void (*init_fct)(void);
480 init_fct = (void(*)(void))load((
char*)file, 1, 0);
481 if (init_fct == NULL) {
484 if (loadbind(0, (
void*)dln_load, (
void*)init_fct) == -1) {
488 return (
void*)init_fct;
#define xrealloc
Old name of ruby_xrealloc.
#define xmalloc
Old name of ruby_xmalloc.
#define xcalloc
Old name of ruby_xcalloc.
#define ALLOCA_N(type, n)