linux下so動態庫一些不為人知的秘密

2021-06-20 16:33:49 字數 4528 閱讀 4495

linux 下有動態庫和靜態庫,動態庫以.so為副檔名,靜態庫以.a為副檔名。二者都使用廣泛。本文主要講動態庫方面知識。

基本上每乙個linux 程式都至少會有乙個動態庫,檢視某個程式使用了那些動態庫,使用

ldd命令檢視 

# ldd /bin/ls

linux-vdso.so.1 =

>

(0x00007fff597ff000)

libselinux.so.1 =

>

/lib64/libselinux.so.1 (0x00000036c2e00000)

librt.so.1 =

>

/lib64/librt.so.1 (0x00000036c2200000)

libcap.so.2 =

>

/lib64/libcap.so.2 (0x00000036c4a00000)

libacl.so.1 =

>

/lib64/libacl.so.1 (0x00000036d0600000)

libc.so.6 =

>

/lib64/libc.so.6 (0x00000036c1200000)

libdl.so.2 =

>

/lib64/libdl.so.2 (0x00000036c1600000)

/lib64/ld-linux-x86-64.so.2 (0x00000036c0e00000)

libpthread.so.0 =

>

/lib64/libpthread.so.0 (0x00000036c1a00000)

libattr.so.1 =

>

/lib64/libattr.so.1 (0x00000036cf600000)

這麼多so,是的。使用ldd顯示的so,並不是所有so都是需要使用的,下面舉個例子

main.cpp

#include 

#include 

#include <

string

>

using namespace std;

int main ()

使用預設引數編譯結果

# g+

+-o demo main.cpp

# ldd demo

linux-vdso.so.1 =

>

(0x00007fffcd1ff000)

libstdc+

+.so.6 =

>

/usr/lib64/libstdc+

+.so.6 (0x00007f4d02f69000)

libm.so.6 =

>

/lib64/libm.so.6 (0x00000036c1e00000)

libgcc_s.so.1 =

>

/lib64/libgcc_s.so.1 (0x00000036c7e00000)

libc.so.6 =

>

/lib64/libc.so.6 (0x00000036c1200000)

/lib64/ld-linux-x86-64.so.2 (0x00000036c0e00000)

如果我鏈結一些so,但是程式並不用到這些so,又是什麼情況呢,下面我加入鏈結壓縮庫,數學庫,執行緒庫

# g+

+-o demo -lz -lm -lrt main.cpp

# ldd demo

linux-vdso.so.1 =

>

(0x00007fff0f7fc000)

libz.so.1 => /lib64/libz.so.1 (0x00000036c2600000)

librt.so.1 => /lib64/librt.so.1 (0x00000036c2200000)

libstdc+

+.so.6 =

>

/usr/lib64/libstdc+

+.so.6 (0x00007ff6ab70d000)

libm.so.6 => /lib64/libm.so.6 (0x00000036c1e00000)

libgcc_s.so.1 =

>

/lib64/libgcc_s.so.1 (0x00000036c7e00000)

libc.so.6 =

>

/lib64/libc.so.6 (0x00000036c1200000)

libpthread.so.0 =

>

/lib64/libpthread.so.0 (0x00000036c1a00000)

/lib64/ld-linux-x86-64.so.2 (0x00000036c0e00000)

看看,雖然沒有用到,但是一樣有鏈結進來,那看看程式啟動時候有沒有去載入它們呢

# strace .

/demo

execve(

"./demo",[

"./demo"],

[/* 30 vars */]

)= 0..

.= 0

open

("/lib64/libz.so.1"

, o_rdonly)

= 3...

close

(3)= 0

open

("/lib64/librt.so.1"

, o_rdonly)

= 3...

close

(3)= 0

open

("/usr/lib64/libstdc++.so.6"

, o_rdonly)

= 3...

close

(3)= 0

open

("/lib64/libm.so.6"

, o_rdonly)

= 3...

close

(3)= 0

open

("/lib64/libgcc_s.so.1"

, o_rdonly)

= 3...

close

(3)= 0

open

("/lib64/libc.so.6"

, o_rdonly)

= 3...

close

(3)= 0

open

("/lib64/libpthread.so.0"

, o_rdonly)

= 3...

close

(3)= 0..

. 看,有載入,所以必定會影響程序啟動速度,所以我們最後不要把無用的so編譯進來,這裡會有什麼影響呢?

大家知不知道linux從程式(program或物件)變成程序(process或程序),要經過哪些步驟呢,這裡如果詳細的說,估計要另開一篇文章。簡單的說分三步:

1、fork程序,在核心建立程序相關核心項,載入程序可執行檔案;

2、查詢依賴的so,一一載入對映虛擬位址

3、初始化程式變數。

可以看到,第二步中dll依賴越多,程序啟動越慢,並且發布程式的時候,這些鏈結但沒有使用的so,同樣要一起跟著發布,否則程序啟動時候,會失敗,找不到對應的so。所以我們不能像上面那樣,把一些毫無意義的so鏈結進來,浪費資源。但是開發人員寫makefile 一般有沒有那麼細心,圖省事方便,那麼有什麼好的辦法呢。繼續看下去,下面會給你解決方法。

先 使用 ldd -u demo 檢視不需要鏈結的so,看下面,一面了然,無用的so全部暴露出來了吧

# ldd -u demo

unused direct dependencies:

/lib64/libz.so.1

/lib64/librt.so.1

/lib64/libm.so.6

/lib64/libgcc_s.so.1

使用 -wl,-

-as-needed 編譯選項

# g+

+-wl,

--as-needed -o demo -lz -lm -lrt main.cpp

# ldd demo

linux-vdso.so.1 =

>

(0x00007fffebfff000)

libstdc+

+.so.6 =

>

/usr/lib64/libstdc+

+.so.6 (0x00007ff665c05000)

libc.so.6 =

>

/lib64/libc.so.6 (0x00000036c1200000)

libm.so.6 =

>

/lib64/libm.so.6 (0x00000036c1e00000)

/lib64/ld-linux-x86-64.so.2 (0x00000036c0e00000)

libgcc_s.so.1 =

>

/lib64/libgcc_s.so.1 (0x00000036c7e00000)

# ldd -u demo

unused direct dependencies:

linux下so動態庫一些不為人知的秘密(中)

介紹了linux下so一些依賴問題,本篇將介紹linux的so路徑搜尋問題。我們知道linux鏈結so有兩種途徑 顯示和隱式。所謂顯示就是程式主動呼叫dlopen開啟相關so 這裡需要補充的是,如果使用顯示鏈結,上篇文章討論的那些問題都不存在。首先,dlopen的so使用ldd是檢視不到的。其次,使...

linux下so動態庫一些不為人知的秘密(中)

本篇將介紹linux的so路徑搜尋問題。我們知道linux鏈結so有兩種途徑 顯示和隱式。所謂顯示就是程式主動呼叫dlopen開啟相關so 這裡需要補充的是,如果使用顯示鏈結,上篇文章討論的那些問題都不存在。首先,dlopen的so使用ldd是檢視不到的。其次,使用dlopen開啟的so並不是在程序...

linux下so動態庫一些不為人知的秘密(上)

1 linux下so動態庫一些不為人知的秘密 中 2 linux下動態共享庫載入時遇到的問題解決方案及原理 3 linux找不到動態鏈結庫 so檔案的解決方法 linux 下有動態庫和靜態庫,動態庫以.so為副檔名,靜態庫以.a為副檔名。二者都使用廣泛。本文主要講動態庫方面知識。基本上每乙個linu...