linux 静态库与共享库

网友投稿 922 2022-09-06

linux 静态库与共享库

linux 静态库与共享库

本文笔记学习自《Professional Assembly Language》

静态库

当我们将不同的函数写在不同的文件中,如果主程序调用这些函数,就需要相应的目标文件才能生成可执行文件。目标文件很多的话,不便于管理。我们可以将目标文件整合到一个存档文件中,编译器从存档文件挑选出需要的目标文件,这样的存档文件称之为库文件(library file)。 假设库文件的目标代码被编译到了主程序中,就称之为静态库文件(windows下对应着LIB文件)。 linux下有ar工具可以创建静态库文件。

ar - create, modify, and extract from archivesar [--plugin name] [-X32_64] [-]p[mod [relpos] [count]] archive [member...]

以计算圆的面积areafunc.s进行说明。 areafunc.s:

.section .text.type areafunc,@function.globl areafuncareafunc:pushl %ebp movl %esp,%ebp #store esp registerfldpi #store PI at st(0)filds 8(%ebp) #store first parameter at st(0) and PI moved to st(1) fmul %st(0),%st(0) fmul %st(1),%st(0) #make sure st(0) has current anwser.movl %ebp,%esppopl %ebp

areafunc.c:

#include float areafunc(int);int main(){ float result; result = areafunc(1); printf("result is %f\n",result); result = areafunc(10); printf("result is %f\n",result); return 0;}

生成目标文件 ​​gcc -c areafunc.s -o areafunc.o​​​ linux操作系统下的静态库文件通常命名为​​​libx.a​​​,x是自己的文件命名,.a表示这是一个静态库文件。 使用ar生成库文件liball.a: 下面我用所有的.o文件生成一个库文件。

[edemon@CentOS workspace]$ ls *.oareafunc.o area.o ftest.o movl.o mov.o quadtest.o[edemon@CentOS workspace]$ ar -r liball.a *.oar: creating liball.a[edemon@CentOS workspace]$ file liball.aliball.a: current ar archive[edemon@CentOS workspace]$ ar -t liball.a areafunc.oarea.oftest.omovl.omov.oquadtest.o

创建索引提高连接速度: ​​ranlib liball.a​​​ 再介绍一个工具nm

nm - list symbols from object filesnm [-a|--debug-syms] [-g|--extern-only][--plugin name] [-B] [-C|--demangle[=style]] [-D|--dynamic] [-S|--print-size] [-s|--print-armap] [-A|-o|--print-file-name][--special-syms] [-n|-v|--numeric-sort] [-p|--no-sort] [-r|--reverse-sort] [--size-sort] [-u|--undefined-only] [-t radix|--radix=radix] [-P|--portability] [--target=bfdname] [-fformat|--format=format] [--defined-only] [-l|--line-numbers] [--no-demangle] [-V|--version] [-X 32_64] [--help] [objfile...]

可查看函数所在文件位置

[edemon@CentOS workspace]$ nm -s liball.a Archive index:areafunc in areafunc.oarea in area.omain in ftest.o_start in movl.o_start in mov.o_start in quadtest.oareafunc.o:00000000 T areafuncarea.o:00000000 T areaftest.o: U area00000000 T main00000000 d precision00000002 d reportmovl.o:00000000 T _start00000000 d valuemov.o:00000000 T _startquadtest.o:00000000 T _start00000000 d data100000014

使用静态库进行编译:

[edemon@CentOS workspace]$ gcc areafunc.c liball.a -o areafunc[edemon@CentOS workspace]$ ./areafunc result is 3.141593result is 314.159271

因为gcc是提取所需函数代码得到可执行文件,所以areafunc的大小并不会因为使用库文件编译而变大。

[edemon@CentOS workspace]$ gcc areafunc.c areafunc.o -o areafunc1[edemon@CentOS workspace]$ du -h areafunc areafunc18.0K areafunc8.0K areafunc1

共享库

和静态库文件不同,有一类存档文件的目标代码不被编译到可执行文件中,主程序不用把函数代码加入它的内存空间,这类存档文件称之为共享库文件。 Linux操作系统的命名格式为libx.so,其中x是自己的文件命名,.so表明这是共享库(windows下对应着DLL文件)。 静态编译(将函数代码连接到可执行文件)得到的可执行文件,我们使用objdump进行反汇编,可以查看函数调用的痕迹。 以areafunc为例:

[edemon@CentOS workspace]$ objdump -D areafunc > read[edemon@CentOS workspace]$ vim read#查找含有areafunc的地方:/areafunc345 8048432: e8 65 00 00 00 call 804849c 359 8048462: e8 35 00 00 00 call 804849c 379 0804849c :380 804849c: 55 push %ebp381 804849d: 89 e5 mov %esp,%ebp382 804849f: d9 eb fldpi383 80484a1: df 45 08 fild 0x8(%ebp)384 80484a4: d8 c8 fmul %st(0),%st385 80484a6: d8 c9 fmul %st(1),%st386 80484a8: 89 ec mov %ebp,%esp387 80484aa: 5d pop %ebp388 80484ab: c3 ret

以共享库编译方式得到的可执行文件是不含有函数代码的。 共享库编译方式​​​shell> gcc sourcefile -Ldir -llibname -o executefile​​​ -L 告诉编译器库文件在哪个位置(假设不在系统定义的位置) -l 后跟上库的名字(x) 生成共享库文件:

[edemon@CentOS workspace]$ gcc -shared -o libshared.so areafunc.o area.o ftest.o[edemon@CentOS workspace]$ file libshared.so libshared.so: ELF 32-bit LSB shared object, Intel 80386, version 1

生成可执行文件:

[edemon@CentOS workspace]$ gcc -o areafunc2 -L. -lshared areafunc.c[edemon@CentOS workspace]$ ./areafunc2result is 3.141593result is 314.159271

再次反汇编,查找函数areafunc的踪迹:

[edemon@CentOS workspace]$ objdump -D areafunc2 > read[edemon@CentOS workspace]$ vim read361 08048440 :362 8048440: ff 25 b8 98 04 08 jmp *0x80498b8363 8048446: 68 10 00 00 00 push $0x10364 804844b: e9 c0 ff ff ff jmp 8048410 <_init+0x30>505 80485a2: e8 99 fe ff ff call 8048440 519 80485d2: e8 69 fe ff ff call 8048440

可以发现,函数的代码并没有在这份反汇编后的文件中。 ldd可查看依赖的共享库:

[edemon@CentOS workspace]$ ldd areafunc2 linux-gate.so.1 => (0x00bb1000) libshared.so (0x00395000) libc.so.6 => /lib/libc.so.6 (0x00397000) /lib/ld-linux.so.2 (0x001ee000)

可执行文件需要Linux动态加载器(/lib/ld-linux.so.2)自动加载所需的函数。 假设动态加载器找不到库文件的位置,怎么办? 系统文件​​​/etc/ld.so.conf​​​含有定位共享库文件位置的信息,我们改变它(增添位置信息),再使用​​ldconfig​​​更新。还有一种添加库文件位置信息的方法,就是更改​​LD_LIBRARY_PATH​​变量,例如:

[edemon@CentOS workspace]$ echo $LD_LIBRARY_PATH /home/edemon/workspace/[edemon@CentOS workspace]$ export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/home/edemon/"[edemon@CentOS workspace]$ echo $LD_LIBRARY_PATH /home/edemon/workspace/:/home/edemon/

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:程序员新人,如何在复杂代码中找 bug?
下一篇:矩阵乘法经典应用之路径条数
相关文章

 发表评论

暂时没有评论,来抢沙发吧~