2017-07-07 88 views
0

比方說,我們有:C全局靜態變量初始化是由鏈接器完成的?

在f1.c

#include <stdio.h> 
static int x = 10; 

void f1() { 
    printf("f1.c : %d\n", x); 
} 

的main.c

​​

我們將編譯和閱讀兩個ELF文件symboltables(相對ELF和exec ELF。):

$> gcc -c *.c 
$> readelf -s f1.o | grep x 
     Num: Value   Size Type Bind Vis  Ndx Name 
     5: 0000000000000000  4 OBJECT LOCAL DEFAULT 3 x 
$> gcc *.o 
$> readelf -s a.out | grep x 
     Num: Value   Size Type Bind Vis  Ndx Name 
     38: 0000000000601038  4 OBJECT LOCAL DEFAULT 25 x 

我可以看到Value(也稱爲地址),其中全局靜態變量x0000000000000000從讀取可重定位目標文件f1.o
這意味着我們還沒有初始化它,因爲它仍然是一個rel。 ELF對象文件和鏈接器將處理此問題。

所以我的問題是,如果鏈接器是在鏈接0000000000601038後將已知地址設置爲x的值爲10的鏈接器,那麼它是如何實現的?鏈接器獲取信息到將值設置爲10以及誰提供此信息(f1.o?)?

+0

這裏的值是變量'x'的*地址*,而不是'x'的值 –

+0

@ChrisDodd是的,我已經注意到在最初的問題已經不是混淆了,我看看它是如何聽起來像我的意思是它沒有被初始化,因爲那個。 – Seoul

回答

5

0000000000000000(在對象文件f1.o)是相對地址(靜態變量),因此被偏移,而且文件也包含relocation與它的指令。用於獲取參數x以打印的代碼也有一些重定位(在某些加載機器指令上)。

在該目標文件中,您可能有一個.data部分。該部分應以包含10的單詞開頭(包含您在f1.o中觀察到的0偏移量)。

閱讀更多關於linkers(我推薦Levine的Linkers and loaders書)。鏈接過程(獲取ELF可執行文件)正在處理重定位指令。另請參閱更多關於ELF格式的信息,從elf(5)開始(在閱讀ELF wikipage之後)。研究ABI規範(對於Linux x86-64,請參閱here,從this的答案),其中詳細說明了可能的重定位指令。

您可能要編譯f1.cgcc -Wall -S -fverbose-asm -O1 f1.c再看看發出彙編文件f1.s

您可能還需要檢查的對象文件f1.o和ELF可執行a.out與像readelf(1)objdump(1)各種工具。兩者都接受許多選項(特別是-r選項到objdump以顯示重定位指令)。

Dynamic linking(的C standard librarylibc.*.so)在ELF可執行文件中引入了一些額外的複雜性。另請參閱ld-linux(8)(在運行時啓動時執行一些鏈接作業)和vdso(7)。您可能還想閱讀Drepper的How To Write Shared Libraries論文。

免費提供的教科書Operating Systems: Three Easy Pieces也值得閱讀(它解釋什麼是process以及它的執行過程如何)。

0

存儲具有特定值的靜態存儲持續時間變量的此段稱爲.data(這是ELF標準使用的名稱,但其他連接器也傾向於使用同樣的名稱)。

如何設置這些變量取決於目標系統。

  • 在基於RAM的系統(如PC),整個.data段被預先初始化爲可執行的一部分,並加載到與節目一起RAM。
  • 在基於ROM的系統(如帶閃存的微控制器)上,.data無法預先初始化。而是在調用main()之前,通過一些啓動代碼(「CRT」)將其從ROM複製到RAM。所以它實際上是在運行時設置的,這意味着這樣的系統在程序啓動時總會有延遲。爲了擺脫延遲,通常會有一個非標準的啓動選項(「最小」),它會完全跳過靜態存儲持續時間變量的初始化。