Linux下編譯動態鏈結庫與使用詳解

2021-07-16 13:58:23 字數 3929 閱讀 4375

兩種庫

靜態庫動態庫

區別:在於**被載入的時刻不同。靜態庫的**在編譯過程中已經被載入可執行程式,因此體積較大。共享庫的**是在可執行程式執行時才載入記憶體的,在編譯過程中僅簡單的引用,因此**體積較小

庫的儲存位置和命名規範

儲存:一般放在/usr/lib和/lib下

命名規範

1. 靜態庫的名字一般為lib***x.a,其中***x是該lib的名稱

2. 動態庫的名字一般為lib***x.so.major.minor,***x是該動態庫的名稱,major是主版本號, minor是副版本號

檢視乙個可執行程式依賴哪些庫

ldd命令可以檢視乙個可執行程式依賴的共享庫

在新安裝乙個庫之後如何讓系統能夠找到他標頭檔案so.h

#ifndef  so_h

#define so_h

int add(int a, int b);

#endif /*so_h*/

實現檔案so.c

#include "so.h"

int add(int a, int b)

gcc -fpic -c so.c//生成so.o

gcc -shared -o libtest.so so.o

(上面兩行可以整合成一行:gcc so.c -fpic -shared -o libtest.so)

-fpic 使輸出的物件模組是按照可重定位位址方式生成的(即與位置無關)。

$ nm -g libtest.so 

0000000000000670

t add

0000000000201030 b __bss_start

w __cxa_finalize@@glibc_2.2.5

0000000000201030 d _edata

0000000000201038 b _end

0000000000000684

t _fini

w __gmon_start__

0000000000000540

t _init

w _itm_deregistertmclonetable

w _itm_registertmclonetable

w _jv_registerclasses

#include 

#include "so.h"

int main(int argc, char *argv)

使用gcc main.c -l. -ltest -o test進行編譯。

此時通過readelf test -d已經能看到生成的可執行檔案test的dynamic section裡依賴libtest.so了

$ readelf test -d

dynamic section at offset 0xe18 contains 25 entries:

tag type name/value

0x0000000000000001 (needed) shared

library: [libtest.so]

0x0000000000000001 (needed) shared

library: [libc.so.6]

......

dynamic symbols中也有乙個undefined symbol(add)

$ nm -d test 

u add

0000000000601048 b __bss_start

0000000000601048

d _edata

0000000000601050 b _end

00000000004007b4 t _fini

w __gmon_start__

0000000000400578 t _init

w _itm_deregistertmclonetable

w _itm_registertmclonetable

w _jv_registerclasses

u __libc_start_main

u printf

在執行隱式鏈結的程式之前要注意設定ld_library_path環境變數,或者把前面生成的libtest.so複製到系統路徑下,否則會找不到動態庫。

$ ./test 

./test: error while loading shared libraries: libtest.so: cannot open

shared object file: no such file

or directory

$ export ld_library_path=.

$ ./test

3

顯式鏈結(執行時鏈結)

編寫主程式dyn_main.c

#include 

#include

int main(int argc, char *argv)

add = (int(*)(int, int))dlsym(dl, "add");

if( dlerror() != null )

printf("%d\n", add(1, 2));

return

0;}

使用gcc dyn_main.c -ldl -o dyn_test編譯。

這時通過readelf dyn_test -d可以發現,dyn_test不依賴libtest.so:

$ readelf dyn_test -d

dynamic section at offset 0xe18 contains 25 entries:

tag type name/value

0x0000000000000001 (needed) shared

library: [libdl.so.2]

0x0000000000000001 (needed) shared

library: [libc.so.6]

......

dyn_test的dynamic symbols中也沒有add:

$ nm -d dyn_test 

u dlerror

u dlopen

u dlsym

w __gmon_start__

w _itm_deregistertmclonetable

w _itm_registertmclonetable

w _jv_registerclasses

u __libc_start_main

u printf

u puts

執行程式也不需要設定ld_library_path環境變數

$ ./dyn_test 

3

參考資料

linux下編譯鏈結動態庫

Linux 編譯靜態鏈結庫與動態鏈結庫的方法

hello.c include int main int argc,char argv 1 編譯生成可執行檔案 gcc o test hello.c 2 編譯生成目標檔案 gcc c o test.o hello.c string.c define endstring 0 int strlen ch...

linux 編譯靜態鏈結庫和動態鏈結庫

我們通常把一些公用函式製作成函式庫,供其它程式使用。函式庫分為靜態庫和動態庫兩種。靜態庫在程式編譯時會被連線到目標 中,程式執行時將不再需要該靜態庫。動態庫在程式編譯時並不會被連線到目標 中,而是在程式執行是才被載入,因此在程式執行時還需要動態庫存在。本文主要通過舉例來說明在linux中如何建立靜態...

Linux下動態鏈結庫和靜態鏈結庫

第一部分 編譯過程 預處理過程,負責標頭檔案展開,巨集替換,條件編譯的選擇,刪除注釋等工作。gcc e表示進行預處理。編譯過程,負載將預處理生成的檔案,經過詞法分析,語法分析,語義分析及優化後生成彙編檔案。gcc s表示進行編譯。彙編,是將彙編 轉換為機器可執行指令的過程。通過使用gcc c或者as...