i have to deal a lot w/ dyn sym libs/calls for my stuff @samygo and came up w/ some self-including .h file.
its basically for *nix but i ve hacked some windows support though not all features are available there
- should compile as C and C++
- type safe
- easy to use (imho)
- supports logging
here some example usage:
PHP Code:
// msvc doesn't support weak linking
#define DYNSYM_LOG __dynsym_log
#define DYNSYM_CALL_DECL WINAPI
#define DYNSYM_H "u32.h"
#include "dynsym.h"
#define DYNSYM_CALL_DECL WINAPI
#define DYNSYM_H "k32.h"
#include "dynsym.h"
void main()
{
if(user32_init() > 0)
{
user32.MessageBoxA(0, "test", "test", 0);
user32_deinit();
}
if(k32_init() > 0)
{
k32.Sleep(0);
k32_deinit();
}
}
u32.h:
PHP Code:
#ifdef DYNSYM_BEGIN
DYNSYM_BEGIN("user32", user32)
DYNSYM_DEF(int, MessageBoxA, HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
DYNSYM_END(user32)
#endif // #ifdef DYNSYM_BEGIN
dynsym.h macro hell
PHP Code:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// bugficks@samygo
// (c) 2016 - 2018
//
// License: GPLv3
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//lib_blub.h:
// DYNSYM_BEGIN("lib_blub.so.0", lib_blub)
// supports patterns (glob w/ braces) and colon-separated list of libs
// //DYNSYM_BEGIN("{/usr/lib/{lib_blub.so,lib_bla.so*}}", lib_blub)
// //DYNSYM_BEGIN("lib_blub.so*:lib_bla.so*", lib_blub)
// //DYNSYM_BEGIN("lib_blub.so:lib_blub.so.0:lib_blub.so.1", lib_blub)
// // required symbols
// DYNSYM_DEF(int, func_bla, int)
// DYNSYM_DEF_EX(int, short_bla, func_loooooooong_bla, int)
// //optional symbols
// DYNSYM_OPT(int, func_blub, int)
// DYNSYM_OPT_EX(int, short_blub, func_loooooooong_blub, int)
// DYNSYM_END(lib_blub)
//
// // add additional data to lib_blub structure
//#ifndef DYNSYM_DATA
//#define DYNSYM_DATA \
// int bla; \
// void *blub;
//#endif
//
//code:
// #define DYNSYM_H "lib_blub.h"
// optionally supply a colon-separated list of directories as library search path
// #define DYNSYM_LIB_PATH "/usr/lib:/some/lib/dir"
// #include <samygo/dynsym.h>
//
// lib_blub_init();
// lib_blub.func_bla(0);
// if(lib_blub.func_blub)
// lib_blub.func_blub(0);
// lib_blub_deinit();
// < 0 : error
// else: num resolved symbols
// int xxx_init();
// int xxx_init_ex(void *lib);
//
// void xxx_deinit();
#ifndef __DYNSYM_DONE_H__
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef DYNSYM_H
#error DYNSYM_H is not defined.
#endif
#ifdef DYNSYM_BEGIN
#undef DYNSYM_BEGIN
#endif
#ifdef DYNSYM_END
#undef DYNSYM_END
#endif
#ifdef DYNSYM_DEF
#undef DYNSYM_DEF
#endif
#ifdef DYNSYM_DEF_EX
#undef DYNSYM_DEF_EX
#endif
#ifdef DYNSYM_VAR
#undef DYNSYM_VAR
#endif
#ifdef DYNSYM_VAR_EX
#undef DYNSYM_VAR_EX
#endif
#ifdef DYNSYM_OPT
#undef DYNSYM_OPT
#endif
#ifdef DYNSYM_OPT_EX
#undef DYNSYM_OPT_EX
#endif
#ifdef DYNSYM_VAR_OPT
#undef DYNSYM_VAR_OPT
#endif
#ifdef DYNSYM_VAR_OPT_EX
#undef DYNSYM_VAR_OPT_EX
#endif
#ifdef DYNSYM_INIT
#undef DYNSYM_INIT
#endif
#ifdef DYNSYM_DEINIT
#undef DYNSYM_DEINIT
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if __DYNSYM_INC_LEVEL == 1
#undef __DYNSYM_INC_LEVEL
#define __DYNSYM_INC_LEVEL 2
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef DYNSYM_DATA
#define DYNSYM_DATA void *_dummy_;
#endif
#define DYNSYM_BEGIN(DLL, STRUCT) \
typedef union \
{ \
struct \
{ \
const uint32_t nSyms;
#define DYNSYM_END(STRUCT) \
DYNSYM_DATA \
}; \
dynsym_tab_t symtab; \
} STRUCT##_t; \
DYNSYM_STRUCT_DATA(STRUCT);
#define DYNSYM_DEF(RET, NAME, ...) \
DYNSYM_DEF_EX(RET, NAME, NAME, __VA_ARGS__)
#define DYNSYM_DEF_EX(RET, FUNC, NAME, ...) \
struct { FUNC##_t FUNC; const char *name_##FUNC; };
#define DYNSYM_VAR(TYPE, NAME) \
DYNSYM_VAR_EX(TYPE, NAME, NAME)
#define DYNSYM_VAR_EX(TYPE, VNAME, SNAME) \
struct { TYPE *VNAME; const char *name_##VNAME; };
#define DYNSYM_OPT(RET, NAME, ...) \
DYNSYM_DEF_EX(RET, NAME, NAME, __VA_ARGS__)
#define DYNSYM_OPT_EX(RET, FUNC, NAME, ...) \
DYNSYM_DEF_EX(RET, FUNC, NAME, __VA_ARGS__)
#define DYNSYM_VAR_OPT(TYPE, NAME) \
DYNSYM_VAR_EX(TYPE, NAME, NAME)
#define DYNSYM_VAR_OPT_EX(TYPE, VNAME, SNAME) \
DYNSYM_VAR_EX(TYPE, VNAME, SNAME)
#define DYNSYM_STRUCT_DATA(STRUCT) \
typedef struct \
{ \
DYNSYM_DATA \
} STRUCT##_data_t;
#include DYNSYM_H
#undef DYNSYM_DATA
#undef DYNSYM_STRUCT_DATA
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#elif __DYNSYM_INC_LEVEL == 2
#undef __DYNSYM_INC_LEVEL
#define __DYNSYM_INC_LEVEL 3
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define DYNSYM_BEGIN(DLL, STRUCT) \
static STRUCT##_t STRUCT = \
{ {\
(((sizeof(STRUCT##_t) - sizeof(STRUCT##_data_t)) - sizeof(STRUCT.symtab)) / sizeof(dynsym_sym_t)),
#define DYNSYM_END(STRUCT) \
} }; \
DYNSYM_INIT(DLL, STRUCT) \
DYNSYM_DEINIT(DLL, STRUCT)
#define DYNSYM_DEF(RET, NAME, ...) \
DYNSYM_DEF_EX(RET, NAME, NAME, __VA_ARGS__)
#define DYNSYM_DEF_EX(RET, FUNC, NAME, ...) \
{ 0, #NAME },
#define DYNSYM_VAR(TYPE, NAME) \
DYNSYM_VAR_EX(TYPE, NAME, NAME)
#define DYNSYM_VAR_EX(TYPE, VNAME, SNAME) \
{ 0, #SNAME },
#define DYNSYM_OPT(RET, NAME, ...) \
DYNSYM_OPT_EX(RET, NAME, NAME, __VA_ARGS__)
#define DYNSYM_OPT_EX(RET, FUNC, NAME, ...) \
{ (FUNC##_t)eDYNSYM_OPTIONAL, #NAME },
#define DYNSYM_VAR_OPT(TYPE, NAME) \
DYNSYM_VAR_OPT_EX(TYPE, NAME, NAME)
#define DYNSYM_VAR_OPT_EX(TYPE, VNAME, SNAME) \
{ (TYPE*)eDYNSYM_OPTIONAL, #SNAME },
#ifndef DYNSYM_LIB_PATH
#define DYNSYM_LIB_PATH "/lib:/usr/lib"
#endif
#define DYNSYM_INIT(DLL, STRUCT) \
static int STRUCT##_init_ex(void *lib) \
{ \
return dynsym_init_ex(lib, &STRUCT##_lib, &STRUCT.symtab); \
} \
\
static int STRUCT##_init() \
{ \
return dynsym_init(&STRUCT##_lib, &STRUCT.symtab, DYNSYM_LIB_PATH); \
}
#define DYNSYM_DEINIT(DLL, STRUCT) \
static void STRUCT##_deinit() \
{ \
dynsym_tab_deinit(&STRUCT##_lib, &STRUCT.symtab); \
STRUCT##_lib.lib = 0; \
}
#include DYNSYM_H
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#elif __DYNSYM_INC_LEVEL == 3
#define __DYNSYM_DONE_H__
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#else
#define __DYNSYM_INC_LEVEL 1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __DYNSYM_H__
#define __DYNSYM_H__
#include <stdint.h>
#include <errno.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#define __attribute__(...)
#define PATH_MAX MAX_PATH
enum {
RTLD_LAZY = 0x0001
};
inline void* dlopen(const char *n, int)
{
return (void*)LoadLibraryA(n);
}
inline int dlclose(void *h)
{
return FreeLibrary((HMODULE)h) ? 0 : -1;
}
inline void* dlsym(void *h, const char *n)
{
return (void*)GetProcAddress((HMODULE)h, n);
}
#define LIBRARY_PATH "PATH"
#define TOKEN_PATH_SPLIT ";"
#define strtok_r(A, B, C) strtok(A, B)
#else
#include <dlfcn.h>
#include <link.h>
#include <glob.h>
#define LIBRARY_PATH "LD_LIBRARY_PATH"
#define TOKEN_PATH_SPLIT ":"
#endif
typedef struct
{
const char *name;//[PATH_MAX];
void *lib;
} dynsym_lib_t;
typedef struct
{
void *fn;
const char *name;
} dynsym_sym_t;
typedef struct
{
uint32_t nSyms;
dynsym_sym_t syms[];
} dynsym_tab_t;
typedef enum
{
eDYNSYM_DEFAULT = 0,
eDYNSYM_OPTIONAL = (1 << 0),
eDYNSYM_MASK = 3,
} dynsym_flags_t;
typedef enum
{
eDYNSYM_LOG_NONE,
eDYNSYM_LOG_ERROR,
eDYNSYM_LOG_WARN,
eDYNSYM_LOG_INFO,
eDYNSYM_LOG_DBG
} dynsym_log_level_t;
void dynsym_log(
int l, const char *fmt, ...) __attribute__ ((weak));
#ifndef DYNSYM_LOG
#define DYNSYM_LOG(L, ...) \
{ \
if(dynsym_log) \
dynsym_log(L, __VA_ARGS__); \
else \
__dynsym_log(L, __VA_ARGS__); \
}
#endif
static void __dynsym_log(
int l, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
switch(l)
{
case eDYNSYM_LOG_ERROR:
printf("[E]");
break;
case eDYNSYM_LOG_WARN:
printf("[W]");
break;
case eDYNSYM_LOG_INFO:
printf("[I]");
break;
case eDYNSYM_LOG_DBG:
printf("[D]");
break;
default:
break;
}
printf("[DYNSYM] ");
vprintf(fmt, ap);
va_end(ap);
fflush(stdout);
}
static inline const char *dynsym_libname(
const dynsym_lib_t *lib)
{
const char *lib_name = "(nil)";
if(!lib)
return lib_name;
if(!lib->name)
return lib_name;
if(!lib->name[0])
return lib_name;
return lib->name;
}
static int dynsym_tab_init(
dynsym_lib_t *lib, dynsym_tab_t *symtab)
{
int n = 0;
const char *lib_name = dynsym_libname(lib);
dynsym_sym_t *syms = symtab->syms;
for(uint32_t i = 0; i < symtab->nSyms; i++)
{
uintptr_t flags = (uintptr_t)syms[i].fn;
int opt = flags & eDYNSYM_OPTIONAL;
void *fn = dlsym(lib->lib, syms[i].name);
if(!fn)
{
int l = opt ? eDYNSYM_LOG_WARN : eDYNSYM_LOG_ERROR;
DYNSYM_LOG(l,"dlsym lib: '%s' '%s' failed.\n", lib_name, syms[i].name);
if(!opt)
return -1;
}
else
{
DYNSYM_LOG(eDYNSYM_LOG_INFO,"dlsym lib: '%s' '%s' %p.\n", lib_name, syms[i].name, fn);
n++;
}
syms[i].fn = fn;
}
return n;
}
static void dynsym_tab_deinit(
dynsym_lib_t *lib, dynsym_tab_t *symtab)
{
void *_lib = lib->lib;
if(_lib)
{
lib->lib = 0;
dynsym_sym_t *syms = symtab->syms;
for(uint32_t i = 0; i < symtab->nSyms; i++)
syms[i].fn = 0;
dlclose(_lib);
}
const char *name = lib->name;
if(name)
{
lib->name = 0;
free((void*)name);
}
}
static int dynsym_init_ex(
void *lib, dynsym_lib_t *dynsymlib, dynsym_tab_t *symtab)
{
if(!lib)
return -1;
if(dynsymlib->lib)
return -1;
dynsymlib->lib = lib;
#ifndef _WIN32
struct link_map *lm = 0;
dlinfo(lib, RTLD_DI_LINKMAP, &lm);
if(lm && lm->l_name && lm->l_name[0])
dynsymlib->name = strdup(lm->l_name);
else if(!dynsymlib->name || !dynsymlib->name[0])
dynsymlib->name = realpath(program_invocation_name, 0);
#else
{
char tmp[MAX_PATH];
memset(tmp, 0, sizeof(tmp));
if(GetModuleFileNameA((HMODULE)lib, tmp, ARRAYSIZE(tmp)))
dynsymlib->name = _strdup(tmp);
}
#endif
DYNSYM_LOG(eDYNSYM_LOG_DBG,"lib: '%s' %p.\n", dynsym_libname(dynsymlib), dynsymlib->lib);
int n = dynsym_tab_init(dynsymlib, symtab);
return n;
}
typedef int (*sgo_log_t)(
int l, const char *tag, const char *comp, const char *fmt, ...);
static void *dynsym_dlopen(
const char *name_pattern, dynsym_lib_t *dynsymlib, const char *const _LIB_PATH, sgo_log_t logger)
{
if(!name_pattern)
{
void *lib = dlopen(0, RTLD_LAZY);
return lib;
}
char *strtok_name = 0;
char name_wrk[PATH_MAX];
memset(name_wrk, 0, sizeof(name_wrk));
strncpy(name_wrk, name_pattern, sizeof(name_wrk));
const char *name = strtok_r(name_wrk, TOKEN_PATH_SPLIT, &strtok_name);
while(name)
{
// no pattern, just use dlopen
if(!strpbrk(name, "?*[]{}"))
{
void *lib = dlopen(name, RTLD_LAZY);
if(lib)
return lib;
}
#ifdef HAVE_GLOB
// pattern, we need absolute path for dlopen, fill lib search dirs
char LIB_PATH[PATH_MAX] = { 0 };
if(!strchr(name, '/'))
{
const char *const LD_LIBRARY_PATH = getenv(LIBRARY_PATH);
if(LD_LIBRARY_PATH && LD_LIBRARY_PATH[0])
snprintf(LIB_PATH, sizeof(LIB_PATH) - 1, "%s:", LD_LIBRARY_PATH);
strncat(LIB_PATH, _LIB_PATH, sizeof(LIB_PATH) - 1);
DYNSYM_LOG(eDYNSYM_LOG_DBG, "LIB_PATH: '%s'\n", LIB_PATH);
}
char *strtok_dir = 0;
const char *libdir = strtok_r(LIB_PATH, TOKEN_PATH_SPLIT, &strtok_dir);
void *lib = 0;
do
{
char libpath[PATH_MAX];
memset(libpath, 0, sizeof(libpath));
if(libdir)
snprintf(libpath, sizeof(libpath) - 1, "%s/%s", libdir, name);
else
strncpy(libpath, name, sizeof(libpath) - 1);
glob_t blob;
int r = glob(libpath, GLOB_BRACE, 0, &blob);
if(r)
{
DYNSYM_LOG(eDYNSYM_LOG_DBG, "glob('%s') failed. [%s]\n", libpath, strerror(ENOENT));
}
else
{
for(size_t i = 0; i < blob.gl_pathc; i++)
{
const char *name = blob.gl_pathv[i];
lib = dlopen(name, RTLD_LAZY);
if(lib)
break;
}
}
globfree(&blob);
if(lib)
return lib;
libdir = strtok_r(0, TOKEN_PATH_SPLIT, &strtok_dir);
}
while(libdir);
#endif
name = strtok_r(0, TOKEN_PATH_SPLIT, &strtok_name);
}
return 0;
}
static int dynsym_init(
dynsym_lib_t *dynsymlib, dynsym_tab_t *symtab, const char *const LIB_PATH)
{
void *lib = dynsym_dlopen(dynsymlib->name, dynsymlib, LIB_PATH, 0);
if(!lib)
{
DYNSYM_LOG(eDYNSYM_LOG_ERROR,"dlopen lib: '%s' failed.\n", dynsym_libname(dynsymlib));
}
return dynsym_init_ex(lib, dynsymlib, symtab);
}
#endif // #ifndef __DYNSYM_H__
#ifndef DYNSYM_CALL_DECL
#define DYNSYM_CALL_DECL
#endif
#define DYNSYM_DEF(RET, NAME, ...) \
DYNSYM_DEF_EX(RET, NAME, NAME, __VA_ARGS__)
#define DYNSYM_DEF_EX(RET, FUNC, NAME, ...) \
typedef RET (DYNSYM_CALL_DECL * FUNC##_t)(__VA_ARGS__);
#define DYNSYM_VAR(T, NAME) \
DYNSYM_VAR_EX(T, VNAME, SNAME)
#define DYNSYM_VAR_EX(T, VNAME, SNAME)
#define DYNSYM_OPT(RET, NAME, ...) \
DYNSYM_DEF_EX(RET, NAME, NAME, __VA_ARGS__)
#define DYNSYM_OPT_EX(RET, FUNC, NAME, ...) \
DYNSYM_DEF_EX(RET, FUNC, NAME, __VA_ARGS__)
#define DYNSYM_VAR_OPT(T, NAME) \
DYNSYM_VAR_OPT_EX(T, NAME, NAME)
#define DYNSYM_VAR_OPT_EX(T, VNAME, SNAME)
#define DYNSYM_BEGIN(DLL, STRUCT) \
static dynsym_lib_t STRUCT##_lib = { DLL, 0 };
#define DYNSYM_END(STRUCT)
#include DYNSYM_H
#undef DYNSYM_CALL_DECL
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if __DYNSYM_INC_LEVEL < 4
#include "dynsym.h"
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#else // #ifndef __DYNSYM_DONE_H__
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#undef __DYNSYM_DONE_H__
#ifdef DYNSYM_LIB_PATH
#undef DYNSYM_LIB_PATH
#endif
#undef DYNSYM_H
#undef __DYNSYM_INC_LEVEL
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif // #ifndef __DYNSYM_DONE_H__
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|