ELF格式與bss段

2021-07-08 11:11:55 字數 1616 閱讀 8870

elf(executable linkable format)是linux系統下的一種可執行可鏈結檔案的格式,是coff格式的變種。在linux系統中包括了可重定位檔案(.o檔案),可執行檔案(/bin/bash檔案),共享目標檔案(.so)和核心轉儲檔案(core dump)。

elf檔案頭(elf header):位於elf檔案的頭部,包含了描述整個檔案的基本屬性。

**段(.text):用於存放程式**,唯讀屬性

資料段(.text):用於存放程式中經初始化的全域性變數和靜態區域性變數,讀寫屬性

bss段(.bss):用於存放程式中未經初始化的全域性變數和靜態區域性變數。在目標檔案中,這個段並不佔據實際空間,它僅僅只是乙個佔位符。

為了更好的**bss段的一些細節,我們來看以下的一段**(******test.c)

int printf(const char* format,...);

int global_init_var = 100;

int global_uninit_var;

void func(int i)

int main(void)

先使用gcc -c ******test.c生成目標檔案******test.o

使用objdump -h ******test.o檢視目標檔案的結構和內容:

從圖中我們可以看出,bss段只有「alloc」,沒有「contents」,這表明這個段在這個檔案中並沒有實際內容。另外bss段的長度也足以使我們產生疑問:為什麼bss段的長度是4而不是8?在******test.c檔案中未初始化的全域性變數和靜態區域性變數總共佔了8位元組,那為什麼存放這兩個變數的bss段的長度只有4呢?

為了解決這個問題,我們可以使用readelf -s ******test.o來檢視檔案中符號表

ndx表示的是段在elf檔案中的下標,其中的4便是bss段。通過readelf我們可以看到,static_var2是存放在bss段中的,而global_uninit_var卻並沒有存放於任何段中,只是乙個未定義的「common」符號。這涉及到了強符號和弱符號以及編譯器的具體實現。

在c/c++語言的編譯器中,預設函式名和初始化的全域性變數是強符號,未初始化的全域性變數為弱符號。由於c/c++語言編譯器允許多個檔案模組中出現同名的不同型別的弱符號,所以在編譯期間,編譯器並不能正確的知道這個弱符號所佔的大小是多少,所以只能使用乙個未定義的common符號來代替。只有在鏈結期間,鏈結器在鏈結所有檔案模組後,才能得出這些同名不同型別的弱符號所需占用的空間大小。舉個例子,假設現在有兩個檔案模組a.o和b.o,其中a.o中有乙個int型別名為global的未初始化全域性變數,而b.o中有乙個double型別也名為global的未初始化的全域性變數。這樣在編譯過程中,由於編譯器無法知道這個名為global的全域性變數究竟應該占多大的記憶體空間,所以它使用了乙個commen來表示。在鏈結的過程中,鏈結器在對這兩個模組進行鏈結後,知道了這個global變數最大需要分配8個位元組的空間,此時global變數在bss段中所需的大小也就確定了。

ELF格式與bss段

elf executable linkable format 是linux系統下的一種可執行可鏈結檔案的格式,是coff格式的變種。在linux系統中包括了可重定位檔案 o檔案 可執行檔案 bin bash檔案 共享目標檔案 so 和核心轉儲檔案 core dump elf檔案頭 elf heade...

ELF檔案學習 bss

elf格式與bss段 linux下目標檔案的bss段 資料段 段 elf executable linkable format 是linux系統下的一種可執行可鏈結檔案的格式,是coff格式的變種。在linux系統中包括了可重定位檔案 o檔案 可執行檔案 bin bash檔案 共享目標檔案 so 和...

Text段 Data段和BSS段

不同的compiler在編譯的過程中對於儲存的分配可能略有不同,但基本結構大致相同。大體上可分為三段 text段 data段和bss段。text段用於存放 通常情況下在記憶體中被對映為唯讀,但data和bss是可寫的。資料存放通常分成如下幾個部分 1 棧 由編譯器自動分配,儲存函式的區域性變數和引數...