日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

jni加载第三方so_Linux的so文件到底是干嘛的?浅析Linux的动态链接库

發(fā)布時(shí)間:2024/8/1 linux 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jni加载第三方so_Linux的so文件到底是干嘛的?浅析Linux的动态链接库 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

HelloWorld背后的故事:在Linux上編譯C語言程序 我們分析了Hello World是如何編譯的,即使一個(gè)非常簡單的程序,也需要依賴C標(biāo)準(zhǔn)庫和系統(tǒng)庫,鏈接其實(shí)就是把其他第三方庫和自己源代碼生成的二進(jìn)制目標(biāo)文件融合在一起的過程。經(jīng)過鏈接之后,那些第三方庫中定義的函數(shù)就能被調(diào)用執(zhí)行了。早期的一些操作系統(tǒng)一般使用靜態(tài)鏈接的方式,現(xiàn)在基本上都在使用動(dòng)態(tài)鏈接的方式。

靜態(tài)鏈接和動(dòng)態(tài)鏈接

雖然靜態(tài)鏈接和動(dòng)態(tài)鏈接都能生成可執(zhí)行文件,但兩者的代價(jià)差異很大。下面這張圖可以很形象地演示了動(dòng)態(tài)鏈接和靜態(tài)鏈接的區(qū)別:

動(dòng)態(tài)鏈接 v.s 靜態(tài)鏈接

左側(cè)的人就像是一個(gè)動(dòng)態(tài)鏈接的可執(zhí)行文件,右側(cè)的海象是一個(gè)靜態(tài)鏈接的可執(zhí)行文件。比起人,海象臃腫得多,那是因?yàn)殪o態(tài)鏈接在鏈接的時(shí)候,就把所依賴的第三方庫函數(shù)都打包到了一起,導(dǎo)致最終的可執(zhí)行文件非常大。而動(dòng)態(tài)鏈接在鏈接的時(shí)候并不將那些庫文件直接拿過來,而是在運(yùn)行時(shí),發(fā)現(xiàn)用到某些庫中的某些函數(shù)時(shí),再從這些第三方庫中讀取自己所需的方法。

我們把編譯后但是還未鏈接的二進(jìn)制機(jī)器碼文件稱為目標(biāo)文件(Object File),那些第三方庫是其他人編譯打包好的目標(biāo)文件,這些庫里面包含了一些函數(shù),我們可以直接調(diào)用而不用自己動(dòng)手寫一遍。在編譯構(gòu)建自己的可執(zhí)行文件時(shí),使用靜態(tài)鏈接的方式,其實(shí)就是將所需的靜態(tài)庫與目標(biāo)文件打包到一起。最終的可執(zhí)行文件除了有自己的程序外,還包含了這些第三方的靜態(tài)庫,可執(zhí)行文件比較臃腫。相比而言,動(dòng)態(tài)鏈接不將所有的第三方庫都打包到最終的可執(zhí)行文件上,而是只記錄用到了哪些動(dòng)態(tài)鏈接庫,在運(yùn)行時(shí)才將那些第三方庫裝載(Load)進(jìn)來。裝載是指將磁盤上的程序和數(shù)據(jù)加載到內(nèi)存上。例如下圖中的Program 1,系統(tǒng)首先加載Program 1,發(fā)現(xiàn)它依賴libx.so后才去加載libx.so。

靜態(tài)鏈接(Static Link)和動(dòng)態(tài)鏈接(Dynamic Link)

所以,靜態(tài)鏈接就像GIF圖中的海象,把所需的東西都帶在了身上。動(dòng)態(tài)鏈接只把精簡后的內(nèi)容帶在自己身上,需要什么,運(yùn)行的時(shí)候再去拿。

不同操作系統(tǒng)的動(dòng)態(tài)鏈接庫文件格式稍有不同,Linux稱之為共享目標(biāo)文件(Shared Object),文件后綴為.so,Windows的動(dòng)態(tài)鏈接庫(Dynamic Link Library)文件后綴為.dll。

地址無關(guān)

無論何種操作系統(tǒng)上,使用動(dòng)態(tài)鏈接生成的目標(biāo)文件中凡是涉及第三方庫的函數(shù)調(diào)用都是地址無關(guān)的。假如我們自己編寫的程序名為Program 1,Program 1中調(diào)用了C標(biāo)準(zhǔn)庫的printf(),在生成的目標(biāo)文件中,不會(huì)立即確定printf()的具體地址,而是在運(yùn)行時(shí)去裝載這個(gè)函數(shù),在裝載階段確定printf()的地址。這里提到的地址指的是進(jìn)程在內(nèi)存上的虛擬地址。動(dòng)態(tài)鏈接庫的函數(shù)地址在編譯時(shí)是不確定的,在裝載時(shí),裝載器根據(jù)當(dāng)前地址空間情況,動(dòng)態(tài)地分配一塊虛擬地址空間。

