轉(zhuǎn)載鏈接:https://xiaozhuanlan.com/topic/2395487601
1. 預(yù)編譯(Prepressing)
clang -E main.m -o main.i
處理源代碼文件中的以"#"開頭的預(yù)編譯指令陨晶。規(guī)則如下:
- "#define"刪除并展開對應(yīng)宏定義先誉。
- 處理所有的條件預(yù)編譯指令的烁。如#if/#ifdef/#else/#endif。
- "#include/#import"包含的文件遞歸插入到此處铃芦。
刪除所有的注釋"http://或/**/"。- 添加行號和文件名標(biāo)識杨帽。如“# 1 "main.m"”,編譯調(diào)試會用到。
2. 編譯(Compilation)
clang -S main.i -o main.s
把上面得到的.i文件進行:詞法分析晃危、語法分析僚饭、靜態(tài)分析、優(yōu)化生成相應(yīng)的匯編代碼胧砰,得到.s文件鳍鸵。
- 詞法分析:源代碼的字符序列分割成一個個token(關(guān)鍵字、標(biāo)識符尉间、字面量偿乖、特殊符號),比如把標(biāo)識符放到符號表(靜態(tài)鏈接那篇哲嘲,重點講符號表)贪薪。
- 語法分析:生成抽象語法樹 AST,此時運算符號的優(yōu)先級確定了眠副;有些符號具有多重含義也確定了画切,比如“*”是乘號還是對指針取內(nèi)容;表達式不合法囱怕、括號不匹配等霍弹,都會報錯。
- 靜態(tài)分析:分析類型聲明和匹配問題娃弓。比如整型和字符串相加典格,肯定會報錯。
- 中間語言生成:CodeGen根據(jù)AST自頂向下遍歷逐步翻譯成 LLVM IR忘闻,并且在編譯期就可以確定的表達式進行優(yōu)化钝计,比如代碼里t1=2+6恋博,可以優(yōu)化t1=8。(假如開啟了bitcode炼吴,)
- 目標(biāo)代碼生成與優(yōu)化:根據(jù)中間語言生成依賴具體機器的匯編語言。并優(yōu)化匯編語言童芹。這個過程中署咽,假如有變量且定義在同一個編譯單元里宁否,那給這個變量分配空間,確定變量的地址台谊。假如變量或者函數(shù)不定義在這個編譯單元,得鏈接時候狠角,才能確定地址。
3. 匯編(Assembly)
clang -c main.s -o main.o
匯編就是把上面得到的.s文件里的匯編指令一一翻譯成機器指令立帖。得到.o文件,也就是目標(biāo)文件绑咱,后面會重點講的Mach-O文件。
3. 鏈接(Linking)
clang main.o -o main
遠古時代窿克,一個程序只有一個源代碼文件具被,導(dǎo)致程序的維護非常困難。現(xiàn)在程序都是分模塊組成啸蜜,比如一個App,對應(yīng)有多個源代碼文件蜂林。每個源代碼文件匯編成目標(biāo)文件,根據(jù)上面流程A目標(biāo)文件訪問B目標(biāo)文件的函數(shù)或者變量睁蕾,是不知道地址的子眶,鏈接就是要解決這個問題。鏈接過程主要包括地址和空間分配渴杆、符號決議和重定位。
鏈接就是把目標(biāo)文件(一個或多個)和需要的庫(靜態(tài)庫/動態(tài)庫)鏈接成可執(zhí)行文件艾疟。后面會分別講靜態(tài)鏈接和動態(tài)鏈接弟疆。