【问题标题】:Does Clang/GCC really support a delay loading feature?Clang/GCC 真的支持延迟加载功能吗?
【发布时间】:2014-06-22 12:33:22
【问题描述】:

如果您真正体验过与上述标题相关的内容,您介意留下您的评论吗?我试图在 Ubuntu 上使用 Clang 和 GCC 延迟加载共享对象(我实际上不介意使用哪个编译器),但它们看起来并不真正支持任何延迟加载功能(我期望延迟加载功能在父对象中放置一个存根,该对象试图在需要该功能时按需加载另一个对象,但实际上并没有)。以下命令显示我试图使 libbar.so 延迟加载到 libfoo.so:

clang bar.c -fPIC -shared -o libbar.so
clang foo.c -Wl,-zlazy,lL'/path/to/where/lib/is',-lbar -o foo

如果 libbar.so 不存在,您将在进入条目之前看到 libfoo.so 引发异常。无论如何,我不介意上述命令中是否有任何拼写错误,但我想知道 Clang/GCC 是否真的支持延迟加载功能。

然而,如果 Clang/GCC 不支持任何延迟加载功能,我个人无法相信 Linux 程序开发人员是否需要调用 dlopen() 或 dlsym() 来延迟加载共享对象。如果对象是用 C 写的还好,但如果是用 C++ 写的,情况肯定很复杂 :(

我相信在编译器或链接器的帮助下实现的解决方案是最好的,因为我已经在 Windows 和 Mac OS 上成功地做到了。所以我觉得这是一个自然的反应,公民想要梦想即使在 Clang/GCC 上也有延迟加载功能。如果您对我的感受有任何意见,我也将不胜感激。

PS。我知道 Solaris 支持延迟加载功能,但这不适合我,因为我不会在上面开发任何东西。

无论如何,提前非常感谢您。

【问题讨论】:

  • 是的,这可以在 Linux 上完成。
  • @kec,谢谢。您的意思是 GCC/Clang 可以通过向它们传递一些选项来加载共享对象延迟吗?有没有官方文档描述如何使用它?很高兴知道您能否解释为什么我得到上述结果。
  • 其实重读之后,我不确定我是否知道你在说什么。你在谈论 dlopen() 吗?你想发生什么?
  • @kec,很抱歉让您感到困惑。我知道可以使用 dlopen() 和 dlsum() 实现延迟加载功能,但不想在源代码中调用它们。相反,我想通过只是将一些选项标志传递给链接器或编译器并保持源代码原样来实现。
  • 嗯...惰性绑定是默认设置。加载是否真的是懒惰的,我不确定,但真的有实际区别吗?如果你真的想知道,你可以使用strace 来找出库何时被mmap'ped in。你想达到什么目的?

标签: c++ linux gcc clang


【解决方案1】:

这更多是运行时链接器ld-linux.so提供的功能问题。

此链接器支持符号的延迟绑定,但不支持库的延迟加载。这意味着可执行文件所需的每个共享对象都在程序启动时被加载,但程序中的符号在首次引用之前不会解析为加载的库。

这样做的原因是性能。一个库可能包含数千个函数符号,这些符号在程序的单次执行中永远不会被调用。解决所有问题将是浪费时间。

因此,如果一个库不包含预期的符号,您可能会在程序开始运行后得到“未定义符号”错误,但如果一个库完全丢失,您将在程序启动之前收到错误.

您引用的-zlazy 选项仅控制惰性符号绑定。事实上它是默认启用的(至少对于 GCC,我没有检查 clang)。

在程序启动后加载库的唯一方法是调用dlopen。

您可能想四处寻找一个好的插件框架 - 参考请参阅:

【讨论】:

  • @harmic,感谢您留下您的评论。它回答了我做错的所有事情。我会阅读您在上面发布的参考资料。再次感谢你! :)
  • @harmic,我犹豫使用 dlopen 方式的原因是它看起来很复杂。我实际上已经确认它适用于一个非常简单的 C++ 程序(它调用一个类的成员函数,该函数由从 dlsym() 返回的类指针获得)。但是如果我尝试将该技术应用于第三方库(与我测试的教程程序相比,它越来越复杂),一切都会变得疯狂......
  • @user3591878 很难从该描述中知道问题所在!我建议您将其作为一个单独的问题发布。尽可能包含导致“疯狂”行为的最小示例程序。
  • @harmic,请不要介意我在上面的评论,感谢您的建议。如果可以帮助读者理解问题,我将尝试将每个问题单元的 cmets 分开并放置示例代码:)
  • 可以在现有链接器功能之上构建延迟加载,方法是生成将在第一次调用时调用 dlopen 的存根库(参见另一个答案)。
【解决方案2】:

Linux 不支持开箱即用的延迟加载库,但它可以使用在 Windows 上使用的相同机制轻松实现,即通过链接到第一次调用 dlopens 主要共享库的小型存根静态库它的任何功能。

您可以手动实现此类存根库,通过为您的项目量身定制的自定义脚本或使用Implib.so 自动生成它:

$ clang bar.c -fPIC -shared -o libbar.so
$ implib-gen.py libbar.so
$ clang foo.c libbar.tramp.S libbar.init.c -o foo

【讨论】:

  • 我喜欢你的努力,但我们应该在链接器中直接有类似的东西。我认为 LLVM LLD 的人可能比 GNU ld 的人更开放。您尝试联系他们了吗?
  • @ceztko 你是对的,实际上在 Sun 的 shlibs 中(之后实现了 GNU shlibs)延迟加载确实有效。所以不清楚为什么它没有在 GNU libc 中实现。已经有discussions in mailing list 没有得到任何回应。我只是用我的工具走了阻力最小的道路。
  • 我刚刚阅读了您链接的消息,在两个回复中人们基本上不了解该功能:)
  • @ceztko LLD 可能确实可行,我会尝试与他们交谈。
  • 我订阅了llvm-dev 邮件列表,该列表目前正在审核,但他们仍然手动接受所有订阅。这是要求 LLD 的正确地方。我可以发送介绍性帖子,同时引用您的项目,要求 LLD 中的 /DELAYLOAD 等效项并表现出一些兴趣。之后,您可以从技术角度进行干预,因为您的专业知识。告诉我它是否适合你
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-18
  • 1970-01-01
相关资源
最近更新 更多