2011-09-04 96 views
12

我制成一块代码,由在一个动态库(lib.c),和主可执行文件(main.c)。 在这两个文件中,我定义了一个名为int global的全局变量。 不是很聪明,但它不是问题。全局变量,共享库和-fPIC效果

当我编译动态库-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中全球和lib.c全球都是一样的变量:

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

没有-fPIC,全球在lib.c不main.c中相关的全球:

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

这里是源:

lib.c

#include <stdio.h> 
#include <stdlib.h> 

int global; 

int f_one() { 

    printf("global lib: %d (%p)\n", global, &global); 

    return EXIT_SUCCESS; 
} 

的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; 

} 

GCC --version:GCC(Ubuntu的/ Linaro的4.5.2-8ubuntu4)4.5.2

UNAME -a:Linux的XXX 2.6.38-11泛型# 48 Ubuntu的SMP周五7月29日19时02分55秒UTC 2011 x86_64的x86_64的x86_64的GNU/Linux的

编辑:代码在SUN/SPARC测试和x86/Linux的架构与同类意外共享全局变量(用-fPIC)。

+0

相关:http://stackoverflow.com/q/7216244/168175 – Flexo

回答

7

当您使用-fPIC编译时,所讨论的对象将使用全局偏移量表确定全局符号的地址。尽管部分代码是-fPIC而部分代码不是int global将使用此表来确定地址,而另一部分则不是。

如果您有两个与-fPIC链接的共享对象,但是您的主程序不是这样,那么您仍然有两个地址int global,一个使用全局偏移量表,另一个仅在非PIC代码本地。

,如果你想继续读下去有一个really great discussion on PIC vs pic vs non PIC

1

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

但是,你传递-fPIC和获取全球数据通过GOT转换为接入和GOT加入重定位。