全局变量,共享库和-fPIC效果

我制作了一段代码,它包含一个动态库( lib.c )和一个主可执行文件( main.c )。 在这两个文件中,我定义了一个名为: int global的全局变量。 不是很聪明,但这不是问题。

当我编译动态库时, -fPIC选项似乎是强制性的:

 gcc lib.c -fPIC -shared -o lib.so 

否则我得到:

 /usr/bin/ld: /tmp/ccpUvIPj.o: relocation R_X86_64_32 against '.rodata' can not be used when making a shared object; recompile with -fPIC 

当我编译可执行文件时,它不是。

 gcc main.c -fPIC -ldl gcc main.c -ldl 

两者都有效,但有不同的行为,我无法解释,是吗? :

使用-fPIC,main.c中的global和lib.c中的global是相同的变量:

 global main: 23 (0x601050) global lib: 23 (0x601050) 

没有-fPIC,lib.c中的global与main.c中的global不相关:

 global main: 23 (0x601048) global lib: 0 (0x7f7742e64028) 

这是来源:

lib.c

 #include  #include  int global; int f_one() { printf("global lib: %d (%p)\n", global, &global); return EXIT_SUCCESS; } 

main.c中

 #include  #include  #include  void * handle; int global; int main() { int q = 7; int (* f_one_p)(int a) = NULL; global = 23; handle = dlopen("./lib.so", RTLD_NOW); if (handle == 0) { return EXIT_FAILURE; } f_one_p = dlsym(handle, "f_one"); printf("global main: %d (%p)\n", global, &global); f_one_p(q); return EXIT_SUCCESS; } 

gcc –version:gcc(Ubuntu / Linaro 4.5.2-8ubuntu4)4.5.2

uname -a:Linux xxx 2.6.38-11-generic#48-Ubuntu SMP Fri 7月29日19:02:55 UTC 2011 x86_64 x86_64 x86_64 GNU / Linux

编辑 :在SUN / sparc和x86 / Linux体系结构下测试的代码,具有相同类型的意外共享全局变量(使用-fPIC)。

使用-fPIC进行编译时,相关对象将使用全局偏移表确定全局符号的地址。 但是当代码的一部分是-fPIC而部分不是时,会发生什么呢?你的一个int global s将使用这个表来确定地址,而另一部分不是。

如果你有两个与-fPIC链接的共享对象,但你的主程序没有,那么你仍然会有两个地址用于int global ,一个使用全局偏移表,另一个使用非PIC代码本地。

如果你想进一步阅读, 有关PIC与PIC和非PIC的真正讨论 。

默认情况下,构建可执行文件时,对变量的引用是在内部完成的,具有固定的偏移量且没有重定位。

但是,您正在传递-fPIC并且通过GOT -fPIC全局数据的访问转换为访问,并添加GOT重定位。