【问题标题】:How to update a shared library without restarting the application in C如何在不重新启动 C 中的应用程序的情况下更新共享库
【发布时间】:2015-12-29 01:09:11
【问题描述】:

我了解dlopen/dlclose/dlsym/dlerror API 用于与 动态加载库,但这对于已经编译的二进制文件如何工作 引用 .so 库(共享库、后台/加载时间链接)的 -L 标志。编辑:我指的是在不重新启动应用程序的情况下实时更新共享库。

【问题讨论】:

  • 你没有。当你想做这样的事情时,你可以使用dlopen() 和朋友。
  • 你打算用这个实现什么目标?
  • 您可以使用 LD_PRELOAD 在可执行文件中定义的库之前加载库。见stackoverflow.com/questions/426230/what-is-the-ld-preload-trick
  • @Pradheep 我想实现共享库的实时更新,并在不使用 dlopen() 系列调用的情况下对使用它的应用程序产生影响,同时保持我当前的应用程序构建过程完好无损。跨度>
  • @Paul 正确的总结。根据我的研究,请参阅下面的答案以获取详细信息。

标签: c .so


【解决方案1】:

马聪提供了一些很好的建议。以下是经过更多研究后我可以得出的结论:

  • 如果应用程序链接到 .so,并且共享库被替换为它的新副本,而不停止应用程序,结果将是“不确定的”或“不可预测的”。
  • 在应用的“链接/加载”阶段,库被映射到应用/进程的地址空间。
  • 类 Unix 操作系统维护 COW,因此作为参考,如果在写入时进行复制,则应用程序不会产生任何影响,但无法实现能够使用新 .so 代码的目标
  • 这一切都与应用正在访问的内存区域有关 - 如果访问区域的地址没有变化,则应用不会受到任何影响。
  • 新版本的 lib 可能具有增量性质,这可能不会影响应用程序 - 可重定位地址生成也可能具有编译魔法。
  • 您可能很幸运,有时属于上述类别,并且在将 .so 替换为引用它的正在运行的应用程序时没有任何问题,但实际上您大多数时候会遇到 SIGSEGV/SIGBUS 等,作为地址/交叉-reference 与库中的重大变化混为一谈。

dlopen() 解决了这个问题,因为我们减少了库的访问窗口。如果您执行 dlopen() 并使其保持打开足够长的时间,那么您的应用程序就会面临同样的问题。所以这个想法是减少访问窗口以防止更新场景发生故障。

【讨论】:

    【解决方案2】:

    我想说在应用程序运行时重新加载动态库是可能的。但要做到这一点,您必须从一开始就将这种“实时重新加载”设计到库中。

    从概念上讲,这并不难。

    首先,您必须提供一种机制来通知应用程序重新加载库。这实际上是最简单的部分 - 至少在 Unix 世界中:重命名或取消链接原始库并将新库放在它的位置,然后让应用程序在旧库上调用 dlclose(),在新库上调用 dlopen()。 Windows 可能更难。在 Unix 或 Unix 类型的系统上,您甚至可以在应用程序仍在运行时进行取消链接/重命名。事实上,在 Unix 类型的系统上,您根本不想覆盖现有的库,因为这会给您带来严重的问题。现有的磁盘库是从该库映射到进程地址空间的页面的后备存储 - 物理覆盖共享库的文件内容将再次导致未定义的行为 - 操作系统加载它期望找到入口点的页面函数 foo() in 但该地址现在是 bar() 函数的一半。取消链接或重命名是安全的,因为文件内容在进程仍在映射时不会从磁盘中删除。

    其次,在使用库时无法卸载它(在某些操作系统上使用库时可能会卸载它,但我看不出这会导致除未定义行为之外的任何其他事情,所以“不能”是事实上正确的,如果不是法律上...)。

    因此,您必须在重新加载库时控制对库的访问。这并不是真的那么困难 - 有一个 shim 库,可以将您的 API 呈现给任何应用程序,并在该库中使用读/写锁。对库的每次调用都必须在读/写锁上持有读锁,并且只有在读/写锁上持有写锁时才能重新加载库。

    这些都是简单的部分。

    困难的部分是设计和编码您的库,以便在重新加载时不会丢失或损坏任何内容。你如何做到这一点取决于你的代码。但是,如果您犯了任何错误,就会出现更多未定义的行为。

    由于无论如何您都必须停止对库的访问才能重新加载它,并且您不能在重新加载过程中传递状态,因此仅退回应用程序会容易得多。

    【讨论】:

      【解决方案3】:
      1. 不要假设。阅读它...Inside stories on shared libraries and dynamic loading。 tldr:共享库(大部分)在应用程序执行之前加载,而不是“在后台”。

      2. 您的意思是“在不重新启动应用程序的情况下实时更新共享库”吗?如果不破解您自己的装载机,我认为这是不可能的。查看this question的答案。

      【讨论】:

      • 实际上,在现代操作系统上,库可能是按需加载的,即在第一次访问时。这可以很好地称为“后台”加载。并且很可能动态加载/卸载库。您链接的文档中甚至提到了它。请注意,该文档已有约 15 年的历史,并且从那时起技术已经进步(我没有阅读它,因此后者只是一般性的评论,阅读时要谨慎)。
      猜你喜欢
      • 1970-01-01
      • 2018-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-15
      • 2019-12-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多