程式的編譯 鏈結

2021-08-03 19:14:21 字數 2441 閱讀 1951

在linux下,使用gcc來編譯hello world時,只使用最簡單的命令

$gcc hello.c

$./a.out

hello

world

但上述過程可以分解為4個步驟,即預處理、編譯、彙編、鏈結

預處理/預編譯

$gcc -e hello.c -o hello.i

或者$cpp hello.c > hello.i

預編譯過程主要處理源**中以#開始的預編譯命令。比如#include#define等,主要規則如下:

編譯

$gcc -s hello.i -o hello.s
編譯把預處理完的檔案進行一系列詞法分析、羽凡分析、語義分析及優化後生成相應的彙編檔案**。現在版本的gcc把兩個步驟合併成乙個,並使用乙個叫cc1的程式來完成。

array[index] = (index+4) * (2+6)
以一段簡單的c語言**為例來描述從源**(source code)最終目標**(final target code)的過程。

首先**被輸入到掃瞄器(scanner)。它只是簡單地進行詞法分析,將源**的字串行分割成一系列的記號(token)。比如上面那行**,經過掃瞄以後,產生了16個記號。詞法分析產生的記號一般可以分為:關鍵字、識別符號、字面量(包含數字、字串等)和特殊符號(如加號、等號)。在識別記號的同時,掃瞄器也將識別符號存放到符號表,將數字、字串常量存放到文字表等。

有乙個叫做lex的程式可以實現詞法掃瞄。

接下來到語法分析器(grammar parser)。它採用上下文無關語法(context-free grammar)對掃瞄器產生的記號進行語法分析,產生語法樹(syntax tree)。因為符號和數字不是由其他表示式組成的,所以他們通常作為樹的葉子節點。在語法分析的同時,符號的優先順序和含義(有些符號具有多重含義)也被確定下來。

語法分析可以用yacc(yet another compiler compiler)。由於可以對它改變語法規則來實現乙個新的語法分析器,因此它又被稱為「編譯器編譯器(compiler compiler)」

語義分析由語義分析器(semantic analyzer)完成。例如兩個指標乘法在語法上是合法的,但卻沒有意義。

編譯器所能分析的是靜態語義(static semantic),即編譯期可以確定的語義。(執行時才能確定的稱為動態語義)。靜態語義包括:宣告型別匹配型別的轉換。如果某些型別需要做隱式轉換,語義分析器會在語法樹中插入相應的結點。

現代編譯器有很多層優化。比如原始碼級優化(source code optimizer)會在源**級別進行優化。比如上例中(2+6)這個表示式就可以被優化掉,因為它的值可以在編譯期確定。優化後的語法樹如下。

彙編

$as hello.s -o hello.o

或者$gcc -c hello.s -o hello.o

彙編器將彙編**轉變成機器可以執行的命令。上面的彙編過程我們可以呼叫彙編器as來完成

鏈結

在編譯過程中,變數的位址該如何確定?如果這些變數是定義在其他檔案中的時候還如何處理?事實上,定義在其他模組的全域性變數和函式在最終執行時的絕對位址都要在鏈結時才能確定

鏈結過程主要包括了位址和空間分配(address and storage allocation)、符號決議(symbol resolution)重定位(relocation)。目標檔案(object file)和庫(library)被鏈結器一起鏈結形成最終的可執行檔案。

程式的編譯,鏈結

我們基本都知道乙個程式由 行再到最後被執行生成目標檔案,會經歷四個過程 1 預編譯 prepressing 2.編譯 compilation 3.彙編 linking 4.鏈結 assembly 但其中每個步驟都發生了什麼,還是不太清楚,今天我們就來學習了解下這個過程.一.預編譯.假設原檔案是.c檔...

程式編譯鏈結

認識各種儲存部件 暫存器 記憶體 磁碟 暫存器 快取記憶體 記憶體 磁碟快取 磁碟 主存 儲存程序執行時的程式和資料 暫存器 速度最快,昂貴容量不大,一般以字為單位,只要存放指令一次操作的資料就夠了 儲存部件的層次 快取記憶體 一種速度比記憶體快的儲存裝置,一般同暫存器一樣整合在cpu中。存放記憶體...

程式的編譯和鏈結

一般來說,無論是c c 還是pas,首先要把原始檔編譯成中間 檔案,在windows下也就是 obj 檔案,unix下是 o 檔案,即 object file,這個動作叫做編譯 compile 然後再把大量的 object file合成執行檔案,這個動作叫作鏈結 link 編譯時,編譯器需要的是語法...