GCC中C++源程序到可執行文件的四個步驟

最近在參加提前批的面試,今天面的是vivo的嵌入式。其中問到一個問題,c++的源程序到生成可執行文件的過程。喵哥吞吞吐吐的答出了一部分。現在面完了,在網上找了下標準答案:預處理、編譯、彙編、鏈接。

在Windows下,VC編譯一個源程序都是一鍵完成,不知道過程,而我用Linux的gcc生成執行文件時,都是用

g++ hello.cpp -o test

然後用

./test

執行。原來我給自己挖了這麼久的坑啊,完全省去了中間步驟。

test用vim打開的結果是:

如果按照上面提到的四個步驟處理源文件,過程如下。

1.預處理

g++ -E hello.cpp -o hello.i

vim打開hello.i的結果

2.編譯

g++ -S hello.i -o hello.s

用vim打開hello.s

3.彙編

g++ -c hello.s -o hello.o

用vim打開hello.o

4.鏈接

g++ hello.o -o hello

用vim打開hello

於是,發現hello跟test是一樣的,但是我之前都是一步生成可執行文件,所以對這個過程不是太瞭解。

在生成過程中產生的文件也就只有最終的可執行文件可以執行。

 

 

鏈接可以執行與編譯時(源代碼被翻譯成機器代碼時),也可以執行與加載時(在程序被加載器加載到存儲器並執行時),甚至執行與運行時,由應用程序來執行。在現代系統中,鏈接是由鏈接器自動執行的。鏈接器分爲:靜態鏈接器和動態鏈接器兩種。

a.  靜態鏈接器

靜態鏈接器以一組可重定位目標文件和命令行參數作爲輸入,生成一個完全鏈接的可以加載和運行的可執行目標文件作爲輸出。

靜態鏈接器主要完成兩個任務:

  (1)符號解析:目標文件定義和引用符號。符號解析的目的在於將每個符號引用和一個符號定義聯繫起來。
  (2)重定位:編譯器和彙編器生成從地址零開始的代碼和數據節。鏈接器通過把每個符號定義和一個存儲器位置聯繫起來,然後修改所有對這些符號的引用,使得他們執行這個存儲位置,從而重定位這些節。

b.  動態鏈接

動態鏈接方式下,函數的定義在動態鏈接庫或共享對象的目標文件中。在編譯的鏈接階段,動態鏈接庫只提供符號表和其他少量信息用於保證所有符號引用都有定義,保證編譯順利通過。動態鏈接器鏈接程序在運行過程中根據記錄的共享對象的符號定義來動態加載共享庫,然後完成重定位。在此可執行文件被執行時,動態鏈接庫的全部內容將被映射到運行時相應進程的虛地址空間。動態鏈接程序將根據可執行程序中記錄的信息找到相應的函數代碼。  
目標文件有三種形式:
1> 可重定位的目標文件:
包含二進制代碼和數據,其形式可以再編譯時與其他可定位目標文件合併起來,創建一個可執行目標文件。
2> 可執行目標文件:
包含二進制代碼和數據,其形式可以被直接拷貝到存儲器並執行。
3> 共享目標文件:
一種特殊的可重定位目標文件,可以再加載或運行時,被動態地夾在到存儲器並執行。編譯器和彙編器生成可重定位目標文件(包括共享目標文件),鏈接器生成可執行目標文件。

 

gcc優化的方式:

1.  -O0:無優化(默認)。

2.  -O1:使用能減少目標文件大小以及執行時間並且不會使編譯時間明顯增加的優化.在編譯大型程序的時候會顯著增加編譯時內存的使用。

3.  -O2: 包含-O1的優化並增加了不需要在目標文件大小和執行速度上進行折衷的優化.編譯器不執行循環展開以及函數內聯.此選項將增加編譯時間和目標文件的執行性能。(一般優化到-O2就可以了)

4.  -Os:專門優化目標文件大小,執行所有的不增加目標文件大小的-O2優化選項.並且執行專門減小目標文件大小的優化選項。

5.  -O3: 打開所有-O2的優化選項並且增加 -finline-functions, -funswitch-loops,-fpredictive-commoning, -fgcse-after-reload and -ftree-vectorize優化選項。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章