如何在Linux上加载共享库延迟

时间:2014-05-01 07:35:40

标签: c++ linux gcc shared-libraries clang

我一直在寻找一种方法来创建一个共享库(让我们在Linux上命名库libbar.so延迟加载,并希望在的帮助下实现它只有链接器,不修改用C ++编写的源代码的任何内容;我的意思是我不想在父库的源代码中调用dlopen()dlsym()(让它命名为libfoo.so)来调用libbar.so的函数,因为它们使源代码混乱,维护过程变得困难。 (简而言之,即使在Linux上,我也期望以类似的方式使用Visual Studio的/DELAYLOAD选项)

无论如何,到目前为止,我已经在互联网上找到了与我的问题相关的一些不确定的信息片段,所以很高兴能得到你们所有人的答案,以便让信息清晰明白。

  1. GNU ld 是否支持Linux上的任何延迟加载机制?
  2. 如果没有, Clang 怎么样?
  3. dlopen()系列是在Linux上加载共享库延迟的唯一方法吗?
  4. 我测试了将-zlazy标志传递给GCC(g ++)并带有一个库的路径,它似乎接受了标志,但行为看起来没有加载libbar.so延迟(没有{{ 1}},我希望在libbar.so的第一次调用时遇到异常,但在进入libbar.so之前实际引发了异常。另一方面,Clang(libfoo.so)发出警告,忽略了选项标志。

    致以最诚挚的问候,

3 个答案:

答案 0 :(得分:6)

延迟加载不是运行时功能。 MSVC ++在没有Windows帮助的情况下实现了它。就像dlopen是Linux上的唯一方法一样,GetProcAddress是Windows上唯一的运行时方法。

那么,什么是延迟加载呢?它非常简单:对DLL的任何调用都必须通过一个指针(因为你不知道它将加载到哪里)。这总是由编译器和链接器为您处理。但是通过延迟加载,MSVC ++最初将此指针设置为一个为您调用LoadLibraryGetProcAddress的存根。

Clang可以在没有ld帮助的情况下做同样的事情。在运行时,它只是一个普通的dlopen调用,Linux无法确定Clang是否插入了它。

答案 1 :(得分:6)

可以使用Proxy design pattern以便携方式实现此功能。

在代码中,它可能看起来像这样:

#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();
}

答案 2 :(得分:0)

要添加到MSalters答案,可以通过创建一个小的静态存根库来轻松模仿Windows在Linux上进行延迟加载的方法,该库将首次调用任何函数时尝试dlopen所需的库(发出诊断消息)如果dlopen失败则终止,然后将所有调用转发给它。

此类存根库可以手工编写,由项目/库特定脚本生成或由通用工具Implib.so生成:

$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...