yot*_*ota 13 c fpic dynamic-library
我制作了一段代码,其中包含一个动态库(lib.c)和一个主可执行文件(main.c).在这两个文件,我定义一个名为一个全局变量:int global.不是很聪明,但这不是问题.
当我编译动态库时,该-fPIC选项似乎是强制性的:
gcc lib.c -fPIC -shared -o lib.so
Run Code Online (Sandbox Code Playgroud)
否则我得到:
/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
Run Code Online (Sandbox Code Playgroud)
当我编译可执行文件时,它不是.
gcc main.c -fPIC -ldl
gcc main.c -ldl
Run Code Online (Sandbox Code Playgroud)
两者都有效,但有不同的行为,我无法解释,是吗?:
使用-fPIC,main.c中的global和lib.c中的global是相同的变量:
global main: 23 (0x601050)
global lib: 23 (0x601050)
Run Code Online (Sandbox Code Playgroud)
没有-fPIC,lib.c中的global与main.c中的global不相关:
global main: 23 (0x601048)
global lib: 0 (0x7f7742e64028)
Run Code Online (Sandbox Code Playgroud)
这是来源:
lib.c
#include <stdio.h>
#include <stdlib.h>
int global;
int f_one() {
printf("global lib: %d (%p)\n", global, &global);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
main.c中
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
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;
}
Run Code Online (Sandbox Code Playgroud)
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 Jul 29 19:02:55 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
编辑:在SUN/sparc和x86/Linux体系结构下测试的代码,具有相同类型的意外共享全局变量(使用-fPIC).
使用-fPIC相关对象进行编译时,将使用全局偏移表确定全局符号的地址.但是当部分代码是-fPIC部分代码而不是部分代码时,您int global的某个人将使用此表来确定地址,而另一部分不是.
如果你有两个链接的共享对象-fPIC,但你的主程序没有,那么你仍然会有两个地址int global,一个使用全局偏移表,另一个只是非PIC代码的本地.
如果你想进一步阅读,对PIC与PIC和非PIC有很好的讨论.