可執行程式的組成

2021-06-29 06:58:15 字數 2092 閱讀 4346

上一節分析了c語言應用程式中各段的情況,實際的c語言可執行程式,將由各個檔案經過連線生成。目標檔案是由每乙個c語言源程式(*.c)經過編譯器生成,目標檔案(.o)的主要組成部分即**段、唯讀資料段和讀寫資料段三個段。未初始化資料段、堆和棧不會占用目標檔案的空間。

可執行程式是由各個目標檔案經過連線而成。其主體部分依然是**段、唯讀資料段和讀寫資料段,這三個段由各個目標檔案(.o)經過「組合」而成。c語言目標檔案到可執行程式的連線如圖13-2所示。

聯結器將根據連線順序將各個檔案中的**段取出,組成可執行程式的**段,唯讀資料段和讀寫資料段也是如此。在連線過程中,如果出現符號重名、符號未定義等問題,將會產生連線錯誤。如果連線成功,將會生成乙個統一的檔案,這就是可執行程式。

由聯結器生成的可執行程式包含了各個目標檔案的各個段的內容,並且會附加可執行程式的頭資訊。在可執行程式中,各個目標檔案的**段、唯讀資料段、讀寫資料段經過了重新的排列組合。因此,在最終的可執行程式中,已經沒有了各個目標檔案的概念。

值得注意的是,在連線的過程中,聯結器可以得到未初始化資料段的大小,它也是各個目標檔案的各個未初始化資料段資料段之和,但是這個段是不會影響可執行程式大小的。從c語言使用的角度,讀寫資料段和未初始化資料段都是可讀寫的。實質上,在目標檔案(*.o)中未初始化資料段和讀寫資料段的區別也在於此:讀寫資料段占用目標檔案的容量,而未初始化資料段只是乙個標識,不需要占用實際的空間。

圖13-2  c語言目標檔案到可執行程式的連線

例如,在某乙個c語言的源程式檔案中,具有以下的內容:

static char bss_data[2048];

static char rw_data[1024] = ;

以上定義了兩個靜態陣列,由於bss_data沒有初始化,是乙個未初始化資料段的陣列,編譯器只需要標識它的大小即可,而rw_data已經有了一定的初始化資料(即使這個初始化資料沒有實際的內容),它建立在已初始化資料段之上,編譯器需要在讀寫資料段內為其開闢空間並賦初值。因此,在生成目標檔案的時候,由於rw_data[1024]的存在,目標檔案的大小將增加1024位元組,而bss_data [2048]雖然定義了2048位元組的陣列,目標檔案的大小並不會因此而增加。

聯結器在處理的過程中,會將各個目標檔案讀寫資料段組合成可執行程式的讀寫資料段,類似rw_data等內容都會被組合,因此可執行程式中讀寫資料段的大小會等於各個目標檔案讀寫資料段之和。對於bss_data等未初始化資料段上的變數,聯結器也將各個目標檔案中的資訊相加得到可執行程式的未初始化段的大小,但是這個段同樣不會占用可執行檔案的空間。

在c語言中,讀寫資料段和未初始化資料段都包含了以下幾種情況:整個程式的全域性變數、單個檔案內使用的全域性變數(函式外部用static修飾的)、區域性靜態變數(函式內部用static修飾的)。對於這幾種變數,聯結器都會按照相同的方式進行組合。

知識點:在連線過程中,c語言的各個目標檔案的**段、唯讀資料段和讀寫資料段將組合成可執行程式的這三個段,未初始化資料段只有在執行時才會產生。

各個目標檔案的關係

程式中通常會有大量的函式呼叫,這些被呼叫的函式只要有宣告(而不需要定義實現),編譯器就可以成功處理。在生成可執行檔案的過程中,聯結器將各個可執行程式的**段組合到一起,而有函式呼叫的地方還需要找到真正的函式定義才可以完成連線。因此,函式的定義和呼叫者可以在乙個**段內,也可以在不同的**段內。聯結器會根據需要根據實際的情況修改編譯器生成的機器**,完成正確的跳轉。

函式跳轉的連線過程如圖13-3所示。

圖13-3  函式跳轉的連線

與函式跳轉類似的是全域性變數的訪問,在c語言編譯的過程中,程式可以訪問用extern宣告的外部全域性變數,在連線的過程中,聯結器需要找到實際變數在資料段中的位置,完成正確的變數訪問。

程式中全域性變數的連線如圖13-4所示。

圖13-4  全域性變數的連線

對於可執行檔案的生成,其主要的工作是組合各個目標檔案中的三個段。還將包含一些其他的過程。首先,所有的可執行程式都需要指定乙個入口,在c語言中入口即main函式,在乙個c語言的應用程式各個原始檔中,只能包含乙個main函式。其次,不同系統所使用的可執行程式可能包含不同的頭資訊,頭資訊是在主要段之外附加的資訊,可以供作業系統載入可執行程式的時候使用。        

知識點:在連線過程之前,各個原始檔生成目標檔案相互沒有關係。在連線之後,各目標檔案函式和變數可以相互呼叫和訪問,從而被聯絡在一起。

python 執行可執行程式

python do exe.pyw coding utf 8 import os exe dir c program files q dir exe file q dir.exe def do cmd dir,file if os.access dir,os.f ok os.chdir dir if...

Android可執行程式

最近應用了android kernel下高通的乙個security patch,各種方式出log,也沒有走到patch處。通過網上查詢,看到有人寫了個main函式,呼叫此patch所在的module。但是建立出執行檔案,push到某家手機的 system bin下,告訴是唯讀檔案系統,不能push進...

可執行程式的裝載

elf檔案頭部有一些重要的資訊 例如 entry point address 0x8048000 是可執行檔案載入到記憶體中開始執行的第一行 裝載時動態鏈結 load time dynamic linking 這種方法的前提是在編譯之前已經明確知道要呼叫的動態庫的哪些函式,編譯時在目標檔案中只保留必...