2011-09-04 97 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加入重定位。