JackieMium / my_blog

在 Issues 中建立的个人博客
GNU General Public License v3.0
31 stars 12 forks source link

关于源码编译的基础知识 via LinuxSir (上篇) #6

Open JackieMium opened 6 years ago

JackieMium commented 6 years ago
2017-05-18 

这一篇博文很长,我分成下上下两篇。

内容来自已经不存在的 LinuxSir 社区(RIP)的 LFS 板块,当时很多东西我并不懂,只是觉得很有趣所以复制粘贴到我的笔记软件里了。 几年之后我对 Linux 熟悉一些,也用过 Gentoo 很久并一直认为这是我最喜欢的 Linux 发行版。虽然我对源码编译很感兴趣,但是知之甚少。偶然再看到这篇博客很多东西有种豁然开朗的感觉。再想回去 LinuxSir 社区,发现它早已不复存在。

我现在仍然觉得这两篇博文很有趣,并且打算还保留它们。如果原作者看到的话,有什么问题请和我联系。

以下时原文,有少量改动。


如果不出意外的话,会出现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环境变量中的地址. 如果系统在这一步也没发现我们需要的库呢. /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 

为了说明顺序,我们做如下很危险的实验:

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 

恢复系统正常.