summaryrefslogtreecommitdiff
path: root/dln.c
diff options
context:
space:
mode:
Diffstat (limited to 'dln.c')
-rw-r--r--dln.c98
1 files changed, 59 insertions, 39 deletions
diff --git a/dln.c b/dln.c
index 89f16b54f0..d3b03e3e87 100644
--- a/dln.c
+++ b/dln.c
@@ -25,6 +25,7 @@ static void dln_loaderror(const char *format, ...);
#endif
#include "dln.h"
#include "internal.h"
+#include "internal/box.h"
#include "internal/compilers.h"
#ifdef HAVE_STDLIB_H
@@ -76,11 +77,9 @@ void *xrealloc();
# include <unistd.h>
#endif
-bool
-dln_supported_p(void)
-{
- return true;
-}
+#ifndef UNREACHABLE_RETURN
+# define UNREACHABLE_RETURN(x) return (x)
+#endif
#ifndef dln_loaderror
static void
@@ -200,6 +199,7 @@ dln_strerror(char *message, size_t size)
}
return message;
}
+#define dln_strerror() dln_strerror(message, sizeof message)
#elif defined USE_DLN_DLOPEN
static const char *
dln_strerror(void)
@@ -289,7 +289,7 @@ dln_incompatible_func(void *handle, const char *funcname, void *const fp, const
void *ex = dlsym(handle, funcname);
if (!ex) return false;
if (ex == fp) return false;
-# if defined(HAVE_DLADDR)
+# if defined(HAVE_DLADDR) && !defined(__CYGWIN__)
Dl_info dli;
if (dladdr(ex, &dli)) {
*libname = dli.dli_fname;
@@ -344,13 +344,17 @@ dln_disable_dlclose(void)
#endif
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
-void *
-dln_open(const char *file, char *error, size_t size)
+static void *
+dln_open(const char *file)
{
static const char incompatible[] = "incompatible library version";
+ const char *error = NULL;
void *handle;
#if defined(_WIN32)
+# define DLN_DEFINED
+ char message[1024];
+
/* Convert the file path to wide char */
WCHAR *winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL);
if (!winfile) {
@@ -362,19 +366,20 @@ dln_open(const char *file, char *error, size_t size)
free(winfile);
if (!handle) {
- strlcpy(error, dln_strerror(error, size), size);
- return NULL;
+ error = dln_strerror();
+ goto failed;
}
# if defined(RUBY_EXPORT)
if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
FreeLibrary(handle);
- strlcpy(error, incompatible, size);
- return NULL;
+ error = incompatible;
+ goto failed;
}
# endif
#elif defined(USE_DLN_DLOPEN)
+# define DLN_DEFINED
# ifndef RTLD_LAZY
# define RTLD_LAZY 1
@@ -385,12 +390,16 @@ dln_open(const char *file, char *error, size_t size)
# ifndef RTLD_GLOBAL
# define RTLD_GLOBAL 0
# endif
+# ifndef RTLD_LOCAL
+# define RTLD_LOCAL 0 /* TODO: 0??? some systems (including libc) use 0x00100 for RTLD_GLOBAL, 0x00000 for RTLD_LOCAL */
+# endif
/* Load file */
- handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL);
+ int mode = rb_box_available() ? RTLD_LAZY|RTLD_LOCAL : RTLD_LAZY|RTLD_GLOBAL;
+ handle = dlopen(file, mode);
if (handle == NULL) {
- strlcpy(error, dln_strerror(), size);
- return NULL;
+ error = dln_strerror();
+ goto failed;
}
# if defined(RUBY_EXPORT)
@@ -412,15 +421,11 @@ dln_open(const char *file, char *error, size_t size)
libruby_name = tmp;
}
dlclose(handle);
-
if (libruby_name) {
- snprintf(error, size, "linked to incompatible %s - %s", libruby_name, file);
- }
- else {
- strlcpy(error, incompatible, size);
+ dln_loaderror("linked to incompatible %s - %s", libruby_name, file);
}
-
- return NULL;
+ error = incompatible;
+ goto failed;
}
}
}
@@ -428,9 +433,12 @@ dln_open(const char *file, char *error, size_t size)
#endif
return handle;
+
+ failed:
+ dln_loaderror("%s - %s", error, file);
}
-void *
+static void *
dln_sym(void *handle, const char *symbol)
{
#if defined(_WIN32)
@@ -440,7 +448,7 @@ dln_sym(void *handle, const char *symbol)
#endif
}
-static void *
+static uintptr_t
dln_sym_func(void *handle, const char *symbol)
{
void *func = dln_sym(handle, symbol);
@@ -449,14 +457,14 @@ dln_sym_func(void *handle, const char *symbol)
const char *error;
#if defined(_WIN32)
char message[1024];
- error = dln_strerror(message, sizeof(message));
+ error = dln_strerror();
#elif defined(USE_DLN_DLOPEN)
const size_t errlen = strlen(error = dln_strerror()) + 1;
error = memcpy(ALLOCA_N(char, errlen), error, errlen);
#endif
dln_loaderror("%s - %s", error, symbol);
}
- return func;
+ return (uintptr_t)func;
}
#define dln_sym_callable(rettype, argtype, handle, symbol) \
@@ -500,16 +508,11 @@ abi_check_enabled_p(void)
}
#endif
-void *
-dln_load(const char *file)
+static void *
+dln_load_and_init(const char *file, const char *init_fct_name)
{
-#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
- char error[1024];
- void *handle = dln_open(file, error, sizeof(error));
-
- if (handle == NULL) {
- dln_loaderror("%s - %s", error, file);
- }
+#if defined(DLN_DEFINED)
+ void *handle = dln_open(file);
#ifdef RUBY_DLN_CHECK_ABI
typedef unsigned long long abi_version_number;
@@ -520,18 +523,17 @@ dln_load(const char *file)
}
#endif
- char *init_fct_name;
- init_funcname(&init_fct_name, file);
-
/* Call the init code */
dln_sym_callable(void, (void), handle, init_fct_name)();
return handle;
#elif defined(_AIX)
+# define DLN_DEFINED
{
void (*init_fct)(void);
+ /* TODO: check - AIX's load system call will return the first/last symbol/function? */
init_fct = (void(*)(void))load((char*)file, 1, 0);
if (init_fct == NULL) {
aix_loaderror(file);
@@ -544,7 +546,25 @@ dln_load(const char *file)
}
#else
dln_notimplement();
+ UNREACHABLE_RETURN(0);
#endif
+}
- return 0; /* dummy return */
+void *
+dln_load(const char *file)
+{
+ return dln_load_feature(file, file);
+}
+
+void *
+dln_load_feature(const char *file, const char *fname)
+{
+#if defined(DLN_DEFINED)
+ char *init_fct_name;
+ init_funcname(&init_fct_name, fname);
+ return dln_load_and_init(file, init_fct_name);
+#else
+ dln_notimplement();
+ UNREACHABLE_RETURN(0);
+#endif
}