1. 程式人生 > >動態連結中資料的重定向例子

動態連結中資料的重定向例子

程式的大致框架:
主程式:

#include <stdio.h>
extern void hello(void);
extern int a;
int main(void)
{
    printf("in main.c a=%d\n", a);
    printf("in main.c &a=%p\n", &a);
    hello();
    return 0;
}

共享物件:

#include <stdio.h>
int a = 1;
void hello(void)
{
    printf("lib.c a=%d\n"
, a); printf("lib.c &a=%p\n", &a); return; }

考慮這麼幾種情況
(1)共享物件定義了靜態變數a=1,主程式定義了全域性變數a並且沒有初始化,分別在共享物件和主程式裡面列印a的值
結果:共享物件中a=1,主程式a=0.
分析:因為共享物件中使用了靜態變數,屬於模組內部的資料引用,使用了位置無關程式碼,並且a不需要重定向,因此a=1,主程式中由於a沒有定義,被分配到了.bss段,當載入程式時初始化為0.
(2)共享物件定義了全域性變數a=1,主程式定義了全域性變數a並且沒有初始化,分別在共享物件和主程式裡面列印a的值
結果:共享物件中a=1,主程式a=1.
分析:因為共享物件中使用了全域性變數,屬於模組之間的資料引用,此時a被放在了.got段,需要重定向,主程式中由於a定義了,被分配到了.bss段,當載入程式時,由於主程式中a沒有初始化,在動態連結時,會把共享物件中a的值拷貝到主程式中a的地址,於是a=1,因此無論是在主程式還是在共享物件中,兩者列印的都是主程式中a的值。通過列印a的地址也可以知道,列印的是同一個地址的值。
這時我們檢視一下a在兩個模組中動態連結的資訊:
主程式動態連結資訊:

Relocation section '.rela.dyn' at offset 0x4d8 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000600a60  000700000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000600ab0  000900000005 R_X86_64_COPY     0000000000600ab0 a + 0

共享物件動態連結資訊:

Relocation section '.rela.dyn' at offset 0x400 contains 9
entries: Offset Info Type Sym. Value Sym. Name + Addend 000000200758 000000000008 R_X86_64_RELATIVE 0000000000000640 000000200760 000000000008 R_X86_64_RELATIVE 0000000000000600 000000200988 000000000008 R_X86_64_RELATIVE 0000000000200988 000000200930 000200000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0 000000200938 000700000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0 000000200940 000900000006 R_X86_64_GLOB_DAT 0000000000200990 a + 0 000000200948 000b00000006 R_X86_64_GLOB_DAT 0000000000000000 _Jv_RegisterClasses + 0

很明顯在主程式中,從Type屬性看,a其實是一個copy,複製了共享物件中的a的值。而共享物件,a的值是一個需要重定向的資料,存放在.got.
(3)共享物件定義了全域性變數a=1,主程式定義了全域性變數a=2,分別在共享物件和主程式裡面列印a的值
結果:共享物件中a=2,主程式a=2.
分析:這個和情況2有點類似,只是主程式中a已經有值了,動態連結時,不會把共享物件中a的值複製到主程式中,剩下的重定向一樣。

這個例子很好的說明了共享物件和主程式中資料的重定向,當然這個例子也可以延伸為函式的呼叫,不過基本思想大致一樣。