函數庫、鏈接和載入
絕大多數編譯器并不是一個單一的龐大程序。通常由多大67個稍小的策劃年供需組成。這些程序再由一個叫做“編譯器驅動器”的控制程序來調用。
靜態鏈接(傳統的可執行文件生成):
可執行文件并不能直接執行,需要載入到鏈接器。鏈接器把需要使用的每個庫函數機器指令的一份拷貝加到生成的最終的可執行文件里。
動態鏈接
正如上面所說。如果函數庫的一份拷貝是可執行文件的物理組成部分,那么我們稱之為靜態鏈接;如果可執行文件只是包含了文件名,讓載入器在運行時能夠尋找程序所需要的函數(函數的機器指令),那么我們稱之為動態鏈接。
不調用也不產生額外開銷
動態鏈接:在運行時進行鏈接以便運行,但外部函數在被真正調用之前,運行時載入器并不解析他們。所以即使鏈接了函數庫,如果并沒有實際調用,也不會再來額外開銷。
動態鏈接的優點
最好只使用動態鏈接
使用靜態鏈接最大的危險是將來版本的操作系統可能與可執行文件綁定的系統函數庫不兼容,我們無法保證早期版本的系統函數庫能夠在后期版本的系統上正確運行。
之前編譯鏈接出的可執行文件(機器指令)在新的系統上不能起作用。因為舊的函數邊一處的機器指令在以前版本的操作系統剛好是做那一件事,而在新的系統上就是做其他的事了。
而且有些函數庫只能以動態鏈接的形式使用。因為為了規避上述所說的問題,最好的策略就是所有的應用都使用動態鏈接。
函數鏈接的5個特殊秘密
1、動態庫文件的擴展名是".so",而靜態庫文件的擴展名是".a";
2、例如通過-lthread選項,是告訴編譯鏈接到libthread.so;
3、編譯器期望在確定的目錄找到庫;如果沒喲用-Lhe -R選項,默認會去/usr/lib等幾個目錄下找;
4、不知道你的程序會使用哪些函數庫時,可以通過觀察包含什么頭文件。例如math.h就提示你應該會用到math函數庫。
5、與提取動態庫的符號相比,靜態庫的符號提取的方法限制更嚴
小啟發:始終將-l函數庫選項放在編譯命令行的最右邊
警惕編寫與庫函數同名的函數以取代該庫函數的行為(Interpositioning)
為了避免你自己聲明的取代某個庫函數的函數被其他文件也適用(本來是想使用標準庫函數)。最好的辦法就是把你的函數聲明為static,這樣它的作用就局限在一個文件中了。
產生鏈接器報告文件
ld 的-m選項可以讓鏈接器產生一個報告,這個報告里面包括了被interpose的符號的說明。
略