跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

这是您第一次登陆到 developerWorks,已经自动为您创建了您的概要文件。 选择您概要文件中可以公开的信息的信息(如姓名、国家/地区,以及公司),这些信息同时也会与您所发布的内容相关联。 您可以随时更新您的 IBM 账号。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

学习 Linux,101: 管理共享库

找到并加载程序所需要的共享库

Ian Shields, 资深程序员, EMC
Ian Shields
Ian Shields 参与 developerWorks Linux 专区的许多 Linux 项目。他是 IBM 北卡罗来纳州 Research Triangle Park 的一名高级程序员。他于 1973 年作为一名系统工程师加入 IBM 位于澳大利亚堪培拉的子公司。此后,在加拿大蒙特利尔和北卡罗来纳州 RTP 从事通信系统和普适计算。他拥有多项专利。他毕业于 Australian National University,本科学位是纯粹数学和哲学。他拥有北卡罗来纳州州立大学的计算机硕士和博士学位。
(An IBM developerWorks Contributing Author)

简介: 学习如何为 Linux 中可执行程序选择共享库以及如何加载共享库。 您可以使用本文中的资料来学习,备考 Linux 系统管理员认证的 LPI 101 考试,当然也可以是出于爱好而学习。

查看本系列更多内容

发布日期: 2010 年 4 月 15 日
级别: 中级 其他语言版本: 英文
访问情况 : 8674 次浏览
评论: 


关于本系列

本系列文章帮助您学习 Linux 系统管理任务相关知识。 您可以使用本系列文章中的资料准备 Linux Professional Institute Certification 级别 1 (LPIC-1)考试

请参见我们的 学习 Linux,101:LPIC-1 路线图,查看本系列中各文章的介绍和链接。该路线图目前仍然在更新中,目前反映的最新内容是 LPIC-1 考试的最新目标(2009 年 4 月)。在我们完成文章后,我们会将其添加到路线图中。但是,与此同时,您可以在我们的 LPI 认证考试准备教程 中找到类似资料的早期版本,这些内容支持 2009 年 4 月以前发布的 LPIC-1 目标。

概述

在本文中,学习如何找到并加载 Linux 可执行程序所需的共享库。 您将学到:

  • 确定程序需要哪些共享库
  • 了解系统如何找到共享库
  • 加载共享库

本文将帮助您准备 Linux Professional Institute's Junior Level Administration (LPIC-1) 考试 101 中主题 102 下的目标 102.3。该目标的权值为 1。

先决条件

为了更有效利用这部分内容,您需要具有基本的 Linux 知识, 并需要准备一个 Linux 系统,用于练习本文介绍的命令。 有时候不同版本的程序输出格式不同,因此您所得到的结果未必总是与此处的相同。 特别要指出,这里的很多例子来自 64 位系统。 我们引入了很多来自 32 位系统的例子,来说明两者的显著差异 。


静态与动态链接

联系 Ian

Ian 是我们的一位最受欢迎、最高产的作者。查看 Ian 的个人信息,与 Ian、其他作者和 My developerWorks 的其他读者联系。

Linux 系统当中有两类可执行程序:

  • 静态链接 可执行程序包含了其所需的全部库函数;所有库函数都连接到程序中。 这类程序是完整的,其运行不需要外部库的支持。 静态链接程序的优点之一是其安装之前不需要做环境准备工作 。
  • 动态链接 可执行程序要小得多;这类程序运行时需要外部共享 函数库的支持,因此好像并不完整。除了程序体小之外,动态链接允许程序包指定必须的库,而不必将库装入程序包内。动态链接技术还允许多个运行中的程序共享一个库,这样就不会出现同一代码的多份拷贝共占内存的情况了。由于这些原因,当前多数程序采用动态链接技术。

