Code Section¶
概述¶
在動態鏈接器創建了進程鏡像,並且執行了重定位後,每一個共享目標文件都有機會去執行一些初始化的代碼。所有的共享目標文件會在可執行文件獲得權限之前進行初始化。
在調用目標文件 A 的初始化代碼之前,會首先調用所有 A 依賴的共享目標文件的初始化代碼。比如說,如果目標文件 A 依賴於另外一個目標文件 B,那麼 B 就會在 A 的依賴列表中,這會被記錄在動態結構的 DT_NEEDED 中。循環依賴的初始化是未被定義的。
目標文件的初始化通過遞歸每一個被依賴的表項來完成。只有當一個目標文件依賴的所有的目標文件都處理完自己的依賴後,這個目標文件纔會執行初始化代碼。
下面的例子解釋了兩種正確的可以用來生成給定例子的順序。在這個例子中,a.out 依賴於b,d 以及 e。b依賴於d 和 f,並且 d 依賴於 e 和 g。根據這個信息,我們可以畫出如下的依賴圖。那麼我們上面所說的算法,將允許我們按照如下的順序進行初始化。
類似的,共享目標文件也會有結束的函數,這些函數在進程完成自己的終止序列時通過 atexit 機制來執行。動態鏈接器調用終止函數的順序恰好與上面初始化的順序相反。動態鏈接器將會確保它只會執行初始化或者終止函數最多一次。
共享目標文件通過動態結構中的 DT_INIT 和 DT_FINI 來指定它們的初始化以及結束函數。在一般情況下,這些函數在.init節與.fini節中。
注意:
儘管ateixt終止處理函數通常來說會被執行,但它並不會保證在程序消亡時被執行。更特殊的是,如果程序調用了_exit函數或者進程由於接收到一個信號後消亡了,那麼它將不會執行對應的函數。
動態鏈接器並不負責調用可執行文件的 .init 節或者利用 atexit 註冊可執行文件的 .fini 節。由用戶通過 atexit 機制指定的終止函數必須在所有共享目標文件的結束函數前執行。
.init & .init_array¶
此節區包含可執行指令,是進程初始化代碼的一部分。程序開始執行時,系統會在開始調用主程序入口(通常指 C 語言的 main 函數)前執行這些代碼。
.text¶
此節區包含程序的可執行指令。
.fini & .fini_array¶
此節區包含可執行的指令,是進程終止代碼的一部分。程序正常退出時,系統將執行這裏的代碼。