青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

tqsheng

go.....
隨筆 - 366, 文章 - 18, 評論 - 101, 引用 - 0
數據加載中……

Linux下靜態庫_庫的基本概念;如何生成靜態庫動態庫;nm查看庫中包含那些函數、ar生成靜態庫,查看庫中包含那些.o文件、ldd查看程序依賴的.so文件;gcc/g++與庫相關的參數-L,-l,-fPIC,-shared;靜態庫鏈接時搜索過程;動態庫鏈接時,加載時搜索的過程;動態庫找不到的問題;動態庫升級步驟

Linux下靜態庫_庫的基本概念;如何生成靜態庫動態庫;nm查看庫中包含那些函數、ar生成靜態庫,查看庫中包含那些.o文件、ldd查看程序依賴的.so文件;gcc/g++與庫相關的參數-L,-l,-fPIC,-shared;靜態庫鏈接時搜索過程;動態庫鏈接時,加載時搜索的過程;動態庫找不到的問題;動態庫升級步驟

2010-11-23 10:47:45| 分類: Linux系統編程 | 標簽: |字號 訂閱

一、基本概念

1.1、什么是庫

在 windows 平臺和 linux 平臺下都大量存在著庫。

本質上來說庫是 一種可執行代碼的二進制形式,可以被操作系統載入內存執行

由于 windows 和 linux 的平臺不同(主要是編譯器、匯編器和連接器 的不同),因此二者庫的二進制是不兼容的。

本文僅限于介紹 linux 下的庫。

 

1.2、 庫的種類

linux 下的庫有兩種:靜態庫和共享庫(動態庫)。

二者的不同點在于代碼被載入的時刻不同。

靜態庫的代碼在編譯過程中已經被載入可執行程序,因此體積較大。

靜態用.a為后綴, 例如: libhello.a

共享庫(動態庫)的代碼是在可執行程序運行時才載入內存的,在編譯過程中僅簡單的引用,因此代碼體積較小。

動態通常用.so為后綴, 例如:libhello.so

共享庫(動態庫)的好處是,不同的應用程序如果調用相同的庫,那么在內存里只需要有一份該共享庫的實例。

為了在同一系統中使用不同版本的庫,可以在庫文件名后加上版本號為后綴,例如: libhello.so.1.0,由于程序連接默認以.so為文件后綴名。所以為了使用這些庫,通常使用建立符號連接的方式。

ln -s libhello.so.1.0 libhello.so.1 ln -s libhello.so.1 libhello.so

1.3、靜態庫,動態庫文件在linux下是如何生成的:
以下面的代碼為例,生成上面用到的hello庫:
/* hello.c */  
#include "hello.h"  
void sayhello()  
{      
    printf("hello,world ");  
}

首先用gcc編繹該文件,在編繹時可以使用任何合法的編繹參數,例如-g加入調試代碼等:

$gcc -c hello.c -o hello.o

1、生成靜態庫 生成靜態庫使用ar工具,其實ar是archive的意思

$ar cqs libhello.a hello.o

2、生成動態庫 用gcc來完成,由于可能存在多個版本,因此通常指定版本號:

$gcc -shared -o libhello.so.1.0 hello.o
 
1.4、庫文件是如何命名的,有沒有什么規范: 
在 linux 下,庫文件一般放在/usr/lib和/lib下, 
靜態庫的名字一般為libxxxx.a,其中 xxxx 是該lib的名稱;
動態庫的名字一般為libxxxx.so.major.minor,xxxx 是該lib的名稱,major是主版本號,minor是副版本號 
 
1.5、可執行程序在執行的時候如何定位共享庫(動態庫)文件 :
    當系統加載可執行代碼(即庫文件)的時候,能夠知道其所依賴的庫的名字,但是還需要知道絕對路徑,此時就需要系統動態載入器 (dynamic linker/loader) 
    對于 elf 格式的可執行程序,是由 ld-linux.so* 來完成的,它先后搜索 elf 文件的 DT_RPATH 段—環境變量LD_LIBRARY_PATH—/etc/ld.so.cache 文件列表— /lib/,/usr/lib 目錄找到庫文件后將其載入內存
    如: export LD_LIBRARY_PATH=’pwd’ 
將當前文件目錄添加為共享目錄
 
