《程序员的自我修养》第8章学习笔记

《程序员的自我修养》第8章个人学习笔记

8.1共享库的版本

8.1.1 共享库的兼容

共享库的更新可以被分为两类:

兼容更新。原有接口不变。

不兼容更新。改变了原有的接口,使用该共享库原有的接口的程序可能不能运行或运行不正常。

实际上,这些对接口兼容的考虑是ABI上的。主要包括堆栈结构、符号命名、参数规则、数据构造的内存分布等方面。

导致c语言的共享库ABI改变的行为主要有如下4个:

1.导出函数的行为发生变化。

2.导出函数被删除。

3.导出数据的结构发生变化。

4.导出函数的接口发生变化,如函数返回值、参数被更改。

其实以上的不兼容都可以从汇编的角度思考,我们写好的c语言源代码经过编译后的汇编代码就已经根据我们的编译器写好,这些已经固定(不妨打开ida看看),假如我们的库变了,但汇编因为已经完成,无法改变,就会出现不兼容问题。试想一下,我们共享库函数的第一个第二个变量位置顺序变了,但可执行文件没变,将会产生怎样的效果。从这里也能看出,脚本语言相比编译语言的优越性,其的可兼容性。

8.1.2 共享库版本命名

Linux规定共享库的文件命名规则:

libname.so.x.y.z  //x主版本号,y次版本号,z发布版本号

主版本号表示库的重大升级,不同主版本号无法兼容。

次版本号表示库的增量升级,如增加接口。向下兼容。

发布版本号表示库的一些bug修正、性能改进。不对接口更改。

linux中的c语言库,动态链接器等命名比较特殊。如我们平常接触的libc2.23.so。

8.1.3 SO-NAME

在linux系统中,系统会为每个共享库在它所在的目录创建一个跟“SO-NAME"相同的并指向它的软连接。这个SO-NAME即共享库的文件名去掉次版本号和发布版本号,保留主版本号。

例如,一个共享库叫lib.so.2.6.1,那么其SO-NAME就叫lib.so.2

由于历史原因,动态链接器和c语言库的共享对象文件名规则不按linux标准的命名方式。如我们现在的libc库的软连接都叫libc.so.6。

这些软连接会指向目录中主版本号相同,次版本号和发布版本号最新的共享库。

这样一来,我们可执行文件在转移时就不用天天修改各种.dynamic段了,只要大家都遵循上述标准就行,libc库名统一软连接名就行。

用ida打开某程序的汇编下最开头就可以看到interpret段和.dynamic段记录依赖的库。

Linux中提供一个工具叫Idconfig,当系统中新安装或更新了一个共享库时,就运行它遍历,更新所有或创建新的软连接。

8.2 符号版本

有一种问题叫做此版本交会问题。例如我们的可执行文件用到了2.6版本新增加的符号。但该机器上只有2.5版本,因此链接时通过软连接的最新库也就是2.5了,这是动态链接器运行时就会报错,为了解决这个问题,这时引入基于符号的版本机制。

8.2.1 基于符号的版本机制

其实就是为符号添加一个标签,来分明这个符号是哪个版本引入的

8.2.2 Solaris中的符号版本机制

见p237举例。好处是引入了符号的范围机制,比如说我希望某符号不要被其他模块访问,我可以把其变成局部符号,不再对外显示。

链接器会计算出该可执行文件所用到的最高版本符号,记录在可执行文件中,从而规避版本交会问题。

8.2.3 Linux中的符号版本

详见p239,p240有Linux系统中符号版本机制实践示例。

8.3 共享库系统路径

目前大多数包括linux在内的开源操作系统都遵守一个叫做FHS的标准。

具体在p241.

8.4 共享库查找过程

动态链接器在查找.dynamic段给出的模块路径时按照以下规则。

如果该项保存的是绝对路径,那么动态链接器就按照这个路径去查找;如果保存的是相对路径,那么动态链接器就会在/lib、/usr/lib和由/etc/ld.so.conf配置文件指定的目录中查找。(p205讲解dynamic段,其中如果是相对路径,实际上保存的只是共享文件的SO-NAME,不像.interpret保存了相对地址的路径,这也是为什么我们需要遍历这些目录,这一点算是暂时解惑了)

但这样挨个目录找很麻烦,所以又用到了Idconfig程序。这个程序除了之前说的会建立或刷新SO-NAME以外,还会收集起来,放到/etc/ld.so.cache里。当寻找时,直接在这里面找,如果找不着了,再去上述的地方遍历找。

8.5 环境变量

LD_LIBRARY_PATH

该环境变量由若干个路径组成,每个路径之间由冒号隔开。默认情况下为空。

感觉书中讲的不够详细,( 我理解能力不够,找个时间把这块再学学。

LD_PRELOAD

类似上面的,这个是提前装载共享库(在ld加载其他共享库前),可以利用全局符号介入机制去改写部分函数,但不影响整体运行。

LD_DEBUG

打开动态链接器的调试功能。

参数:

files 打印出整个装载过程,显示程序依赖的共享库,装载步骤和初始化,共享库装载时的地址。

bindings 显示动态链接的符号绑定过程

详见p244

8.6 共享库的创建和安装

8.6.1 共享库的创建

记得利用SO-NAME,不过也可以利用rpath在链接可执行文件时修改成绝对地址。

8.6.2 清除符号信息

方法:strip工具,gcc中的 -W1,-S或s

8.6.3 共享库的安装

使用Idconfig指定共享库所在的目录。在编译程序时,也需要指定共享库的位置。

注:时时刻刻注意编译器与动态链接器的区别,书里说的很笼统,并不分明!

8.6.4 共享库构造和析构函数

指定共享库的构造和析构函数的方法p247

8.6.5 共享库脚本

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值