【问题标题】:linking, loading, and virtual memory链接、加载和虚拟内存
【发布时间】:2014-11-04 20:34:19
【问题描述】:

我知道以前有人问过这些问题 - 但我仍然无法将所有内容调和成一个整体。

  1. 静态库与动态库
    • 静态库将其代码复制并链接到生成的可执行文件中
    • 静态库仅将所需模块复制并链接到可执行文件中,而不是整个库实现
    • 静态库不需要编译为 PIC,因为它们是生成的可执行文件的一部分
    • 动态库在描述如何在运行时加载/链接(?)函数实现的存根中复制和链接
    • 动态库可以是 PIC 或可重定位的
    • 为什么有单独的静态库和动态库?以上所有似乎都是静态或动态链接器的工作。为什么我需要 2 个实现 scanf 的库?
    • bonus #1共享库指的是什么?我听说它被用作 (1) 总括术语,与库同义,(2) 直接用于动态库,(3) 使用虚拟内存将库的相同物理内存映射到多个地址空间。您只能使用动态库来做到这一点吗? (4) 内存中有同一个动态库的不同版本。
    • (bonus #2) 标准库(libc、libc++、stdlibc++、..)是默认动态链接还是静态链接?我永远不需要dlopen()..
  2. 静态与动态链接
    • 这与静态库和动态库有何不同?我不明白为什么不只有 1 个库,我们使用静态或动态链接器(除了 PIC 问题)。与其讨论静态库与动态库,不如讨论更通用的静态动态链接?
    • 是否仍然在编译时执行符号解析?
  3. 静态与动态加载
    • 静态加载意味着在执行之前将完整的可执行文件复制到 MM 中
    • 动态加载意味着在执行前只将可执行文件头复制到 MM 中,在请求时将附加功能加载到 MM 中。这与分页有何不同?
    • 如果可执行文件是动态链接的,为什么不能动态加载?
    • 静态加载和动态加载可能会也可能不会执行重定位

我知道这里有很多让我感到困惑的事情 - 我没有必要找人来解决每个问题。我希望通过列出所有让我感到困惑的事情,了解这一点的人会看到我的理解失误在哪里,并能够描绘出关于这些事情如何协同工作的更大图景..

【问题讨论】:

  • 如果在 Linux 上,请阅读 Drepper's paper: How to Write Shared Libraries。这是一篇很长的论文,但它回答了你的大部分问题。
  • @BasileStarynkevitch 谢谢你的论文——我会读的!操作系统之间的概念是否有很大差异?
  • 您应该将语句“静态库仅将所需模块复制并链接到可执行文件中,而不是整个库实现”改写为“链接器仅将每个静态库的所需模块链接到可执行文件中"。
  • @BasileStarynkevitch 是的,我以前看过推荐的,我会看看!感谢您的回复

标签: c linker shared-libraries loading paging


【解决方案1】:

为什么要加载两种类型的库

  • 动态节省空间(您不会在所有使用 foo.lib 的二进制文件中拥有数百个相同代码的副本
  • 动态允许 foo.lib 供应商可以发布新版本的库,并且现有代码可以利用它
  • 静态使依赖管理更容易 - 理论上二进制文件可以是一个文件

什么是“共享库”

  • 动态库的unix名称。 Windows 称之为 DLL

标准库是静态的还是动态的

  • 取决于平台。在一些你可以选择其他的它为你选择。例如,在windwos 上有编译器开关来说明您是否需要静态或动态运行时。不要将动态库的使用与 dlopen 混淆 - 见后

'为什么我们要讨论两种不同类型的库'

通常静态库与动态库的格式不同。通常,静态库就像任何其他编译单元一样输入到链接器。动态库通常由链接器输出。即使它们都向您的应用程序提供相同的代码块,它们的使用方式也不同

符号解析在加载 DLL 时完成

完全动态加载。这是 dlopen 的领域。这是您想要调用编译时可能不存在的库中的入口点的地方。用例:

  • 符合众所周知的接口但可以有许多实现的插件(PAM 和 NSS 就是很好的例子)。应用选择在运行时从指定文件加载一个或多个实现

  • 应用程序需要加载库并调用任意函数。想象一下,例如,脚本语言如何加载和调用任意方法

要在 unix 上使用 .so,您不需要使用 dlopen。您可以为您加载它(在 Windows 上相同)。要真正动态加载共享库/dll,您需要 dlopen 或 LoadLibrary

【讨论】:

    【解决方案2】:

    请注意,静态链接库的加载速度更快,因为对所有运行时库文件的磁盘搜索更少。如果库很小并且非常不寻常,那么静态链接可能会更好。如果存在严重的版本依赖/功能差异(如 MFC),则 DLL 需要不同的名称。

    【讨论】:

    • 我不确定,至少在 Linux 上是这样。 Linux 上常用的共享库(例如libc.so.6libX11.so.6)已经在RAM 中被mmap-ed。如果它是静态链接的,则需要为 & 从每个可执行文件中获取它。
    猜你喜欢
    • 2011-11-03
    • 1970-01-01
    • 2011-12-11
    • 1970-01-01
    • 2020-05-21
    • 2021-07-25
    • 2013-11-23
    • 2016-07-09
    • 2018-07-09
    相关资源
    最近更新 更多