Skip to content

Commit

Permalink
dln_symbol: make dln_sym accessible Ruby internally
Browse files Browse the repository at this point in the history
The symbol resolved by dln_symbol will eventually be passed to
extensions. The error handling of dln_sym is also separated into
dln_sym_func because the new call resolving symbols will not raise
LoadError.
  • Loading branch information
tagomoris authored and nobu committed Dec 14, 2023
1 parent 35a6b69 commit 8a37df8
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 21 deletions.
70 changes: 49 additions & 21 deletions dln.c
Expand Up @@ -419,33 +419,63 @@ dln_open(const char *file)
static void *
dln_sym(void *handle, const char *symbol)
{
void *func;
const char *error;

#if defined(_WIN32)
char message[1024];
return GetProcAddress(handle, symbol);
#elif defined(USE_DLN_DLOPEN)
return dlsym(handle, symbol);
#endif
}

static void *
dln_sym_func(void *handle, const char *symbol)
{
void *func = dln_sym(handle, symbol);

func = GetProcAddress(handle, symbol);
if (func == NULL) {
const char *error;
#if defined(_WIN32)
char message[1024];
error = dln_strerror();
goto failed;
}

#elif defined(USE_DLN_DLOPEN)
func = dlsym(handle, symbol);
if (func == NULL) {
const size_t errlen = strlen(error = dln_strerror()) + 1;
error = memcpy(ALLOCA_N(char, errlen), error, errlen);
goto failed;
}
#endif

dln_loaderror("%s - %s", error, symbol);
}
return func;

failed:
dln_loaderror("%s - %s", error, symbol);
}

#define dln_sym_callable(rettype, argtype, handle, symbol) \
(*(rettype (*)argtype)dln_sym_func(handle, symbol))
#endif

void *
dln_symbol(void *handle, const char *symbol)
{
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
if (EXTERNAL_PREFIX[0]) {
const size_t symlen = strlen(symbol);
char *const tmp = ALLOCA_N(char, symlen + sizeof(EXTERNAL_PREFIX));
if (!tmp) dln_memerror();
memcpy(tmp, EXTERNAL_PREFIX, sizeof(EXTERNAL_PREFIX) - 1);
memcpy(tmp + sizeof(EXTERNAL_PREFIX) - 1, symbol, symlen + 1);
symbol = tmp;
}
if (handle == NULL) {
# if defined(USE_DLN_DLOPEN)
handle = dlopen(NULL, 0);
# elif defined(_WIN32) && defined(RUBY_EXPORT)
handle = rb_libruby_handle();
# else
return NULL;
# endif
}
return dln_sym(handle, symbol);
#else
return NULL;
#endif
}


#if defined(RUBY_DLN_CHECK_ABI) && defined(USE_DLN_DLOPEN)
static bool
Expand All @@ -464,20 +494,18 @@ dln_load(const char *file)

#ifdef RUBY_DLN_CHECK_ABI
typedef unsigned long long abi_version_number;
typedef abi_version_number abi_version_func(void);
abi_version_func *abi_version_fct = (abi_version_func *)dln_sym(handle, EXTERNAL_PREFIX "ruby_abi_version");
abi_version_number binary_abi_version = (*abi_version_fct)();
abi_version_number binary_abi_version =
dln_sym_callable(abi_version_number, (void), handle, EXTERNAL_PREFIX "ruby_abi_version")();
if (binary_abi_version != ruby_abi_version() && abi_check_enabled_p()) {
dln_loaderror("incompatible ABI version of binary - %s", file);
}
#endif

char *init_fct_name;
init_funcname(&init_fct_name, file);
void (*init_fct)(void) = (void(*)(void))dln_sym(handle, init_fct_name);

/* Call the init code */
(*init_fct)();
dln_sym_callable(void, (void), handle, init_fct_name)();

return handle;

Expand Down
1 change: 1 addition & 0 deletions dln.h
Expand Up @@ -25,6 +25,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
char *dln_find_exe_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
char *dln_find_file_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
void *dln_load(const char*);
void *dln_symbol(void*,const char*);

RUBY_SYMBOL_EXPORT_END

Expand Down
9 changes: 9 additions & 0 deletions dmydln.c
Expand Up @@ -8,3 +8,12 @@ dln_load(const char *file)

UNREACHABLE_RETURN(NULL);
}

NORETURN(void *dln_symbol(void*,const char*));
void*
dln_symbol(void *handle, const char *symbol)
{
rb_loaderror("this executable file can't load extension libraries");

UNREACHABLE_RETURN(NULL);
}

0 comments on commit 8a37df8

Please sign in to comment.