我做了一段代码,它包含在动态库(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)

来源如下:
库C
#include <stdio.h>
#include <stdlib.h>

int global;

int f_one() {

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

    return EXIT_SUCCESS;
}

主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——版本:gcc(ubuntu/linaro 4.5.2-8ubuntu4)4.5.2
uname-a:linux xxx 2.6.38-11-generic 48 ubuntu smp周五7月29日19:02:55 UTC 2011 x86 x86 x86 x86 GNU/linux
编辑:在sun/sparc和x86/linux架构下测试的代码,使用了相同类型的意外共享全局变量(with-fpic)。

最佳答案

使用-fPIC编译时,有问题的对象将使用全局偏移表确定全局符号的地址。但是当代码的一部分是-fPIC而另一部分不是时,会发生的情况是其中一个int global将使用此表来确定地址,而另一部分不是。
如果您有两个与-fPIC链接的共享对象,但您的主程序没有,那么您仍将有两个int global地址,一个使用全局偏移表,另一个只是非pic代码的本地地址。
如果你想进一步阅读,这里有一个really great discussion on PIC vs pic vs non PIC

关于c - 全局变量,共享库和-fPIC效果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7298186/

10-11 21:56