編譯鏈結執行原理 編譯鏈結執行過程

2021-09-02 01:35:56 字數 2114 閱讀 1203

乙個.c/.cpp源程式檔案要最後變成.exe(windows)或者.out(linux)可執行檔案,要經過編譯和鏈結過程。

四個步驟:預編譯,編譯,彙編,連線

(一)預編譯:處理以「#」開頭的預編譯指令,比如#include,#define等,規則如下:

(1)刪除所有的#define,並展開所有的巨集替換(文字替換);

(2)處理所有的條件預編譯指令,如#if,#endif,#elif,#else,#ifdef;

(3)處理#include預編譯指令,將被包含的檔案插入到該預編譯指令的位置,當乙個標頭檔案包含其他檔案,則遞迴展開標頭檔案;

(4)刪除所有注釋,「//」和「/**/」;

(5)新增行號和檔名標識,如#2 "hello.c" 2,便於編譯時編譯器產生除錯用的行號資訊,以及用於編譯時產生編譯錯誤或警告是能夠顯示行號;

(6)保留#pragma編譯器指令,因為編譯器需要使用。

(二)編譯:把預處理完的檔案進行一系列如下操作產生相應的彙編**檔案

(1)詞法分析 :使用一種叫做lex的程式實現詞法掃瞄,它會按照使用者之前描述好的詞法規則將輸入的字串分割成乙個個記號。產生的記號一般分為:關鍵字、識別符號、字面量(包含數字、字串等)和特殊符號(運算子、等號等),然後他們放到對應的表中。

(2)語法分析 :語法分析器根據使用者給定的語法規則,將詞法分析產生的記號序列進行解析,然後將它們構成一棵語法樹。對於不同的語言,只是其語法規則不一樣。用於語法分析也有乙個現成的工具,叫做:yacc。

(3)語義分析:根據上下文來推斷

(4)**優化;

(5)生成相應的彙編**(指令)

(6)符號彙總

(三)彙編:將彙編**轉變為機器可執行的指令,生成可重定位的二進位制目標檔案

因為我們任何乙個原始檔在進行編譯階段的時候會去產生我們的符號表,符號表中存放的就是我們程式所產生的符號(例如:函式名,變數名等),我們的編譯階段是不會去給我們的符號分配正確的位址,因此當我們檢視.obj(.o)檔案的符號表資訊時就會出現下面這種情況

可以發現符號的位址都是0x00000000,這些都是保留區位址,因此計算機無法通過正確的位址去尋找到它的指令,那麼計算機就無法去執行,這也就是.obj(.o)檔案沒有鏈結為何不能執行的根本原因。

(1)位址和空間分配

(2)合併各個段和符號表(調整段的偏移和段長度,合併.o檔案的符號表)

掃瞄所有的輸入的.o檔案,去獲得它們各個段的長度,屬性和位置,然後按照段的屬性和段的長度合併,並且去把每個.o檔案的符號全部收集起來放入同乙個符號表中。在這裡要注意的是在鏈結的時候不光是要去鏈結我們使用者自己所寫編譯後的.o檔案還有一些庫函式中的(例如:printf.o),同時還會去鏈結我們的glibc的輔助庫函式。

靜態鏈結是指在編譯階段直接把靜態庫加入到可執行檔案中去,這樣可執行檔案會比較大;

動態鏈結則是指鏈結階段僅僅只加入一些描述資訊,而程式執行時再從系統中把相應動態庫載入到記憶體中去。

linux作業系統中分步完成這些操作;

預編譯:gcc  -e  main.c  -o  mian.i

編譯:   gcc  -s  mian.i   -o  main.s

彙編:   gcc  -c  main.s  -o  main.o

gcc -c main.c

gcc -o main main.o

一步完成:

gcc -o main main.c

(五)執行

(1)建立虛擬位址空間到物理記憶體的對映(建立對映結構體pcb)常見頁目錄,頁表

(2)載入指令和資料

編譯鏈結執行原理

預編譯.i 刪除 define 文字替換 處理 include 遞迴展開 處理 if end if等預編譯指令 刪除注釋 新增行號和檔案標識 保留 pragma 編譯.s 1.詞法分析 2.語法分析 3.語義分析 4.優化 5.生成彙編指令 低階語言 以下是彙編指令的 int main 彙編.o 翻...

C 編譯鏈結執行原理

1.預編譯 生成.i檔案 1.將所有的 define 刪除,並且展開所有巨集 2.處理掉所有條件預編譯指令,如 if ifdef elif else endif 3.處理 include 指令,這是乙個遞迴過程 4.刪除所有的注釋 和 5.新增行號和檔名標識 6.保留所有的 pragma編譯器指令,...

編譯鏈結執行原理 函式堆疊呼叫

首先先提出下面五個問題 1 形參開闢記憶體嗎?由誰開闢?2 形參的入棧順序?3 返回值如何帶出?4 被呼叫方結束後如何知道回退到呼叫方棧幀上?5 函式呼叫完成如何知道執行下一行指令?要解決這些問題,我們就要從彙編的角度切入。通過彙編 能夠使我們更加清晰地掌握函式的堆疊呼叫。彙編分為兩種形式inter...