linux下乙個可執行檔案各資料段分配

2021-08-08 15:24:59 字數 3513 閱讀 4795

1. 檔案格式:

現在pc平台流行的可執行檔案格式,主要是windows下的pe(portable executable)和linux的elf(executable linkable format),它們都是coff(common file format)格式的變種。

目標檔案就是源**編譯後但未進行鏈結的那些中間檔案(windows的.obj和linux的.o),它跟可執行檔案的內容與結構很相似,所以一般跟可執行檔案格式採用一種格式儲存。

動態鏈結庫(windows的.dll和linux的.so)及靜態鏈結庫(windows的.lib和linux的.a)檔案都按照可執行檔案格式儲存。

2. 檔案內容:

目標檔案中的內容包含編譯後的機器指令**,資料。還包括了鏈結時所需要的一些資訊,比如符號表,除錯資訊,字串等。

目標檔案將這些資訊按不同的屬性,以「節(section)」的形式儲存,有時候也叫做「段(segment)」,它們表示乙個一定長度的區域。

(1)**段(.text)

程式源**編譯後的機器指令

(2)資料段(.data)

已初始化了的全域性變數和區域性靜態變數資料

(3).bss段(.bss)

未初始化的全域性變數和區域性靜態變數

注:

未初始化的全域性變數和區域性靜態變數預設值都為0,本來也可以被放在.data段,但是在目標檔案中為它們分配空間是沒有必要的。因此,統一放到.bss段,.bss段大小為0,不出現在目標檔案中。而變數名以及變數的大小,與其他變數一樣,放在了符號表(.symtab段)中。

(4)其他段

除了.text,.data,.bss這3個最常用的段之外,目標檔案也有可能包含其他的段,用來儲存與程式相關的其他資訊。

3. 詳細分析:

(1)用gcc編譯******scriont.c得到了目標檔案******section.o

$ gcc -c ******section.c
(2)使用binutils的工具objdump來檢視目標檔案內部結構,-h顯示各個段的基本資訊

其中,size表示段的長度,file off(file offset)表示段所在的位置,

每個段第二行表示段的屬性,例如,contents表示該段在檔案中存在。

根據偏移位址我們就可以畫出檔案結構了。

我們看到,.bss段和.note.gnu-stack段在檔案中都不存在。

(3)檢視**段

$ objdump -s -d ******section.o
其中,

-s用於將所有段的內容以16進製制的方式列印出來,

-d用於將所有包含指令的段反彙編。

段資料:

最左邊一列是偏移量,中間4列是16進製制內容,最右邊一列是.text段的ascii碼形式。

反彙編結果:

對照反彙編結果,可以看到.text段裡包含的正是******section.c裡兩個函式func1()和main()的機器指令。

(4)檢視資料段

我們看到54000000(0x00000054)正好是全域性變數global_init_var的值84,

55000000(0x00000055)正好是區域性靜態變數static_var的值85。

注:

.rodata段存放的是唯讀資料,一般是程式裡面的唯讀變數和字串常量。

(5).bss段

雖然在段的基本資訊裡,.bss段的大小為4位元組,但是.bss段的資料為空,因此不占用目標檔案的空間。

.bss段基本資訊:

注:

程式中,未初始化的全域性變數global_uninit_var和區域性靜態變數static_var2共佔8位元組空間,可是.bss段的大小只有4位元組大小。原因是,有些編譯器會將全域性未初始化的變數放到.bss段,有些則不然,只是預留乙個未定義的全域性變數符號。因此,這裡的4位元組,指的是static_var2。

4. 符號表

鏈結的本質,就是把不同的多個目標檔案粘合到一起。

每個函式或變數都必須有自己獨特的名字,才能避免在鏈結過程中產生混亂。

在鏈結中,函式和符號統稱為符號(symbol),函式名或變數名稱為符號名(symbol name)

每個目標檔案都有乙個相應的符號表(symbol table),記錄了目標檔案中用到的所有符號。每個符號都有乙個對應的值,叫做符號值(symbol value),符號值可以是符號所對應的資料在段中的偏移量,也可以是該符號的對齊屬性。

符號表儲存在.symtab段中,資訊如下:

第1列num表示符號表陣列的下標,第2列value就是符號值,第3列size為符號大小,第4列第5列分別為符號型別和繫結資訊,第6列暫時忽略它,第7列ndx表示該符號所屬的段,最後一列,符號名稱。

我們看到func和main的ndx為1,表示**段,因為.text在段表中的下標為1。

其中,段表資訊如下:

printf這個符號,ndx為und(shn_undef),沒有在******section.c中定義,是被引用的。

global_init_var是已初始化的全域性變數,ndx是3,定義在.data段,偏移量為0

static_var.1553是已初始化的區域性靜態變數,ndx是3,定義在.data段,偏移量為4

global_uninit_var是未初始化的全域性變數,ndx是com(shn_common)本身並沒有在.bss段中。

static_var2.1534是未初始化的區域性靜態變數,ndx是4,定義在.bss段,偏移量為0

對於型別為stt_section的符號,名稱並沒有顯示,它們是ndx所示段的段名

******section.c這個符號表示編譯單元的源檔名。

linux 如何執行乙個可執行檔案

本文只為整理思路,供自己日後參考。現在就從從乙個執行檔案a.out的執行開始,自上而下地分析linux是如何執行乙個執行檔案的。1 首先,需要了解一下a.out這個目標檔案。a.out在linux下是elf executable linkable format 檔案格式,該目標檔案由乙個檔案頭 段 ...

linux 執行可執行檔案

1 首先,需要了解一下a.out這個目標檔案。a.out在linux下是elf executable linkable format 檔案格式,該目標檔案由乙個檔案頭 段 資料段 已初始化 從定位資訊區 符號表及符號名字字串構成,如下左圖所示,經過鏈結後生成執行檔案如下右圖所示,需要說明的是1 bs...

linux編譯和執行乙個可執行檔案初學篇

在大公司上班,系統中的模組都有明確的分工,一直以來也只是熟悉自己負責的那一點點東西,感覺就是井底之蛙。所以希望自己能夠靜下心來,學一點,多學一點。本篇作為乙個學習的起點,先學習如何編譯和執行乙個可執行檔案。測試 如下 include int main int argc,char argv int i...