gpt4 book ai didi

c++ - 防止链接器删除导出的函数

转载 作者:太空狗 更新时间:2023-10-29 21:23:59 25 4
gpt4 key购买 nike

我有一个程序可以静态链接到几个导出一些函数的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

所以这里的关键是我使用动态链接在我自己的主程序中调用一个函数。

(为什么我这样做超出了问题的范围,但简短的回答:这是一个插件架构,但我有一些标准插件直接链接到主二进制文件 - 但我仍然想通过加载它们相同的插件加载接口(interface)。例如,对于内置插件,我通过传入当前可执行文件作为插件接口(interface)的源来加载它们。)

问题是:链接器不知道我将需要这些函数,也没有链接它们。

如何强制链接这些函数?对于动态库,导出它们就足够了。但是对于exe,连dll导出的函数都会被链接器删除。

我知道我可以通过让主二进制文件将这些函数地址分配给某些东西或其他类似的 hack 来强制链接。有正确的方法吗?

@UPDATE:所以我有一个可行的解决方案 - 但它的内部确实很丑陋。仍在寻找更好的方法。

所以我必须以某种方式在加载内置接口(interface)的对象中定义我需要的符号。我认为没有办法强制链接器以其他方式链接到符号中。例如。据我所知,没有办法构建一个函数库,无论它看起来是否需要,它总是被链接起来。这完全取决于可执行文件的链接步骤。

所以在可执行文件中我有一个定义我需要的内置接口(interface)的宏。每个内置插件都有一个指向其所有接口(interface)函数的前缀,因此,在文件的顶部我做了:

DEFINE_BUILT_IN_PLUGIN( PluginOne )
DEFINE_BUILT_IN_PLUGIN( PluginTwo )

这将强制定义我需要的函数。但是这样做的宏是如此丑陋,以至于我充满了愤怒和 self 怀疑的感觉(为了便于阅读,我已经从宏中删除了尾部的斜线):

#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 中,我将竭尽全力诱使编译器链接一个未引用的函数。该宏仅在函数内部起作用。所以我必须创建这个伪造的 Magic 类。一定有更好的方法。

无论如何 - 它确实有效。

最佳答案

我至少见过两种不同的方法来解决类似的任务。

  1. 例如,在 Qt 中,您可以拥有需要通过调用特定宏“导入”到主可执行文件中的静态插件:

    https://qt-project.org/doc/qt-4.8/qtplugin.html#Q_IMPORT_PLUGIN

    它创建自定义类的静态实例,其构造函数调用从静态插件导出的初始化函数。

  2. Poco 人员在 Linux 上使用 extern "C" 声明,在 Windows 上使用 pragma 强制从静态库中导出特定符号:

    __pragma(comment (linker, "/export:CreateRequestHandler"))

    在 Linux 上使用相同的 extern "C" 声明强制链接到静态库,在 Windows 上使用链接器编译指示:

    __pragma(comment (linker, "/include:CreateRequestHandler"))

    您可以在 blog post 中找到详细信息.

关于c++ - 防止链接器删除导出的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17070536/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com