說明:這是程序員的自我修養1書的讀書總結,隨著瀏覽的推動,逐漸增加內容。
分為4個步驟:
處理源代碼中以#開始的預編譯指令,進行宏定義展開,處理所有條件預編譯指令,將被包括文件插入到預編譯指令的位置,刪除所有注釋,添加行號及文件標識,保存#pragma編譯器指令,由于編譯器需用到。
進行1系列詞法分析,語法分析,語義分析及優化后生成匯編代碼文件。
將匯編代碼轉變成機器可履行的指令,生成的是目標文件
將目標文件和所包括的庫文件等鏈接到1起生成終究的可履行文件。
從源代碼開始,輸入到掃描器(scanner)中,進行詞法分析(應用類似有限狀態機的算法),分割為1系列的記號(Token)。然落后行語法分析,產生語法樹,采取上下文無關語法的分析手段。以后進行語義分析,由語義分析器完成,語法分析僅僅完成了對表達式的語法層面上的分析,但其實不了解語句是不是真正成心義。編譯器能分析的語義是靜態語義,在編譯期可以肯定的語義。而動態語義只有在運行期才能肯定。靜態語義通常包括聲明和類型匹配,類型轉換。動態語義1般指在運行期出現的語義相干的問題,比如講0作為除數是1個運行期語義毛病。然后是中間語言生成,即源碼級優化器,在原代碼級別進行優化,此時依然是與目標機器和運行時環境無關的,其實不包括數據尺寸、變量地址和寄存器的名字。中間代碼情勢很多,常見的有3地址碼,表示兩個地址上的數據進行某項操作,賦值給另外一個地址上。中間代碼使得編譯器可以被分為前端和后端,編譯器前端負責產生與機器無關的中間代碼,后端負責將中間代碼轉換為目標代碼,所以對1些跨平臺的編譯器而言,他們可以針對不同的平臺使用同1個前端和針對不同機器的數個后端。以后是代碼生成器和目標代碼優化器,對應的都是編譯器的后端,代碼生成器將中間代碼轉換為目標機器代碼,此進程10分依賴目標機器,由于不同的機器有著不同的字長、寄存器、整數數據類型和浮點數據類型等。最后目標代碼優化器對目標代碼進行優化,選擇適合的尋址方式,使用位移代替乘法,刪除過剩指令等。這個目標代碼中變量地址還沒有肯定,而且如果函數或變量是定義在其他模塊呢時呢?定義在其他模塊的全局變量和函數在終究運行時的絕對地址都要在終究鏈接的時候才能肯定。現代編譯器可以將1個源代碼文件編譯成1個未鏈接的目標文件,然后由鏈接器終究將這些目標文件連接起來構成可履行文件。
重定位,符號,用來表示1個地址,既多是1個變量的起始地址,也能是1段代碼或函數的起始地址。訪問函數需要知道目標函數的地址,訪問變量需要知道目標變量的地址,兩種方式可以歸結為1種方式,那就是模塊間符號的援用,依托符號來通訊,類似拼圖版,定義符號的模塊多出1塊區域,援用該符號的模塊恰好少了那1塊,二者的拼接恰好完善組合,這個拼接進程就是“鏈接”。
鏈接的主要內容是把各個模塊之間相互援用的部份處理好,使得各個模塊之間能夠正確鏈接。
主要包括:地址和空間分配,符號決議和重定位等步驟。
符號決議也被叫做符號綁定,名稱綁定,名稱決議,地址綁定,指令綁定等。決議更偏向于靜態鏈接,綁定更偏向于動態鏈接。
最基本的靜態鏈接進程:
每一個模塊的源代碼經過編譯器編譯成目標文件(.o或.obj),目標文件和庫1起鏈接構成終究可履行文件。最多見的庫就是運行時庫,runtime library,指的是支持程序運行的基本函數的集合。庫實際上是1組目標文件的包,就是1些最經常使用的代碼編譯成目標文件后打包寄存。
編譯器編譯的時候每一個模塊都是單獨編譯的,其實不知道具體調用的函數入口地址,使用鏈接器可以直接援用其他模塊的函數和全局變量而無需知道它們的地址,由于鏈接器在鏈接的時候會根據使用的符號,自動去相應的目標文件中查找對應的地址,然后將援用到的符號地址重新修正,這就是靜態鏈接的最基本的進程和作用。地址修正的進程被叫做重定位Relocation,每一個被修正的地方叫1個重定位入口Relocation Entry。重定位所做的就是給程序中每個這樣的絕對地址援用的位置打補釘,是他們指向正確的地址。
上一篇 iOS開發相關資源