`
cryolite
  • 浏览: 580410 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

关于库的深入思考(转载)

阅读更多
来自:http://blog.chinaunix.net/u/16651/showart_361289.html

    经常见有人提起关于库的种种问题,今天我也终于按捺不住,根据自己的经验,实验,学习中得到的一些,来说说自己的一点看法.
    我们都知道库对系统的重要.没了它,系统几乎无法运转,包括LFS整个过程至少是对工具链调整来调整去的过程是以对库的倚赖为核心的.这其中又以动态库为精华.
    那先来说简单的静态库.它简单到只是ar打包的目标文件的集合罢了,于是,它的作用也就和目标文件没什么区别了,链接进目标文件,ok,使命完成,至于程序以后的事包括运行则和这个静态库没有关系了.其实我觉的最有说服力的就是例子了,那我们就举最简单的例子.
cat >say.c<<eof
#include "stdio.h"
void say() {
  printf("Say!");
}
eof
cat >test.c <<eof
#include "stdio.h"
void say();
main(){
  say();
}

eof

gcc -c say.c
ar -r say.a say.o
gcc test.c say.a -o test
ldd test

输出结果让我们看不到任何跟say.a这个我们自己写的静态库的关系.说明程序运行时已经不需要这个静态库了,它已经被ld链接进最终的程序了.
那么动态库,我们继续
gcc -fPIC -shared say.c -o say.so
gcc test.c say.so -o test
ldd test

如果不出意外的话,会出现say.so => not found.这时的./test是不能运行的.但至少说明程序运行时是需要这个库的.那为什么找不到这个库呢?那就让我们看看系统是怎样寻找这些库的吧.
首先是ld-linux.so.2这个不能不说,它太重要了,以至于也决定了后面的搜索方式.
先是程序内部决定的.
strings test
还好我们这个test程序不大,不用过滤输出,好,你看见什么,/lib/ld-linux.so.2,say.so,libc.so.6,对,用到的库!
但我们发现不同,有的有路径,有的没有,先不管没有路径的怎么寻找,有路径的肯定是能找到了,那好,我们让say.so也有了路径.

gcc test.c ./say.so -o test2
strings test2

我们发现原来的输出中原来的say.so已经变成了./say.so.运行一下./test2,可以运行了!好,找到库了,这里用的相对路径,无疑,我们 将say.so移动到非当前文件夹.那test就又不能运行了.这样无疑是把我们用到的库硬编码进了程序里.我不喜欢硬编码,太死板.那不硬编码系统怎么找到我们需要的文件呢.
    在程序没有把库地址硬编码经进去的前提下,系统会寻找LD_LIBRARY_PATH环境变量中的地址.
LD_LIBRARY_PATH=./ ./test2
如我们所愿,程序正常运行.
如果系统在这一步也没发现我们需要的库呢.
/etc/ld.so.cache这个由ldconfig生成的文件,记载着在/etc/ld.so.conf文件中指明的所有库路径加上/lib,/usr/lib里的所有库的信息.
其实以上这句话只是在大多数情况下是正确的,是否是这个文件由ld-linux.so.2决定.如过你的LFS中的第一遍工具链/tools还在的话,
strings /tools/lib/ld-linux.so.2|grep etc
输出很可能是/tools/etc/ld.so.cache.那么它用的哪个文件我们就清楚了吧.
可这个路径前面的/tools到底和什么有关呢?首先我们可能会想到与ld-linux所在的位置有关.还好我们有3套glib,感谢LFS,现在我们拿第二遍的工具链下手.假设我们的LFS在/lfsroot
strings /lfsroot/lib/ld-linux.so.2
很奇怪的是输出竟然是/etc/ld.so.cache!那这到底和什么有关呢,没错就是我们编译时候的--prefix有关.
现在再看这个/etc/ld.so.conf,和/lib,/usr/lib这些默认ldconfig路径.也都要加上个这个prefix了.
strings /tools/sbin/ldconfig|grep etc
strings /tools/sbin/ldconfig|grep /lib

验证一下吧.
那要是ld.so.cache里也没有记载这个库的地址怎么办呢.
最后在默认路径里找.这个路径一般是/lib,/usr/lib,但也不全是.
strings /tools/lib/ld-linux.so.2|grep /lib
还是要加个prefix.
现在我们反过来思考,不用程序中硬编码的/lib/ld-linux.so.2做动态加载器了.这也可以?!是的!虽然不一定成功.
LD_TRACE_LOADED_OBJECTS=y /tools/lib/ld-linux.so.2 /bin/test
LD_TRACE_LOADED_OBJECTS=y /lib/ld-linux.so.2 /bin/test
LD_TRACE_LOADED_OBJECTS=y /lfsroot/lib/ld-linux.so.2 /bin/test
试着比较结果吧.
不出意外的话第一个是在/tools/lib中搜索的库,二三个都是在/lib中的库.原因我想上面已经说清楚了.
下面以第二个为例说明问题:
LD_LIBRARY_PATH=./ /tools/lib/ld-linux.so.2 ./test
/tools/sbin/ldconfig ./;/tools/lib/ld-linux.so.2 ./test
cp ./say.so /tools/lib/;/tools/lib/ld-linux.so.2 ./test

三种方法应该都会出现我们想要的结果,这里说明/tools/lib/ld-linux.so.2在这里的含义,是用/tools/lib/ld- linux.so.2这个做动态装载器.不信把这个去掉,后两种方法一定不行.因为以./test自己硬编码进去的/lib/ld-linux.so.2 来说,是不会去管/tools/etc/ld.so.cache,和/tools/lib下的库的.

为了说明顺序,我们做如下很危险的实验:
ldconfig /lfsroot/lib;
ldconfig -p
会出现很多内容,但不要试着过滤,因为这时的系统应该很多程序不能运行了.先踏下心来观察.你会发现很多库出现两次/lfsroot/lib,和/lib 而且/lfsroot/lib在前,说明ldconfig先处理参数给出的地址,最后是默认地址.但顺序也不一定,应该还和编译glibc时我们的参数- -enable-kernel有关(我根据种种表现猜测).
加上export LD_LIBRARY_PATH=/lib 环境变量在前面,不能运行的程序又能运行了,说明LD_LIBRARY_PATH变量的优先级优于ld.so.cache
unset LD_LIBRARY_PATH
echo >/etc/ld.so.cache
ldconfig -p
应该什么都不出现,可大部分程序能运行.说明ld-linux.so.2决定的默认路径起了作用(注意,这里的ldconfig的默认路径没有作用)
ldconfig
恢复系统正常.
如果你原意,可以chroot /lfsroot后,再做类似的操作看有什么不同.

懂了原理我们就来应用一下.
拿./test2为例.
我们把它的库给换了!!!
cat >saa.c <<eof
#include "stdio.h"
say(){
printf("I can do something here!!!");
}
eof
gcc -fPIC -shared saa.c -o saa.so
sed "s#\./say\.so#./saa.so#" test >test3
./test3
看看结果吧!
很令人惊奇是么,如果是setuid程序的话...其实这个也很难,因为这种程序我们一般是无法写的(给自己搞破坏不算).这也就明白了为什么长久以来对setuid程序的权限始终如此重视----因为太危险了.
惊奇过后你可能会想,对于未硬编码库地址的程序,我们直接把LD_LIBRARY_PATH改了不也行么?!指向我们的地址,用我们的库,然后...根本不用改什么文件了,要什么写权限了.
呵呵,要真那么容易我们可爱的Linux不也太脆弱了,这恐怕就玩大了,也是你我都不原意见到的.所以,ld-linux.so.2早以作出限止,setsid程序,LD_LIBRARY_PATH变量不起作用.不过文件中的还是有作用的.
最后,说一下ld,和ld-linux.so.2的区别,一个编译时用,一个运行时用,ld负责在它的搜索路径里找到要求的库,并查看是否有提供了需要的 符号(如函数等),如果有,记录相关信息到程序中,由ld-linux.so.2在执行时查找到该库并,并根据相关信息进行需要符号的重定位等工作.注意 这两者的搜索库的方式是不同的.
LC_ALL=C ld --verbose|grep search -i
显示了它默认的查找地址.我们可以做个实验.一般它会有个类似i686-pc-linux-gnu/lib的路径,同时是不在ld-linux.so.2的搜索路径里的.其余的是我们编译是--with-lib-path和LIB_PATH变量指定的.
mv ./say.so XXXX/i686-pc-linux-gnu/lib/libsay.so
gcc -o test4 -lsay test.c
ldd ./test4
结果肯定是libsay.so找不到的.

好了,写到这吧,想起什么再加,有什么不对的地方也望大家多多提出来^^

------------------Skymoon作品,转贴请注明出处作者.
分享到:
评论

相关推荐

    Boost程序库完全开发指南:深入C++“准”标准库+

    Boost程序库完全开发指南:深入C++“准”标准库+Boost程序库完全开发指南:深入C++“准”标准库+Boost程序库完全开发指南:深入C++“准”标准库+Boost程序库完全开发指南:深入C++“准”标准库+Boost程序库完全开发...

    boost程序库完全开发指南深入c++准标准库第3版-目录

    boost程序库完全开发指南深入c++准标准库第3版-目录

    深入实践Boost:Boost程序库开发的94个秘笈

    《深入实践Boost:Boost程序库开发的94个秘笈》是一本专为软件开发者设计的指南,旨在帮助读者深入理解和充分利用Boost库。Boost库是C++编程中的一个强大工具集,它提供了一系列高质量的、经过广泛测试的库,旨在...

    STM32 LL库使用指南PDF

    STM32 LL库使用指南为开发者提供了关于STM32微控制器(MCU)的低层抽象层(LL)库的详细介绍。LL库是一个寄存器级别的API集合,允许开发者直接对硬件寄存器进行操作,以实现更高的效率。这种库是在STM32Cube库1.1.0...

    VC++动态链接库(dll)编程深入浅出-----PDF和源码

    静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。  对动态链接库,我们还需建立如下概念:  (1)DLL 的...

    2021最新最全AD封装库3D封装库元件库.zip

    标题中的“2021最新最全AD封装库3D封装库元件库.zip”指的是一个包含各种封装库、3D模型库以及元件库的压缩文件,适用于Altium Designer(AD)设计软件。这个资源集合了2021年截止时最新的电子设计组件,包括电路板...

    VC++动态链接库(DLL)编程深入浅出(汇总+全部源码)

    《VC++动态链接库(DLL)编程深入浅出》是一本专门为VC++开发者设计的教程,专注于DLL(Dynamic Link Library)编程技术。DLL是Windows操作系统中的一个重要组件,它允许多个程序共享同一段代码和数据,从而节省内存并...

    ALtium Design 全套封装库

    《ALtium Design 全套封装库:电路设计与单片机嵌入式的基石》 在电子设计领域,ALtium Designer是一款广受好评的电路...通过深入理解和有效利用这套封装库,设计师可以更好地应对各种挑战,创造出更加优秀的产品。

    dll动态链接库和c++依赖库缺失修复工具

    总的来说,处理dll动态链接库和C++依赖库缺失问题需要对系统组件有深入的理解,并且要有耐心和细心去排查每一个可能导致问题的原因。使用专门的修复工具可以简化这个过程,但同时也需要注意工具的来源,确保其安全...

    ARCGIS出图常用符号库大全,32个非常齐全

    仿Google风格地图符号库 山洪灾害调查字体与符号库 影像地图符号库 林业图例 水利符号库 矢量地图符号库 体育运动符号.zip 场所-彩色.zip 1264_地图常用符号.zip Arcgis制图规范符号库.rar ArGIS符号库-1:1万地形图...

    ANSYS Workbench材料库

    ANSYS Workbench是一款广泛使用的工程仿真软件,它集成了多种分析工具,如结构力学、热力学、流体力学等,为工程师提供了强大...对于经验丰富的用户,深入研究材料库可以进一步优化他们的仿真策略,解决更复杂的问题。

    HAL库手册非常全面

    在“HAL库手册”中,包含了关于HAL库的详细使用指南,对于初学者来说是非常宝贵的资源。 首先,HAL库函数手册通常包含以下几个部分: 1. **简介**:这部分会介绍HAL库的基本概念、设计目标和优点。HAL库旨在为不同...

    Rust标准库内部原理(inside-rust-std-library).epub

    Rust标准库内部原理(inside-rust-std-library)

    深入理解Android卷1全

    2.3.1 加载JNI库 / 16 2.3.2 Java的native函数和总结 / 17 2.4 JNI层MediaScanner的分析 / 17 2.4.1 注册JNI函数 / 18 2.4.2 数据类型转换 / 22 2.4.3 JNIEnv介绍 / 24 2.4.4 通过JNIEnv操作jobject / 25 2.4.5 ...

    GJB 5716-2006开发库、受控库、产品库通用要求.pdf

    GJB 5716-2006开发库、受控库、产品库通用要求.pdf

    C语言函数库手册(转载)

    c函数库查询 用法一条龙服务,适合新手哦

    STM32F4官方最新固件库

    STM32F4系列是意法半导体(STMicroelectronics)推出的一款高性能、低功耗的32位微控制器,基于ARM Cortex-M4内核。...开发者可以通过这些库文件深入理解STM32F4的外设功能,并快速构建自己的应用系统。

    STM32F4系列完整固件库

    通过阅读和理解STM32F4xx固件库中的源码,开发者可以深入学习微控制器的内部工作原理,提升自己的嵌入式系统设计能力。 此外,STM32F4固件库还支持MDK(Keil uVision)、IAR、GCC等主流的编译工具,兼容多种RTOS...

    ardiuno wire库文件

    Arduino Wire库为用户提供了简单易用的API,使得Arduino用户无需深入了解I2C协议的细节就能进行I2C通信。Wire库包含了`Wire.begin()`、`Wire.beginTransmission()`、`Wire.write()`、`Wire.endTransmission()`等一...

    红外遥控码库

    红外遥控码库是一种用于控制各种电子设备的代码集合,它包含了一组预定义的指令,这些指令能够被红外遥控器发送以实现对电视、空调、音响等家电的远程操作。在给定的资源中,提供了约50至60种不同设备的红外遥控码,...

Global site tag (gtag.js) - Google Analytics