.so文件之于Linux

什么是链接

即使一个非常简单的程序,也需要依赖C标准库和系统库,链接其实就是把其他第三方库和自己源代码生成的二进制目标文件融合在一起的过程。经过链接之后,那些第三方库中定义的函数就能被调用执行了。早期的一些操作系统一般使用静态链接的方式,现在基本上都在使用动态链接的方式。
静态链接在链接的时候,就把所依赖的第三方库函数都打包到了一起,导致最终的可执行文件非常大。而动态链接在链接的时候并不将那些库文件直接拿过来,而是在运行时,发现用到某些库中的某些函数时,再从这些第三方库中读取自己所需的方法。
我们把编译后但是还未链接的二进制机器码文件称为目标文件(Object File),那些第三方库是其他人编译打包好的目标文件,这些库里面包含了一些函数,我们可以直接调用而不用自己动手写一遍。在编译构建自己的可执行文件时,使用静态链接的方式,其实就是将所需的静态库与目标文件打包到一起。最终的可执行文件除了有自己的程序外,还包含了这些第三方的静态库,可执行文件比较臃肿。相比而言,动态链接不将所有的第三方库都打包到最终的可执行文件上,而是只记录用到了哪些动态链接库,在运行时才将那些第三方库装载(Load)进来。装载是指将磁盘上的程序和数据加载到内存上。例如下图中的Program 1,系统首先加载Program 1,发现它依赖libx.so后才去加载libx.so
在这里插入图片描述

不同系统下的动态链接库

Linux称之为共享目标文件(Shared Object),文件后缀为.so,Windows的动态链接库(Dynamic Link Library)文件后缀为.dll

C语言中的静态库和动态库

c语言中存在静态库(.a)和动态库(.so)。

静态库实际上是一些目标文件的集合,只用于链接生成可执行文件阶段。链接器会将程序中使用到函数的代码从库文件中拷贝到应用程序中,一旦链接完成生成可执行文件之后,在执行程序的时候就不需要静态库了。

特性:

  1. 由于每个使用静态库的应用程序都需要拷贝所用函数的代码,所以静态链接的生成的可执行文件会比较大,多个程序运行时占用内存空间比较大(每个程序在内存中都有一份重复的静态库代码)
    由于运行的时候不用从外部动态加载额外的库了,速度会比共享库快一些
  2. 更换一个静态库或者修改一个静态库后,需要重新编译应用程序

动态库也叫共享库(share object),在程序链接的时候只是作些标记,然后在程序开始启动运行的时候,动态地加载所需库(模块)。

特性:

  1. 应用程序在运行的时候需要共享库
  2. 共享库链接出来的可执行文件比静态库链接出来的要小得多,运行多个程序时占用内存空间比也比静态库方式链接少(因为内存中只有一份共享库代码的拷贝)
  3. 由于有一个动态加载的过程所以速度稍慢
  4. 更换动态库不需要重新编译程序,只需要更换相应的库即可
    动态库和静态库各有特点,适用于不同的场合。本文主要阐述动态库的使用,重点在于显式运行时链接。

查看.so文件信息Linux命令

readelf命令,一般用于查看ELF格式的文件信息,常见的文件如在Linux上的可执行文件,动态库(.so)或者静态库(.a) 等包含ELF格式的文件。
语法:readelf (选项)(参数:文件),除了-v和-H之外,其它的选项必须有一个被指定参数

1、选项 -h(elf header),显示elf文件开始的文件头信息。
2、选项 -l(program headers),segments 显示程序头(段头)信息(如果有数据的话)
3、选项 -S(section headers),sections 显示节头信息(如果有数据的话)。
4、选项 -g(section groups),显示节组信息(如果有数据的话)。
5、选项 -t,section-details 显示节的详细信息(-S的)。
6、选项 -s,symbols 显示符号表段中的项(如果有数据的话)。
7、选项 -e,headers 显示全部头信息,等价于: -h -l -S 。
8、选项 -n,notes 显示note段(内核注释)的信息 。
9、选项 -r,relocs 显示可重定位段的信息。
10、选项 -u,unwind 显示unwind段信息。当前只支持IA64 ELF的unwind段信息。
11、选项 -d,dynamic 显示动态段的信息。
12、选项 -V,version-info 显示版本段的信息。
13、选项 -A,arch-specific 显示CPU构架信息。
14、选项 -I,histogram 显示符号的时候,显示bucket list长度的柱状图。
15、选项 -x,hex-dump= 以16进制方式显示指定段内内容。number指定段表中段的索引,或字符串指定文件中的段名
16、选项 -D,use-dynamic 使用动态段中的符号表显示符号,而不是使用符号段 。
17、选项 -a,all 显示全部信息,等价于 -h -l -S -s -r -d -V -A -I。
18、选项 -v,version 显示readelf的版本信息。
19、选项 -H,help 显示readelf所支持的命令行选项。

LINUX下C++生成.so文件及编译生成可执行文件的过程

如果.cpp文件不多的话,可以将.cpp和.hpp文件都放在一个目录下,依次输入名称进行编译.也可以用指令将整个目录下的.cpp文件全部编译

g++ -std=gnu++11 test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so

在这里插入图片描述
生成名为libtest.so的动态链接库:
在这里插入图片描述
当前目录下调用刚才生成的共享库.其中,Test是生成的运行文件; test.cpp是主函数的.cpp; ltest是libtest的库名称相对应

g++ -std=gnu++11 -o Test test.cpp -L. -ltest

运行生成的Test文件

ldd Test

结果失败
在这里插入图片描述
找不到该共享库,即程序启动时依赖于该共享库。执行export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:路径/so_lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:路径/so_lib把库的路径加到LD_LIBRARY_PATH里面就ok了,运行结果如下:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值