http://ads.buzzcity.net/adpage.php?partnerid=40096
分类: LINUX
2010-01-30 11:09:25
1. 简介
什么是 Prelink ? 它能为我做什么 ?
许多的应用程式使用共用函式库. 在这些程式被执行的时候, 共用函式库会被读进记忆体中, 并且跟程式中所参用到的符号(symbol)连结起来. 对大多的小程式而言, 通常这样的动态连结非常快. 但是对一些依存於大量函式库的 C++ 程式而言, 动态连结却可能花上不少的时间.
在大多数的系统上, 函式库并不会常常被更动, 每次程式被执行时所进行的连结动作都是完全相同的,Prelink 利用这点, 将程式与函式库连结的方式弄出来记录在执行档中, 达成"预先连结"的效果. 你需要 glibc 中的 ld-linux.so 来进行连结, 要能够认出"预先连结"的纪录则需要 >=glibc-2.3.1-r2.
"预先连结"能够节省应用程式的启动时间. 以典型的 KDE 程式为例, 程式的读取时间能够减少 50% 那么多. 唯一必要的维护只有每当被"预先连结"过的执行档所连结到的函式库有所更新时, 需要再次执行 prelink.
摘要
2. 设定 Prelink
安装所需程式
注释: 我们假设你的系统是 Gentoo-1.4, 并且是使用 gcc-3.2 与 binutils-2.13.90.0.xx 以后版本编出来的. 这样编出来的执行档才能够进行"预先连结". |
警告: 你必须已经安装了 glibc-2.3.1-r2 或更新的版本, 不然 prelink 会搞烂你的执行档! |
先更新你的 portage tree, 因为大多数需要用到的程式都还新, 而常常加入新的错误修正.
代码 2.1: 更新你的 portage tree |
# emerge sync |
接下来确定你已经安装了 portage-2.0.46 或更新版本. 这样 portage 才能够认出"预先连结"过的执行档, 在使用者要反安装时才能正确移除. 需要这样做是因为"预先连结"会造成执行档的 MD5sum 值改变.
代码 2.2: 确保 Portage 的版本 |
# emerge ">=portage-2.0.46" |
现在你可以开始安装"预先连结"工具了. emerge 程式能够自动测试你的系统是否能够安全正常地进行"预先连结".
代码 2.3: 安装 Prelink |
# emerge prelink |
有不少人在安装 prelink 的时候遭遇到测试失败的错误讯息. 这些测试是为了安全理由才被放上的, 如果你关闭这些测试, prelink 的行为将无法保证. 这些错误大多是由这些核心套件造成: binutils, gcc, 及 glibc. 试试看照以上顺序重新安装这些套件.
注释: 小提示: 如果你在尝试自行手动编译测试 prelink (./configure ; make ; make check )时遭遇到错误, 你可以察看 testsuite 目录中的 *.log 档案, 它们可能能给你一些有用的线索. |
如果你能提出一套能在多个系统上复现产生 emerge 错误的步骤, 请 e-mail 给 .
组态设定
Portage 会自动产生 /etc/prelink.conf 档告诉 prelink 哪些档案需要"预先连结".
可惜的是你没办法"预先连结"旧版 binutils 编出来的程式. 大多这些来自预先编好, 执行档发布的套件都被安装在 /opt. 编写以下档案能告知 prelink 不要尝试去"预先连结"它们.
代码 2.4: /etc/env.d/99prelink |
PRELINK_PATH_MASK="/opt" |
注释: 你可以用冒号分隔加入更多的目录在这个清单中. |
3. 进行"预先连结"
Prelink 使用方式
我们可以用下列指令来"预先连结"所有列在 /etc/prelink.conf 中的目录里的执行档.
代码 3.1: 预先连结清单中的档案 |
# prelink -afmR |
警告: 有人发现如果你在磁碟空间吃紧的时候"预先连结"系统上所有执行档, 你的执行档有可能会被截断, 这样会弄爆你的系统. 你可以用 file 或 readelf 来检查执行档的状态. 或者每次在进行"预先连结"前先用 df -h 检查硬碟的剩余空间. |
每个选项的解说: | |
-a | "All": 对所有执行档进行"预先连结". |
-f | 强制 prelink 重新"预先连结"已经做过"预先连结"的执行档. 加上这个选项是因为 prelink 在看见做过"预先连结"的执行档的时候会 中止执行, 即使相依的函式库有更动过. |
-m | 节省虚拟定址分配. 如果你有一卡车的函式库要"预先连结"就会需要这个选项. (译注: 这里的原文 virtual memory space 是有问题的, 应该是 virtual address space 比较正确.) |
-R | Random -- 用乱数进行定址分配, 这样可以增进安全性对缓冲区溢出(buffer overflow) 攻击的抵抗能力. |
注释: 如想知道更多的选项细节, 请见 man prelink. |
4. 已知问题与处理
"Cannot prelink against non-PIC shared library"
这个问题是由那些没有使用 -fPIC gcc 选项编译全部目的档(object file)的问题函式库所造成.
以下是一份问题函式库, 以及当你遇到上述问题时需要重新安装的对应套件.
代码 4.1: 修正 |
// 对 ORBit 函式库, /usr/lib/libIIOP.so.0.5.17 |
注释: 许多函式库有静态连结到 zlib 与/或 tcp-wrappers, 所以先试著安装它们, 并重新安装问题函式库. |
如果你在"预先连结" QT/KDE 时遇到问题, 先试著更新到 >=x11-base/xfree-4.2.1-r2 与 >=x11-libs/qt-3.1.0-r1 套件. 如果 QT 还是不过的话, 则可以试著在 qt 的 ebuild 档中加上 myconf="-no-xinerama ${myconf}" 来编译不包含 xinerama 支援的 QT .
这里有一些函式库是还没修正或是无法修正的:
如果你的问题函式库没有在列表中, 请回报, 最好能够附上一份为相映的 CFLAGS 加上 -fPIC 选项的修补档.
当对档案进行"预先连结"的时候发生中止, 像是 "1631 Aborted ...."
你需要为 prelink 加上 -f 参数. 也就是说, 如果你要对整个系统重新进行"预先连结"的话, 用 prelink -af.
"<档名>: error while loading shared libraries: unexpected reloc type..."
这个错误在 2002/11/18 时, 在 sys-libs/glibc-2.3.1-r2 中已修正了, 如果你还在用旧版本的话, 请重新安装 glibc.
已知 prelink -u -a -m ; prelink -a -m 可能也有用. 如果这些方法都失败的话就 prelink -u
我的 nVIDIA openGL 函式库发生问题
nvidia-glx 套件中具有加速功能的 openGL 函式库是用非标准的方式编译出来的, 所以 prelink 会发出警告. 这没什么好担心的, 而且除了 nVIDIA 以外没有人能够进行修正. 如果你不需要 3D 加速的话, 你也可以随时换回 XFree 内建的 libGL.so. XFree 的 nvidia 驱动程式足以正常运作了.
当我对整个系统进行"预先连结"之后, 一些静态连结的执行档不会动了
就 glibc 而言是没有 100% 的静态连结执行档这回事的. 如果你是用 glibc 静态编译了一个执行档, 则这个执行档还是有可能会依存其它系统档案. 以下是 Dick Howell 的解释.
"我想你的想法是认为所有相依函式库都会在下载下来的档案之中(译注: 下载下来的静态连结执行档), 所以它不用依赖任何本地端的函式库. 但是很可惜的, 对於 Linux, 甚至我想对於任何使用 glibc 的系统, 这样的想法并不正确. 有个叫做 "libnss" 的东西 (名称服务选择 name service switch, 也有人管它叫网路安全系统, network security system), 它提供了一些处理认证资料库, 网路资讯, 以及一些其它东西的函式. 它被设计来使应用程式可以直接适应於不同的网路环境. 这是个聪明的设计, 但是使用不同系统的 glibc 却可能对它的载入造成问题. 但它又根据不同的系统设定而有所不同, 所以你没办法对它作静态连结. 我想问题就是这样发生的, 程式静态连结了不同系统的 glibc 函式库, 主要是 "libpthread", "libm", "libc", 这些函式库对 "libnss" 呼叫了不相容的函式."
Prelink 发出 "prelink: dso.c:306: fdopen_dso: Assertion `j == k' failed." 并中止了
这是个已知的问题, 有亲切的解说. Prelink 没办法处理用 UPX 压缩过的执行档. 直到了 prelink-20021213 都还没有修正, 你只能在进行"预先连结"时把这些压缩过的执行档藏起来. 你可以参考上方的 来简单地完成这件事.
我使用 grsecurity 而"预先连结"似乎无法运作
如果你要在一个使用 grsecurity 使 mmap() 基底位址乱数化(randomized mmap() base)的系统上使用"预先连结", 你必须把 /lib/ld-2.3.*.so 的 "randomized mmap() base" 设定关闭. 你可以用 chpax 公用程式来完成这个动作,但是这必须在该档没有在使用时才能进行. (比方说用救援光碟开机)
5. 结论
"预先连结"可以大大地增进一些大型应用程式的启动时间. Portage 也有内建的支援. "预先连结"也很安全, 发生问题的时候你可以还原任何的执行档. 你只要记得当更新了 glibc 或其它有被"预先连结"到的函式库时必须重新执行 prelink. 总之最后, 祝你好运!