而靜態(tài)鏈接庫其實(shí)是在編譯時(shí)就確定了庫函數(shù)地址。比如,我們使用了printf()函數(shù),printf()函數(shù)對(duì)應(yīng)有一個(gè)目標(biāo)文件printf.o,靜態(tài)鏈接時(shí),會(huì)把printf.o鏈接打包到可執(zhí)行文件中。在可執(zhí)行文件中,printf()函數(shù)相對(duì)于文件頭的偏移量是確定的,所以說它的地址在編譯鏈接后就是確定的。

動(dòng)態(tài)鏈接的優(yōu)缺點(diǎn)

相比之下,動(dòng)態(tài)鏈接主要有以下好處:

  • 多個(gè)可執(zhí)行文件可以共享使用系統(tǒng)中的共享庫。每個(gè)可執(zhí)行文件都更小,占用的磁盤空間也相對(duì)比較小。而靜態(tài)鏈接把所依賴的庫打包進(jìn)可執(zhí)行文件,假如printf()被其他程序使用了上千次,就要被打包到上千個(gè)可執(zhí)行文件中,這樣會(huì)占用了大量磁盤空間。
  • 共享庫的之間隔離決定了共享庫可以進(jìn)行小版本的代碼升級(jí),重新編譯并部署到操作系統(tǒng)上,并不影響它被可執(zhí)行文件調(diào)用。靜態(tài)鏈接庫的任何函數(shù)有了改動(dòng),除了靜態(tài)鏈接庫本身需要重新編譯構(gòu)建,依賴這個(gè)函數(shù)的所有可執(zhí)行文件都需要重新編譯構(gòu)建一遍。

當(dāng)然,共享庫也有缺點(diǎn):

  • 如果將一份目標(biāo)文件移植到一個(gè)新的操作系統(tǒng)上,而新的操作系統(tǒng)缺少相應(yīng)的共享庫,程序?qū)o法運(yùn)行,必須在操作系統(tǒng)上安裝好相應(yīng)的庫才行。
  • 共享庫必須按照一定的開發(fā)和升級(jí)規(guī)則升級(jí),不能突然重構(gòu)所有的接口,且新庫文件直接覆蓋老庫文件,否則程序?qū)o法運(yùn)行。

ldd命令查看動(dòng)態(tài)鏈接庫依賴

在Linux上,動(dòng)態(tài)鏈接庫有默認(rèn)的部署位置,很多重要的庫放在了系統(tǒng)的/lib和/usr/lib兩個(gè)路徑下。一些常用的Linux命令非常依賴/lib和/usr/lib64下面的各個(gè)庫,比如:scp、rm、cp、mv等Linux下常用的命令非常依賴/lib和/usr/lib64下的各個(gè)庫。不小心刪除了這些路徑,可能導(dǎo)致系統(tǒng)的很多命令和工具都無法繼續(xù)使用。

我們可以用ldd命令查看某個(gè)可執(zhí)行文件依賴了哪些動(dòng)態(tài)鏈接庫。

# on Ubuntu 16.04 x86_64$ ldd /bin/ls linux-vdso.so.1 => (0x00007ffcd3dd9000) libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f4547151000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4546d87000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f4546b17000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f4546913000) /lib64/ld-linux-x86-64.so.2 (0x00007f4547373000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f45466f6000)復(fù)制代碼

可以看到,我們經(jīng)常使用的ls命令依賴了不少庫,包括了C語言標(biāo)準(zhǔn)庫libc.so。

如果某個(gè)Linux的程序報(bào)錯(cuò)提示缺少某個(gè)庫,可以用ldd命令可以用來檢查這個(gè)程序依賴了哪些庫,是否能在磁盤某個(gè)路徑下找到.so文件。如果找不到,需要使用環(huán)境變量LD_LIBRARY_PATH來調(diào)整,下文將介紹環(huán)境變量LD_LIBRARY_PATH。

SONAME文件命名規(guī)則

so文件后面往往跟著很多數(shù)字,這表示了不同的版本。so文件命名規(guī)則被稱為SONAME:

libname.so.x.y.z