1.6、使用ldd工具,查看可執行程序依賴那些動態庫或著動態庫依賴于那些動態庫
   ldd 命令可以查看一個可執行程序依賴的共享庫, 
    例如 # ldd /bin/lnlibc.so.6 
        => /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2 
        => /lib/ld- linux.so.2 (0×40000000) 
    可以看到 ln 命令依賴于 libc 庫和 ld-linux 庫 
 
1.7、使用nm工具,查看靜態庫和動態庫中有那些函數名(T類表示函數是當前庫中定義的,U類表示函數是被調用的,在其它庫中定義的,W類是當前庫中定義,被其它庫中的函數覆蓋)。
    有時候可能需要查看一個庫中到底有哪些函數,nm工具可以打印出庫中的涉及到的所有符號,這里的庫既可以是靜態的也可以是動態的。

nm列出的符號有很多, 常見的有三種::

一種是在庫中被調用,但并沒有在庫中定義(表明需要其他庫支持),用U表示

一種是在庫中定義的函數,用T表示,這是最常見的

另外一種是所 謂的“弱態”符號,它們雖然在庫中被定義,但是可能被其他庫中的同名符號覆蓋,用W表示

例如,假設開發者希望知道上文提到的hello庫中是否引用了 printf():

    $nm libhello.so | grep printf 

發現printf是U類符號,說明printf被引用,但是并沒有在庫中定義。

由此可以推斷,要正常使用hello庫,必須有其它庫支持,使用ldd工具查看hello依賴于哪些庫:

$ldd hello libc.so.6=>/lib/libc.so.6(0x400la000) /lib/ld-linux.so.2=>/lib/ld-linux.so.2 (0x40000000)

從上面的結果可以繼續查看printf最終在哪里被定義,有興趣可以go on

1.8、使用ar工具,可以生成靜態庫,同時可以查看靜態庫中包含那些.o文件,即有那些源文件構成

可以使用 ar -t libname.a 來查看一個靜態庫由那些.o文件構成。

可以使用 ar q libname.a xxx1.o xxx2.o xxx3.o ... xxxn.o 生成靜態庫

 
Linux下進行程序設計時,關于庫的使用:
 
一、gcc/g++命令中關于庫的參數:
-shared: 該選項指定生成動態連接庫(讓連接器生成T類型的導出符號表,有時候也生成弱連接W類型的導出符號),不用該標志外部程序無法連接。相當于一個可執行文件
-fPIC:表示編譯為位置獨立(地址無關)的代碼,不用此選項的話,編譯后的代碼是位置相關的,所以動態載入時,是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正代碼段共享的目的。
-L:指定鏈接庫的路徑,-L. 表示要連接的庫在當前目錄中
-ltest:指定鏈接庫的名稱為test,編譯器查找動態連接庫時有隱含的命名規則,即在給出的名字前面加上lib,后面加上.so來確定庫的名稱
LD_LIBRARY_PATH:這個環境變量指示動態連接器可以裝載動態庫的路徑
當然如果有root權限的話,可以修改/etc/ld.so.conf文件,然后調用 /sbin/ldconfig來達到同樣的目的,
   不過如果沒有root權限,那么只能采用修改LD_LIBRARY_PATH環境變量的方法了。 
調用動態庫的時候,有幾個問題會經常碰到:
    1、有時,明明已經將庫的頭文件所在目錄 通過 “-I” include進來了,庫所在文件通過 “-L”參數引導,并指定了“-l”的庫名,但通過ldd命令察看時,就是死活找不到你指定鏈接的so文件,這時你要作的就是通過修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件來指定動態庫的目錄。通常這樣做就可以解決庫無法鏈接的問題了。
 
二、靜態庫鏈接時搜索路徑的順序: 
1. ld會去找gcc/g++命令中的參數-L;
2. 再找gcc的環境變量LIBRARY_PATH,它指定程序靜態鏈接庫文件搜索路徑;
      export LIBRARY_PATH=$LIBRARY_PATH:data/home/billchen/lib 
3. 再找默認庫目錄 /lib /usr/lib /usr/local/lib,這是當初compile gcc時寫在程序內的。
   
