Skip to content

Commit

Permalink
Add crossplatform dynamic library loading related stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Kotb committed Jul 2, 2023
1 parent 5066a29 commit 47d822f
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 0 deletions.
182 changes: 182 additions & 0 deletions src/rvdl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/*
rvdl.c - Dynamic library related stuff implementation
Copyright (C) 2023 0xCatPKG <github.com/0xCatPKG>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include <string.h>
#include <stdio.h>

#include "rvdl.h"
#include "utils.h"

#ifndef NO_DLOPEN

#ifdef _WIN32
#include <windows.h>
#include <libloaderapi.h>
#else
#include <dlfcn.h>
#endif

rvdlib* rvdlib_open(const char* path, uint16_t flags)
{
int oflags = 0;
void* dl_handle = NULL;

#ifdef _WIN32
HMODULE win_handle = GetModuleHandleA((LPSTR)path);
if (!win_handle)
{
if (flags & RVDLIB_NOLOAD)
{
oflags |= LOAD_LIBRARY_AS_DATAFILE;
}
win_handle = LoadLibraryExA((LPSTR)path, NULL, (DWORD)oflags);
if (!win_handle) {
rvvm_error("rvdlib_open failed");
return NULL;
}
dl_handle = (void*)win_handle;
}

#else
if (flags & RVDLIB_NOW)
{
oflags = RTLD_NOW;
} else {
oflags = RTLD_LAZY;
}

if (flags & RVDLIB_NODELETE) {
oflags |= RTLD_NODELETE;
}

if (flags & RVDLIB_NOLOAD) {
oflags |= RTLD_NOLOAD;
}

dl_handle = dlopen(path, oflags);
if (!dl_handle) {

rvvm_error("rvdlib_open failed: %s", dlerror());
return NULL;
}
#endif
rvdlib* handle = safe_new_obj(rvdlib);
handle->library_handle = dl_handle;
strcpy(handle->library_path, path);
handle->flags = flags;
return handle;
}

void rvdlib_close(rvdlib* handle)
{
if (!handle)
{
rvvm_error("rvdlib_close: Invalid dynamic library handle");
return;
}

#ifdef _WIN32
if (!(handle->flags & RVDLIB_NODELETE))
{
if (!FreeLibrary((HMODULE)handle->library_handle))
{
rvvm_error("rvdlib_close failed");
}
}
#else
if (dlclose(handle->library_handle))
{
rvvm_error("rvdlib_close failed: %s", dlerror());
}
#endif
free(handle);
}

void* rvdlib_resolve(rvdlib* handle, const char* symbol_name)
{
if (!handle)
{
rvvm_error("rvdlib_resolve: Invalid dynamic library handle");
return NULL;
}
void* fn_ptr = NULL;
#ifdef _WIN32
fn_ptr = (void*)GetProcAddress((HMODULE)handle->library_handle, (LPSTR)symbol_name);
if (!fn_ptr)
{
rvvm_error("rvdlib_resolve failed");
return NULL;
}
#else
fn_ptr = dlsym(handle->library_handle, symbol_name);
if (!fn_ptr)
{
rvvm_error("rvdlib_resolve: symbol resolve error: %s", dlerror());
return NULL;
}
#endif
return fn_ptr;
}

rvdlib* rvdlib_reopen(rvdlib* handle, uint16_t flags)
{
if (!handle)
{
rvvm_error("rvdlib_reopen: Invalid dynamic library handle");
return NULL;
}
char library_path[256];
memset(library_path, 0, 256);
memcpy(handle->library_path, library_path, 256);
rvdlib_close(handle);
return rvdlib_open(library_path, flags);
}

#else

rvdlib* rvdlib_open(const char* path, uint16_t flags)
{
UNUSED(path);
UNUSED(flags);
rvvm_error("rvdlib_open: Dynamic loading not supported");
return NULL;
}

rvdlib* rvdlib_reopen(rvdlib* handle, uint16_t flags)
{
UNUSED(handle);
UNUSED(flags);
rvvm_error("rvdlib_reopen: Dynamic loading not supported");
return NULL;
}

void rvdlib_close(rvdlib* handle)
{
UNUSED(handle);
rvvm_error("rvdlib_close: Dynamic loading not supported");
}

void* rvdlib_resolve(rvdlib* handle, const char* symbol_name)
{
UNUSED(handle);
UNUSED(symbol_name);
rvvm_error("rvdlib_resolve: Dynamic loading not supported");
return NULL;
}

#endif
45 changes: 45 additions & 0 deletions src/rvdl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
rvdl.h - Dynamic library related stuff
Copyright (C) 2023 0xCatPKG <github.com/0xCatPKG>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef RVDL_H
#define RVDL_H

#include "compiler.h"

#define RVDLIB_LAZY 0 // Default behavior, resolve syms only in rvdlib_resolve
#define RVDLIB_NOW 1 // Takes no effect on Windows as i not found how to list all procedures by HMODULE

#define RVDLIB_NODELETE 1 << 1 // Do not really unload dynamic object in rvdlib_close, just free handle
#define RVDLIB_NOLOAD 1 << 2 // Do not really load dynamic object in rvdlib_open, just check if it exists in lookup directories, rvdlib_open will return NULL if dynamic object not found

typedef struct
{
void* library_handle;
char library_path[256];
uint16_t flags;
} rvdlib;

// rvdlib managment methods
rvdlib* rvdlib_open(const char* path, uint16_t flags);
rvdlib* rvdlib_reopen(rvdlib* handle, uint16_t flags);
void rvdlib_close(rvdlib* handle);

// Symbol managment methods
void* rvdlib_resolve(rvdlib* handle, const char* symbol_name);

#endif

0 comments on commit 47d822f

Please sign in to comment.