使用共享库会导致全局变量只有一个实例吗?

Does using shared libraries lead to having a single instance of global variables?

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

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

  1. prog 是 link 到 libAlibB 是动态的,但是这两个 link 到 libX 是静态的。 (我假设有两个例子?)
  2. prog 是 link 到 libAlibB 是动态的,而这两个 link 到 libX 是动态的。 (我假设一个例子?)
  3. prog 是 link 到 libAlibB 是静态的,而这两个 link 到 libX 是静态的。 (我又假设一个例子?)

此外:

C 没有全局命名空间。它具有文件范围(和其他)和外部 linkage(以及内部和 none)。在所描述的情况下,使用正常的 link 方法,在 libX 中定义的静态对象将在程序中有一个实例,无论其 linkage 是否是内部的(用 [=11 声明) =]) 或外部(无)。

prog is linking to libA and libB is dynamically, but both of those link to libX statically. (I assume two instances?)

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

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

同样,如果变量没有静态 linkage,但是 libX 是用例如编译的。 -fvisibility-hidden,或者如果 libA.solibB.so 被 link 编辑了一个 linker 脚本以防止 glob 被导出,你将有两个独立的实例。

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

更新:

will there be two instances of that variable in memory, but just the first one is accessible, or the linker will not reserve any space at all for the second variable?

内存中会有两个实例。

当 link 人构建 libA.solibB.so 时,它 不知道 还有哪些其他库存在,因此它必须在相应库的可读写段(.data.bss段通常进入的段)保留space。

在运行时,加载程序mmap整个段,因此没有机会保留内存space 为每个库中的变量。

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

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

prog is linking to libA and libB is dynamically, and both of those link to libX dynamically. (I assume one instance?)

正确。

prog is linking to libA and libB is statically, and both of those link to libX statically. (I assume one instance again?)

这是一个不可能的场景:你不能 link libA.a 对抗 libX.a.

但是当 linking prog 反对 libA.alibB.alibX.a 时,是的:你最终会得到一个 glob.