在许多 Linux 系统中有个很有趣的例子, ln 命令(/bin/ln),用于在文件之间生成链接, 不论是 链接还是(或者 符号)链接。 该命令使用共享库。 共享库经常会引入库通用名与库特定层级之间的符号链接, 所以如果因为某些原因链接没有出现或已断开, 那么 ln 命令本身就无法起作用,会发生循环错误。 为避免此类问题,一些 Linux 系统包含了 ln sln(/sbin/sln)之间的静态链接版本。 清单 1 说明了采用动态链接的 ln 与采用静态链接的 sln之间大小的显著差别。 该例子来自 Fedora 12 64-bit 系统。


清单 1. sln 与 ln 的大小
				
[ian@echidna ~]$ ls -l /sbin/sln /bin/ln
-rwxr-xr-x. 1 root root  47384 2010-01-12 09:35 /bin/ln
-rwxr-xr-x. 1 root root 603680 2010-01-04 09:07 /sbin/sln


需要哪些库?

尽管当前的 LPI 考试不涉及此类问题, 但您还是应当明确当今很多 Linux 系统所运行的硬件同时支持 32 位及 64 位程序。 很多库同时编译为 32 位及 64 位版本。 64 位版本通常存放在文件系统的 /lib64 目录树中,而 32 位版本则位于 /lib 目录树中。 您可能会在 64 位 Linux 系统中同时发现 /lib/libc-2.11.1.so 以及 /lib64/libc-2.11.1.so 。 这两个库允许 32 位及 64 位 C 程序在 64 位 Linux 系统当中运行。

关于 ldd 命令

除了明确静态链接程序比较大之外,如何确定程序是否为静态链接? 如果是静态链接,如何知道它需要哪些库?ldd 命令能够回答这些问题。 如果您正在运行 Debian 或 Ubuntu之类的程序, 可能找不到 sln 命令,因此您可能会检查 /sbin/ldconfig 能否执行。 清单 2 展示了 ldd 命令关于 ln 以及 sln 执行情况, 还有 ldconfig 可执行情况的输出。该例子来自 Fedora 12 64-bit 系统(echidna)。 为了进行对比,还列出了来自旧版本 Fedora 8 32-bit 系统(pinguino)关于 /bin/ln 的输出 。


清单 2. ldd 关于 sln 以及 ln 的输出
				
[ian@echidna ~]$ #Fedora 12 64-bit
[ian@echidna ~]$ ldd /sbin/sln /sbin/ldconfig /bin/ln
/sbin/sln:
        not a dynamic executable
/sbin/ldconfig:
        not a dynamic executable
/bin/ln:
        linux-vdso.so.1 =>  (0x00007fff644af000)
        libc.so.6 => /lib64/libc.so.6 (0x00000037eb800000)
        /lib64/ld-linux-x86-64.so.2 (0x00000037eb400000)

[ian@pinguino ~]$ # Fedora 8 32-bit
[ian@pinguino ~]$ ldd /bin/ln
        linux-gate.so.1 =>  (0x00110000)
        libc.so.6 => /lib/libc.so.6 (0x00a57000)
        /lib/ld-linux.so.2 (0x00a38000)

因为 ldd 与动态链接有关, 这告诉我们 sln 与 ldconfig 都是静态链接的, 它们 “不是一个动态可执行文件”, 同时告诉我们 ln 命令所需共享库的名字(linux-vdso.so.1、libc.so.6 和 /lib64/ld-linux-x86-64.so.2)。 注意,.so 指明这些是共享库 或者动态库。 这一输出结果提供了您想了解的三类不同信息。

linux-vdso.so.1
是 Linux Virtual Dynamic Shared Object,这一点我们稍后讨论。 您还可以在 Fedora 8 中发现 linux-gate.so.1。
libc.so.6
具有指向 /lib64/libc.so.6. 的指针。
/lib64/ld-linux-x86-64.so.2
指向其他库的绝对路径。

在清单 3 中,通过 ls -l 命令, 发现最后的两个库依次与库的特定版本之间具有符号链接。 该例子来自 Fedora 12 64-bit系统 。


清单 3. 库符号链接
				
