Lib库使用学习笔记_第1页
Lib库使用学习笔记_第2页
Lib库使用学习笔记_第3页
Lib库使用学习笔记_第4页
Lib库使用学习笔记_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Lib库使用学习笔记一、Chapter1.为什么使用库文件我们在实际编程工作中肯定会遇到这种情况:有几个项目里有一些函数模块的功能相同,实现代码也相同,也是我们所说的重灾代码。比如,很多项目里都有一个用户验证的功能。代码段如下:/UserLogin.h文件,提供函数声明intlsValidUser(char*username,intnamelen);/UserLogin.c文件,实现对用户信息的验证intlsValidUser(char*username,intnamelen)(intIsValid=0;/*下面是具体的处理代码,略去*/returnIsValid;)如果每个项目都保存着这两个

2、UserLogin.h和UserLogin.c文件,会有以下几个弊端:1 .每个项目里都有重复的模块,造成代码重更。2 .代码的重用性不好,一旦IsValidUser的代码发生了变化,为了保持设计的一致性,我们还要手工修改其他项目里的UserLogin.c文件,既费时又费力,还容易出错。库文件就是对公共代码的一种组织形式。为了解决上面两个弊端,就提出了用库文件存放公共代码的解决方案,其要点就是把公共的(也就是可以被多次好用的)目标代码从项目中分离出来,统一存放到库文件中,项目要用到这些代码的时候,在编译或者运行的时候从库文件中取得目标代码即可。库文件又分两种:静态库和动态库。二、Chapter

3、2.静态库和动态库简单的说,如果程序是在编译时加载库文件的,就是使用了静态库,静态库的文件名格式是lib*.ao如果是在运行时加载目标代码,就成为动态库,动态库的文件名格式是换句话说,如果是使用静态库,则静态库代码在编译时就拷贝到了程序的代码段,程序的体积会膨胀。如果使用动态库,则程序中只保留库文件的名字和函数名,在运行时去查找库文件和函数体,程序的体积基本变化不大。静态库的原则是“以空间换时间”,增加程序体积,减少运行时间:动态库则是“以时间换空间”,增加了运行时间,但减少了程序本身的体积。在附录的欧部分,也会做一些说明。从文件的格式角度讲,静态库的本质是一种档案文件(.。文件的集合),其中

