日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Linux從外到內剝開動態庫,一個簡單例子看懂Linux下的動態庫開發原理

來源: 責編: 時間:2023-12-20 17:47:01 244觀看
導讀本文將演示4種各自獨立的得到最終二進制文件的方式。代碼采用C語言。用gcc將C語言代碼生成靜態庫 .a 文件,再與編譯后的 main.o 合成最終的靜態鏈接的可執行文件,查看運行結果。用gcc將C語言代碼生成動態庫,待用。用gcc

本文將演示4種各自獨立的得到最終二進制文件的方式。代碼采用C語言。G5d28資訊網——每日最新資訊28at.com

  • 用gcc將C語言代碼生成靜態庫 .a 文件,再與編譯后的 main.o 合成最終的靜態鏈接的可執行文件,查看運行結果。
  • 用gcc將C語言代碼生成動態庫,待用。
  • 用gcc將C語言代碼編譯并鏈接動態庫,生成可執行文件main,運行時依賴動態庫so文件。
  • 演示用ar如何轉換 靜態庫文件得到動態庫文件。可被用于可執行文件的鏈接。

G5d28資訊網——每日最新資訊28at.com

本文代碼文件內容

首先列出所有代碼文件內容,一共3個文件:drive.h,drive.c,main.c,分別為 動態庫libdrive.so 的頭文件、函數實現文件、主入口main()文件。內容分別如下。為了簡明易懂,只以最簡單的功能實現。G5d28資訊網——每日最新資訊28at.com

(1) drive.h 文件內容:G5d28資訊網——每日最新資訊28at.com

//聲明 加法函數的函數入參和返回值。int dr(int a, int b);

(2) drive.c 文件內容:G5d28資訊網——每日最新資訊28at.com

#include <stdio.h>//定義一個加法函數int dr(int a, int b) {    return a + b;}

(3) main.c 文件內容G5d28資訊網——每日最新資訊28at.com

//調用動態庫內的add()函數,3+5,所以打印結果應當為8#include <stdio.h>#include "drive.h"int main() {    // 調用加法函數    int result = add(3, 5);    printf("Sum: %d/n", result);    return 0;}

用gcc將C語言代碼生成靜態庫 .a,被鏈接入最終可執行文件

(1) 編譯 drive.c 文件為.o 文件:G5d28資訊網——每日最新資訊28at.com

# gcc -c drive.c -o drive.o

gcc 的幾個重要編譯參數,上面用到了-c 、-o 等參數,下面還會用到所以再次貼上參數說明:G5d28資訊網——每日最新資訊28at.com

-c                      編譯、匯編到目標代碼,不進行鏈接。  -o <文件>                輸出到 <文件>。  -pie                     生成動態鏈接的位置無關可執行文件。  -shared                  生成一個共享庫。  -static                  告訴ld在鏈接的時候生成純靜態可執行文件。

(2) 使用編譯drive.c得到的drive.o 文件作為材料,生成 libdrive.a 靜態庫文件。文件名前面加lib是為了gcc鏈接文件時 默認的約定找以lib開始的庫文件:G5d28資訊網——每日最新資訊28at.com

# ar rcs libdrive.a  drive.o

(3) 鏈接得到最終可執行文件:G5d28資訊網——每日最新資訊28at.com

# gcc main.c  -L$PWD -ldrive -o main-static# file main-static   main-static: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=84fa8514ed5a9ef043b88d1957de83248208dac2, for GNU/Linux 3.2.0, not stripped[lph@localhost 2023-12-12]$ ldd  main-static         linux-vdso.so.1 (0x00007ffd087f3000)        libc.so.6 => /lib64/libc.so.6 (0x00007fb2cbb82000)        /lib64/ld-linux-x86-64.so.2 (0x00007fb2cbd79000)

當前目錄下只有libdrive.a 庫,沒有動態庫,所以不會優先鏈接.so庫,只能鏈接libdrive.a庫。所以我使用file 命令查看main-static的成分,我以為它就是靜態文件,結果發現怎么還是動態鏈接的?(鏈接了3個動態庫文件)G5d28資訊網——每日最新資訊28at.com