[ian@echidna ~]$ ls -l /lib64/libc.so.6 /lib64/ld-linux-x86-64.so.2
lrwxrwxrwx. 1 root root 12 2010-01-14 14:24 /lib64/ld-linux-x86-64.so.2 -> ld-2.11.1.so
lrwxrwxrwx. 1 root root 14 2010-01-14 14:24 /lib64/libc.so.6 -> libc-2.11.1.so

Linux Virtual Dynamic Shared Objects

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

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


动态加载

通过前面的内容,您会很奇怪的发现 /lib/ld-linux.so.2 以及它的 64 位版本,/lib64/ld-linux-x86-64.so.2,看上去都像是共享库, 都在其各自的权限内可执行。它们是负责实现动态加载的代码。 它们读取可执行程序的头信息,这些信息采用 Executable and Linking Format 或者(ELF)格式。 它们通过这些消息,来确定哪些库是必须的,以及哪些库需要加载。 然后执行动态链接,把可执行程序当中所有的地址指针与需要加载的库联系起来, 这样程序就可以运行了。

有关 ld-linux.so 的帮助也描述了 ld.so, 它为早期的 a.out 二进制格式提供类似的功能。 清单 4 举例说明, 如何利用 ld-linux.so 的 --list 选项来显示与清单 2 当中ln命令 与 ldd 命令显示结果相同的内容。


清单 4. 利用 ld-linux.so 来展示库需求
				
[ian@echidna ~]$ /lib64/ld-linux-x86-64.so.2 --list /bin/ln
        linux-vdso.so.1 =>  (0x00007fffc9fff000)
        libc.so.6 => /lib64/libc.so.6 (0x00000037eb800000)
        /lib64/ld-linux-x86-64.so.2 (0x00000037eb400000)

[ian@pinguino ~]$ /lib/ld-linux.so.2 --list /bin/ln
        linux-gate.so.1 =>  (0x00110000)
        libc.so.6 => /lib/libc.so.6 (0x00a57000)
        /lib/ld-linux.so.2 (0x00a38000)

注意,两个清单中的十六进制地址有可能不同。 在两次运行 ldd 命令时,该地址也可能不相同。


动态库配置

动态加载器怎样找到可执行程序?对于 Linux 当中的很多问题, 都在 /etc 当中有相应的配置文件。 事实上,有两个配置文件,/etc/ld/so/conf 以及 /etc/ld.so.cache。 清单 5 展示了 Fedora 12 64 位系统当中 /etc/ld.so.conf 的内容。 注意,/etc/ld.so.conf 文件指明所有来自 ld.so.conf.d 子目录的 .conf 文件都应当被包含。 旧版系统中可能包含 /etc/ld/so/conf 的所有条目, 而不包含 /etc/ld.so.conf.d 目录中的条目。 您的系统当中 /etc/ld.so.conf 或者 /etc/ld.so.conf.d 目录的实际内容可能与此处有所差别。


清单 5. /etc/ld.so.conf 的内容
				
