C++静态库中的共享全局变量:Linux

4

这是C++代码:

一个静态库"A"定义了全局变量foo。

"B"和"C"是两个动态库,都依赖于A,因此会与A链接(静态链接)。

然后B和C最终加载到同一进程中(例如:应用程序加载B和C)。

如果我们在Windows环境下运行,则会得到两个不同的foo实例,一个在B中,一个在C中,如此清楚地解释在这里:

C++静态库中共享全局变量

那么在Linux环境下呢?

背景: 我们目前正在将Windows项目移植到Linux。


如果你得不到答案,我猜你可以通过更改全局变量并从第二个库检查其值来执行一个简单的测试。 - Eric Abramov
1个回答

1
每个库都将包含 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

libxc.so中的:

    53: 000000000020098c     4 OBJECT  GLOBAL DEFAULT   24 a

默认可见性为STV_DEFAULT,根据LSB

STV_DEFAULT:具有STV_DEFAULT属性的符号的可见性由其绑定类型指定。 全局和弱符号在它们定义的组件(可执行文件或共享对象)之外可见。本地符号是隐藏的,如下所述。 全局和弱符号也是可抢占的,即它们可以被另一个组件中同名定义的符号抢占。

man 5 elf

STV_DEFAULT:默认的符号可见性规则。 全局和弱符号可以供其他模块使用;本地模块中的引用可以被其他模块中的定义替换。
关于SysV ABI
在解析符号引用时,动态链接器会进行广度优先搜索来检查符号表。也就是说,它首先查看可执行程序本身的符号表,然后查看DT_NEEDED条目(按顺序),然后查看第二级DT_NEEDED条目,以此类推。
如果这不是期望的结果,使用STV_HIDDEN可以防止该符号在共享对象之外被看到。
相比之下,在Windows上,符号总是从给定的DLL中导入,并且默认情况下不会将符号导出到其他DLL中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接