首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >防止链接器删除导出的函数。

防止链接器删除导出的函数。
EN

Stack Overflow用户
提问于 2013-06-12 16:22:32
回答 3查看 1.3K关注 0票数 3

我有一个程序,静态地将链接到几个c++库,这些库导出几个函数:

代码语言:javascript
复制
extern "C" 
{ 
    KSrvRequestHandler* CreateRequestHandler( const char* name );
    bool                DestroyRequestHandler( KSrvRequestHandler* handler );
    const char**        ListRequestHandlerTypes();
}

然后,主程序使用GetProcAddress/dlsym调用这些函数:

代码语言:javascript
复制
#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:所以我有一个可行的解决方案--但它的内部确实很难看。还在找更好的方法。

因此,我必须以某种方式定义加载内置接口的对象中所需的符号。我不认为有办法迫使链接器链接在一个符号,否则。据我所知,建立一个函数的库是不可能的,不管函数看起来是否需要。这完全取决于可执行文件的链接步骤。

因此,在可执行文件中,我有一个宏,它定义了我需要的内置接口。每个内置插件对其所有接口功能都有一个前缀,因此,在文件的顶部,我这样做:

代码语言:javascript
复制
DEFINE_BUILT_IN_PLUGIN( PluginOne )
DEFINE_BUILT_IN_PLUGIN( PluginTwo )

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

代码语言:javascript
复制
#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中,我将尽最大努力使编译器链接一个未引用的函数。该宏仅在函数内部工作。所以我必须创建这个假魔法课。一定有更好的办法。

不管怎么说-确实管用。

EN

回答 3

Stack Overflow用户

发布于 2013-06-12 23:17:50

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

  1. 例如,在Qt中,可以通过调用特定的宏将静态插件“导入”到主可执行文件中: 插件 它创建一个自定义类的静态实例,该类的构造函数调用从静态插件导出的初始化函数。
  2. Poco人员使用Linux上的extern "C"声明和Windows上的杂注强制从静态库导出特定的符号: __pragma(comment (linker, "/export:CreateRequestHandler")) 与静态库的链接是通过在Linux上使用相同的extern "C"声明和在Windows上使用链接器务实来强制实现的: __pragma(comment (linker, "/include:CreateRequestHandler")) 您可以在这个博客帖子中找到详细信息。
票数 3
EN

Stack Overflow用户

发布于 2013-06-13 16:41:26

你不能为你的主可执行链接器提供一个.def文件吗?该文件应该导出有关函数,这将防止它们被删除。

我好像还记得很久以前我做过类似的事情。

票数 0
EN

Stack Overflow用户

发布于 2015-10-08 12:46:43

问题:在windows上,静态LIB包含一个OBJ文件,该文件的函数标记为__decl-spec(dll导出),但如果EXE中没有使用该函数,则函数不会从EXE导出。在其他平台上,我们也有同样的问题,但是我们有一些编译器选项,比如-存档/ -force_load,让它工作。

链接:Link1 Link2

在我看来,唯一的解决方案就是不要创建静态库,而是在可执行文件中包含所有代码(静态libs ):1.它在Windows 2上工作,在没有完整存档的Linux上工作。它在没有-force_load 4的Mac上工作。我们也不需要担心2和3是否包含死代码、exe膨胀等等。

这是唯一的解决方案,直到链接器变得聪明,扔掉所有未使用的符号,除了那些专门标记为外部消费的符号,即标记为要导出的符号。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17070536

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档