【C進階】20、連結過程簡介

bryson發表於2021-12-16

Summary

1)連結的定義:將目標檔案最終連結為可執行程式

2)連結的2種方式:

  • 靜態連結:目標檔案會被直接*連結*進可執行程式slib.a被刪掉後,程式依舊可以執行
  • 動態連結:程式啟動後才動態載入目標檔案dlib.so被刪掉後,程式無法執行

3)靜態連結和動態連結方式的抉擇:

  • 靜態連結:適用於比較簡單的程式,開發出來不需要變動的,比如純本地的記事本這種;把所有目標檔案都編到可執行程式裡,可能會導致可執行程式很大
  • 動態連結:一個大型軟體的各個模組,如果採用動態庫的形式,哪個模組需要更新了,只需要修改這個模組,然後把dlib.so傳到伺服器上。使用者在使用軟體時,直接去伺服器上拿這一個庫更新下就可以了,而不需要更新整個程式。

連結過程簡介

問題:工程裡的每個.c原始檔在編譯後都會生成目標檔案.o,那這些.o檔案怎麼生成最終的可執行程式.out呢?

答:連結器的主要作用是把各個模組間相互引用的部分處理好,使得各個模組之間能正常的銜接。
image.png

1、靜態連結

  • 連結器在連結時將庫的內容直接加入到可執行程式中
  • 靜態庫的建立和使用
    1)生成靜態庫目標檔案:gcc -c slib.c -o slib.o
    2)生成靜態庫:ar -q slib.a slib.o (輸出:ar:creating slib.a;ar指的是archive,把後面列出的所有目標檔案全都打包進slib.a中
    3)使用靜態庫編譯:gcc 20-1.c slib.a -o 20-1.out (使用靜態庫進行編譯)

2、動態連結

  • 可執行程式在執行時才動態載入庫進行連結(執行時才去找我需要的symbol)
  • 庫的內容不會進入到可執行程式中
// dlib.c
char* name()
{
    return "Dynamic Lib";
}

int add(int a, int b)
{
    return a+b;
}
// 20-2.c
#include <stdio.h>
#include <dlfcn.h>

int main()
{
    void* pdlib = dlopen("./dlib.so", RTLD_LAZY);    // pdlib指向了目錄下dlib.so這個動態庫
                                                     // 這個開啟就相當於一個載入到記憶體裡的指標
    
    char* (*pName)();        // 定義函式指標
    int (*pAdd)(int, int);
    
    if(NULL != pdlib)
    {
        pName = dlsym(pdlib, "name");    // 查詢pdlib指向的動態庫裡的函式
        pAdd = dlsym(pdlib, "add");
        
        if(NULL != pName && NULL != pAdd)
        {
            printf("Name: %s\n", pName());
            printf("Ret: %d\n", pAdd(2, 3));
        }
        
        dlclose(pdlib);        // 關閉pdlib指向的動態庫
    }
    else
    {
        printf("Cannot open dynamic lib...");
    }
}
// linux命令
gcc -shared dlib.c -o dlib.so : 建立了動態庫dlib.so
gcc 20-2.c -ldl -o a.out : 使用動態庫建立了可執行程式a.out
./a.out : 執行可執行程式

注意:-ldl告訴編譯器,這個程式用動態庫的方式來編譯,我們的程式依賴動態庫。如果動態庫dlib.so刪掉了,這個程式就執行不起來了,輸出cannot open,因為a.out每次執行時需要去動態庫裡找symbol的(我要用啥,我每次得去你的倉庫裡拿),庫都沒了,自然找不到了。

本文總結自“狄泰軟體學院”唐佐林老師《C語言進階課程》。
如有錯漏之處,懇請指正。

相關文章