三、動態鏈接時、執行時搜索路徑順序: 
1. 編譯目標代碼時指定的動態庫搜索路徑;
    2. 環境變量LD_LIBRARY_PATH指定動態庫搜索路徑,它指定程序動態鏈接庫文件搜索路徑;
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:data/home/billchen/lib 
3. 配置文件/etc/ld.so.conf中指定的動態庫搜索路徑;
4. 默認的動態庫搜索路徑/lib;
5. 默認的動態庫搜索路徑/usr/lib。
 
四、靜態庫和動態鏈接庫同時存在的問題:
   當一個庫同時存在靜態庫和動態庫時,比如libmysqlclient.a和libmysqlclient.so同時存在時:
    在Linux下,動態庫和靜態庫同事存在時,gcc/g++的鏈接程序,默認鏈接的動態庫。

可以使用下面的方法,給連接器傳遞參數,看是否鏈接動態庫還是靜態庫。

-WI,-Bstatic -llibname //指定讓gcc/g++鏈接靜態庫

使用:

gcc/g++ test.c -o test -WI,-Bstatic -llibname

-WI,-Bdynamic -llibname //指定讓gcc/g++鏈接動態庫

使用:

gcc/g++ test.c -o test -WI,-Bdynamic -llibname

如果要完全靜態加在,使用-static參數,即將所有的庫以靜態的方式鏈入可執行程序,這樣生成的可執行程序,不再依賴任何庫,同事出現的問題是,這樣編譯出來的程序非常大,占用空間。

 
五、有關環境變量: 
LIBRARY_PATH環境變量:指定程序靜態鏈接庫文件搜索路徑
LD_LIBRARY_PATH環境變量:指定程序動態鏈接庫文件搜索路徑
 
六、動態庫升級問題:
   在動態鏈接庫升級時,
不能使用cp newlib.so oldlib.so,這樣有可能會使程序core掉;
而應該使用:
rm oldlib.so 然后 cp newlib.so oldlib.so
或者
mv oldlib.so oldlib.so_bak 然后 cp newlib.so oldlib.so


為什么不能用cp newlib.so oldlib.so ?

在替換so文件時,如果在不停程序的情況下,直接用 cp new.so old.so 的方式替換程序使用的動態庫文件會導致正在運行中的程序崩潰。

 

解決方法:

解決的辦法是采用“rm+cp” 或“mv+cp” 來替代直接“cp” 的操作方法。

linux系統的動態庫有兩種使用方法:運行時動態鏈接庫,動態加載庫并在程序控制之下使用。

 

1、為什么在不停程序的情況下,直接用 cp 命令替換程序使用的 so 文件,會使程序崩潰?
很多同學在工作中遇到過這樣一個問題,在替換 so 文件時,如果在不停程序的情況下,直接用cp new.so old.so的方式替換程序使用的動態庫文件會導致正在運行中的程序崩潰,退出。

這與 cp 命令的實現有關,cp 并不改變目標文件的 inode,cp 的目標文件會繼承被覆蓋文件的屬性而非源文件。實際上它是這樣實現的:
strace cp libnew.so libold.so 2>&1 |grep open.*lib.*.so
open("libnew.so", O_RDONLY|O_LARGEFILE) = 3
open("libold.so", O_WRONLY|O_TRUNC|O_LARGEFILE) = 4
在 cp 使用“O_WRONLY|O_TRUNC” 打開目標文件時,原 so 文件的鏡像被意外的破壞了這樣動態鏈接器 ld.so 不能訪問到 so 文件中的函數入口。從而導致 Segmentation fault,程序崩潰。ld.so 加載 so 文件及“再定位”的機制比較復雜。

 

2、怎樣在不停止程序的情況下替換so文件,并且保證程序不會崩潰?
答案是采用“rm+cp” 或“mv+cp” 來替代直接“cp” 的操作方法。

在用新的so文件 libnew.so 替換舊的so文件 libold.so 時,如果采用如下方法:
rm libold.so //如果內核正在使用libold.so,那么inode節點不會立刻別刪除掉。
cp libnew.so libold.so
采用這種方法,目標文件 libold.so 的 inode 其實已經改變了,原來的 libold.so 文件雖然不能用 ”ls”查看到,但其 inode 并沒有被真正刪除,直到內核釋放對它的引用。

