




版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、編譯與鏈接的知識(shí)編譯與鏈接的知識(shí)2010-07-05 23:52linux下編譯hello.c程序,使用gcc hello.c,然后./a.out就可以運(yùn)行;在這個(gè)簡(jiǎn)單的命令后面隱藏了許多復(fù)雜的過(guò)程,這個(gè)過(guò)程包括了下面的步驟宏定義展開(kāi),所有的#define在這個(gè)階段都會(huì)被展開(kāi)預(yù)編譯命令的處理,包括#if#ifdef一類(lèi)的命令展開(kāi)#include的文件,像上面hello world中的stdio.h,把stdio.h中的所有代碼合并到hello.c中去掉注釋gcc的預(yù)編譯采用的是預(yù)編譯器cpp,我們可以通過(guò)-E參數(shù)來(lái)看預(yù)編譯的結(jié)果,如:gcc-E hello.c-o hello.i生成的hell
2、o.i就是經(jīng)過(guò)了預(yù)編譯的結(jié)果在預(yù)編譯的過(guò)程中不會(huì)太多的檢查與預(yù)編譯無(wú)關(guān)的語(yǔ)法(#ifdef之類(lèi)的還是需要檢查,#include文件路徑需要檢查),但是對(duì)于一些諸如;漏掉的語(yǔ)法錯(cuò)誤,在這個(gè)階段都是看不出來(lái)的。寫(xiě)過(guò)makefile的人都知道,我們需要加上-Ipath一系列的參數(shù)來(lái)標(biāo)示gcc對(duì)頭文件的查找路徑小提示:1.在一些程序中由于宏的原因?qū)е戮幾g錯(cuò)誤,可以通過(guò)-E把宏展開(kāi)再檢查錯(cuò)誤,這個(gè)在編寫(xiě)PHP擴(kuò)展,python擴(kuò)展這些大量需要使用宏的地方對(duì)于查錯(cuò)誤很有幫助。2.如果在頭文件中,#include的時(shí)候帶上路徑在這個(gè)階段有時(shí)候是可以省不少事情,比如#include public/connec
3、tpool/connectpool.h,這樣在gcc的-I參數(shù)只需要指定一個(gè)路徑,不會(huì)由于不小心導(dǎo)致,文件名正好相同出現(xiàn)沖突的麻煩事情.帶路徑的方式要多寫(xiě)一些代碼,也是麻煩的事情,路徑由外部指定相對(duì)也會(huì)靈活一些.編譯這個(gè)過(guò)程才是進(jìn)行語(yǔ)法分析和詞法分析的地方,他們將我們的C/C+代碼翻譯成為匯編代碼,這也是一個(gè)編譯器最復(fù)雜的地方使用命令gcc-S hello.i-o hello.s可以看到gcc編譯出來(lái)的匯編代碼,現(xiàn)代gcc編譯器一般是把預(yù)編譯和編譯合在一起,使用cc1的程序來(lái)完成這個(gè)過(guò)程,編譯大文件的時(shí)候可以用top命令看一個(gè)cc1的進(jìn)程一直在占用時(shí)間,這個(gè)時(shí)候就是程序在執(zhí)行編譯過(guò)程.后面提到
4、的編譯過(guò)程都是指cc1的處理包括了預(yù)編譯與編譯.匯編現(xiàn)在C/C+代碼已經(jīng)成為匯編代碼了,直接使用匯編代碼的編譯器把匯編變成機(jī)器碼(注意還不是可執(zhí)行的).gcc-c hello.c-o hello.o這里的hello.o就是最后的機(jī)器碼,如果作為一個(gè)靜態(tài)庫(kù)到這里可以所已經(jīng)完成了,不需要后面的過(guò)程.對(duì)于靜態(tài)庫(kù),比如ullib,COM提供的是libullib.a,這里的.a文件其實(shí)是多個(gè).o通過(guò)ar命令打包起來(lái)的,僅僅是為了方便使用,拋開(kāi).a直接使用.o也是一樣的小提示:1.gcc采用as進(jìn)行匯編的處理過(guò)程,as由于接收的是gcc生成的標(biāo)準(zhǔn)匯編,在語(yǔ)法檢查上存在不少缺陷,如果是我們自己寫(xiě)的匯編代碼給
5、as去處理,經(jīng)常會(huì)出現(xiàn)很多莫名奇妙的錯(cuò)誤.鏈接的過(guò)程,本質(zhì)上來(lái)說(shuō)是一個(gè)把所有的機(jī)器碼文件組合成一個(gè)可執(zhí)行的文件上面匯編的結(jié)果得到一個(gè).o文件,但是這個(gè).o要生成二執(zhí)行文件只靠它自己是不行的,它還需要一堆輔助的機(jī)器碼,幫它處理與系統(tǒng)底層打交道的事情.gcc-o hello hello.o這樣就把一個(gè).o文件鏈接成為了一個(gè)二進(jìn)制可執(zhí)行文件.這個(gè)地方也是本文討論的重點(diǎn),在后面會(huì)有更詳細(xì)的說(shuō)明小提示:有些程序在編譯的時(shí)候會(huì)出現(xiàn)linker input because linking not done的提示(雖然gcc不認(rèn)為是錯(cuò)誤,這個(gè)提示還是會(huì)出現(xiàn)的),這里就是把編譯和鏈接使用的參數(shù)搞混了,比如g+-
6、c test.cpp-I././ullib/include-L././ullib/lib/-lullib這樣的寫(xiě)法就會(huì)導(dǎo)致上面的提示,因?yàn)樵诰幾g的過(guò)程中是不需要鏈接的,它們兩個(gè)過(guò)程其實(shí)是獨(dú)立的靜態(tài)鏈接鏈接的過(guò)程這里先介紹一下,鏈接器所做的工作其實(shí)鏈接做的工作分兩塊:符號(hào)解析和重定位符號(hào)解析符號(hào)包括了我們的程序中的被定義和引用的函數(shù)和變量信息在命令行上使用nm./test test是用戶(hù)的二進(jìn)制程序,包括可以把在二進(jìn)制目標(biāo)文件中符號(hào)表輸出009 b8 A_bss_start 004 cc tcall_gmon_start 009 b8 bcompleted.1 00788 d_CTOR_END_
7、 00780 d_CTOR_LIST_ 009 a0 D_data_start 009 a0 Wdata_start 00630 t_do_global_ctors_aux 004 f0 t_do_global_dtors_aux 009 a8 D_dso_handle 00798 d_DTOR_END_ 00790 d_DTOR_LIST_ 007 a8 D_DYNAMIC 009 b8 A_edata 009 c0 A_end 00668 T_fini 00780 A_fini_array_end 00780 A_fini_array_start 00530 tframe_dummy 00
8、778 r_FRAME_END_ 00970 D_GLOBAL_OFFSET_TABLE_ w_gmon_start_ 00448 T_init 00780 A_init_array_end當(dāng)然上面由nm輸出的符號(hào)表可以通過(guò)編譯命令去除,讓人不能直接看到。鏈接器解析符號(hào)引用的方式是將每一個(gè)引用的符號(hào)與其它的目標(biāo)文件(.o)的符號(hào)表中一個(gè)符號(hào)的定義聯(lián)系起來(lái),對(duì)于那些和引用定義在相同模塊的本地符號(hào)(注:static修飾的),編譯器在編譯期就可以發(fā)現(xiàn)問(wèn)題,但是對(duì)于那些全局的符號(hào)引用就比較麻煩了.下面來(lái)看一個(gè)最簡(jiǎn)單程序:#include stdio.h int foo();int main()foo(
9、);return 0;我們把文件命名為test.cpp,采用下面的方式進(jìn)行編譯g+-c test.cpp g+-o test test.o第一步正常結(jié)束,并且生成了test.o文件,到第二步的時(shí)候報(bào)了如下的錯(cuò)誤test.o(.text+0x5):In functionmain:undefined reference tofoo()collect2:ld returned 1exit status由于foo是全局符號(hào),在編譯的時(shí)候不會(huì)報(bào)錯(cuò),等到鏈接的時(shí)候,發(fā)現(xiàn)沒(méi)有找到對(duì)應(yīng)的符號(hào),就會(huì)報(bào)出上面的錯(cuò)誤。但是如果我們把上面的寫(xiě)法改成下面這樣#include stdio.h/注意這里的static st
10、atic int foo();int main()foo();return 0;在運(yùn)行g(shù)+-c test.cpp,馬上就報(bào)出下面的錯(cuò)誤:test.cpp:19:error:int foo()used but never defined在編譯器就發(fā)現(xiàn)foo無(wú)法生成目標(biāo)文件的符號(hào)表,可以馬上報(bào)錯(cuò),對(duì)于一些本地使用的函數(shù)使用static一方面可以避免符號(hào)污染,另一方面也可以讓編譯器盡快的發(fā)現(xiàn)錯(cuò)誤.在基礎(chǔ)庫(kù)中提供的都是一系列的.a文件,這些.a文件其實(shí)是一批的目標(biāo)文件(.o)的打包結(jié)果.這樣的目的是可以方便的使用已有代碼生成的結(jié)果,一般情況下是一個(gè).c/.cpp文件生成一個(gè).o文件,在編譯的時(shí)候如果帶
11、上一堆的.o文件顯的很不方便,像:g+-o main main.cpp a.o b.o c.o這樣大量的使用.o也很容易出錯(cuò),在linux下使用archive來(lái)講這些.o存檔和打包.所以我們就可以把編譯參數(shù)寫(xiě)成g+-o main main.cpp./libullib.a我們可以使用./libullib.a直接使用libullib.a這個(gè)庫(kù),不過(guò)gcc提供了另外的方式來(lái)使用:g+-o main main.cpp-L./-lullib-L指定需要查找的庫(kù)文件的路徑,-l選擇需要使用的庫(kù)名字,不過(guò)庫(kù)的名字需要用lib+name的方式命名,才會(huì)被gcc認(rèn)出來(lái).不過(guò)上面的這種方式存在一個(gè)問(wèn)題就是不區(qū)分動(dòng)
12、態(tài)庫(kù)和靜態(tài)庫(kù),這個(gè)問(wèn)題在后面介紹動(dòng)態(tài)庫(kù)的時(shí)候還會(huì)提到.當(dāng)存在多個(gè).a,并且在庫(kù)之間也存在依賴(lài)關(guān)系,這個(gè)時(shí)候情況就比較復(fù)雜.如果要使用lib2-64/dict,dict又依賴(lài)ullib,這個(gè)時(shí)候需要寫(xiě)成類(lèi)似下面的形式g+-o main main.cpp-L./lib2-64/dict/lib-L./lib2-64/ullib/lib-ldict-lullib-lullib需要寫(xiě)在-ldict的后面,這是由于在默認(rèn)情況對(duì)于符號(hào)表的解析和查找工作是由后往前(內(nèi)部實(shí)現(xiàn)是一個(gè)類(lèi)似堆棧的尾遞歸).所以當(dāng)所使用的庫(kù)本身存在依賴(lài)關(guān)系的時(shí)候,越是基礎(chǔ)的庫(kù)就越是需要放到后面.否則如果上面把-ldict-lulib
13、的位置換一下,可能就會(huì)出現(xiàn)undefined reference to xxx的錯(cuò)誤.當(dāng)然gcc提供了另外的方式的來(lái)解決這個(gè)問(wèn)題g+-o main main.cpp-L./lib2-64/dict/lib-L./l ib2-64/ullib/lib-Xlinker-(-ldict-lullib-Xlinker-)可以看到我們需要的庫(kù)被-Xlinker-(和-Xlinker-)包含起來(lái),gcc在這里處理的時(shí)候會(huì)循環(huán)自動(dòng)查找依賴(lài)關(guān)系,不過(guò)這樣的代價(jià)就是延長(zhǎng)gcc的編譯時(shí)間,如果使用的庫(kù)非常的多時(shí)候,對(duì)編譯的耗時(shí)影響還是非常大.-Xlinker有時(shí)候也簡(jiǎn)寫(xiě)成-Wl,,它的意思是它后面的參數(shù)是給鏈接器
14、使用的.-Xlinker和-Wl的區(qū)別是一個(gè)后面跟的參數(shù)是用空格,另一個(gè)是用,我們通過(guò)nm命令查看目標(biāo)文件,可以看到類(lèi)似下面的結(jié)果109740 T_Z11ds_syn_loadPcS_ 209 c62 T_Z11ds_syn_seekP16Sdict_search_synPcS1_i 307928 T_Z11dsur_searchPcS_S_ 4&nbs p;U _Z11ul_read 5&nbs p;U _Z11ul_writelogiPKcz 6000 a2 T_Z12creat_sign32Pc其中用U標(biāo)示的符號(hào)_Z11ul_read(其實(shí)是ullib中的ul_readfile),表示在
15、dict的目標(biāo)文件中沒(méi)有找到ul_readfile函數(shù).在鏈接的時(shí)候,鏈接器就會(huì)去其他的目標(biāo)文件中查找_Z11ul_read的符號(hào)小提示:編譯的時(shí)候采用-Lxxx-lyyy的形式使用庫(kù),-L和-l這個(gè)參數(shù)并沒(méi)有配對(duì)的關(guān)系,我們的一些Makefile為了維護(hù)方便把他們寫(xiě)成配對(duì)的形式,造成了誤解.其實(shí)完全可以寫(xiě)成-Lpath1,-Lpath2,-Lpath3,-llib1這樣的形式.在具體鏈接的時(shí)候,gcc是以.o文件為單位,編譯的時(shí)候如果寫(xiě)g+-o main main.cpp libx.o那么無(wú)論main.cpp中是否使用到libx.o,libx.o中的所有符號(hào)都會(huì)被載入到mian函數(shù)中.但是如
16、果是針對(duì).a,寫(xiě)成g+-o main main.cpp-L./-lx,這個(gè)時(shí)候gcc在鏈接的時(shí)候只會(huì)鏈接有被用到.o,如果出現(xiàn)libx.a中的某個(gè).o文件中沒(méi)有任何一個(gè)符號(hào)被main用到,那么這個(gè).o就不會(huì)被鏈接到main中重定位經(jīng)過(guò)上面的符號(hào)解析后,所有的符號(hào)都可以找到它所對(duì)應(yīng)的實(shí)際位置(U表示的鏈接找到具體的符號(hào)位置).as匯編生成一個(gè)目標(biāo)模塊的時(shí)候,它不知道數(shù)據(jù)和代碼在最后具體的位置,同時(shí)也不知道任何外部定義的符號(hào)的具體位置,所以as在生成目標(biāo)代碼的時(shí)候,對(duì)于位置未知的符號(hào),它會(huì)生成一個(gè)重定位表目,告訴鏈接器在將目標(biāo)文件合并成可執(zhí)行文件時(shí)候如何修改地址成最終的位置g+和gcc采用gcc和
17、g+在編譯的時(shí)候產(chǎn)生的符號(hào)有所不同.在C+中由于要支持函數(shù)重載,命名空間等特性,g+會(huì)把函數(shù)+參數(shù)(可能還有命名空間),把函數(shù)命變成一個(gè)特殊并且唯一的符號(hào)名.例如:int foo(int a);在gcc編譯后,在符號(hào)表中的名字就是函數(shù)名foo,但是在g+編譯后名字可能就變成了_Z3fooi,我們可以使用c+filt命令把一個(gè)符號(hào)還原成它原本的樣子,比如c+filt _Z3fooi運(yùn)行的結(jié)果可以得到foo(int)由于在C+和純C環(huán)境中,符號(hào)表存在不兼容問(wèn)題,C程序不能直接調(diào)用C+編譯出來(lái)的庫(kù),C+程序也不能直接調(diào)用C編譯出來(lái)的庫(kù).為了解決這個(gè)問(wèn)題C+中引入了externC的方式.externC
18、int foo(int a);這樣在用g+編譯的時(shí)候,c+的編譯器會(huì)自動(dòng)把上面的int foo(int a)當(dāng)做C的接口進(jìn)行符號(hào)轉(zhuǎn)化.這樣在純C里面就可以認(rèn)出這些符號(hào).不過(guò)這里存在一個(gè)問(wèn)題,externC是C+支持的,gcc并不認(rèn)識(shí),所有在實(shí)際中一般采用下面的方式使用+#ifdef _cplusplus externC#endif int foo(int a);#ifdef _cplusplus#endif這樣這個(gè)頭文件中的接口即可以給gcc使用也可以給g+使用,當(dāng)然在externC中的接口是不支持重載,默認(rèn)參數(shù)等特性在我們的64位編譯環(huán)境中如果有g(shù)cc的程序使用上面方式g+編譯出來(lái)的庫(kù),需要
19、加上-lstdc+,這是因?yàn)?,?duì)于我們64位環(huán)境下g+編譯出來(lái)的庫(kù),需要使用到一個(gè)_gxx_personality_v0的符號(hào),它所在的位置是/usr/lib64/libstdc+.so.6(C+的標(biāo)準(zhǔn)庫(kù)iostream都在里面,C+程序都需要的).但是在32位2.96 g+編譯器中是不需要_gxx_personality_v0,所有編譯可以不加上-lstdc+小提示:在linux gcc中,只有在源代碼使用.c做后綴,并且使用gcc編譯才會(huì)被編譯成純C的結(jié)果,其他情況像g+編譯.c文件,或者gcc編譯.cc,.cpp文件都會(huì)被當(dāng)作C+程序編譯成C+的目標(biāo)文件,gcc和g+唯一的不同在于gcc
20、不會(huì)主動(dòng)鏈接-lstdc+在externC中如果存在默認(rèn)參數(shù)的接口,在g+編譯的時(shí)候不會(huì)出現(xiàn)問(wèn)題,但是gcc使用的時(shí)候會(huì)報(bào)錯(cuò).因?yàn)閷?duì)于函數(shù)重載,接口的符號(hào)表還是和不用默認(rèn)參數(shù)的時(shí)候是一樣的.符號(hào)表沖突編譯程序的時(shí)候時(shí)常會(huì)遇到類(lèi)似于multiple definition offoo()的錯(cuò)誤.這些錯(cuò)誤的產(chǎn)生都是由于所使用的.o文件中存在了相同的符號(hào)造成的.比如:libx.cpp int foo()return 30;liby.cpp int foo()return 20;將libx.cpp,liby.cpp編譯成libx.o和liby.o兩個(gè)文件g+-o main main.cpp libx.o
21、 liby.o這個(gè)時(shí)候就會(huì)報(bào)出multiple definition offoo()的錯(cuò)誤(一些參數(shù)可以把這個(gè)警報(bào)關(guān)掉)但是如果把libx.o和liby.o分別打包成libx.a和liby.a用下面的方式編譯g+-o main main.cpp-L./-lx-ly這個(gè)時(shí)候編譯不會(huì)報(bào)錯(cuò),它會(huì)選擇第一個(gè)出現(xiàn)的庫(kù),上面的例子中會(huì)選擇libx中的foo可以通過(guò)g+-o main main.cpp-L./-lx-ly-Wl,-trace-symbol=_Z3foov的命令查看符號(hào)具體是鏈接到哪個(gè)庫(kù)中,g+-o main main.cpp-L./-lx-ly-Wl,-cref可以把所有的符號(hào)鏈接都輸出(無(wú)
22、論是否最后被使用)小提示:對(duì)于一些定義在頭文件中的全局常量,gcc和g+有不同的行為,g+中const也同時(shí)是static的,但gcc不是例如:foo.h中存在一個(gè)const int INTVALUE=2000;的全局常量有兩個(gè)庫(kù)a和b,他們?cè)谏傻臅r(shí)候有使用到了INTVALUE,如果有一個(gè)程序main同時(shí)使用到了a庫(kù)和b庫(kù),在鏈接的時(shí)候gcc編譯的結(jié)果就會(huì)報(bào)錯(cuò),但如果a和b都是g+編譯的話結(jié)果卻一切正常.這個(gè)原因主要是在g+中會(huì)把INTVALUE這種const常量當(dāng)做static的,這樣就是一個(gè)局部變量,不會(huì)導(dǎo)致沖突,但是如果是gcc編譯的話,這個(gè)地方INTVALUE會(huì)被認(rèn)為是一個(gè)對(duì)外的全局
23、常量是非static的,這個(gè)時(shí)候就會(huì)造成鏈接錯(cuò)誤動(dòng)態(tài)鏈接對(duì)于靜態(tài)庫(kù)的使用,有下面兩個(gè)問(wèn)題當(dāng)我們需要對(duì)某一個(gè)庫(kù)進(jìn)行更新的時(shí)候,我們必須把一個(gè)可執(zhí)行文件再完整的進(jìn)行一些重新編譯在程序運(yùn)行的時(shí)候代碼是會(huì)被載入機(jī)器的內(nèi)存中,如果采用靜態(tài)庫(kù)就會(huì)出現(xiàn)一個(gè)庫(kù)需要被copy到多個(gè)內(nèi)存程序中,這個(gè)一方面占用了一定的內(nèi)存,另一方面對(duì)于CPU的cache不夠友好鏈接的控制,從前面的介紹中可以看到靜態(tài)庫(kù)的連接行為我們不好控制,做不到在運(yùn)行期替換使用的庫(kù)編譯后的程序就是二進(jìn)制代碼,有些代碼它們涉及到不同的機(jī)器和環(huán)境,假設(shè)在A機(jī)器上編譯了一個(gè)程序X,把它直接放到B機(jī)器上去運(yùn)行,由于A和B環(huán)境存在差異,直接運(yùn)行X程序可能存
24、在問(wèn)題,這個(gè)時(shí)候如果把和機(jī)器相關(guān)的這部分做成動(dòng)態(tài)庫(kù)C,并且保證接口一致,編譯X程序的時(shí)候只調(diào)用C的對(duì)外接口.對(duì)于一般的用戶(hù)態(tài)的X程序而言,就可以簡(jiǎn)單的從A環(huán)境放到B環(huán)境中.但如果是靜態(tài)編譯,就可能做不到這點(diǎn),需要在B機(jī)器上重新編譯一次.動(dòng)態(tài)鏈接庫(kù)在linux被稱(chēng)為共享庫(kù)(shared library,下文提到的共享庫(kù)和動(dòng)態(tài)鏈接庫(kù)都是指代shared library),它主要是為了解決上面列出靜態(tài)庫(kù)的缺點(diǎn)而提出的.。共享庫(kù)的使用共享庫(kù)的使用主要有兩種方式,一種方式和.a的靜態(tài)庫(kù)類(lèi)似由編譯器來(lái)控制,其實(shí)質(zhì)和二進(jìn)制程序一樣都是由系統(tǒng)中的載入器(ld-linux.so)載入,另一種是寫(xiě)在代碼中,由我們
25、自己的代碼來(lái)控制.還是以前面的例子為例:g+-shared-fPIC-o libx.so libx.cpp編譯的時(shí)候和靜態(tài)庫(kù)類(lèi)似,只是加上了-shared和-fPIC,將輸出命名改為.so然后和可執(zhí)行文件鏈接.a一樣,都是g+-o main main.cpp-L./-lx這樣main就是調(diào)用libx.so,在運(yùn)行的時(shí)候可能會(huì)出現(xiàn)找不到libx.so的錯(cuò)誤,這個(gè)原因是由于動(dòng)態(tài)的庫(kù)查找路徑的問(wèn)題,動(dòng)態(tài)庫(kù)默認(rèn)的查找路徑是由/etc/ld.so.conf文件來(lái)指定,在運(yùn)行可執(zhí)行文件的時(shí)候,按照順會(huì)去這些目錄下查找需要的共享庫(kù)。我們可以通過(guò)環(huán)境變量LD_LIBRARY_PATH來(lái)指定共享庫(kù)的查找路徑(注
26、:LD_LIBRARY_PATH的優(yōu)先級(jí)比ld.so.conf要高).命令上運(yùn)行l(wèi)dd./main我們可以看到這個(gè)二進(jìn)制程序在運(yùn)行的時(shí)候需要使用的動(dòng)態(tài)庫(kù),例如:libx.so=/home/bnh/tmp/test/libx.so(0x003cb000)libstdc+.so.6=/usr/lib/libstdc+.so.6(0x 00702000)libm.so.6=/lib/tls/libm.so.6(0x00bde000)libgcc_s.so.1=/lib/libgcc_s.so.1(0x00c3e000)libc.so.6=/lib/tls/libc.so.6(0x00aab000)這
27、里列出了mian所需要的動(dòng)態(tài)庫(kù),如果有看類(lèi)似libx.so=no found的錯(cuò)誤,就意味著路徑不對(duì),需要設(shè)置LD_LIBRARY_PATH來(lái)指定路徑手動(dòng)載入共享庫(kù)除了采用類(lèi)型于靜態(tài)庫(kù)的方式來(lái)使用動(dòng)態(tài)庫(kù),我們還可以通過(guò)由代碼來(lái)控制動(dòng)態(tài)庫(kù)的使用。這種方式允許應(yīng)用程序在運(yùn)行時(shí)加載和鏈接共享庫(kù),主要有下面的四個(gè)接口載入動(dòng)態(tài)鏈接庫(kù)void*dlopen(const char* flag);獲取動(dòng)態(tài)庫(kù)中的符號(hào)void*dlsym(void*handle,char*symbol);關(guān)閉動(dòng)態(tài)鏈接庫(kù)void dlclose(void*handle);輸出錯(cuò)誤信息const char*dlerror(void)
28、;看下面的例子:typedef int foo_t();foo_t*foo=(foo_t*)dlsym(handle,foo);通過(guò)上面的方式我們可以載入符號(hào)foo所對(duì)應(yīng)的地址,然后通過(guò)強(qiáng)制類(lèi)型轉(zhuǎn)換給一個(gè)函數(shù)指針,當(dāng)然這里函數(shù)指針的類(lèi)型需要和符號(hào)的原型類(lèi)型保持一致,這些一般是由共享庫(kù)所對(duì)應(yīng)的頭文件提供.這里要注意一個(gè)問(wèn)題,在dlsym中載入的符號(hào)表示是和我們使用nm庫(kù)文件所看到符號(hào)表要保持一致,這里就有一個(gè)前面提到的gcc和g+符號(hào)表的不同,一個(gè)int foo(),如果是g+編譯,并且沒(méi)有externC導(dǎo)出接口,那么用dlsym載入的時(shí)候需要用dlsym(handle,_Z3foov)方式才可
29、以載入函數(shù)int foo(),所以建議所以的共享庫(kù)對(duì)外接口都采用externC的方式導(dǎo)出純C接口對(duì)外使用,這樣在使用上也會(huì)比較方便dlopen的flag標(biāo)志可以選擇RTLD_GLOBAL,RTLD_NOW,RTLD_LAZY.RTLD_NOW,RTLD_LAZY只是表示載入的符號(hào)是一開(kāi)始就被載入還等到使用的時(shí)候被載入,對(duì)于多數(shù)應(yīng)用而言沒(méi)有什么特別的影響.這兩個(gè)標(biāo)志都可以通過(guò)|和RTLD_GLOBAL一起連用這里主要是說(shuō)明RTLD_GLOBAL的功能,考慮這樣的一個(gè)情況:我們有一個(gè)main.cpp,調(diào)用了兩個(gè)動(dòng)態(tài)libA,和libB,假設(shè)A中有一個(gè)對(duì)外接口叫做testA,在main.cpp可以通過(guò)dlsym獲取到testA的指針,進(jìn)行使用.但是對(duì)于libB中的接口,它是看到不libA的接口,使用testA是不能調(diào)用到libA中的testA的,但是如果在dlopen打開(kāi)libA.so的時(shí)候,設(shè)置了RTLD_GLOBAL這個(gè)選項(xiàng),就可以把libA.so中的接口升級(jí)為全局可見(jiàn),這樣在libB中就可以直接調(diào)用libA中的te
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024撫州職業(yè)技術(shù)學(xué)院輔導(dǎo)員招聘筆試真題
- 征求意見(jiàn)表2:文成縣糯米山藥種植與加工技術(shù)規(guī)程
- 2025年應(yīng)急救生系統(tǒng)項(xiàng)目合作計(jì)劃書(shū)
- Recycle 1(第1課時(shí)) 教案人教pep英語(yǔ)六年級(jí)上冊(cè)
- 繪畫(huà)語(yǔ)言及其在創(chuàng)作過(guò)程中的思想研究
- 6~9的加、減法第4課時(shí) 練一練 教案 2025人教版數(shù)學(xué)一年級(jí)上冊(cè)
- 在班隊(duì)活動(dòng)中重塑“愛(ài)的教育”
- 2024年深圳市光明區(qū)水務(wù)局招聘專(zhuān)干真題
- 2025年江蘇省第十屆大學(xué)生就業(yè)創(chuàng)業(yè)知識(shí)競(jìng)賽考試練習(xí)題庫(kù)(150題)【答案】
- 2025年江油市招聘屬公費(fèi)師范畢業(yè)生考試試題【答案】
- 2024版《供電營(yíng)業(yè)規(guī)則》學(xué)習(xí)考試題庫(kù)500題(含答案)
- 做自己的心理壓力調(diào)節(jié)師智慧樹(shù)知到期末考試答案章節(jié)答案2024年嘉興大學(xué)
- 學(xué)術(shù)期刊推廣方案
- 安檢設(shè)備采購(gòu)安裝調(diào)試方案
- 2023年保定市蠡縣教師招聘考試真題
- 實(shí)習(xí)生-OFFER正式通知函
- 市政臨時(shí)占道施工方案
- 《分娩方式的選擇》課件
- 《FABE銷(xiāo)售法則》課件
- 直流屏培訓(xùn)課件
- 培訓(xùn)課件 -BBF品牌建設(shè)模型-
評(píng)論
0/150
提交評(píng)論