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

时间:2011-09-04 08:52:49

标签: c dynamic-library 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 <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-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)。

2 个答案:

答案 0 :(得分:8)

使用-fPIC进行编译时,相关对象将使用全局偏移表确定全局符号的地址。但是当部分代码为-fPIC而部分不是int global时,您的-fPIC将使用此表来确定地址,而另一部分不是。

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

如果您想进一步阅读,可以使用really great discussion on PIC vs pic vs non PIC

答案 1 :(得分:1)

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

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