雖然通過-ldrive 我們確實鏈接了libdrive.a靜態文件進入 main-static文件內部(所以以上出現的鏈接信息里不會顯示libdrive.so 或 libdrive.a,但file的結果說得到的main-static文件仍然是dynamically linked得的,為什么會這樣呢?G5d28資訊網——每日最新資訊28at.com

sudo  yum install glibc-static

G5d28資訊網——每日最新資訊28at.com

G5d28資訊網——每日最新資訊28at.com

新安裝的libc的靜態庫文件的路徑:G5d28資訊網——每日最新資訊28at.com

# rpm -q --list glibc-static/usr/lib64/libBrokenLocale.a/usr/lib64/libc.a/usr/lib64/libm-2.37.a/usr/lib64/libm.a/usr/lib64/libmvec.a/usr/lib64/libresolv.a

重新嘗試實現徹底的靜態鏈接:G5d28資訊網——每日最新資訊28at.com

[lph@localhost 2023-12-12]$ gcc -static main.c -L. -ldrive -o main-static-true[lph@localhost 2023-12-12]$ file main-static-true main-static-true: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=be4d6a0e422b3a1ae1ccf0a9b162f5e628eb47b3, for GNU/Linux 3.2.0, not stripped, too many notes (256)[lph@localhost 2023-12-12]$ ldd  main-static-true         不是動態可執行文件

以上 ldd 的結果說明,main-static-true 文件才是真正靜態鏈接的。G5d28資訊網——每日最新資訊28at.com

來對比一下 假的 main-static 跟真的可執行文件大小差距多大:G5d28資訊網——每日最新資訊28at.com

$ ls  -lht  main-static*776K 12月12日 22:01 main-static-true17K  12月12日 21:42 main-static

文件大小相差45倍。由于功能少所以這個倍數并不嚴謹。但大體上我們可以了解純靜態的可執行文件,確實會比 dynamic linked的可執行文件大很多。不過由于現在硬盤和內存的擴大,成本降低,越來越多新編程語言默認采用純靜態編譯可執行文件。以增強跨平臺的運行能力。G5d28資訊網——每日最新資訊28at.com

用gcc將 drive.c 代碼生成動態庫文件 libdrive.so

將當前目錄下的所有.o文件(目前只有 drive.o一個文件)作為材料,生成最終的 libdrive.so動態庫文件(實際相當于將 .o文件打了個壓縮包到 .a文件里,并調整了鏈接符號)。G5d28資訊網——每日最新資訊28at.com

gcc -shared *.o -o libdrive.so

所以我們目錄下截至現在已有這些文件:G5d28資訊網——每日最新資訊28at.com

# ls -lht總計 52K-rwxrwxr-x 1 lph lph  16K 12月12日 16:43  libdrive.so-rwxrwxr-x 1 lph lph  16K 12月12日 16:30  main-static-true-rwxrwxr-x 1 lph lph  16K 12月12日 16:20  main-static-rw-rw-r-- 1 lph lph  136 12月12日 16:18  main.c-rw-rw-r-- 1 lph lph 1.4K 12月12日 16:17  libdrive.a-rw-rw-r-- 1 lph lph 1.3K 12月12日 16:17  drive.o-rw-rw-r-- 1 lph lph   91 12月12日 16:12  drive.c-rw-rw-r-- 1 lph lph   91 12月12日 16:12  drive.h

既然是動態庫,總要能被調用者直到你的暴露的借口。我們驗證下這個libdrive.so動態庫是否也暴露了add函數呢?G5d28資訊網——每日最新資訊28at.com

$ nm -D  libdrive.so 00000000000010f9 T add                 w __cxa_finalize@GLIBC_2.2.5                 w __gmon_start__                 w _ITM_deregisterTMCloneTable                 w _ITM_registerTMCloneTable

從結果看,確實暴露了add 函數。至于其他4個W是什么作用,我們目前暫時不管。G5d28資訊網——每日最新資訊28at.com

用gcc將C語言 main.c 編譯并鏈接動態庫,生成可執行文件 main_share ,運行時是否依賴動態庫so文件?

gcc main.c -L./ -ldrive  -o main_share

上面說過,當libdrive.so 不存在時,libdrive.a 存在,則gcc 根據鏈接 -L./ -ldrive 參數,在對應目錄下只找libdrive.a,所以以前只能鏈接.a文件。現在有了.so文件,那么-L./ -ldrive會優先鏈接libdrive.so。讓我們用ldd 命令檢驗一下:G5d28資訊網——每日最新資訊28at.com

$  LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD  ldd ./main_share        linux-vdso.so.1 (0x00007ffccd74a000)        libdrive.so (0x00007ff2cbb28000)        libc.so.6 => /lib64/libc.so.6 (0x00007ff2cb933000)        /lib64/ld-linux-x86-64.so.2 (0x00007ff2cbb2f000)

這里我們在命令中臨時設置 庫文件搜索路徑包含當前路徑$PWD。G5d28資訊網——每日最新資訊28at.com

從結果看,我們的main_share 確實鏈接了動態庫 libdrive.so。G5d28資訊網——每日最新資訊28at.com

「完」G5d28資訊網——每日最新資訊28at.com

演示用ar如何轉換 靜態庫文件得到動態庫文件。可被用于可執行文件的鏈接。

先清理一下現場:刪掉 drive.o  libdrive.so 這兩個文件。G5d28資訊網——每日最新資訊28at.com

$ rm -f drive.o  libdrive.so

這里使用現有的  libdrive.a 動態庫,看能否轉化成 libdrive.so 文件。G5d28資訊網——每日最新資訊28at.com

(1) 之前說過.a相當于.o 文件的壓縮包,那么我們可以分離出 drive.o 文件G5d28資訊網——每日最新資訊28at.com

ar -x libdrive.a

(2) 編譯生成 .so 文件G5d28資訊網——每日最新資訊28at.com

gcc -shared  *.o -o libdrive.so

(3) 查看導出函數G5d28資訊網——每日最新資訊28at.com

$ nm -D libdrive.so00000000000010f9 T add                 w __cxa_finalize@GLIBC_2.2.5                 w __gmon_start__                 w _ITM_deregisterTMCloneTable                 w _ITM_registerTMCloneTable$

結果與上上面的 nm -D libdrive.so 輸出一致。作為驗證我們將使用這個轉化出的so動態庫測試對main()的鏈接和運行效果:G5d28資訊網——每日最新資訊28at.com

$ gcc main.c -L./ -ldrive  -o main_share_from_libdrive_amain.c: 在函數‘main’中:main.c:6:18: 警告:隱式聲明函數‘add’ [-Wimplicit-function-declaration]    6 |     int result = add(3, 5);      |                  ^~~      $ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD  ./main_share_from_libdrive_aSum: 8

警告信息不管。運行效果符合預期,打印了3+5的結果。說明靜態庫轉成動態庫也是OK可以用的(實際場景gcc還要加-fPIC 參數來生成動態庫,以增強動態庫的通用性不依賴于固定地址,本文不深入解析 -fPIC,請讀者自己查信息 )。G5d28資訊網——每日最新資訊28at.com

總結一下,經過以上4個場景的演示驗證,我們對Linux的動態庫、靜態庫之間的關系,有了更深入的認知。G5d28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-50765-0.htmlLinux從外到內剝開動態庫,一個簡單例子看懂Linux下的動態庫開發原理

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: SpringBoot中如何優雅地個性化定制Jackson

下一篇: C++中的RAII機制及其智能指針的應用

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 屏南县| 九江县| 广丰县| 和静县| 丹寨县| 三门峡市| 赤壁市| 乐山市| 莒南县| 宿松县| 吴旗县| 班戈县| 清新县| 友谊县| 巴中市| 延寿县| 蓬溪县| 涿鹿县| 仁寿县| 灵台县| 景谷| 大丰市| 盈江县| 涿鹿县| 互助| 阿拉善左旗| 革吉县| 都匀市| 乐至县| 霍山县| 广宁县| 儋州市| 乌兰浩特市| 阿勒泰市| 宁武县| 稻城县| 扎鲁特旗| 衡南县| 漾濞| 通海县| 漳平市|