C 開始前篇,深入編譯鏈結(補充1)

2022-08-16 18:03:17 字數 3139 閱讀 3369

針對這些問題,這次做乙個補充:

一,可重定位檔案的格式是什麼,以main.o為例,

格式為elf ,包括:{1,elf header

它描述了整個檔案的檔案屬性,包括檔案是否可以執行,是靜態鏈結還是動態鏈結及入口位址(若是可執行                                             檔案),目標硬體,目標作業系統等等。

2,   .text(**段)  按四位元組對齊

一般c語言編譯後執行語句都編譯成機器**,儲存在這個段中

3,   .data(資料段)

已初始化的全域性變數和區域性變數都儲存在這個段中

4,   .bss(占用虛擬記憶體空間的資料)

未初始化的全域性變數和區域性靜態變數都儲存在這個段中

注:.bss段只是為未初始化的全域性變數和區域性靜態變數預留位置而已,故在檔案中不佔據空間 。

5,   .rodata(唯讀資料段)

6,   .comment(注釋資訊段)

7,   .note.gnu-stack(堆疊提示段)

8,   symtab(符號表段)

9,   其他段。

光說不練假把式,編寫乙個程式main.c,在linux底下編譯得到main.obj檔案

用objdump -h  main.o這個命令得到它的格式

其中,size表示該段的大小,file off為段所在的位置。contents、alloc等表示段的屬性。有contents表示該段在檔案中存在,但是.bss段沒有,表示,.bss段在檔案中不存在內容。而.note.gnu-stack的size為0,所以它在elf檔案中也不存在。

再說明一下,關於.bss段,我們可以看到它的size為4,但是它的file off(位址)卻跟.rodata的file off相同,故.bss段並不佔磁碟空間,它只是預留了未定義的全域性變數符號(?底下會有詳細說明)和未定義的區域性靜態變數符號,等到鏈結時再給它們分配記憶體。

詳細列印一下各個段的內容:

1,text段

我們可以看到,從.text段從0x00到0x50,正好是0x51個位元組。與

,中的一樣。其中,最左邊一行是偏移量,中間四列是十六進製制內容,最右邊是.text段的ascii碼形式。

反彙編結果如下。

2,.data段和.rodata段

.data段儲存的是已經初始化了的全域性靜態變數和區域性靜態變數。.

.rodata段中存放的是唯讀資料,上面的程式中在呼叫printf時有個引數 '%d\n',這就是一種唯讀資料。還有const修飾的變數等等。

.data段中,前四個位元組從低到高為(小端儲存):0x63,0x00,0x00,0x00。轉化為10進製正好為99(全域性初始化global_init)。同理,後四位為1(區域性靜態初始化static_init)。

ok,現在已經把主要的幾個段了解了,現在來學習一下關於elf的檔案結構

來張圖說明

其中,關於elf header前面已經介紹了,包含著整個檔案的基本屬性;緊接著是elf各個段,其中elf檔案中與段相關的重要結構就是section header table(段表),什麼是段表呢,它描述了elf檔案包含的所有段的資訊!比如每個段的段名,長度,在檔案中的偏移讀寫許可權等等其他屬性。再接著就是字串表,符號表等等。接下來詳細的介紹一下段表。

用readelf -s 來檢視詳細的段表結構

我們可以看到,段表其實就是乙個一維陣列,陣列元素的個數等於段的個數,但是第乙個是null的,所以main.o總共有10個有效的段。

關於段表,最重要是兩個,乙個是段的型別(type),乙個是段的標誌位(flags),他們決定了段的屬性。

段的型別分為無效段,程式段(**段,資料段都是這種型別)或者符號表等等。

段的標誌位表示該段在程序虛擬位址空間中的屬性,比如是否可寫,是否可執行等等。

在.text段下有乙個.rel.text段,這個.rel.text段即就是重定位表。此時先提出了,當談到鏈結的時候再解答。

ok,此時已經把第乙個問題算是解答完畢了,接下來繼續解答剩下的兩個問題。

二,可執行檔案的格式

可執行檔案是什麼格式呢?上圖

這是可執行檔案main中的段,

可見,可執行檔案也是由很多段組成的,在mian.o的基礎上多了更多的段。因此,可執行檔案之所以可以執行,肯定與鏈結之後多出來的這些段有關係。這些都是些什麼東東呢,在深入鏈結之前,我們先解決第三個問題。

程式要執行,需要三步。

第一,需建立虛擬位址空間到物理記憶體的對映(建立核心位址對映結構體),建立頁目錄和頁表。

第二,載入**段和資料段。

第三,把可執行檔案的入口位址寫到cpu的pc暫存器中。

所以為什麼可執行檔案可以執行而可重定位檔案不可執行的問題可以得到解決,

2,.obj中無函式入口位址,.exe中有函式入口位址。我們知道程式要執行就必須知道函式入口位址。

3,.exe中有鏈結之後乙個」特殊段「,跟頁表有關。

接下來,我們更加深入到靜態鏈結中去。

C 學習從基礎開始 變數篇

4 浮點型 float double 5 高精度小數 decimal 6 布林型 bool 2.列舉型別 enum e3.結構體型別 struct s4.空型別 null 5.類class c6.介面 inte ce i 7.陣列 1 一維陣列 int 2 二維陣列 int 8.委託 delegat...

Linux之C語言學習前篇

c語言程式入口 main函式 main 每乙個程式都必須有main函式。main函式有什麼特點?1 程式必須以main作為主函式的命名。2 程式從main函式開始執行,從main函式結束。3 程式不能從第乙個函式開始執行,而是從main函式開始。4 main函式在程式中有且僅有乙個。分析main函式...

00基於C語言的設計模式 寫在開始前

已經從事嵌入式軟體開發多年。雖然我做過不少專案,解過無數bug。但回頭看下,總覺得應該把工作的經驗和用到的知識系統梳理和總結下。畢竟我認為掌握乙個知識點至少需要做到三步 1知道,2實踐過,3講得清楚。沒有做到這三點,我是不敢有底氣地說自己掌握了xx知識。我看網上關於嵌入式軟體的帖子,大多講的都是mc...