1. 程式人生 > 其它 >計算機作業系統--連結(六)

計算機作業系統--連結(六)

  1. 編譯系統
  2. 靜態連結
  3. 目標檔案
  4. 動態連結

1.編譯系統

以下是一個c程式

#include <stdio.h>

int main()
{
    printf("hello, world\n");
    return 0;
}

在Unix系統上,由編譯器把原始檔轉換為目標檔案。

gcc -o hello hello.c

這個過程大致如下:

  • 預處理階段:處理以 # 開頭的預處理命令
  • 編譯階段:翻譯成彙編檔案;
  • 彙編階段:將彙編檔案翻譯成可重定位目標檔案;
  • 連結階段:將可重定位目標檔案和printf.o 等單獨預編譯好的目標檔案進行合併,得到最終的可執行檔案。

2.靜態連結

靜態連結器以一組可重定位目標檔案為輸入,生成一個完全連結的可執行目標檔案作為輸出。連結器主要完成以下兩個任務:

  • 符號解析:每個符號對應於一個函式、一個全域性變數或靜態變數,符號解析的目的是將每個符號引用與一個符號定義關聯起來。
  • 重定位:連結器通過把每個符號定義與一個記憶體位置關聯起來,然後修改所有對這些符號的引用,使得它們指向這個記憶體位置。

3.目標檔案

  • 可執行目標檔案:可以直接在記憶體中執行;
  • 可重定位目標檔案:可與其他可重定位目標檔案在連結階段合併,建立一個可執行目標檔案;
  • 共享目標檔案:這是一種特殊的可重定位目標檔案,可以在執行時被動態載入近記憶體並連結;

4.動態連結

靜態庫有以下兩個問題:

  • 當靜態庫更新時那麼整個程式都要重新進行連結;
  • 對於printf這種標準函式庫,如果每個程式都要有程式碼,這會極大浪費資源。

共享庫是為了解決靜態庫的這兩個問題而設計的,在Linux系統中通常用.so 字尾來表示,Windows系統上它們被稱為DLL。它具有以下特點:

  • 在給定的檔案系統中一個庫只有一個檔案,所有引用該庫的可執行目標檔案都共享這個檔案,它不會被複制到引用它的可執行檔案中;
  • 在記憶體中,一個共享庫的.text 節(已編譯程式的機器程式碼)的一個副本可以被不同的正在執行的程序共享。