C語言 程序的編譯系統解析

今天我來補一下C語言篇的程序的編譯的一篇文章,也算是有一個結尾瞭。

程序的翻譯環境和執行環境

在ANSI C的任何一種實現中,存在兩個不同的環境 :

第1種是翻譯環境,在這個環境中源代碼被轉換為可執行的機器指令。

第2種是執行環境 ,它用於實際執行代碼。

一個.c的文件事如何變成.exe的可執行文件的呢?下面這張圖片是一個大概的過程:

請添加圖片描述

編譯和鏈接

翻譯環境

請添加圖片描述

  • 組成一個程序的每個源文件通過編譯過程分別轉換成目標代碼( object code )。
  • 每個目標文件由鏈接器( linker )捆綁在一 起,形成一個單一-而完整的可執行程序。
  • 鏈接器同時也會引入標準C函數庫中任何被該程序所用到的函數,而且它可以搜索程序員個人的程序庫,將其需要的函數也鏈接到程序中。

編譯的幾個階段

接下來,我來用Linux平臺來給大傢演示一下編譯的三個過程:

我們先編寫一個簡單C程序:

請添加圖片描述

然後執行這樣一句指令:

gcc test.c

這句指令是讓gcc這個編譯器來編譯我們的代碼,執行完這句指令我們會發現會生成一個a.out這樣一個可執行文件,

請添加圖片描述

我們執行再下面這樣一句指令:

./a.out

這樣我們就可以執行這個可執行文件瞭,

請添加圖片描述

為瞭讓大傢更好地感受到編譯的過程,我們來一步一步看:

預處理

我們執行再下面這樣一句指令,讓代碼預處理完之後就停下來:

gcc -E test.c -o test.i

這句指令的意思就是把預處理完之後的信息輸出到一個test.i的文件中。

請添加圖片描述

可以發現的是,這裡多瞭一個test,i的文件,我們可以打開看一看:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pGZW3x4b-1637932306122)(C:\Users\久別重逢還不錯\AppData\Roaming\Typora\typora-user-images\image-20211126200920738.jpg)]

可以發現的是,有三個點發生瞭變化:

  • 頭文件被展開
  • 宏被文本替換瞭
  • 註釋被刪除瞭

我們對原代碼做一個處理,不包含stdio.h的頭文件,我們自己寫一個頭文件:

再來看一下,預處理後的文件是什麼樣子的:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-jICkxv4k-1637932306124)(C:\Users\久別重逢還不錯\AppData\Roaming\Typora\typora-user-images\image-20211126201809726.jpg)]

效果通上面一樣。

所以預處理的幾個動作

  • 頭文件的包含
  • 預處理指令的完成(eg:#define、#pragma…)
  • 註釋的刪除

編譯

執行再下面這樣一句指令讓文件進行編譯形成匯編代碼:

gcc -S test.c

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nYnbbB65-1637932306125)(C:\Users\久別重逢還不錯\AppData\Roaming\Typora\typora-user-images\image-20211126202540289.jpg)]

執行完之後就可以生產出一個test.s的文件,我們可以打開看一看:

這裡其實就是匯編代碼。

所以編譯的幾個動作

  • 語法分析
  • 詞法分析
  • 語義分析
  • 符號匯總

符號匯總: 符號匯總的都是全局的符號。例如上面我們的代碼頭文件就匯總瞭一個Add,.c文件就匯總的一個Add和main。

匯編

接下來我們執行這樣一條指令:

gcc -c test.c

對源文件進行匯編,結果生成瞭一個test.o的目標文件:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Segd6oKn-1637932306126)(C:\Users\久別重逢還不錯\AppData\Roaming\Typora\typora-user-images\image-20211126203431140.jpg)]

打開這個文件,我們會發現這是一個我們看不懂的二進制文件:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-YjEQb15l-1637932306127)(C:\Users\久別重逢還不錯\AppData\Roaming\Typora\typora-user-images\image-20211126203517294.jpg)]

所以其實匯編是把匯編代碼轉換為二進制代碼(機器指令)。

這個過程還做瞭一件件事——形成符號表

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-O6xmUQVU-1637932306127)(C:\Users\久別重逢還不錯\AppData\Roaming\Typora\typora-user-images\image-20211126204552806.jpg)]

鏈接

鏈接做的兩個事情

  • 合並段表
  • 符號表的合並和符號表的重定位

在Linux系統下,test.o二進制文件是用一個elf這樣的格式來組織文件的。

elf會把文件組織成一個段。test.o和Add.o都有一個段,那麼我們怎樣才能看懂elf格式的文件呢?

我們有這樣一個工具叫做readelf,他可以看懂這樣一個文件,所以我們輸入這樣一條指令:

readelf test.o -a

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kDmpTiYe-1637932306128)(C:\Users\久別重逢還不錯\AppData\Roaming\Typora\typora-user-images\image-20211126205639154.jpg)]

我們就確實可以看到這樣一個段的存在。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xQnwleYa-1637932306128)(C:\Users\久別重逢還不錯\AppData\Roaming\Typora\typora-user-images\image-20211126210149263.jpg)]

然後這下面還有符號表的匯總:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ufzQtz4Y-1637932306129)(C:\Users\久別重逢還不錯\AppData\Roaming\Typora\typora-user-images\image-20211126210550360.jpg)]

其實a.out這個文件也是elf格式的,所以其實鏈接就是把這幾個elf格式的文件的段表合並,然後test中的Add函數就有瞭地址。

運行環境

程序執行的過程:

  • 程序必須載入內存中。在有操作系統的環境中:一般這個由操作系統完成。在獨立的環境中,程序的載入必須由手工安排,也可能是通過可執行代碼置入隻讀內存來完成。
  • 程序的執行便開始。接著便調用main函數。
  • 開始執行程序代碼。這個時候程序將使用一個運行時堆棧(stack),存儲函數的局部變量和返回地址。程序同時也可以使用靜態(static)內存,存儲於靜態內存中的變量在程序的整個執行過程一直保留他們的值。
  • 終止程序。正常終止main函數;也有可能是意外終止。

到此這篇關於C語言 程序的編譯系統解析的文章就介紹到這瞭,更多相關C語言 程序編譯內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: