libc折腾记录

libc折腾记录

从升级一个虚拟机的Linux系统的glibc引出来一大堆东西,在此记录一下,其实底层的东西也没有那么可怕,抽丝剥茧一点点分析,也能很快理出头绪。

一个开始

起因,太年轻了,竟然想手动升级glibc,一句sudo mv libc.so.6 libc.so.6.bak(我没在root下运行,而是使用sudo的,真是伏笔),然后下意识ls一下,然后就没有然后了。

#ls
ls: error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory

Linux系统几乎任何程序都依赖于glibc,我把glibc的动态链接库重命名了当然只要是个程序都运行不了了。怎么办,好在是虚拟机,很快我就百度到了方法。

#LD_PRELOAD=/lib/libc.so.6.bak ls

果然一切正常,ls可以正常运行,正当我以为找到了希望,想把系统还原的时候

#LD_PRELOAD=/lib/libc.so.6.bak sudo mv libc.so.6.bak libc.so.6

结果error了,这次我倒是一下就反应过来了。sudo是要清理环境变量的,我设置的LD_PRELOAD环境变量就没用了,当时年幼无知的我还不知道sudo -E这种指令。。。好在这是一台虚拟机,我干脆直接关机,把硬盘mount出来,在宿主机上把文件名还原了,启动电脑一切正常。

在这个告一段落的时机做一个小结,上面无非说明了以下几点:

1、libc.so.6是C库的动态链接库,系统几乎任何指令都需要,没了它之后连ls都不能运行,不能乱动。

2、LD_PRELOAD环境变量可以控制程序在查找动态链接库之前先把指定的库加载进来。

3、sudo会清理环境变量。(因此之后我升级libc的时候都先su root)

[task]
sudo -E是可以keep环境变量的

其次,sudo的配置文件里面有env_reset与env_keep两个选项,可以用来keep环境变量,也可以干脆关闭env_reset来保留所有环境变量。[/task]

4、虚拟机就是方便。

 

Linux的动态链接机制

先说句题外话,动态链接库,Linux下扩展名是.so,windows下的扩展名就是.dll。从三年级开始我就特别奇怪一个软件里面明明只要主程序就好,要那么多dll是干嘛的。哈哈,回想起来这个才是真·年幼无知啊。

回到正题,我们知道在编译的过程的最后一步是链接,这个过程是由ld实现的。这个ld是编译工具链里的。程序运行时负责查找加载动态库的程序也叫ld,一般在/lib或者/lib64下,名字类似ld-linux-x86-64.so.2,为了简便,同时体现它跟编译器ld的不同,我们称之为ld.so。这个程序的设置文件一般在/etc/ld.so.conf,配置文件每一行为一个ld.so查找链接库的路径,需要注意的是,除了这些路径,/usr/lib和/lib是默认查找的,不过他们的顺序在最后。对配置的修改并非即是生效的,因为ld.so并不是每次执行程序到文件夹中去搜索,而是根据一个索引,一般位于/etc/ld.so.cache。因此系统提供了ldconfig命令来根据配置文件的信息来配置ld.so.cache。需要指出的是,ld.so与ldconfig都是libc的一部分,可以看出libc对于Linux来说多么重要。

另外有很多以LD开头的环境变量会被ld.so读取,上文提到的LD_PRELOAD是其中一个,还有一个非常有用的环境变量就是LD_LIBRARY_PATH,看字面意思就知道说的是ld.so搜索动态链接库的path。说到这里我们就发现了一个非常有趣的事,我们知道如何去在运行时加载动态链接库,我们可以用环境变量来操控它所查找的文件夹,我们根本不需要系统来帮我们执行程序!让我们来看看这个令人激动的事实,我们可以使用自己的装载器,设置自己的库的路径来运行自己的程序。

比如,我们在一个系统上升级glibc的过程中,make install,发现失败了。现在系统任何命令都运行不了,ls会出现error。假设我们提前备份了整个/lib文件夹到/libbak/,尝试

#LD_PRELOAD=/libbak/libc.so.6 ls

仍然error,这时候怎么办?上面说的就有用了,我们有肯定能运行这个程序的方法

#LD_LIBRARY_PATH=/libbak /libbak/ld-linux-x86-64.so.2 /bin/ls

没错,可以运行!而一般网上的解决方法都是用live CD进入其它系统的环境来修复了。而我们已经知道了Linux装载动态链接库并运行程序的过程,系统出错了,乱了,我们可以自己来。

有了这些基础知识,我终于放心的升级了libc,几经折腾,最终成功!

 

其实在折腾libc的时候还发现了一个有趣的事情,libc.so.6是一个动态链接库,同时也是一个可执行程序,貌似ld.so也是这样,我自己编译了一个程序试图达到这种效果结果失败了,到底怎么做到的呢?

libc里还有一些有用的工具,如ldd等,都有些什么作用呢?

有机会再说吧。。


未分类

发表评论

电子邮件地址不会被公开。 必填项已用*标注