操作系统:链接
編譯系統
以下是一個 hello.c 程序:
#include <stdio.h>int main() {printf("hello, world\n");return 0; }在 Unix 系統上,由編譯器把源文件轉換為目標文件。
gcc -o hello hello.c這個過程大致如下:
?
- 預處理階段:處理以 # 開頭的預處理命令;
- 編譯階段:翻譯成匯編文件;
- 匯編階段:將匯編文件翻譯成可重定向目標文件;
- 鏈接階段:將可重定向目標文件和 printf.o 等單獨預編譯好的目標文件進行合并,得到最終的可執行目標文件。
靜態鏈接
靜態鏈接器以一組可重定向目標文件為輸入,生成一個完全鏈接的可執行目標文件作為輸出。鏈接器主要完成以下兩個任務:
- 符號解析:每個符號對應于一個函數、一個全局變量或一個靜態變量,符號解析的目的是將每個符號引用與一個符號定義關聯起來。
- 重定位:鏈接器通過把每個符號定義與一個內存位置關聯起來,然后修改所有對這些符號的引用,使得它們指向這個內存位置。
?
目標文件
- 可執行目標文件:可以直接在內存中執行;
- 可重定向目標文件:可與其它可重定向目標文件在鏈接階段合并,創建一個可執行目標文件;
- 共享目標文件:這是一種特殊的可重定向目標文件,可以在運行時被動態加載進內存并鏈接;
動態鏈接
靜態庫有以下兩個問題:
- 當靜態庫更新時那么整個程序都要重新進行鏈接;
- 對于 printf 這種標準函數庫,如果每個程序都要有代碼,這會極大浪費資源。
共享庫是為了解決靜態庫的這兩個問題而設計的,在 Linux 系統中通常用 .so 后綴來表示,Windows 系統上它們被稱為 DLL。它具有以下特點:
- 在給定的文件系統中一個庫只有一個文件,所有引用該庫的可執行目標文件都共享這個文件,它不會被復制到引用它的可執行文件中;
- 在內存中,一個共享庫的 .text 節(已編譯程序的機器代碼)的一個副本可以被不同的正在運行的進程共享。
總結
- 上一篇: 操作系统:了解一下磁盘结构
- 下一篇: linux:su认证失败