参见Linux 共享库指南.

库文件是怎样被使用的

在基于 GNU glibc 的系统中,包括所有的 Linux 操作系统,启动一个可执行的带链接库程序时,会自动启动一个载入程序。 在 Linux 系统中,这个载入程序叫做 /lib/ld-linux.so.X (X 是版本号),64 位系统中这个文件是 /lib64/ld-linux-x86-64.so.X。这个载入程序会查找并载入程序所使用的其他共享库至内存中。

共享库文件查询的目录存放在 /etc/ld.so.conf 中。注意,对于 RedHat Linux 系统,/etc/ld.so.conf 这个文件中并没有包含 /usr/local/lib 这个常用的库文件目录。

如果只是想要覆盖一个库文件的某些函数,但保留其余的内容,可以将覆盖库文件名(.o 后缀文件)保存至 /etc/ld.so.preload 文件中。这些覆盖库文件会比标准库文件优先读取,这通常用于紧急的版本补丁。

每次都查找 /etc/ld.so.conf 中的目录是很低效的,因此 ldconfig 程序会读取 /etc/ld.so.conf 文件中的所有目录中的文件,将库文件 real name 设置合适的软链接 soname,并将这些文件名缓存至 /etc/ld.so.cache 中。这样会大大加快库文件的寻找速度。

特殊的库文件 linux-vdso.so,在早期的 x86 处理器中,用户程序与管理服务之间的通信通过软中断实现。 随着处理器速度的提高,这已成为一个严重的瓶颈。 自 Pentium® II 处理器开始,Intel® 引入了 Fast System Call 装置来提高系统调用速度, 即采用 SYSENTERSYSEXIT 指令,而不是中断。

linux-vdso.so.1 是个虚拟库,即 Virtual Dynamic Shared Object,它只存在于程序的地址空间当中。 在旧版本系统中该库为 linux-gate.so.1。 该虚拟库为用户程序以处理器可支持的最快的方式(对于特定处理器,采用中断方式;对于大多数最新的处理器,采用快速系统调用方式)访问系统函数提供了必要的逻辑 。

共享库相关的环境变量

LD_LIBRARY_PATH

在 Linux 系统中,LD_LIBRARY_PATH 是冒号分隔的一组目录,这些目录在查找库文件时将会比标准的库文件目录优先查找。在 debug 一个新共享库或者在特殊目的中使用非标准的库文件时这个变量会很有用。LD_LIBRARY_PATH 对于开发和测试很有用,但最好不要作为生产环境使用。

如果不想使用 LD_LIBRARY_PATH 变量,可以直接调用载入程序并传递参数,例如:

/lib/ld-linux.so.2 --library-path PATH EXECUTABLE

注意:在生产环境中一定不要使用 LD_LIBRARY_PATH,详情可以参考 LD_LIBRARY_PATH Is Not The AnswerWhy LD_LIBRARY_PATH is badAvoiding LD_LIBRARY_PATH

这里总结几个原因:

LD_LIBRARY_PATH 中的库文件会比系统默认库文件载入的优先级更高,如果在 LD_LIBRARY_PATH 中的目录权限设置不当,导致他人放入了带有后门的版本的系统核心库,系统的安全性将大大降低,这是为什么具有 suid 属性的程序会完全的忽略掉 LD_LIBRARY_PATH 这个变量。 由于 LD_LIBRARY_PATH 定义的目录中的库文件将被优先加载,因此当系统更新了库文件位于 /lib64/ 等目录中后,系统还是会使用老版本的库文件。 有时一些预编译的程序可能使用特定位置的第 3 方动态库文件,理想的情况是将这些库文件一同拷贝至主机中,并在预安装过程中重新链接库文件。另一种做法是在一个包装程序或脚本中定义 LD_LIBRARY_PATH 变量指定库文件,这种情况下,LD_LIBRARY_PATH 是会被继承至程序中的,从而可能扰乱系统运行。

LD_PRELOAD

作用和 /etc/ld.so.preload 一样