如何在Linux上延迟加载共享库 我一直在寻找一种方法来创建一个共享的库(让我们在Linux上命名为库 LBBAR,所以)延迟加载< /强>,希望它可以通过“强”>仅链接器< /强>来实现,而不修改C++中的源代码中的任何内容;我的意思是,我不想在父库的源代码中调用dlopen()。(简言之,即使在Linux上,我也希望采用与Visual Studio的/DELAYLOAD选项类似的方式)
无论如何,到目前为止,我在互联网上发现了一些与我的问题相关的不确定信息,所以很高兴能得到大家对以下问题的答案,以使信息更加清晰如何在Linux上延迟加载共享库 我一直在寻找一种方法来创建一个共享的库(让我们在Linux上命名为库 LBBAR,所以)延迟加载< /强>,希望它可以通过“强”>仅链接器< /强>来实现,而不修改C++中的源代码中的任何内容;我的意思是,我不想在父库的源代码中调用dlopen()。(简言之,即使在Linux上,我也希望采用与Visual Studio的/DELAYLOAD选项类似的方式),c++,linux,gcc,shared-libraries,clang,C++,Linux,Gcc,Shared Libraries,Clang,无论如何,到目前为止,我在互联网上发现了一些与我的问题相关的不确定信息,所以很高兴能得到大家对以下问题的答案,以使信息更加清晰 GNU ld在Linux上是否支持延迟加载机制 如果没有,那么叮当声怎么样 在Linux上加载共享库延迟的唯一方法是dlopen()family 我测试通过一个指向库的路径将-zlazy标志传递给GCC(g++),它似乎接受了该标志,但该行为看起来不像是在创建libbar。因此延迟加载(没有libbar.so,我本以为在第一次调用libbar.so时会出现异常,但在进入
dlopen()
family-zlazy
标志传递给GCC(g++),它似乎接受了该标志,但该行为看起来不像是在创建libbar。因此
延迟加载(没有libbar.so
,我本以为在第一次调用libbar.so
时会出现异常,但在进入libfoo.so
之前实际引发了异常)。另一方面,Clang(Clang++
)留下了一条警告,表示它忽略了选项标志
最重要的是,延迟加载不是一个运行时功能。MSVC++在没有Windows帮助的情况下实现了它。就像
dlopen
是Linux上唯一的方法一样,GetProcAddress
是Windows上唯一的运行时方法
那么,什么是延迟加载呢?很简单:对DLL的任何调用都必须经过指针(因为您不知道它将加载到哪里)。这始终由编译器和链接器为您处理。但通过延迟加载,MSVC++会将此指针最初设置为一个存根,该存根为您调用LoadLibrary
和GetProcAddress
Clang可以在没有
ld
帮助的情况下完成同样的操作。在运行时,它只是一个普通的dlopen
调用,Linux无法确定Clang是否插入了它。此功能可以通过使用
在代码中,它可能如下所示:
#include <memory>
// SharedLibraryProxy.h
struct SharedLibraryProxy
{
virtual ~SharedLibraryProxy() = 0;
// Shared library interface begin.
virtual void foo() = 0;
virtual void bar() = 0;
// Shared library interface end.
static std::unique_ptr<SharedLibraryProxy> create();
};
// SharedLibraryProxy.cc
struct SharedLibraryProxyImp : SharedLibraryProxy
{
void* shared_lib_ = nullptr;
void (*foo_)() = nullptr;
void (*bar_)() = nullptr;
SharedLibraryProxyImp& load() {
// Platform-specific bit to load the shared library at run-time.
if(!shared_lib_) {
// shared_lib_ = dlopen(...);
// foo_ = dlsym(...)
// bar_ = dlsym(...)
}
return *this;
}
void foo() override {
return this->load().foo_();
}
void bar() override {
return this->load().bar_();
}
};
SharedLibraryProxy::~SharedLibraryProxy() {}
std::unique_ptr<SharedLibraryProxy> SharedLibraryProxy::create() {
return std::unique_ptr<SharedLibraryProxy>{new SharedLibraryProxyImp};
}
// main.cc
int main() {
auto shared_lib = SharedLibraryProxy::create();
shared_lib->foo();
shared_lib->bar();
}
#包括
//SharedLibraryProxy.h
结构共享库代理
{
virtual~SharedLibraryProxy()=0;
//共享库接口开始。
虚拟void foo()=0;
虚拟空心条()=0;
//共享库接口结束。
静态std::unique_ptr create();
};
//SharedLibraryProxy.cc
结构SharedLibraryProxyImp:SharedLibraryProxy
{
void*shared_lib_uu=nullptr;
无效(*foo_u1;)()=nullptr;
void(*bar_u3;)()=nullptr;
SharedLibraryProxyImp&load(){
//用于在运行时加载共享库的平台特定位。
如果(!shared_lib_u){
//共享库=dlopen(…);
//foo=dlsym(…)
//bar=dlsym(…)
}
归还*这个;
}
void foo()重写{
返回此->加载().foo_u2;();
}
无效条()覆盖{
返回此->加载().条();
}
};
SharedLibraryProxy::~SharedLibraryProxy(){}
std::unique_ptr SharedLibraryProxy::create(){
返回std::unique_ptr{new SharedLibraryProxyImp};
}
//main.cc
int main(){
自动共享_lib=SharedLibraryProxy::create();
共享的_lib->foo();
共享的_lib->bar();
}
要添加到MSalters answer,可以很容易地模仿Windows在Linux上延迟加载的方法,方法是创建一个小型静态存根库,该存根库在第一次调用任何函数时尝试dlopen
所需的库(发出诊断消息,如果dlopen失败则终止),然后将所有调用转发给它
此类存根库可以手工编写、通过特定于项目/库的脚本生成或通过通用工具生成:
clang使用gnu ld进行链接(至少在3.4及更早版本中是这样),因此您在那里找不到任何帮助。@Mats,谢谢您的评论。好的,我不会介意clang对这个问题的提问,稍后编辑上面的原始描述。@oakad,谢谢:)我也找到了这篇文章。那么您认为GNULD真的不支持任何延迟加载机制吗?我们是否必须将dlopen()放在源代码中?(哦,即使这是真的,我也不想接受这个事实…)通过我对ld手册页的阅读-zlazy(应该是-z lazy)使您正在链接的库,在您的例子中是libfoo.so,为其调用者加载延迟。对于所需内容,在构建libbar.so时必须应用此标志。然而,手册页上还说“默认为惰性绑定”,所以libbar.so应该已经与此链接。我前面的评论是错误的。我误解了手册页
-z lazy
用于符号的延迟绑定,而不是库的延迟加载。@MSalters,再次感谢。你是说Clang可以自己处理延迟加载吗?实际上,我希望通过向编译器或链接器传递一个选项标志(尽管我忘记了帮助函数的名称),隐式地拥有一个像MSVC++这样的帮助函数,因为该机制隐藏了延迟加载函数调用背后的所有内容(因此用户不必关心在我们的源代码下面调用了这样的helper函数)。是的,u delayLoadHelper2是helper函数!可能一些编译器或链接器(如Sun的某物或苹果的ld64)一定提供了这样的helper函数,但我不知道Linux上发生了什么。(我是Linux的新手;)@user3591878:Linux上的GCC有混淆操作系统和编译器之间区别的不幸习惯,但这是UNIX的传统
$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...