4、包含了一个内容索引(也可以不包含,但没有索引的静态库不能用来链接,在附录的虹和各个模块既.。文件;而动态库是ELF格式的文件,可以被用来加载和执行,而静态库不可以。还有一种库文件,共享库。看到网上有些资料说,动态库就是共享库的一种变种,由于没有使用到,没有详细研究。有时候,会在目录中看到以或结尾的文件,这些是GNU的工具libtool生成和使用的文件,用来说明实际库文件的使用信息和以来关系,详细的内容会在以后automakeautoconfandlibtool的文档中介绍。三、Chapter3.静态库的生成和使用3.1. 制作最简单的静态库文件编写如下两个文件,放在同一目录中:mylib.h静

5、态库头文件voidtest();mylib.c静态库实现文件#includevoidtest()(printf(Hhelloworld./n11);)使用下边的命令生成静态库:gcc-cmylib.carrclibmy.amylib.o这样就生成了静态库libmy.a,注意一定要以lib*.a这样的格式命名,否则链接器Id不能识别。使用命令filelibmy.a”看看它的格式,是一个档案文件。我们可以使用皿查看它的内部构成:rootBensonlibtest#nmlibmy.alibmy.o:Uprintf00000000Ttest这表示静态库存模块libmy.o,在使用的时候,gcc会根据需

6、要将函数名得到模块,然后从静态库中提取出对应的文件的内容,然后用来链接,就是使用单独的“.0”文件一样。3.2. 使用库文件编写一个测试程序main.c,内容为:#includemylib.hintmain(void)(test();return0;)由于需要调用libmy.a中的test函数,所以在编译时,需通过“-L-I”参数指定链接这个库:gcc-I./-omainmain.c-L./-Imy通过-I和-L参数制定了gcc的头文件和库文件搜索路径为当前目录,也可以根据需要指定为其他目录。生成执行文件main后,执行命令filemain,可以看到:rootBensonlibtest#fil

7、emainmain:ELF32-bitLSBexecutable,Intel80386,version1(SYSV),forGNU/Linux2.2.5,staticllylinked(usessharedlibs),notstripped运行,看到结果,成功。四、Chapter4.动态库的生成和使用4.1. 制作最简单的动态库文件我们同样使用上边的mylib.h和mylib.c文件,但使用不同的命令生成库文件:gcc-fpic-sharedlibmy.solibmy.c这样就生成了动态库文件libmy.s。,-fpic这个选项指定是否使用上反,这个选项的使用需要系统平台的支持,一般建议添加,

8、如果不支持,gcc会报错。生成libmy.so后,使用“filelibmy.so”命令,可以看到是一个ELF格式的文件,这说明共享库的使用需要通过符号解析和重定位加载入内存才能使用。4.2. 动态库的隐式调用动态库有两种使用方法,隐式调用和显示调用。隐式调用的方法跟静态库的使用方法一样,都是通过gcc的F-L”参数指定库文件的路径,如果同一个库文件,在系统中同时存在静态库和动态库,默认情况下gcc主动链接动态库。但也可以通过gcc的“-static”选项,强制指定使用静态库。gcc-I./-omainmain.c-L./-Imy#使用动态库生成maingccmain.c./libmy.so-o

9、main#使用动态库生成main,不同的地方在于指定了libmy.so的加载路径,这种用法很少用。详细的内容附录Id.s。gcc-static-I./-omainmain.c-L/-Imy#使用静态库生成main输入filemain命令,可以看到:rootBensonlibtest#filemainmain:ELF32-bitLSBexecutable,Intel80386,version1(SYSV),forGNU/Linux2.2.5,dynamicallylinked(usessharedlibs),notstripped运行程序,报错:rootBensonlibtest#./main.

10、/main:errorwhileloadingsharedlibraries:libmy.so:cannotopensharedobjectfile:Nosuchfileordirectory没有找到libmy.so这个动态库,我这个库文件就在当前目录下?4.3. 使动态库被系统共享的方法前边已经说过动态库需要加载到内存中,才能使用。注意,链接和加载是两码事,链接发生在生成可执行程序的阶段,加载发生在运行阶段。gcc的”-l-L“参数只是保证在链接阶段指定文件路径,和加载无关,当然也有.办法可以使链接阶段的路径信息在加载阶段起作用,这些涉及到gcc的详细用法,和可执行文件的格式,附录中会简单介

11、绍一些。运行时的加载的工作不是由main完成的,而是由/lib/dso(不同平台会有些出入)完成。他有自己的查找动态连接库的规则,所以在不更新Id.so的查找路径的情况下,会出现上边的错误。根据dso的man手册,dso共有六种方式查找需要的动态库,这里只介绍常用的三种方式,详细的内容见附录dso1 .按照环境变量LD_LIBRARY_PATH的内容查找(setuid类的程序排除)2 .在库高速缓存文件ld.so.conf中给出的路径查找3 .在/lib,/usr/lib目录下查找相对应的,可以分别通过设置环境变量LD_HBRARY_PATH,通过在ld.so.conf文件中添加路径和将动态库

12、文件包:制到/lib、/usr/lib目录下,使动态库可以在加载时被找到。rootBensonlibtest#exportLD_LIBRARY_PATH=$LD_LIBRARY_PATH:/pwdrootBensonlibtest#catpwd/etc/ld.so.conf;IdconfigrootBensonlibtest#cplibmy.so/lib-f以上三种方式都可以工作。关于Idconfig的使用详解,见附录Idconfig此时再执行main,可以正常运行了。通过Idd命令,可以看到main程序依赖于libmy.soorootBensonlibtest#Iddmainlibtest.

13、so=notfoundlibc.so.6=/lib/tls/libc.so.6(0x42000000)/lib/ld-linux.so.2=/lib/ld-linux.so.2(0x40000000)4.4. 动态库的显式调用动态库的显示调用,也需要库文件被加载到内存中。但是使用方法和静态库完全不同。需要系统调用dlopendlsymdlclosedlerror的支持。可以使用同一个libmy.so文件,但是需要新的测试文件:main.c测试动态库显式调用的程序*/#include用于动态库管理的系统头文件includelibmy.h要把函数的头文件包含进来,否则编译时会报错intmain(v

14、oid)(/*声明对应的函数的函数指针*/void(*pTest)();/*加载动态库*/void*pdlHandle=dlopen(,libtest.so,/RTLD_LAZY);/*错误处理*/if(pdlHandle=NULL)printf(nFailedloadlibrary/n11);return-1;)char*pszErr=dlerror();if(pszErr!=NULL)printf(,%s/n/pszErr);return-1;)/*获取函数的地址*/pTest=dlsym(pdlHandle,testn);pszErr=dlerror();if(pszErr!=NULL)