lib是前綴,這是一個(gè)約定俗成的規(guī)則。x為主版本號(hào)(Major Version),y為次版本號(hào)(Minor Version),z為發(fā)布版本號(hào)(Release Version)。

  • Major Version表示重大升級(jí),不同Major Version之間的庫是不兼容的。Major Version升級(jí)后,或者依賴舊Major Version的程序需要更新代碼,重新編譯,才可以在新的Major Version上運(yùn)行;或者操作系統(tǒng)保留舊Major Version,使得老程序依然能運(yùn)行。
  • Minor Version表示增量更新,一般是增加了一些新接口,原來的接口不變。所以,在Major Version相同的情況下,Minor Version從高到低是兼容的。
  • Release Version表示庫的一些bug修復(fù),性能改進(jìn)等,不添加任何新的接口,不改變?cè)瓉淼慕涌凇?/li>

但是我們剛剛看到的.so只有一個(gè)Major Version,因?yàn)檫@是一個(gè)軟連接,libname.so.x軟連接到了libname.so.x.y.z文件上。

$ ls -l /lib/x86_64-linux-gnu/libpcre.so.3/lib/x86_64-linux-gnu/libpcre.so.3 -> libpcre.so.3.13.2

因?yàn)椴煌腗ajor Version之間不兼容,而Minor Version和Release Version都是向下兼容的,軟連接會(huì)指向Major Version相同,Minor Version和Release Version最高的.so文件上。

動(dòng)態(tài)鏈接庫查找過程

剛才提到,Linux的動(dòng)態(tài)鏈接庫絕大多數(shù)都在/lib和/usr/lib下,操作系統(tǒng)也會(huì)默認(rèn)去這兩個(gè)路徑下搜索動(dòng)態(tài)鏈接庫。另外,/etc/ld.so.conf文件里可以配置路徑,/etc/ld.so.conf文件會(huì)告訴操作系統(tǒng)去哪些路徑下搜索動(dòng)態(tài)鏈接庫。這些位置的動(dòng)態(tài)鏈接庫很多,如果鏈接器每次都去這些路徑遍歷一遍,非常耗時(shí),Linux提供了ldconfig工具,這個(gè)工具會(huì)對(duì)這些路徑的動(dòng)態(tài)鏈接庫按照SONAME規(guī)則創(chuàng)建軟連接,同時(shí)也會(huì)生成一個(gè)緩存Cache到/etc/ld.so.cache文件里,鏈接器根據(jù)緩存可以更快地查找到各個(gè).so文件。每次在/lib和/usr/lib這些路徑下安裝了新的庫,或者更改了/etc/ld.so.conf文件,都需要調(diào)用ldconfig命令來做一次更新,重新生成軟連接和Cache。但是/etc/ld.so.conf文件和ldconfig命令最好使用root賬戶操作。非root用戶可以在某個(gè)路徑下安裝庫文件,并將這個(gè)路徑添加到/etc/ld.so.conf文件下,再由root用戶調(diào)用一下ldconfig。

對(duì)于非root用戶,另一種方法是使用LD_LIBRARY_PATH環(huán)境變量。LD_LIBRARY_PATH存放著若干路徑。鏈接器會(huì)去這些路徑下查找?guī)臁7莚oot可以將某個(gè)庫安裝在了一個(gè)非root權(quán)限的路徑下,再將其添加到環(huán)境變量中。

動(dòng)態(tài)鏈接庫的查找先后順序?yàn)?#xff1a;

  • LD_LIBRARY_PATH環(huán)境變量中的路徑
  • /etc/ld.so.cache緩存文件
  • /usr/lib和/lib

比如,我們把CUDA安裝到/opt下面,我們可以使用下面的命令將CUDA添加到環(huán)境變量里。

export LD_LIBRARY_PATH=/opt/cuda/cuda-toolkit/lib64:$LD_LIBRARY_PATH

如果在執(zhí)行某個(gè)具體程序前先執(zhí)行上面的命令,那么這個(gè)程序?qū)⑹褂眠@個(gè)路徑下的CUDA;如果將這行添加到了.bashrc文件,那么該用戶一登錄就會(huì)執(zhí)行這行命令,因此該用戶的所有程序也都將使用這個(gè)路徑下的CUDA。當(dāng)同一個(gè)動(dòng)態(tài)鏈接庫有多個(gè)不同版本的.so文件時(shí),可以將它們安裝到不同的路徑下面,然后使用LD_LIBRARY_PATH環(huán)境變量來控制使用哪個(gè)庫。這種比較適合在多人共享的服務(wù)器上使用不同版本的庫,比如CUDA這種版本變化較快,且深度學(xué)習(xí)程序又高度依賴的庫。