[ian@echidna ~]$ cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
[ian@echidna ~]$ ls /etc/ld.so.conf.d/*.conf
/etc/ld.so.conf.d/kernel-2.6.31.12-174.2.19.fc12.x86_64.conf
/etc/ld.so.conf.d/kernel-2.6.31.12-174.2.22.fc12.x86_64.conf
/etc/ld.so.conf.d/kernel-2.6.31.12-174.2.3.fc12.x86_64.conf
/etc/ld.so.conf.d/mysql-x86_64.conf
/etc/ld.so.conf.d/qt-x86_64.conf
/etc/ld.so.conf.d/tix-x86_64.conf
/etc/ld.so.conf.d/xulrunner-64.conf

程序需要快速加载,因此可以使用 ldconfig 命令来处理 ld.so.conf 文件、 所有 ld.so.conf.d 包含的文件、所有受信目录当中的库、 /lib 和 /usr/lib,以及命令行当中所支持的其他内容 。 ldconfig 命令在 /etc/ld.so.cache 中为最近使用过的共享库生成必须的链接和 cache 。 动态加载器利用来自 ld.so.cache 的缓存文件来定位需要动态加载及链接的文件。 如果改变了 ld.so.conf(或在 ld.so.conf.d 中增加新文件), 必须运行 ldconfig 命令(以 root 用户身份)来重构 ld.so.cache 文件。

通常,可在不加参数的情况下, 使用 ldconfig 命令来重构 ld.so.cache 文件。 可以利用一些参数来改变这一使用习惯。 一般情况下,可使用 man ldconfig 来获得更多信息。 清单 6 举例说明利用参数 -p 来展示 ld.so.cache 的内容。


清单 6. 使用 ldconfig 来展示 ld.so.cache
				
[ian@lyrebird ian]$ /sbin/ldconfig -p | less
1602 libs found in cache `/etc/ld.so.cache'
        libzip.so.1 (libc6,x86-64) => /usr/lib64/libzip.so.1
        libz.so.1 (libc6,x86-64) => /lib64/libz.so.1
        libz.so (libc6,x86-64) => /usr/lib64/libz.so
        libx86.so.1 (libc6,x86-64) => /usr/lib64/libx86.so.1
        libx11globalcomm.so.1 (libc6,x86-64) => /usr/lib64/libx11globalcomm.so.1
        libxul.so (libc6,x86-64) => /usr/lib64/xulrunner-1.9.1/libxul.so
        libxtables.so.2 (libc6,x86-64) => /usr/lib64/libxtables.so.2
        libxslt.so.1 (libc6,x86-64) => /usr/lib64/libxslt.so.1
        libxslt.so (libc6,x86-64) => /usr/lib64/libxslt.so
        libxpcom.so (libc6,x86-64) => /usr/lib64/xulrunner-1.9.1/libxpcom.so
        libxml2.so.2 (libc6,x86-64) => /usr/lib64/libxml2.so.2
        libxml2.so (libc6,x86-64) => /usr/lib64/libxml2.so
       ...
        libABRTdUtils.so.0 (libc6,x86-64) => /usr/lib64/libABRTdUtils.so.0
        libABRTUtils.so.0 (libc6,x86-64) => /usr/lib64/libABRTUtils.so.0
        ld-linux.so.2 (ELF) => /lib/ld-linux.so.2
        ld-linux-x86-64.so.2 (libc6,x86-64) => /lib64/ld-linux-x86-64.so.2


加载指定的库

如果您正在运行需要特定旧版共享库支持的程序, 或者您正在开发新的共享库或现有共享库的新版本, 您可能希望覆盖加载器的默认搜索路径。 使用安装在 /opt 树当中特定于产品共享库的脚本文件可能也需要这一功能。

就如同可通过设置变量 PATH 来为可执行程序指定搜索路径一样, 可以将变量 LD_LIBRARY_PATH 设置为用冒号分割的, 为加载 ld.so.cache 当中所指定的共享库需要搜索的目录清单。 例如,可使用命令:

export LD_LIBRARY_PATH=/usr/lib/oldstuff:/opt/IBM/AgentController/lib

参见下面的 参考资料 来获得细节信息以及相关文章的链接。


参考资料

学习

获得产品和技术

讨论

关于作者

Ian Shields developerWorks 投稿作者

Ian Shields 参与 developerWorks Linux 专区的许多 Linux 项目。他是 IBM 北卡罗来纳州 Research Triangle Park 的一名高级程序员。他于 1973 年作为一名系统工程师加入 IBM 位于澳大利亚堪培拉的子公司。此后,在加拿大蒙特利尔和北卡罗来纳州 RTP 从事通信系统和普适计算。他拥有多项专利。他毕业于 Australian National University,本科学位是纯粹数学和哲学。他拥有北卡罗来纳州州立大学的计算机硕士和博士学位。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux
ArticleID=482919
ArticleTitle=学习 Linux,101: 管理共享库
publish-date=04152010
author1-email=ishields@us.ibm.com
author1-email-cc=