【问题标题】:How to load a shared library without loading its dependencies?如何加载共享库而不加载其依赖项?
【发布时间】:2011-01-01 19:47:21
【问题描述】:

假设我有一个库libfoo.so.1,它依赖于(根据lddlibbar.so.1。但是,libbar.so.1 目前不可用。我的应用需要调用 libfoo.so.1 中的函数,而这根本不需要 libbar.so.1

有没有办法加载libfoo.so.1,解析函数符号,然后在没有libbar.so.1 的情况下调用它来满足依赖关系?这是一个“我知道我在做什么,让我已经做”的案例。我尝试了 RTLD_LAZY 标志,但它仍然尝试在 加载符号之前加载 libbar.so.1 库。


编辑

这是确切的情况。

我们有 3 名玩家:

  • libbar.so.1,共享库位于不在LD_LIBRARY_PATHldconfig的路径中,并且其依赖关系都已解决
  • libfoo.so.1,一个共享库,位于与libbar 不同的目录中,但它依赖于libbar。在运行时,libfoo 会知道在哪里找到libbar
  • App,一个二进制应用程序,需要在运行时的某个时间点加载libfoo

App 不知道在哪里可以找到libbar,但知道libfoo 知道。我想要完成的是在libfoo 中有一个init 函数,它将简单地将App 的当前工作目录更改为libbar 所在的位置,以最终解决所有依赖关系并使每个人都开心。

libfoo最终需要调用libbar中的东西,而不是在这个init函数中。我不认为创建存根会起作用,因为符号最终需要解析为 real 函数。

【问题讨论】:

  • 很好,您提到了 RTLD_LAZY - 它表明您已经尝试过并且阻止了我在建议它的红鲱鱼路径上继续前进。

标签: c linux shared-libraries elf


【解决方案1】:

这里的实际要求是什么?仅仅链接一个库并没有多大作用,而且通常是良性的。你缺图书馆吗?只需创建一个同名的存根库。您想控制或抢占库中符号的使用吗?将它们放在另一个库中(使用正确的版本标签!)并 LD_PRELOAD 它。

我想这里的元问题是我看不到能够抢占依赖链接的价值。它只是一个辅助函数。

【讨论】:

    【解决方案2】:

    另一个想法:是否会从 libfoo.so.1 中提取(使用 ar(1))必要的函数,将其放入 .o 或另一个 .so 文件中,然后链接到该提取帮助?我假设对 libbar.so.1 的引用位于一个 libfoo 函数中,该函数没有被您的程序调用(甚至是间接调用)。

    【讨论】:

    • 其实动态库不是archives。
    【解决方案3】:

    使用dlopen加载库,使用dlsym获取你需要的函数。

    【讨论】:

    • 这就是他尝试 RTLD_LAZY 标志的方式;您无需指定在启动时链接库的时间。
    【解决方案4】:

    只是一个想法,你有没有想过插入依赖 - 只需创建一个具有相同签名、参数等的相同函数,然后让链接器解析这个函数并忽略 libbar.so.1?既然你没有提到这个,我想我会建议这个。

    希望这会有所帮助, 最好的祝福, 汤姆。

    【讨论】:

    • 我认为这行不通。每个库都有一个在链接时编码到其中的依赖项列表,该列表独立于未定义的符号集。加载器将尝试查找这些依赖项,无论它们是否实际需要。
    • @Jay:加载程序的路径被嵌入到可执行文件中,以便动态加载函数......我正在考虑通过指定具有相同签名的重复函数来防止动态加载从而迫使链接器改用该版本...
    • @Jay:刚刚看到你对亚当的回答的回应,这是我的想法……因为想要一个更好的词而存根……
    • @tommieb75,那很好。只要在某处定义符号,在哪里定义符号就无关紧要。 libbar.so 仍然必须存在,即使它是空的。
    【解决方案5】:

    好吧,即使使用RTLD_LAZY,变量仍然可以解析,因此通常您确实需要链接所有库。似乎您应该创建一个没有功能并且可以被链接器找到的存根libbar.so.1

    【讨论】:

    • 我认为这可行,但您需要存根来定义 libfoo.so 所依赖的所有符号。不过,定义本身可以是存根。
    • 正如 tommieb75 指出的那样,存根实际上不必在 libbar.so 中,但它们的符号必须在某处定义。
    • 我觉得你不需要定义所有的符号,这不是RTLD_LAZY会做的吗?
    • RTLD_LAZY 只是建议性的。有可能由于您可能无法控制的事情,它会被忽略(例如,不支持延迟绑定的系统、已启动的程序 suid 或出于安全性或稳健性目的而禁用延迟绑定的管理员配置)。
    猜你喜欢
    • 2012-06-19
    • 2018-04-07
    • 2019-12-02
    • 2011-11-07
    • 1970-01-01
    • 2022-10-24
    • 2011-07-22
    • 2020-05-25
    • 1970-01-01
    相关资源
    最近更新 更多