微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决使用共享库是否会导致只有一个全局变量实例?

假设我们有一个程序(可执行文件prog 链接libAlibBlibAlibB 依次链接到包含全局变量libX

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

  1. prog 正在链接libA,而 libB 是动态的,但两者都是静态链接libX。 (我假设有两个实例?)
  2. prog 正在链接libA 并且 libB 是动态的,并且这两个链接libX 都是动态的。 (我假设一个实例?)
  3. prog 链接libAlibB 是静态的,并且这两个链接libX 都是静态的。 (我又假设一个实例?)

另外:

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

解决方法

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

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

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

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

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

更新:

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

内存中将有两个实例。

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

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

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

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

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

正确。

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

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

但是当将 proglibA.alibB.alibX.a 联系起来时,是的:您最终会得到一个 glob 实例。

,

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。