15、printf(,%s/n/pszErr);dlclose(pdlHandle);return-1;)/*实现函数调用*/pTest();/*程序结束时关闭动态库*/dlclose(pdlHandle);return0;)编译时需要加入-Idl选项:rootBensonlibtest#gcc-Idl-omainmain.c运行程序,成功。这种方式,不需要在链接阶段指定动态库的位置。在运行阶段,调用要使用的函数通过Idd命令,可以看到main程序不再依赖于libmy.so,转为依赖libdl.solibdl.so.2=/lib/libdl.so.2(0x40034000)libc.so.6=/li

16、b/tls/libc.so.6(0x42000000)/lib/ld-linux.so.2=/lib/ld-linux.so.2(0x40000000)Chapter5,链接时同时使用动态库和静态库当一个执行程序链接时需要多个库文件时,通常情况下,我们要么统一采用静态链接,要么统一采用动态链接。实际上,我们可以通过gcc的选项分别指定每种库的链接方式:-WI-Bstatic;-Wl-Bdynamicogcc-omainmain.c-Wl-Bstatic-Ic-Wl-Bdynamic-test上边这个例子中制定了静态链接libc和动态连接libtesto而实际上gcc选项-Wl表示将后边的参数传

17、给链接器-Bstatic和-Bdynamic是Id的选项。AppendixA,附录A.l.IdconfigIdconfig用来维护Id.so加载的动态库的路径信息和依赖信息,路径信息存放在/etc/ld.so.conf中,/etc/dso.cache中存放了/lib/usr/lib和/etc/ld.conf包含的路径内的所有库信息。可以通过Idd命令查看动态库的依赖信息。Idconfig有两种常用的使用方法:1 .将需要查找的目录加入/etc/ld.so.conf,然后运行Idconfig更新,更新结果永久有效2 .Idconfig+路径,这种方式能直接更新指定的目录,但是结果在下次执行Idc

18、onfig时,将会失效。Idconfig的选项比较有用的是-v和-n,其他的可参考man手册: -v或-verbose详细的显示扫描的目录及搜索到的动态连接库,还有它所创建的链接的名字 -n使扫描时,不扫描默认目录/lib、/usr/lib和/etc/ld.so.conf包含的路径A.2.IddIdd命令很简单,用来显示文件所依赖的动态库文件,同样-v选项显示详细信息。A.3.arar命令用来创建归档文件,修改归档文件,和提取归档文件中的模块。这里归档文件就是静态库,模块就是里边的各个文件。在静态库中每个文件的内容,权限,时间戳,文件所有者,文件所属组都将被保留,并且可在提取时回发。ar通过在

19、静态库中创建模块列表来维护内容结构。可以通过“nm-s“命令查看这个列表内容。ar命令的选项很多,可通过杳看man手册获取全部内容,这里我举几个例子来说明它的主要功能:1. 创建静态库文件:2. ar-rclibtest.alibmy.olibtest.o选项分为和co-r表示将后边的.o模块加入库文件中;-c表示当库文件不存在时创建。同样,向存在的库文件添加新的模块时,只需要-r选项即可。3. 查看静态库中的模块:4. rootBensonlibtest#ar-tlibtest.a5. libmy.o6. libtest.o7. 删除静态库中的模块:8. ar-dlibtest.alibmy

20、.o此时在查看库的模块,libmy.o就不存在了。9. 提取静态库中的模块:10. rootBensonlibtest#Is11. libtest.a12. rootBensonlibtest#ar-xlibtest.alibmy.o;Is13. libtest.alibmy.o从libtest.a中提取出了libmy.o文件A.4.nmnm命令用来查看目标文件中的符号信息,nm命令对每个符号显示如下内容: 每个符号的值。 当指定6选项时,显示函数符号对应的函数体的大小。 每个符号的类型,如,U表示该符号没有在库中定义;T表示该符号在库中定义。还有其他的内容涉及到目标文件的格式,这里就不详细介

