在 C++ 中:
静态库“A”定义了一个全局变量 foo。
“B”和“C”是两个动态库,都依赖于 A,因此与 A 链接(静态)。
然后B和C最终加载在同一个进程中
(例如:应用程序负载 B 和 C)。
如果我们在 Windows 环境中,我们将获得 foo 的两个不同实例,一个在 B 中,一个在 C 中,如下所示:
C++静态库中的共享全局变量
Linux环境呢?
语境:
我们目前正在将一个 windows 项目移植到 linux
每个库都将包含 A 的副本。但是,在运行时,进程的所有组件只会使用一个副本。
// h.h
extern int a;
void b(void);
void c(void);
// a.c
#include "h.h"
int a = 0;
// b.c
#include <stdio.h>
#include "h.h"
void b(void)
{
printf("%i\n", a++);
}
// c.c
#include <stdio.h>
#include "h.h"
void c(void)
{
printf("%i\n", a++);
}
//main.c
#include <stdio.h>
#include "h.h"
int main()
{
b();
c();
}
#Makefile
main: libxc.so libxb.so
cc -o main main.c -L. -lxc -lxb
libxb.so:
cc -fPIC -shared a.c b.c -o libxb.so
libxc.so:
cc -fPIC -shared a.c c.c -o libxc.so
$make
$ LD_LIBRARY_PATH=. ./main
0
1
符号表来自libxa.so
:
53: 000000000020098c 4 OBJECT GLOBAL DEFAULT 24 a
From libxc.so
:
53: 000000000020098c 4 OBJECT GLOBAL DEFAULT 24 a
默认可见性是STV_DEFAULT
根据LSB:
STV_DEFAULT
:符号的可见性STV_DEFAULT
属性由符号的绑定类型指定。那是,
全局符号和弱符号在其外部可见
定义
组件(可执行文件或共享对象)。局部符号是
隐藏,如下所述。全局符号和弱符号也是
可抢占的,也就是说,它们可以被相同的定义抢占
另一个组件中的名称。
man 5 elf
:
STV_DEFAULT
:默认符号可见性规则。
Globa 和弱符号可用于其他
模块;本地模块中的引用可以
被其他定义插入
模块。
有关SysV ABI:
当解析符号引用时,
动态链接器使用广度优先搜索来检查符号表。
也就是说,它首先查看可执行文件的符号表
程序本身,然后在符号表DT_NEEDED
条目(按顺序),然后在第二层 DT_NEEDED
条目等。
如果这不是预期的,使用STV_HIDDEN
符号上的阻止它在共享对象外部可见。
相反,在 Windows 上,符号始终从给定的 DLL 导入,并且默认情况下符号不会导出到其他 DLL。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)