成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Linux從外到內(nèi)剝開動態(tài)庫,一個簡單例子看懂Linux下的動態(tài)庫開發(fā)原理

開發(fā) Linux
經(jīng)過以下四個場景的演示驗(yàn)證,我們對Linux的動態(tài)庫、靜態(tài)庫之間的關(guān)系,一定會有深入的認(rèn)知。

本文將演示4種各自獨(dú)立的得到最終二進(jìn)制文件的方式。代碼采用C語言。

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

本文代碼文件內(nèi)容

首先列出所有代碼文件內(nèi)容,一共3個文件:drive.h,drive.c,main.c,分別為 動態(tài)庫libdrive.so 的頭文件、函數(shù)實(shí)現(xiàn)文件、主入口main()文件。內(nèi)容分別如下。為了簡明易懂,只以最簡單的功能實(shí)現(xiàn)。

(1) drive.h 文件內(nèi)容:

//聲明 加法函數(shù)的函數(shù)入?yún)⒑头祷刂怠?int dr(int a, int b);

(2) drive.c 文件內(nèi)容:

#include <stdio.h>

//定義一個加法函數(shù)
int dr(int a, int b) {
    return a + b;
}

(3) main.c 文件內(nèi)容

//調(diào)用動態(tài)庫內(nèi)的add()函數(shù),3+5,所以打印結(jié)果應(yīng)當(dāng)為8
#include <stdio.h>
#include "drive.h"

int main() {
    // 調(diào)用加法函數(shù)
    int result = add(3, 5);
    printf("Sum: %d\n", result);

    return 0;
}

用gcc將C語言代碼生成靜態(tài)庫 .a,被鏈接入最終可執(zhí)行文件

(1) 編譯 drive.c 文件為.o 文件:

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

gcc 的幾個重要編譯參數(shù),上面用到了-c 、-o 等參數(shù),下面還會用到所以再次貼上參數(shù)說明:

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

(2) 使用編譯drive.c得到的drive.o 文件作為材料,生成 libdrive.a 靜態(tài)庫文件。文件名前面加lib是為了gcc鏈接文件時 默認(rèn)的約定找以lib開始的庫文件:

# ar rcs libdrive.a  drive.o

(3) 鏈接得到最終可執(zhí)行文件:

# 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)

當(dāng)前目錄下只有l(wèi)ibdrive.a 庫,沒有動態(tài)庫,所以不會優(yōu)先鏈接.so庫,只能鏈接libdrive.a庫。所以我使用file 命令查看main-static的成分,我以為它就是靜態(tài)文件,結(jié)果發(fā)現(xiàn)怎么還是動態(tài)鏈接的?(鏈接了3個動態(tài)庫文件)