21、绍。 每个符号的名字。nm的选项中,“-s”选项用来显示静态库文件的列表信息。其他选项可查看man手册。A.5.ranlib为静态库生成索引信息,并将索引信息保存在静态库文件中,它是ar-s命令的变形。带有索引的静态库能够加快连接速度,并允许库中的函数相互调用,而不需要考虑函数位置的先后。A.6.PICPIC(PositionIndependentCode),位置无关编码。是一种库文件的编码组织方式,其特点是方便系统装载。是否支持这种格式的动态库,与硬件系统平台有关。简单的说,这种格式的库文件包含两个符号GOT(_GLOBAL_OFFSET_TABLE_)和PLT(ProcedureLinka

22、geTable)。调用函数实际调用的是PLT里的地址,访问全局变量通过GOT里边的地址这些地址在未运行时不确定,在加载运行后,才被解析出来,所以可以加载到进程地址空间的任何地方。摘自网络的一篇文章,含有更多信息:PICcoderadicallydiffersfromconventionalcodeinthewayitcallsfunctionsandoperatesondatavariables.Itwillaccessthesefunctionsanddatathroughanindirectiontable,theGlobalOffsetTable”(GOT),bysoftwareconv

23、entionaccessibleusingthereservedname,_GLOBAL_OFFSET_TABLE_.Theexactmechanismusedforthisishardwarearchitecturedependent,butusuallyaspecialmachineregisterisreservedforsettingupthelocationoftheGOTwhenenteringafunction.Therationalebehindthisindirectaddressingistogeneratecodethatcanbeindependentlyaccesse

24、doftheactualloadaddress.InatruePIClibrarywithoutrelocationsinthetextsegment,onlythesymbolsexportedintheGlobalOffsetTableneedupdatingatrun-timedependingonthecurrentloadaddressofthevarioussharedlibrariesintheaddressspaceoftherunningprocess.Likewise,procedurecallstogloballydefinedfunctionsareredirected

25、throughtheProcedureLinkageTable11(PLT)residinginthedatasegmentofthecoreimage.Again,thisisdonetoavoidrun-timemodificationstothetextsegment.Thelinker-editorallocatestheGlobalOffsetTableandProcedureLinkageTablewhencombiningPICobjectfilesintoanimagesuitableformappingintotheprocessaddressspace.Italsocoll

26、ectsallsymbolsthatmaybeneededbytherun-timelink-editorandstoresthesealongwiththeimagestextanddatabits.Anotherreservedsymbol,_DYNAMICisusedtoindicatethepresenceoftherun-timelinkerstructures.Whenever.DYNAMICisrelocatedto0zthereisnoneedtoinvoketherun-timelink-editor.Ifthissymbolisnon-zero,itpointsatadat

27、astructurefromwhichthelocationofthenecessaryrelocation-andsymbolinformationcanbederived.Thisismostnotablyusedbythestart-upmodule,crtO,crtlSandmorerecentlyScrtl.The_DYNAMICstructureisconventionallylocatedatthestartofthedatasegmentoftheimagetowhichitpertains.Onmostarchitectures,whenyoucompilesourcecod

28、etoobjectcode,youneedtospecifywhethertheobjectcodeshouldbepositionindependentornot.Thereareoccasionalarchitectureswhichdontmakethedistinction,usuallybecauseallobjectcodeispositionindependentbyvirtueoftheApplicationBinaryInterface(ABI),orlessoftenbecausetheloadaddressoftheobjectisfixedatcompiletime,w

29、hichimpliesthatsharedlibrariesarenotsupportedbysuchaplatform).Ifanobjectiscompiledaspositionindependentcode(PIC),thentheoperatingsystemcanloadtheobjectatanyaddressinpreparationforexecution.Thisinvolvesatimeoverhead,inreplacingdirectaddressreferenceswithrelativeaddressesatcompiletime,andaspaceoverhea

30、d,inmaintaininginformationtohelptheruntimeloaderfillintheunresolvedaddressesatruntime.Consequently,PICobjectsareusuallyslightlylargerandsloweratruntimethantheequivalentnon-PICobject.TheadvantageofsharinglibrarycodeondiskandinmemoryoutweightheseproblemsassoonasthePICobjectcodeinsharedlibrariesisreuse

31、d.PICcompilationisexactlywhatisrequiredforobjectswhichwillbecomepartofasharedlibrary.Consequently,libtoolbuildsPICobjectsforuseinsharedlibrariesandnon-PICobjectsforuseinstaticlibraries.WheneverlibtoolinstructsthecompilertogenerateaPICobject,italsodefinesthepreprocessorsymbol,PIC1,sothatassemblycodec