(即: rm libold.so,此時,如果ld.so正在加在libold.so,內核就在引用libold.so的inode節點,rm libold.so的inode并沒有被真正刪除,當ld.so對libold.so的引用結束,inode才會真正刪除。這樣程序就不會崩潰,因為它還在使用舊的libold.so,當下次再使用libold.so時,已經被替換,就會使用新的libold.so)

同理,mv只是改變了文件名,其 inode 不變,新文件使用了新的 inode。這樣動態鏈接器 ld.so 仍然使用原來文件的 inode 訪問舊的 so 文件。因而程序依然能正常運行。

(即: mv libold.so ***后,如果程序使用動態庫,還是使用舊的inode節點,當下次再使用libold.so時,就會使用新的libold.so)


到這里,為什么直接使用“cp new_exec_file old_exec_file”這樣的命令時,系統會禁止這樣的操作,并且給出這樣的提示“cp: cannot create regular file `old': Text file busy”。這時,我們采用的辦法仍然是用“rm+cp”或者“mv+cp”來替代直接“cp”,這跟以上提到的so文件的替換有同樣的道理


但是,為什么系統會阻止 cp 覆蓋可執行程序,而不阻止覆蓋 so 文件呢

這是因為 Linux 有個 Demand Paging 機制,所謂“Demand Paging”,簡單的說,就是系統為了節約物理內存開銷,并不會程序運行時就將所有頁(page)都加載到內存中,而只有在系統有訪問需求時才將其加載。“Demand Paging”要求正在運行中的程序鏡像注意,并非文件本身不被意外修改因此內核在啟動程序后會鎖定這個程序鏡像的 inode

對于 so 文件,它是靠 ld.so 加載的,而ld.so畢竟也是用戶態程序,沒有權利去鎖定inode,也不應與內核的文件系統底層實現耦合

posted on 2013-01-04 16:38 tqsheng 閱讀(8242) 評論(0)  編輯 收藏 引用

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            午夜精品久久久久久久久久久久 | 亚洲国内欧美| 欧美午夜影院| 国产精品国产三级国产aⅴ无密码| 欧美激情一级片一区二区| 欧美国产精品人人做人人爱| 欧美激情视频在线免费观看 欧美视频免费一 | 亚洲欧美精品| 久久精品国产99精品国产亚洲性色 | 最新国产成人在线观看| 免费中文字幕日韩欧美| 亚洲激情在线观看| 亚洲香蕉在线观看| 久久久久一区二区三区| 免费久久久一本精品久久区| 欧美精品色网| 国产欧美一区二区三区久久| 亚洲成色777777女色窝| 99精品福利视频| 久久精品国产久精国产爱| 欧美国产精品v| 亚洲桃色在线一区| 久久中文字幕一区| 欧美韩日一区| 女仆av观看一区| 欧美激情亚洲一区| 国产日韩欧美中文在线播放| 永久91嫩草亚洲精品人人| 一区电影在线观看| 久久综合伊人77777麻豆| 日韩图片一区| 麻豆九一精品爱看视频在线观看免费 | 国产精品a久久久久久| 国内精品美女在线观看| 亚洲视屏在线播放| 欧美多人爱爱视频网站| 欧美亚洲在线观看| 国产精品久久久久久久一区探花| 亚洲国产精品视频一区| 久久久亚洲欧洲日产国码αv | 亚洲一区二区免费| 欧美国产日韩在线观看| 国外成人网址| 香蕉成人啪国产精品视频综合网| 亚洲国产成人午夜在线一区| 欧美在线精品免播放器视频| 国产精品久久久久久久一区探花| 亚洲韩国日本中文字幕| 免费看成人av| 亚洲淫片在线视频| 国产精品一区免费视频| 亚洲香蕉视频| 日韩午夜电影av| 欧美精品久久久久久久免费观看| 亚洲福利一区| 欧美福利影院| 欧美大片免费| 亚洲另类在线视频| 亚洲国产精品一区在线观看不卡| 久久精品国产精品 | 一区二区三区免费网站| 欧美日韩精品免费观看视频| 亚洲免费观看高清在线观看 | 亚洲免费网址| 国语自产精品视频在线看8查询8| 久久精品国产亚洲一区二区三区| 午夜亚洲激情| 一区在线播放| 亚洲国产成人91精品| 欧美黄污视频| 亚洲欧美国产精品专区久久| 亚洲欧美日韩国产精品| 国产亚洲成av人片在线观看桃 | 国产精品亚洲综合天堂夜夜| 国产精品色婷婷久久58| 校园春色综合网| 欧美一区二区三区免费观看| 国内一区二区三区在线视频| 免费成人在线观看视频| 免费在线观看精品| 亚洲一区二区高清| 欧美亚洲系列| 亚洲电影免费观看高清完整版在线| 欧美国产免费| 国产精品乱码久久久久久| 久久久蜜臀国产一区二区| 欧美福利电影在线观看| 亚洲一区二区在线视频 | 欧美mv日韩mv国产网站app| 99视频有精品| 亚洲女同在线| 亚洲久色影视| 亚洲午夜一级| 亚洲欧美日韩国产中文| 亚洲第一主播视频| 一区二区高清| 伊人久久大香线蕉综合热线| 最新亚洲电影| 怡红院精品视频| 一本色道久久综合精品竹菊| 一区二区视频欧美| 一本到12不卡视频在线dvd| 国产老女人精品毛片久久| 欧美电影打屁股sp| 国产美女精品免费电影| 亚洲国产高清aⅴ视频| 国产欧美三级| 亚洲欧洲精品一区| 欧美成人a视频| 久久久久久69| 欧美日韩免费一区二区三区视频| 久久精品视频在线看| 欧美视频一区二区三区四区| 欧美大片免费| 一区二区亚洲精品国产| 亚洲欧美在线aaa| 国产日韩精品电影| 99热免费精品在线观看| 亚洲激情在线观看| 久久久亚洲国产天美传媒修理工| 午夜精品美女久久久久av福利| 欧美激情女人20p| 亚洲国产毛片完整版 | 99在线精品视频| 久久在线免费观看视频| 久久国产免费| 国产伦精品一区二区三区免费| 亚洲黄网站黄| 99在线精品免费视频九九视| 免费欧美日韩| 亚洲国产欧美一区二区三区同亚洲 | 亚洲国产va精品久久久不卡综合| 亚洲一区二区视频在线观看| 亚洲视频大全| 欧美日韩高清在线观看| 欧美电影打屁股sp| 影音先锋久久久| 久久精品国产2020观看福利| 久久精品视频在线看| 国产乱人伦精品一区二区| 亚洲免费视频中文字幕| 欧美有码在线观看视频| 国产日韩欧美视频| 久久黄色影院| 男女视频一区二区| 91久久国产综合久久| 欧美成人免费网| 亚洲精品社区| 性欧美18~19sex高清播放| 欧美少妇一区| 亚洲女人天堂成人av在线| 久久久无码精品亚洲日韩按摩| 国产视频精品xxxx| 久久久免费精品| 亚洲国产第一| 亚洲视频免费在线观看| 国产日韩一区二区三区| 老司机午夜免费精品视频| 亚洲日本乱码在线观看| 午夜精品一区二区三区电影天堂| 国产毛片一区二区| 久久久久这里只有精品| 亚洲欧洲一区二区天堂久久 | 亚洲高清不卡在线观看| 免费在线观看成人av| 一区二区三区高清在线| 久久爱91午夜羞羞| 在线视频国内自拍亚洲视频| 欧美日本一区| 欧美亚洲三级| 亚洲美女在线一区| 久久综合狠狠综合久久综合88| 亚洲乱码日产精品bd| 国产欧美大片| 欧美精品久久天天躁| 亚洲欧美久久久久一区二区三区| 免费久久99精品国产自| 亚洲欧美国产毛片在线| 亚洲国产一区二区三区在线播| 欧美丝袜第一区| 美女爽到呻吟久久久久| 亚洲视频在线二区| 亚洲国产视频一区| 久久免费高清| 亚洲综合不卡| 亚洲精品五月天| 国产综合婷婷| 国产精品久久久久久久浪潮网站 | 国产精品久久久久久久久久久久 | 亚洲电影免费观看高清完整版在线观看| 欧美精品 日韩| 久久av一区二区三区亚洲| 国产精品爽黄69| 在线一区二区三区做爰视频网站| 久久久亚洲午夜电影| 亚洲午夜在线观看视频在线| 在线视频国内自拍亚洲视频| 国产日韩一区在线| 欧美视频在线一区| 欧美精品系列|