如何解决使用共享库是否会导致只有一个全局变量实例?
假设我们有一个程序(可执行文件)prog
链接到 libA
和 libB
。 libA
和 libB
依次链接到包含全局变量的 libX
。
在以下情况下,全局变量在 prog
进程中会有一个实例,还是两个不同的实例?
-
prog
正在链接到libA
,而libB
是动态的,但两者都是静态链接到libX
。 (我假设有两个实例?) -
prog
正在链接到libA
并且libB
是动态的,并且这两个链接到libX
都是动态的。 (我假设一个实例?) -
prog
链接到libA
和libB
是静态的,并且这两个链接到libX
都是静态的。 (我又假设一个实例?)
另外:
- 如果将全局声明为
static
(翻译单元的本地),会产生什么不同吗?在我的用例中,它是。 - 这些问题的答案是否因操作系统而异? (macOS、Linux、Windows)
- 您能否推荐一些阅读来解释我自己回答类似问题所需的基础知识?
解决方法
prog 链接到 libA,libB 是动态的,但两者都是静态链接到 libX。 (我假设有两个实例?)
在这种情况下,答案取决于从 libA.so
和 libB.so
导出哪些符号。
如果变量(我们称之为 glob
)有静态链接,那么它不会被导出,并且你会有两个单独的实例。
同样,如果变量没有静态链接,但是 libX
是用例如编译的-fvisibility-hidden
,或者如果 libA.so
或 libB.so
与阻止导出 glob
的链接描述文件链接,您将有两个单独的实例。
但是,如果变量具有全局链接并且其可见性不受上述机制之一的限制,那么(默认情况下)它将从 libA.so
和 libB.so
导出,并且在那个case 对该变量的所有引用都将绑定到首先加载的库。
更新:
内存中是否会有该变量的两个实例,但只有第一个可以访问,或者链接器根本不会为第二个变量保留任何空间?
内存中将有两个实例。
当链接器构建 libA.so
或 libB.so
时,它不知道还有哪些其他库存在,因此它必须在可读和可写段(相应库的 .data
和 .bss
部分通常进入的部分。
在运行时,加载器mmap
s 整个 段,因此没有机会不为每个库中的变量保留内存空间。
但是当代码在运行时引用变量时,加载器会将所有这样的引用解析到它遇到的第一个符号。
注意:以上是 ELF 系统上的默认行为。 Windows DLL 的行为不同,使用 -Bsymbolic
链接库也可能会改变符号解析的结果。
prog 链接到 libA 和 libB 是动态的,并且这两个链接到 libX 动态。 (我假设一个实例?)
正确。
prog 静态链接到 libA,libB 是静态链接,并且这两个链接都是静态链接到 libX。 (我又假设一个实例?)
这是一个不可能的场景:您不能将 libA.a
与 libX.a
关联起来。
但是当将 prog
与 libA.a
、libB.a
和 libX.a
联系起来时,是的:您最终会得到一个 glob
实例。
C 没有全局命名空间。它具有文件范围(和其他)和外部链接(以及内部和无)。在所描述的情况下,使用普通链接方法,libX
中定义的静态对象将在程序中具有一个实例,无论其链接是内部(用 static
声明)还是外部(无)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。