除了LD_LIBRARY_PATH環(huán)境變量外,還有一個(gè)LD_PRELOAD環(huán)境變量。LD_PRELOAD的查找順序比LD_LIBRARY_PATH還要優(yōu)先。LD_PRELOAD里是具體的目標(biāo)文件列表(A list of shared objects);LD_LIBRARY_PATH是目錄列表(A list of directories)。

GCC編譯選項(xiàng)

使用GCC編譯鏈接時(shí),有兩個(gè)參數(shù)需要注意,一個(gè)是-l(小寫的L),一個(gè)是-L(大寫的L)。我們前面曾提到,Linux有個(gè)約定速成的規(guī)則,假如庫名是name,那么動(dòng)態(tài)鏈接庫文件名就是libname.so。在使用GCC編譯鏈接時(shí),-lname來告訴GCC使用哪個(gè)庫。鏈接時(shí),GCC的鏈接器ld就會(huì)前往LD_LIBRARY_PATH環(huán)境變量、/etc/ld.so.cache緩存文件和/usr/lib和/lib目錄下去查找libname.so。我們也可以用-L/path/to/library的方式,讓鏈接器ld去/path/to/library路徑下去找?guī)煳募?/p>

如果動(dòng)態(tài)鏈接庫文件在/path/to/library,庫名叫name,編譯鏈接的方式如下:

$ gcc -L/path/to/library -lname myfile.c

總結(jié)

以上是生活随笔為你收集整理的jni加载第三方so_Linux的so文件到底是干嘛的?浅析Linux的动态链接库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产又黄又粗又长 | 久久久久成人精品免费播放动漫 | 日韩无码电影 | 中文字幕一区二区在线播放 | 欧美性猛交xxx乱久交 | 风韵少妇性饥渴推油按摩视频 | 日本久久久久久久久久久 | 蜜桃免费在线视频 | 成人爱爱免费视频 | www久久久久久 | 美女视频一区二区 | 一区二区黄色片 | 国产污在线观看 | 91丨国产| av不卡一区 | wwwxxx欧美| 日本一区二区三区精品视频 | 日韩亚洲影院 | 免费观看日韩av | 欧色图| 日韩美女黄色片 | 国产高清不卡一区 | 好了av在线 | 神马午夜av | 国产美女久久久久久 | 男人的天堂免费视频 | 亚洲成人av一区二区 | 久久久久午夜 | 狠狠躁夜夜躁人人爽视频 | 精品无码一区二区三区的天堂 | 欧美成人久久久免费播放 | 在线爽 | 黄色免费在线播放 | 亚洲精品国产精品乱码不卡 | 一边摸一边做爽的视频17国产 | 欧美日韩免费在线观看 | 尤物视频在线观看免费 | 成人免费看高清电影在线观看 | 欧美在线播放视频 | 久久东京 | 波多野结衣影片 | 涩涩涩涩涩涩涩涩涩 | 久久久久国产精 | 依依成人综合网 | 国产理论影院 | 91天天操 | 日产精品久久久久 | 亚洲在线观看视频 | 国产一区第一页 | 亚洲第一看片 | 中文字幕无码精品亚洲资源网久久 | 黄色一级片在线 | 主播av在线 | 波多野在线播放 | 女人被狂躁c到高潮 | a级片日本 | 中文字幕人乱码中文字 | 欧美黄色大片在线观看 | 播金莲一级淫片aaaaaaa | 女人私密又肥又大 | 欧美日韩一区二区不卡 | 美女啪啪网址 | 一级特级片 | 有色影院 | 色资源在线 | 嫩草视屏| 日日夜夜爱爱 | 91av导航| 东京久久 | 天天干天天摸 | 日韩不卡视频一区二区 | 超在线视频| 亚洲免费精品视频在线观看 | 欧洲黄视频 | 成人黄页网站 | 小视频在线看 | 情欲少妇人妻100篇 黄色一级片欧美 | 亚洲一区二区免费电影 | 成人毛片一区二区三区 | 国产性猛交普通话对白 | 欧美xxxxx自由摘花 | 高清乱码免费 | 亚洲五月网 | 人妻射精一区二区 | 亚洲生活片| 国产xxx | 极品一区 | 自拍偷拍第八页 | 制服丝袜影音先锋 | 亚洲一区二区三区四区 | 国产suv精品一区二区68 | 久久久久无码精品国产 | 久久久久久久久国产 | 天堂网8| 99精品视频一区二区 | www.com黄色| 熟妇高潮一区二区三区在线播放 | www.精品一区| 朝桐光av在线一区二区三区 |