靜態庫
目前以lib後綴的庫有兩種,一種為靜態程式庫(Static Libary,以下簡稱“靜態庫”),另一種為動態連線庫(DLL,以下簡稱“動態庫”)的導入庫(Import Libary,以下簡稱“導入庫”)。
靜態庫是一個或者多個obj檔案的打包,所以有人乾脆把從obj檔案生成lib的過程稱為Archive,即合併到一起。比如你連結一個靜態庫,如果其中有錯,它會準確的找到是哪個obj有錯,即靜態lib只是殼子。
動態庫一般會有對應的導入庫,方便程式靜態載入動態程式庫,否則你可能就需要自己LoadLibary調入DLL檔案,然後再手工GetProcAddress獲得對應函式了。有了導入庫,你只需要連結導入庫後按照頭檔案函式接口的聲明調用函式就可以了。
導入庫和靜態庫的區別很大,他們實質是不一樣的東西。靜態庫本身就包含了實際執行代碼、符號表等等,而對於導入庫而言,其實際的執行代碼位於動態庫中,導入庫只包含了地址符號表等,確保程式找到對應函式的一些基本地址信息。
這也是實際上很多開原始碼發布的慣用方式:
1. 預編譯的開發包:包含一些.dll檔案和一些.lib檔案。其中這裡的.lib就是導入庫,而不要錯以為是靜態庫。但是引入方式和靜態庫一樣,要在連結路徑上添加找到這些.lib的路徑。而.dll則最好放到最後產生的應用程式exe執行檔案相同的目錄。這樣運行時,就會自動調入動態程式庫。
2. 用戶自己編譯: 下載的是原始碼,按照readme自己編譯。生成很可能也是.dll + .lib(導入庫)的庫檔案
3. 如果你只有dll,並且你知道dll中函式的函式原型,那么你可以直接在自己程式中使用LoadLibary調入DLL檔案,然後使用GetProcAddress調用DLL中的函式。
當DLL被連結時,連結程式要查找關於輸出變數,函式,或C++類的信息,並自動生成一個lib檔案。該lib檔案包含一個DLL輸出的符號列表。如果要連結引用該DLL的輸出符號的任何可執行模組,該lib檔案是必不可少的(使用GetProcAddress除外)。
其實導入庫中並不含RVA(每個符號的相對虛擬地址),只是一些符號而已,還有關於這個lib所對應的DLL的名字等。 (這只是我現在的理解)
那當應用程式調用一個DLL的函式時,是怎么進行的呢?(使用lib的情況下)
答案是在進程的主執行緒開始運行之前,由載入器完成。
載入器根據輸入節中DLL的名字按照windows的搜尋路徑搜尋DLL,找到後DLL映射到進程的地址空間,這是DLL中對應於輸入節中的各個符號的地址就可以確定了,載入器在這個時候將地址重新填入可執行模組的輸入節中,動態連線完成。