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"
29#include "internal/namespace.h"
35#if defined(HAVE_ALLOCA_H)
46# include <AvailabilityMacros.h>
56#define free(x) xfree(x)
60#include "missing/file.h"
66# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
69#ifdef HAVE_SYS_PARAM_H
70# include <sys/param.h>
73# define MAXPATHLEN 1024
82dln_loaderror(
const char *format, ...)
86 vfprintf(stderr, format, ap);
92#if defined(HAVE_DLOPEN) && !defined(_AIX) && !defined(_UNICOSMP)
94# define USE_DLN_DLOPEN
97#if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(NeXT)
98# define EXTERNAL_PREFIX "_"
100# define EXTERNAL_PREFIX ""
102#define FUNCNAME_PREFIX EXTERNAL_PREFIX"Init_"
104#if defined __CYGWIN__ || defined DOSISH
105#define isdirsep(x) ((x) == '/' || (x) == '\\')
107#define isdirsep(x) ((x) == '/')
110#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
117init_funcname_len(const char *file)
119 const char *p = file, *base, *dot = NULL;
122 for (base = p; *p; p++) {
123 if (*p ==
'.' && !dot) dot = p;
124 if (isdirsep(*p)) base = p+1, dot = NULL;
127 const size_t len = (dot ? dot : p) - base;
132concat_funcname(
char *buf,
const char *prefix,
size_t plen,
const struct string_part base)
137 memcpy(buf, prefix, plen);
138 memcpy(buf + plen, base.ptr, base.len);
139 buf[plen + base.len] =
'\0';
143#define build_funcname(prefix, buf, file) do {\
144 const struct string_part f = init_funcname_len(file);\
145 const size_t plen = sizeof(prefix "") - 1;\
146 *(buf) = concat_funcname(ALLOCA_N(char, plen+f.len+1), prefix, plen, f);\
149#define init_funcname(buf, file) build_funcname(FUNCNAME_PREFIX, buf, file)
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
180dln_strerror(
char *message,
size_t size)
182 int error = GetLastError();
184 size_t len = snprintf(message, size,
"%d: ", error);
186#define format_message(sublang) FormatMessage(\
187 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
188 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
189 message + len, size - len, NULL)
190 if (format_message(SUBLANG_ENGLISH_US) == 0)
191 format_message(SUBLANG_DEFAULT);
192 for (p = message +
len; *p; p++) {
193 if (*p ==
'\n' || *p ==
'\r')
198#define dln_strerror() dln_strerror(message, sizeof message)
199#elif defined USE_DLN_DLOPEN
203 return (
char*)dlerror();
209aix_loaderror(
const char *pathname)
211 char *message[1024], errbuf[1024];
213#define ERRBUF_APPEND(s) strlcat(errbuf, (s), sizeof(errbuf))
214 snprintf(errbuf,
sizeof(errbuf),
"load failed - %s. ", pathname);
216 if (loadquery(L_GETMESSAGES, &message[0],
sizeof(message)) != -1) {
217 ERRBUF_APPEND(
"Please issue below command for detailed reasons:\n\t");
218 ERRBUF_APPEND(
"/usr/sbin/execerror ruby ");
219 for (i=0; message[i]; i++) {
221 ERRBUF_APPEND(message[i]);
222 ERRBUF_APPEND(
"\" ");
227 ERRBUF_APPEND(strerror(
errno));
228 ERRBUF_APPEND(
"[loadquery failed]");
230 dln_loaderror(
"%s", errbuf);
234#if defined _WIN32 && defined RUBY_EXPORT
235HANDLE rb_libruby_handle(
void);
238rb_w32_check_imported(HMODULE ext, HMODULE mine)
241 const IMAGE_IMPORT_DESCRIPTOR *desc;
243 desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
246 PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((
char *)ext + desc->Characteristics);
247 PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((
char *)ext + desc->FirstThunk);
248 for (; piat->u1.Function; piat++, pint++) {
249 static const char prefix[] =
"rb_";
250 PIMAGE_IMPORT_BY_NAME pii;
253 if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal))
continue;
254 pii = (PIMAGE_IMPORT_BY_NAME)((
char *)ext + (size_t)pint->u1.AddressOfData);
255 name = (
const char *)pii->Name;
256 if (strncmp(name, prefix,
sizeof(prefix) - 1) == 0) {
257 FARPROC addr = GetProcAddress(mine, name);
258 if (addr)
return (FARPROC)piat->u1.Function == addr;
267#if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
268#define translit_separator(src) do { \
269 char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
271 *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
276#define translit_separator(str) (void)(str)
281# include "internal/warnings.h"
283dln_incompatible_func(
void *handle,
const char *funcname,
void *
const fp,
const char **libname)
285 void *ex = dlsym(handle, funcname);
286 if (!ex)
return false;
287 if (ex == fp)
return false;
288# if defined(HAVE_DLADDR) && !defined(__CYGWIN__)
290 if (dladdr(ex, &dli)) {
291 *libname = dli.dli_fname;
298#if defined(__clang__) || GCC_VERSION_SINCE(4, 2, 0)
299COMPILER_WARNING_IGNORED(-Wpedantic)
302dln_incompatible_library_p(
void *handle,
const char **libname)
304#define check_func(func) \
305 if (dln_incompatible_func(handle, EXTERNAL_PREFIX #func, (void *)&func, libname)) \
307 check_func(ruby_xmalloc);
313#if !defined(MAC_OS_X_VERSION_MIN_REQUIRED)
315# define dln_disable_dlclose() false
317#elif !defined(MAC_OS_X_VERSION_10_11) || \
318 (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11)
320# define dln_disable_dlclose() true
322#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
324# define dln_disable_dlclose() false
328# include <sys/sysctl.h>
331dln_disable_dlclose(
void)
333 int mib[] = {CTL_KERN, KERN_OSREV};
335 size_t size =
sizeof(rev);
336 if (sysctl(mib, numberof(mib), &rev, &size, NULL, 0))
return true;
337 if (rev < MAC_OS_X_VERSION_10_11)
return true;
342#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
344dln_open(
const char *file)
346 static const char incompatible[] =
"incompatible library version";
347 const char *error = NULL;
354 WCHAR *winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL);
360 handle = LoadLibraryW(winfile);
364 error = dln_strerror();
368# if defined(RUBY_EXPORT)
369 if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
371 error = incompatible;
376#elif defined(USE_DLN_DLOPEN)
385# define RTLD_GLOBAL 0
392 int mode = rb_namespace_available() ? RTLD_LAZY|RTLD_LOCAL : RTLD_LAZY|RTLD_GLOBAL;
393 handle = dlopen(file, mode);
394 if (handle == NULL) {
395 error = dln_strerror();
399# if defined(RUBY_EXPORT)
401 const char *libruby_name = NULL;
402 if (dln_incompatible_library_p(handle, &libruby_name)) {
403 if (dln_disable_dlclose()) {
406 dln_fatalerror(
"linked to incompatible %s - %s", libruby_name, file);
408 dln_fatalerror(
"%s - %s", incompatible, file);
412 const size_t len = strlen(libruby_name);
414 if (tmp) memcpy(tmp, libruby_name,
len + 1);
419 dln_loaderror(
"linked to incompatible %s - %s", libruby_name, file);
421 error = incompatible;
432 dln_loaderror(
"%s - %s", error, file);
436dln_sym(
void *handle,
const char *symbol)
439 return GetProcAddress(handle, symbol);
440#elif defined(USE_DLN_DLOPEN)
441 return dlsym(handle, symbol);
446dln_sym_func(
void *handle,
const char *symbol)
448 void *func = dln_sym(handle, symbol);
454 error = dln_strerror();
455#elif defined(USE_DLN_DLOPEN)
456 const size_t errlen = strlen(error = dln_strerror()) + 1;
457 error = memcpy(
ALLOCA_N(
char, errlen), error, errlen);
459 dln_loaderror(
"%s - %s", error, symbol);
461 return (uintptr_t)func;
464#define dln_sym_callable(rettype, argtype, handle, symbol) \
465 (*(rettype (*)argtype)dln_sym_func(handle, symbol))
469dln_symbol(
void *handle,
const char *symbol)
471#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
472 if (EXTERNAL_PREFIX[0]) {
473 const size_t symlen = strlen(symbol);
474 char *
const tmp =
ALLOCA_N(
char, symlen +
sizeof(EXTERNAL_PREFIX));
475 if (!tmp) dln_memerror();
476 memcpy(tmp, EXTERNAL_PREFIX,
sizeof(EXTERNAL_PREFIX) - 1);
477 memcpy(tmp +
sizeof(EXTERNAL_PREFIX) - 1, symbol, symlen + 1);
480 if (handle == NULL) {
481# if defined(USE_DLN_DLOPEN)
482 handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
483# elif defined(_WIN32)
484 handle = rb_libruby_handle();
489 return dln_sym(handle, symbol);
496#if defined(RUBY_DLN_CHECK_ABI) && defined(USE_DLN_DLOPEN)
498abi_check_enabled_p(
void)
500 const char *val = getenv(
"RUBY_ABI_CHECK");
501 return val == NULL || !(val[0] ==
'0' && val[1] ==
'\0');
506dln_load_and_init(
const char *file,
const char *init_fct_name)
508#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
509 void *handle = dln_open(file);
511#ifdef RUBY_DLN_CHECK_ABI
512 typedef unsigned long long abi_version_number;
513 abi_version_number binary_abi_version =
514 dln_sym_callable(abi_version_number, (
void), handle, EXTERNAL_PREFIX
"ruby_abi_version")();
515 if (binary_abi_version != RUBY_ABI_VERSION && abi_check_enabled_p()) {
516 dln_loaderror(
"incompatible ABI version of binary - %s", file);
521 dln_sym_callable(
void, (
void), handle, init_fct_name)();
527 void (*init_fct)(void);
530 init_fct = (void(*)(void))load((
char*)file, 1, 0);
531 if (init_fct == NULL) {
534 if (loadbind(0, (
void*)dln_load, (
void*)init_fct) == -1) {
538 return (
void*)init_fct;
548dln_load(
const char *file)
550#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
552 init_funcname(&init_fct_name, file);
553 return dln_load_and_init(file, init_fct_name);
561dln_load_feature(
const char *file,
const char *fname)
563#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
565 init_funcname(&init_fct_name, fname);
566 return dln_load_and_init(file, init_fct_name);
#define xrealloc
Old name of ruby_xrealloc.
#define xmalloc
Old name of ruby_xmalloc.
#define xcalloc
Old name of ruby_xcalloc.
int len
Length of the buffer.
#define ALLOCA_N(type, n)
#define errno
Ractor-aware version of errno.