我有一个程序,静态与出口的一些功能几个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->插件),以将diag插件作为单独的dyn来完成此操作。库。 –
请不要使用符号名称的前导双下划线,它们是为编译器保留的。如果您担心名称冲突,请将它们放在名称空间中。 –