【发布时间】:2013-06-12 16:22:32
【问题描述】:
我有一个程序静态链接到几个导出一些函数的 c++ 库:
extern "C"
{
KSrvRequestHandler* CreateRequestHandler( const char* name );
bool DestroyRequestHandler( KSrvRequestHandler* handler );
const char** ListRequestHandlerTypes();
}
然后主程序使用 GetProcAddress/dlsym 调用这些函数:
#ifdef WIN32
HINSTANCE hDll = GetModuleHandle( NULL );
mCreateHandler = GetProcAddress( hDll, createFuncName );
mDestroyHandler = GetProcAddress( hDll, destroyFuncName );
mGetHandlerTypes = GetProcAddress( hDll, listFuncName );
#else // POSIX
void* handle = dlopen( NULL, 0 );
mCreateHandler = dlsym( handle, createFuncName );
mDestroyHandler = dlsym( handle, destroyFuncName );
mGetHandlerTypes = dlsym( handle, listFuncName );
dlclose( handle );
#endif // !POSIX
所以这里的关键是我正在使用动态链接在我自己的主程序中调用一个函数。
(我为什么这样做超出了问题的范围,但简短的回答:这是一个插件架构,但我有一些直接链接到主二进制文件的标准插件 - 但我仍然想通过相同的插件加载接口。例如,对于内置插件,我通过传入当前可执行文件作为插件接口的源来加载它们。)
问题是:链接器不知道我将需要这些函数,也没有链接它们。
如何强制链接这些函数?对于动态库,导出它们就足够了。但是对于exe来说,连dll导出的函数都会被链接器删除。
我知道我可以通过使主二进制文件将这些函数地址分配给某些东西或其他类似的黑客来强制链接。有正确的方法吗?
@UPDATE:所以我有一个可行的解决方案 - 但它的内部确实很难看。仍在寻找更好的方法。
所以我必须以某种方式在加载内置接口的对象中定义我需要的符号。我认为没有办法强制链接器以其他方式链接符号。例如。我不知道如何构建一个具有始终链接的函数的库,无论它看起来是否需要。这完全取决于可执行文件的链接步骤。
所以在可执行文件中我有一个宏来定义我需要的内置接口。每个内置插件都有其所有接口函数的前缀,因此,在文件的顶部,我这样做:
DEFINE_BUILT_IN_PLUGIN( PluginOne )
DEFINE_BUILT_IN_PLUGIN( PluginTwo )
这将强制定义我需要的函数。但是这样做的宏太丑了,以至于我充满了愤怒和自我怀疑的感觉(为了便于阅读,我已经从宏中删除了尾部的斜杠):
#define FORCE_UNDEFINED_SYMBOL(x)
void* _fp_ ## x ## _fp =(void*)&x;
if (((ptrv) _fp_ ## x ##_fp * ( rand() | 1 )) < 1 )
exit(0);
#define DEFINE_BUILT_IN_PLUGIN( PREFIX )
extern "C"
{
KSrvRequestHandler* PREFIX ## CreateRequestHandler( const char* name );
bool PREFIX ## DestroyRequestHandler( KSrvRequestHandler* handler );
const char** PREFIX ## ListRequestHandlerTypes();
}
class PREFIX ## HandlerInterfaceMagic
{
public:
PREFIX ## HandlerInterfaceMagic()
{
FORCE_UNDEFINED_SYMBOL( PREFIX ## CreateRequestHandler );
FORCE_UNDEFINED_SYMBOL( PREFIX ## DestroyRequestHandler );
FORCE_UNDEFINED_SYMBOL( PREFIX ## ListRequestHandlerTypes );
}
};
PREFIX ## HandlerInterfaceMagic PREFIX ## HandlerInterfaceMagicInstance;
由于编译器是一个优化天才,在 FORCE_UNDEFINED_SYMBOLS 中,我将竭尽全力欺骗编译器链接一个未引用的函数。该宏仅在函数内部有效。所以我必须创建这个虚假的魔法类。一定有更好的办法。
无论如何 - 它确实有效。
【问题讨论】:
-
我可能误解了您的情况,但是您能否将导出的函数移动到单独编译的库中,然后根据需要从库中链接它们?
-
如果我将内置插件放入他们自己的动态库中,这将起作用 - 基本上只是将它们编写为始终与可执行文件一起提供的常规插件。但这是次优的,因为我希望它们都在同一个文件中。但更大的问题是内置插件需要访问主程序的内部。例如。其中之一是报告内部程序状态的诊断插件。我必须创建一个完整的反向接口(例如 exe->plugin)才能将 diag 插件用作单独的 dyn。库。
-
请不要在符号名称中使用前导双下划线,这些是为编译器保留的。如果您担心名称冲突,请将它们放在命名空间中。
标签: c++ visual-c++ gcc dll shared-libraries