全局变量,共享库和-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重定位。