從編譯,鏈接到運行,程序員應該了解自己所寫的代碼最終是怎么成為程序,又怎樣在計算機上運行起來的。另不得不對作者能在碩士期間就能寫出此書感到佩服。精讀此書需要花些功夫,當然肯定能從中收獲很多。我對此書也只是泛讀,主要是想了解編譯,鏈接及程序在內(nèi)存中運行整個實現(xiàn)原理。本篇筆記主要記錄自己在讀此書過程中一些概念上有誤解或不清晰的地方。
IDE一般將編譯和鏈接的過程一步完成,通常將這種編譯和鏈接合并到一起的過程稱為構建(Build)
一個靜態(tài)庫可以簡單地看成一組目標文件的集## 標題 ##合,即很多目標文件經(jīng)過壓縮打包后形成的一個文件。linux下使用“ar”壓縮程序將目標文件壓縮到一起,并且對## 標題 ##其進行編號和索引,以便于查找和檢索。(與自己對靜態(tài)庫的理解有差錯,不是簡單的函數(shù)代碼集合。這也是方便于程序在對靜態(tài)庫進行鏈接時,只包含所使用到得函數(shù)代碼,而不是靜態(tài)庫中的全部函數(shù)代碼)
創(chuàng)建虛擬地址空間,并不是創(chuàng)建實際的物理空間,而是創(chuàng)建映射函數(shù)所需要的相應的數(shù)據(jù)結構。頁映射函數(shù)將虛擬空間的各個頁映射至相應的物理空間。
讀取可執(zhí)行文件頭,并且建立空間與可執(zhí)行文件的映射關系。這一步所做的是虛擬空間與可執(zhí)行文件的映射關系。當對所需的頁進行裝載時,易定位到其在可執(zhí)行文件中的位置。
將CPU指令寄存器設置成可執(zhí)行文件入口,啟動運行。
上面步驟執(zhí)行完以后,其實可執(zhí)行文件的真正指令和數(shù)據(jù)都沒有被裝載入到內(nèi)存中。操作系統(tǒng)是通過捕獲程序運行時產(chǎn)生的頁錯誤,通過先前建立的映射關系計算出相應的頁面在可執(zhí)行文件中的偏移,然后在物理內(nèi)存中分配一個物理頁面,將其載入再將進程中該虛擬頁與分配的物理頁之間建立映射關系。進程從剛產(chǎn)生頁錯誤的位置重新開始執(zhí)行。
C標準運行庫 是C語言程序與不同程序之間的抽象層,將不同的操作系統(tǒng)API抽象成相同的庫函數(shù)。但現(xiàn)在各個操作系統(tǒng)提供的C運行庫包含了更多的功能如線程相關函數(shù)。
Linux下的C運行庫是Glibc,它是完全支持POSIX標準,除了實現(xiàn)C標準庫之外,還提供對linux系統(tǒng)調用的封裝函數(shù)(例如read,write,頭文件unistd.h)
windows下的C運行庫是MSVCRT 實現(xiàn)了C標準庫之外還實現(xiàn)了線程相關操作函數(shù)。
系統(tǒng)調用 是應用程序(運行庫也是應用程序的一部分)與操作系統(tǒng)內(nèi)核之間的接口,它決定了應用程序時如何與內(nèi)核打交道的。無論程序是直接進行系統(tǒng)調用,還是通過運行庫,最終還是會達到系統(tǒng)調用這個層面上。
Linux的系統(tǒng)調用的C語言形式被定義在 unistd.h中,應用程序可以繞過C標準庫的相關函數(shù)如fopen,而直接使用open來實現(xiàn)文件的讀取。
Windows API (Win32是使用最廣泛也是最成熟的版本)是Windows操作系統(tǒng)提供給應用程序開發(fā)者的最底層、最直接與Windows打交道的接口。CRT是建立在Windows API之上的。MFC是對API一種C++形式的封裝庫。頭文件”Windows.h”包含了Windows API的核心部分。