雖然通過-ldrive 我們確實(shí)鏈接了libdrive.a靜態(tài)文件進(jìn)入 main-static文件內(nèi)部(所以以上出現(xiàn)的鏈接信息里不會顯示libdrive.so 或 libdrive.a,但file的結(jié)果說得到的main-static文件仍然是dynamically linked得的,為什么會這樣呢?

sudo  yum install glibc-static

新安裝的libc的靜態(tài)庫文件的路徑:

# 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

重新嘗試實(shí)現(xiàn)徹底的靜態(tài)鏈接:

[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 
        不是動態(tài)可執(zhí)行文件

以上 ldd 的結(jié)果說明,main-static-true 文件才是真正靜態(tài)鏈接的。

來對比一下 假的 main-static 跟真的可執(zhí)行文件大小差距多大:

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

文件大小相差45倍。由于功能少所以這個倍數(shù)并不嚴(yán)謹(jǐn)。但大體上我們可以了解純靜態(tài)的可執(zhí)行文件,確實(shí)會比 dynamic linked的可執(zhí)行文件大很多。不過由于現(xiàn)在硬盤和內(nèi)存的擴(kuò)大,成本降低,越來越多新編程語言默認(rèn)采用純靜態(tài)編譯可執(zhí)行文件。以增強(qiáng)跨平臺的運(yùn)行能力。

用gcc將 drive.c 代碼生成動態(tài)庫文件 libdrive.so

將當(dāng)前目錄下的所有.o文件(目前只有 drive.o一個文件)作為材料,生成最終的 libdrive.so動態(tài)庫文件(實(shí)際相當(dāng)于將 .o文件打了個壓縮包到 .a文件里,并調(diào)整了鏈接符號)。

gcc -shared *.o -o libdrive.so

所以我們目錄下截至現(xiàn)在已有這些文件:

# ls -lht
總計(jì) 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

既然是動態(tài)庫,總要能被調(diào)用者直到你的暴露的借口。我們驗(yàn)證下這個libdrive.so動態(tài)庫是否也暴露了add函數(shù)呢?

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

從結(jié)果看,確實(shí)暴露了add 函數(shù)。至于其他4個W是什么作用,我們目前暫時不管。

用gcc將C語言 main.c 編譯并鏈接動態(tài)庫,生成可執(zhí)行文件 main_share ,運(yùn)行時是否依賴動態(tài)庫so文件?

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

上面說過,當(dāng)libdrive.so 不存在時,libdrive.a 存在,則gcc 根據(jù)鏈接 -L./ -ldrive 參數(shù),在對應(yīng)目錄下只找libdrive.a,所以以前只能鏈接.a文件。現(xiàn)在有了.so文件,那么-L./ -ldrive會優(yōu)先鏈接libdrive.so。讓我們用ldd 命令檢驗(yàn)一下:

$  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)

這里我們在命令中臨時設(shè)置 庫文件搜索路徑包含當(dāng)前路徑$PWD。

從結(jié)果看,我們的main_share 確實(shí)鏈接了動態(tài)庫 libdrive.so。

「完」

演示用ar如何轉(zhuǎn)換 靜態(tài)庫文件得到動態(tài)庫文件。可被用于可執(zhí)行文件的鏈接。

先清理一下現(xiàn)場:刪掉 drive.o  libdrive.so 這兩個文件。

$ rm -f drive.o  libdrive.so

這里使用現(xiàn)有的  libdrive.a 動態(tài)庫,看能否轉(zhuǎn)化成 libdrive.so 文件。

(1) 之前說過.a相當(dāng)于.o 文件的壓縮包,那么我們可以分離出 drive.o 文件

ar -x libdrive.a

(2) 編譯生成 .so 文件

gcc -shared  *.o -o libdrive.so

(3) 查看導(dǎo)出函數(shù)

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

結(jié)果與上上面的 nm -D libdrive.so 輸出一致。作為驗(yàn)證我們將使用這個轉(zhuǎn)化出的so動態(tài)庫測試對main()的鏈接和運(yùn)行效果:

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

警告信息不管。運(yùn)行效果符合預(yù)期,打印了3+5的結(jié)果。說明靜態(tài)庫轉(zhuǎn)成動態(tài)庫也是OK可以用的(實(shí)際場景gcc還要加-fPIC 參數(shù)來生成動態(tài)庫,以增強(qiáng)動態(tài)庫的通用性不依賴于固定地址,本文不深入解析 -fPIC,請讀者自己查信息 )。

總結(jié)一下,經(jīng)過以上4個場景的演示驗(yàn)證,我們對Linux的動態(tài)庫、靜態(tài)庫之間的關(guān)系,有了更深入的認(rèn)知。

責(zé)任編輯:趙寧寧 來源: 深入理解Linux
相關(guān)推薦

2010-03-04 09:51:07

Linux動態(tài)庫

2010-03-04 10:04:10

Linux動態(tài)庫

2015-11-16 10:34:19

Linux動態(tài)庫總結(jié)

2010-03-04 10:17:57

Linux動態(tài)庫

2010-01-07 17:40:41

Linux動態(tài)庫

2024-02-28 08:10:15

Linux靜態(tài)庫動態(tài)庫

2011-03-17 17:50:39

SQL Server數(shù)

2010-01-07 17:55:44

Linux動態(tài)庫

2023-03-21 15:36:27

Linux編程

2023-03-30 15:07:57

Linux編程開發(fā)

2012-05-04 08:24:14

LinuxUnix

2010-01-07 18:03:03

Linux動態(tài)庫

2012-05-08 14:48:23

LinuxUnix動態(tài)鏈接庫

2010-01-07 17:42:23

Linux動態(tài)庫

2023-12-27 08:27:03

Linuxldconfig命令

2022-07-10 21:20:11

C語言Linux

2023-03-05 16:36:14

Linux鏈接目標(biāo)文件

2023-03-14 08:02:14

靜態(tài)路由動態(tài)路由設(shè)備

2010-03-04 09:30:40

Linux動態(tài)庫

2009-07-07 20:57:20

LinuxUnix動態(tài)鏈接庫
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 日韩高清不卡 | 欧美成人精品激情在线观看 | 欧美日韩一区二区在线 | 黑人中文字幕一区二区三区 | 又黄又色 | 99精品视频免费观看 | 激情福利视频 | 亚洲成人免费视频在线观看 | 亚洲va中文字幕 | 精品一二三区在线观看 | 欧美日产国产成人免费图片 | 日韩一区二区免费视频 | 国产一区欧美 | 国产精品亚洲欧美日韩一区在线 | 亚洲永久免费观看 | 羞羞色视频 | 日韩aⅴ片 | 一区二区三区中文字幕 | 久久国产精品-久久精品 | 亚洲va欧美va人人爽午夜 | 亚洲一区免费在线 | 狠狠久久 | 日本久久久影视 | 美女天天操 | 中文字幕av中文字幕 | 婷婷久久精品一区二区 | 国产一区二区a | 最新黄色毛片 | 欧美成人免费在线视频 | 日韩视频在线观看中文字幕 | 性色的免费视频 | 国产精品 欧美精品 | 国产成人精品一区二区三 | 国产无人区一区二区三区 | 日日久| 国产精品99久久久久久动医院 | 亚洲免费一区二区 | 99精品欧美一区二区蜜桃免费 | 狠狠av| 福利成人| 免费观看黄网站 |