32、anbeawareofwhetheritwillresideinaPICobjectornot.Typically,aslibtooliscompilingsources,itwillgeneratea.Io*object,asPIC,andao*object,asnon-PIC,andthenitwillusetheappropriateoneofthepairwhenlinkingexecutablesandlibrariesofvarioussorts.Onarchitectureswherethereisnodistinction,theMofileisjustasoftlinktot

33、he.ofile.Inpractice,youcanlinkPICobjectsintoastaticarchiveforasmalloverheadinexecutionandloadspeed,andoftenyoucansimilarlylinknon-PICobjectsintosharedarchives.Whenyouuseposition-independentcode,relocatablereferencesaregeneratedasanindirectionthatusedatainthesharedobjectsdatasegment.Thetextsegmentcod

34、eremainsread-only,andallrelocationupdatesareappliedtocorrespondingentrieswithinthedatasegment.Ifasharedobjectisbuiltfromcodethatisnotposition-independent,thetextsegmentwillusuallyrequirealargenumberofrelocationstobeperformedatruntime.Althoughtheruntimelinkerisequippedtohandlethis,thesystemoverheadth

35、iscreatescancauseseriousperformancedegradation.YoucanidentifyasharedobjectthatrequiresrelocationsagainstitstextsegmentusingtoolssuchasYeadelf-dfooandinspecttheoutputforanyTEXTRELentry.ThevalueoftheTEXTRELentryisirrelevant.Itspresenceinasharedobjectindicatesthattextrelocationsexist.A.7.Id.so/lib/ld.s

36、o是系统的动态库加载器,属于Glibc编译生成的,与系统平台密切相关。加载目标代码涉及的内容很多,但是这里主要围绕dso的动态库搜索过程,做全面的解释。Id.so在加载动态库的时候,分先后顺序,按以下六步搜索:1 .可执行文件自身的动态段(.dynamicsection)中DT_NEED入口中包含的路径。首先应该了解到,每个执行文件的数据是按照段来存储的,有代码段,数据段,BSS段等。那么这里的动态段也是其中的一部分。我们借助readelf命令来查看这部分信息:rootBensonlibtest#readelf-dmainTagType0x00000001(NEEDED)0x00000001(

37、NEEDED)0x0000000c(INIT)OxOOOOOOOd(FINI)0x00000004(HASH)0x001000005(STRTAB)0x00000006(SYMTAB)0x0000000a(STRSZ)OxOOOOOOOb(SYMENT)0x00000015(DEBUG)0x00000003(PLTGOT)0x00000002(PLTRELSZ)0x00000014(PLTREL)0x00000017(JMPREL)0x00000011(REL)0x00000012(RELSZ)0x00000013(RELENT)0x6ffffffe(VERNEED)0x6fffffff(VE

38、RNEEDNUM)0x6ffffff0(VERSYM)Name/ValueShared library: liba.soShared library: libc.so.60x80483400x80484e40x80481280x80482400x8048170172 (bytes)16 (bytes)0x00x80495fc16 (bytes)REL0x80483300x80483288 (bytes)8 (bytes)0x804830810x80482ec0x00x00000000(NULL)readelf命令,能够查看ELF格式的文件的所有信息,在这里先不详细介绍。对于上边显示的信息我们注

39、意前两行,类型是NEEDED,后便对应的是内容,这些就是DT_NEED部分的内容。而内容部分的liba.so和libc.so.6是没有路径信息的。所以dso不能根据这里的信息加载liba.so库。但如果使用如下的命令生成main程序:root Benson libtest# readelf-d main0x00000001 (NEEDED)0x00000001 (NEEDED)0x0000000c (INIT)OxOOOOOOOd (FINI)0x00000004 (HASH)0x001000005 (STRTAB)0x00000006 (SYMTAB)0x0000000a (STRSZ)Sh

40、ared library: ./liba.soShared library: libc.so.6 0x80483400x80484e40x80481280x80482400x8048170172 (bytes)rootBensonlibtest#gcc-omainmain.o./liba.so16 (bytes)0x00x80495fc16 (bytes)REL0x80483300x80483288 (bytes)8 (bytes)0x804830810x80482ec0x0OxOOOOOOOb(SYMENT)0x00000015(DEBUG)0x00000003(PLTGOT)0x00000002(PLTRELSZ)0x00000014(PLTREL)0x00000017(JMPREL)0x00000011(REL)0x00000012(RELSZ)0x00000013(RELENT)0x6ffffffe(VERNEED)0x6fffffff(VERNEEDNUM)0x6

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论