【问题标题】:Does using shared libraries lead to having a single instance of global variables?使用共享库会导致拥有一个全局变量实例吗?
【发布时间】:2021-06-07 05:30:31
【问题描述】:

假设我们有一个程序(可执行)prog 链接到 libAlibBlibAlibB 又链接到 libX,其中包含一个全局变量。

在下列情况下,全局变量会在prog进程中有一个实例,还是两个不同的实例?

  1. prog 链接到 libAlibB 是动态的,但是这两个链接到 libX 是静态的。 (我假设有两种情况?)
  2. prog 链接到 libAlibB 是动态的,并且这两个链接到 libX 是动态的。 (我假设一个例子?)
  3. prog 链接到 libAlibB 是静态链接,并且这两个链接到 libX 静态链接。 (我再假设一个例子?)

另外:

  • 如果将全局声明为static(翻译单元的本地),是否会有所不同?在我的用例中,它是。
  • 这些问题的答案是否因操作系统而异? (macOS、Linux、Windows)
  • 您能否推荐一些阅读材料来解释我自己回答类似问题所需的基本知识?

【问题讨论】:

  • 为什么不检查一下?
  • @KamilCuk 我希望对该主题有更深入的了解。在单个平台上检查这个不会给我那个。
  • “静态链接到...”对我来说很奇怪。您不能与某些东西“静态链接”。静态库是目标文件的集合,您不能“与它链接”。您可以将其编译为可执行文件或共享库。静态链接基本上意味着编译。
  • @KamilCuk 我真的不想挑剔术语。你需要澄清这个问题吗?如果是,我可以尝试改进它。
  • @KamilCuk 静态链接不是编译。我可以在一台计算机上编译一个对象库并将其链接到我在另一台计算机上编译的代码。该库甚至可以用第二台计算机没有编译器的语言编译。静态和动态链接是两个独立的概念(前者在构建时,后者在运行时)。

标签: c global-variables shared-libraries static-linking dynamic-linking


【解决方案1】:

prog 链接到 libA 和 libB 是动态的,但是这两个链接到 libX 是静态的。 (我假设有两个例子?)

在这种情况下,答案取决于从libA.solibB.so导出的符号。

如果变量(我们称之为glob)具有静态链接,那么它不会被导出,您将拥有两个单独的实例。

同样,如果变量没有静态链接,但 libX 使用例如编译-fvisibility-hidden,或者如果 libA.solibB.so 与阻止导出 glob 的链接器脚本链接,您将拥有两个单独的实例。

但是,如果变量具有全局链接并且其可见性不受上述机制之一的限制,那么(默认情况下)它将从 libA.solibB.so 导出,在这种情况下,所有对该变量将绑定到首先加载的任何库。

更新:

内存中是否有该变量的两个实例,但只有第一个可访问,或者链接器根本不会为第二个变量保留任何空间?

内存中会有两个实例。

当链接器构建libA.solibB.so 时,它不知道存在哪些其他库,因此它必须在可读可写段(@ 987654333@ 和 .bss 部分通常放在相应的库中。

在运行时,加载器mmaps 整个段,因此不可能为每个库中的变量保留内存空间。

但是当代码在运行时引用变量时,加载器会将所有此类引用解析为它遇到的第一个符号。

注意:以上是 ELF 系统上的 默认 行为。 Windows DLL 的行为不同,使用-Bsymbolic 链接库也可能会改变符号解析的结果。

prog 链接到 libA 和 libB 是动态的,并且这两个链接到 libX 动态。 (我假设一个实例?)

正确。

prog 正在链接到 libA,而 libB 是静态的,并且它们都静态链接到 libX。 (我再假设一个实例?)

这是一个不可能的场景:您不能将 libA.alibX.a 关联起来。

但是当链接proglibA.alibB.alibX.a 时,是的:你最终会得到一个glob 的实例。

【讨论】:

  • 我很好奇it will be exported from both libA.so and libB.so, and in that case all references to that variable will bind to whichever library is loaded first 在这种情况下:内存中是否会有该变量的两个实例,但只有第一个是可访问的,否则链接器根本不会为第二个变量?
【解决方案2】:

C 没有全局命名空间。它具有文件范围(和其他)和外部链接(内部链接和无链接)。在所描述的情况下,使用普通链接方法,libX 中定义的静态对象将在程序中拥有一个实例,无论它的链接是内部的(用static 声明的)还是外部的(没有)。

【讨论】:

  • 即使 libA 和 libB(都是共享库)静态链接到 libX 也是这种情况吗?我本来希望这会创建两个单独的全局变量实例,一个在 libA 中,一个在 libB 中。
  • @Szabolcs:如果将 libX 链接到 libA,创建新的组合对象模块(独立的或在新的库文件中)并删除 libX 的外部符号并对 libX 执行相同的操作到 libB,然后将这两个新的目标模块或库链接到一个可执行文件,您可以生成一个包含两个 libX 副本及其内部数据的可执行文件。因此,可以使用特殊的链接技术。 (如果您不删除其中至少一个中的外部符号,则指向一个可执行文件的链接应该会由于多个定义而失败。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-26
  • 1970-01-01
相关资源
最近更新 更多