一 編譯階段
預編譯:gcc -e main.c -o main.i (main.c是原始碼檔案,main.i是生成的預編譯後的檔案)
編譯:gcc -s main.i(預設生成彙編指令檔案main.s)
彙編:gcc -c main.s(預設生成main.o檔案)
預編譯:
#include 的展開,將被包含的檔案插入到該預編譯指令的位置。注意,這個過程是遞迴進行的,也就是說被包含的檔案可能還包含其他檔案
巨集替換刪除注釋
處理預編譯指令如:#if,#endif,#ifdef,#elif,#else
新增行號和檔名標識,比如#2 "hello.c" 2,以便於編譯時編譯器產生除錯用的行號資訊及用於編譯時產生編譯錯誤或警告時能產生行號
保留所有的#pragma編譯器指令,因為編譯器需要使用他們
編譯:進行語法,詞法的解析
**優化
彙總符號(資料(全域性,靜態)和函式會生成符號)
將原始碼轉成彙編指令
彙編:將彙編指令翻譯成二進位制
生成各個section
生成符號表
彙編過後生成的main.o檔案是可重定位的二進位制檔案
編譯階段每個原始檔都是單獨編譯的
objdump -h main.o 用來檢視main.o檔案的section header資訊
可重定位檔案的elf檔案格式:
二 鏈結階段
或 gcc 所有生成的中間檔案 -o 自己命名的檔案(可執行檔名)
鏈結的主要內容就是把各個模組之間相互引用的部分都處理好,使得各個模組之間能夠正確的銜接。鏈結可以分為靜態鏈結和動態鏈結。相應的也有靜態庫和動態庫來供鏈結使用。
合併所有檔案的各個section,調整段大小的起始位置,合併符號表,進行符號解析,並給符號分配乙個虛擬位址
符號重定位
1、段的合併是根據什麼來合併的?
段的合併是根據各個段的屬性來進行合併,比如data段合併到data段,text合併到 text 段等。
2、什麼是符號解析?
符號解析:所有對符號的引用,都有找到該符號定義的地方。常見錯誤:符號重定義,符號未定義。
3、什麼是重定位?
《程式設計師自我修養》這本書中給重定位的定義是:在編譯多個目標檔案時,無法確定變數/函式位址的情況下,會將其目標位址置為0,等到鏈結時將目標位址進行修改。這個位址修正的過程就被叫做重定位。就是給程式中的每個絕對位址引用的位置打補丁,使它們指向正確的位置。
因為在編譯過程中符號是不分配虛擬位址的,但是編譯過程指令已經生成。所以先把符號的位址都置為0,等到鏈結時符號解析成功以後,給所有的符號分配虛擬位址,寫入指令中置0的地方,稱之為符號的重定向。
參考資料:可執行檔案的elf格式:
編譯鏈結原理
從源 到可執行程式,需要經歷以下幾個過程 預處理 編譯 彙編 連線。1.預處理 預處理主要是處理以 開頭的預編譯指令,包括 include define if等 刪除注釋 新增行號以及標頭檔案展開。2.編譯 編譯的主要工作是詞法分析 語法分析 優化編譯,將源 翻譯成彙編 3.彙編 彙編是將彙編 翻譯...
編譯鏈結原理
32位計算機,每個程式都有4g的虛擬位址空間。首先虛擬位址空間分為兩大塊,乙個是使用者空間,乙個是核心空間。使用者空間佔3g的大小,並且它是每個程序所獨有的,它的開頭128m存放的是我們無法訪問的地方。1 預編譯 生成 i 檔案 操作命令 gcc e main.c o main.i 具體內容 1 巨...
編譯鏈結原理
32位計算機,每個程式都有4g的虛擬位址空間。首先虛擬位址空間分為兩大塊,乙個是使用者空間,乙個是核心空間。使用者空間佔3g的大小,並且它是每個程序所獨有的,它的開頭128m存放的是我們無法訪問的地方。text c語言的編譯後執行語句都編譯成機器 儲存在.text段 data 已初始化的全域性變數和...