diff options
Diffstat (limited to 'dln.c')
| -rw-r--r-- | dln.c | 98 |
1 files changed, 59 insertions, 39 deletions
@@ -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 } |
