<?xml version='1.0' encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/xsl/guide.xsl" ?>
<!-- $Header: /var/www/www.gentoo.org/raw_cvs/gentoo/xml/htdocs/doc/tw/prelink-howto.xml,v 1.1 2004/05/30 08:31:42 bennyc Exp $ -->
<!-- rev 1.25 by Freak -->
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd">
<guide link="doc/tw/prelink-howto.xml">
<title>Gentoo Linux Prelink 指南</title>

<author title="Author">
  <mail link="cretin@gentoo.org">Stefan Jones</mail>
</author>
<author title="Editor"><!-- zhen@gentoo.org -->
  John P. Davis
</author>
<author title="Editor">
  <mail link="peesh@gentoo.org">Jorge Paulo</mail>
</author>
<author title="Editor">
  <mail link="swift@gentoo.org">Sven Vermeulen</mail>
</author>
<author title="Editor">
  <mail link="erwin@gentoo.org">Erwin</mail>
</author>
<author title="Translator">
  <mail link="k92902003@csie.ntu.edu.tw">Tien-Ren Chen</mail>
</author>
<author title="Reviewer">
  <mail link="bennyc@gentoo.org">Benny Chuang</mail>
</author>

<abstract>
这份指南用来解说如何利用 portage 2.0.46 以后的 prelink 支援.
</abstract>

<license/>

<version>1.4</version>
<date>September 7, 2003</date>


<chapter>
<title>简介</title>
<section>
<title>什么是 Prelink ? 它能为我做什么 ?</title>
<body>

<p>
许多的应用程式使用共用函式库. 在这些程式被执行的时候,
共用函式库会被读进记忆体中, 并且跟程式中所参用到的符号(symbol)连结起来.
对大多的小程式而言, 通常这样的动态连结非常快.
但是对一些依存於大量函式库的 C++ 程式而言, 动态连结却可能花上不少的时间.
</p>

<p>
在大多数的系统上, 函式库并不会常常被更动, 每次程式被执行时所进行的连结动作都是完
全相同的,Prelink 利用这点, 将程式与函式库连结的方式弄出来记录在执行档中, 
达成"预先连结"的效果. 你需要 glibc 中的 ld-linux.so 来进行连结, 要能够认出"预先
连结"的纪录则需要 &gt;=glibc-2.3.1-r2.
</p>

<p>
"预先连结"能够节省应用程式的启动时间.
以典型的 KDE 程式为例, 程式的读取时间能够减少 50% 那么多.
唯一必要的维护只有每当被"预先连结"过的执行档所连结到的函式库有所更新时,
需要再次执行 prelink.
</p>

</body>
</section>
<section>
<title>摘要</title>
<body>

<ul>
  <li>
    我们可以用一个就叫做 <path>prelink</path> 的程式来进行"预先连结".
    它能够修改执行档的内容, 使启动的时间变短.
  </li>
  <li>
    如果某个"预先连结"过的应用程式所依存的函式库有所变动,
    你必须重新"预先连结"这个应用程式, 不然速度上的增快将继续无法作用.
    也就是说, 每次你用 portage 更新一些套件而更新了一些函式库,
    这些函式库必须重新被"预先连结"起来.
  </li>
  <li>
    对执行档的更动是完全可逆的. <path>prelink</path> 拥有复原的功能.
  </li>
  <li>
    新版的 Portage 能够应付 <path>prelink</path> 对执行档的 MD5sum 与 mtime 造成的改变.
  </li>
  <li>
    你需要 glibc-2.3.1-r2 或更新版本, 以及 binutils-2.13.90.0.xx 或更新版本所编
    译出的执行档.
  </li>
</ul>

</body>
</section>
</chapter>

<chapter>
<title>设定 Prelink</title>
<section>
<title>安装所需程式</title>
<body>

<note>
我们假设你的系统是 Gentoo-1.4, 并且是使用 gcc-3.2 与 binutils-2.13.90.0.xx 以后
版本编出来的. 这样编出来的执行档才能够进行"预先连结".
</note>

<warn>
你必须已经安装了 glibc-2.3.1-r2 或更新的版本, 不然 <path>prelink</path> 会搞烂你
的执行档!
</warn>

<p>
先更新你的 portage tree, 因为大多数需要用到的程式都还新, 而常常加入新的错误修正.
</p>

<pre caption = "更新你的 portage tree">
# <i>emerge sync</i>
</pre>

<p>
接下来确定你已经安装了 portage-2.0.46 或更新版本.
这样 portage 才能够认出"预先连结"过的执行档, 在使用者要反安装时才能正确移除.
需要这样做是因为"预先连结"会造成执行档的 MD5sum 值改变.
</p>

<pre caption = "确保 Portage 的版本">
# <i>emerge ">=portage-2.0.46"</i>
</pre>

<p>
现在你可以开始安装"预先连结"工具了. emerge 程式能够自动测试你的系统是否能够安全
正常地进行"预先连结".
</p>

<pre caption = "安装 Prelink">
# <i>emerge prelink</i>
</pre>

<p>
有不少人在安装 prelink 的时候遭遇到测试失败的错误讯息.
这些测试是为了安全理由才被放上的, 如果你关闭这些测试, prelink 的行为将无法保证.
这些错误大多是由这些核心套件造成: binutils, gcc, 及 glibc. 试试看照以上顺序重新
安装这些套件.
</p>

<note>
小提示: 如果你在尝试自行手动编译测试 <c>prelink</c> (<c>./configure</c> ; 
<c>make</c> ; <c>make check</c> )时遭遇到错误, 你可以察看 testsuite 目录中的 
*.log 档案, 它们可能能给你一些有用的线索.
</note>

<p>
如果你能提出一套能在多个系统上复现产生 emerge 错误的步骤,
请 e-mail 给 <mail link="cretin@gentoo.org">Stefan Jones</mail>.
</p>

</body>
</section>
<section>
<title>组态设定</title>
<body>

<p>
Portage 会自动产生 <path>/etc/prelink.conf</path> 档告诉 <path>prelink</path> 哪
些档案需要"预先连结".
</p>

<p>
可惜的是你没办法"预先连结"旧版 binutils 编出来的程式.
大多这些来自预先编好, 执行档发布的套件都被安装在 <path>/opt</path>.
编写以下档案能告知 prelink 不要尝试去"预先连结"它们.
</p>

<pre caption="/etc/env.d/99prelink">
PRELINK_PATH_MASK="/opt"
</pre>

<note>
你可以用冒号分隔加入更多的目录在这个清单中.
</note>

</body>
</section>
</chapter>

<chapter>
<title>进行"预先连结"</title>
<section>
<title>Prelink 使用方式</title>
<body>

<p>
我们可以用下列指令来"预先连结"所有列在 <path>/etc/prelink.conf</path> 中的目录里
的执行档.
</p>

<pre caption = "预先连结清单中的档案">
# <i>prelink -afmR</i>
</pre>

<warn>
有人发现如果你在磁碟空间吃紧的时候"预先连结"系统上所有执行档,
你的执行档有可能会被截断, 这样会弄爆你的系统.
你可以用 <c>file</c> 或 <c>readelf</c> 来检查执行档的状态.
或者每次在进行"预先连结"前先用 <c>df -h</c> 检查硬碟的剩余空间.
</warn>

<table>
<tr>
  <th>每个选项的解说:</th>
</tr>
<tr>
  <th>-a</th>
  <ti>"All": 对所有执行档进行"预先连结".</ti>
</tr>
<tr>
  <th>-f</th>
  <ti>
    强制 <path>prelink</path> 重新"预先连结"已经做过"预先连结"的执行档.
    加上这个选项是因为 <path>prelink</path> 在看见做过"预先连结"的执行档的时候会
    中止执行, 即使相依的函式库有更动过.
  </ti>
</tr>
<tr>
  <th>-m</th>
  <ti>
    节省虚拟定址分配. 如果你有一卡车的函式库要"预先连结"就会需要这个选项.
    (译注: 这里的原文 virtual memory space 是有问题的, 应该是 virtual address 
    space 比较正确.)
  </ti>
</tr>
<tr>
  <th>-R</th>
  <ti>
    Random -- 用乱数进行定址分配, 这样可以增进安全性对缓冲区溢出(buffer overflow)
    攻击的抵抗能力.
  </ti>
</tr>
</table>

<note>
如想知道更多的选项细节, 请见 <c>man prelink</c>.
</note>

</body>
</section>
</chapter>

<chapter>
<title>已知问题与处理</title>
<section>
<title>&quot;Cannot prelink against non-PIC shared library&quot;</title>
<body>

<p>
这个问题是由那些没有使用 -fPIC gcc 选项编译全部目的档(object file)的问题函式库所
造成.
</p>

<p>
以下是一份问题函式库, 以及当你遇到上述问题时需要重新安装的对应套件.
</p>

<pre caption = "修正">
<codenote>对 ORBit 函式库, /usr/lib/libIIOP.so.0.5.17</codenote>
# <i>emerge "&gt;=sys-apps/tcp-wrappers-7.6-r4" ORBit</i>

<codenote>对 zlib 函式库, /usr/lib/libz.so.1.1.4</codenote>
# <i>emerge "&gt;=sys-libs/zlib-1.1.4"</i>

<codenote>对 svgalib, /usr/lib/libsvga.so.xx</codenote>
# <i>emerge "&gt;=media-libs/svgalib-1.9.16"</i>

<codenote>对 XFree openGL 函式库, libGLU.so.1</codenote>
# <i>emerge "&gt;=x11-base/xfree-4.2.1-r2"</i>

<codenote>对 libpcap.so.0.6</codenote>
# <i>emerge "&gt;=net-libs/libpcap-0.7.1-r2"</i>

<codenote>对 lcms 函式库, /usr/lib/liblcms.so.1</codenote>
# <i>emerge "&gt;=media-libs/lcms-1.09"</i>
</pre>

<note>
许多函式库有静态连结到 zlib 与/或 tcp-wrappers, 所以先试著安装它们,
并重新安装问题函式库. 
</note>

<p>
如果你在"预先连结" QT/KDE 时遇到问题, 先试著更新到
&gt;=x11-base/xfree-4.2.1-r2 与 &gt;=x11-libs/qt-3.1.0-r1 套件.
如果 QT 还是不过的话, 则可以试著在 qt 的 ebuild 档中加上 myconf="-no-xinerama 
${myconf}" 来编译不包含 xinerama 支援的 QT .
</p>

<p>
这里有一些函式库是还没修正或是无法修正的:
</p>

<ul>
  <li>
    wine 套件中的函式库, winex 也不例外.
    但是"预先连结"本来就无法对 MS Windows 执行档进行加速.
  </li>
  <li>
    media-video/mjpegtools 中的函式库
    <path>/usr/lib/liblavfile-1.6.so.0</path>.
  </li>
</ul>

<p>
如果你的问题函式库没有在列表中, 请回报,
最好能够附上一份为相映的 CFLAGS 加上 <c>-fPIC</c> 选项的修补档.
</p>

</body>
</section>
<section>
<title>当对档案进行"预先连结"的时候发生中止, 像是 &quot;1631 Aborted ....&quot;</title>
<body>

<p>
你需要为 <path>prelink</path> 加上 <c>-f</c> 参数.
也就是说, 如果你要对整个系统重新进行"预先连结"的话, 用 <c>prelink -af</c>.
</p>

</body>
</section>
<section>
<title>&quot;&lt;档名&gt;: error while loading shared libraries: unexpected
reloc type...&quot;</title>
<body>

<p>
这个错误在 2002/11/18 时, 在 <c>sys-libs/glibc-2.3.1-r2</c> 中已修正了,
如果你还在用旧版本的话, 请重新安装 glibc.
</p>

<p>
已知 <c>prelink -u -a -m</c> ; <c>prelink -a -m</c> 可能也有用.
如果这些方法都失败的话就 <c>prelink -u &lt;file&gt;</c> 吧.
</p>

</body>
</section>
<section>
<title>我的 nVIDIA openGL 函式库发生问题</title>
<body>

<p>
nvidia-glx 套件中具有加速功能的 openGL 函式库是用非标准的方式编译出来的,
所以 <path>prelink</path> 会发出警告.
这没什么好担心的, 而且除了 nVIDIA 以外没有人能够进行修正.
如果你不需要 3D 加速的话, 你也可以随时换回 XFree 内建的 libGL.so.
XFree 的 nvidia 驱动程式足以正常运作了.
</p>

</body>
</section>
<section>
<title>当我对整个系统进行"预先连结"之后, 一些静态连结的执行档不会动了</title>
<body>

<p>
就 glibc 而言是没有 100% 的静态连结执行档这回事的.
如果你是用 glibc 静态编译了一个执行档, 则这个执行档还是有可能会依存其它系统档案.
以下是 Dick Howell 的解释.
</p>

<p>
&quot;我想你的想法是认为所有相依函式库都会在下载下来的档案之中(译注: 下载下来的
静态连结执行档), 所以它不用依赖任何本地端的函式库. 但是很可惜的, 对於 Linux, 甚
至我想对於任何使用 glibc 的系统, 这样的想法并不正确. 有个叫做 &quot;libnss&quot;
的东西 (名称服务选择 name service switch, 也有人管它叫网路安全系统, network 
security system), 它提供了一些处理认证资料库, 网路资讯, 以及一些其它东西的函式.
它被设计来使应用程式可以直接适应於不同的网路环境. 这是个聪明的设计, 但是使用不同
系统的 glibc 却可能对它的载入造成问题. 但它又根据不同的系统设定而有所不同, 所以
你没办法对它作静态连结. 我想问题就是这样发生的, 程式静态连结了不同系统的 glibc 
函式库, 主要是 &quot;libpthread&quot;, &quot;libm&quot;, &quot;libc&quot;, 这些
函式库对 &quot;libnss&quot; 呼叫了不相容的函式.&quot;
</p>

</body>
</section>
<section>
<title>Prelink 发出 &quot;prelink: dso.c:306: fdopen_dso: Assertion
`j == k' failed.&quot; 并中止了</title>
<body>

<p>
这是个已知的问题, <uri link="http://bugs.gentoo.org/show_bug.cgi?id=13878">
这里</uri> 有亲切的解说. Prelink 没办法处理用 UPX 压缩过的执行档. 直到了 
prelink-20021213 都还没有修正, 你只能在进行"预先连结"时把这些压缩过的执行档藏起来.
你可以参考上方的 <uri link="#doc_chap2_sect2">组态设定 章节</uri> 来简单地完成这件事.
</p>

</body>
</section>
<section>
<title>我使用 grsecurity 而"预先连结"似乎无法运作</title>
<body>

<p>
如果你要在一个使用 grsecurity 使 mmap() 基底位址乱数化(randomized mmap() base)的
系统上使用"预先连结", 你必须把 <path>/lib/ld-2.3.*.so</path> 的 "randomized 
mmap() base" 设定关闭. 你可以用 <c>chpax</c> 公用程式来完成这个动作,但是这必须在
该档没有在使用时才能进行. (比方说用救援光碟开机)
</p>

</body>
</section>    
</chapter>

<chapter>
<title>结论</title>
<section>
<body>

<p>
"预先连结"可以大大地增进一些大型应用程式的启动时间.
Portage 也有内建的支援. "预先连结"也很安全, 发生问题的时候你可以还原任何的执行档.
你只要记得当更新了 glibc 或其它有被"预先连结"到的函式库时必须重新执行 
<path>prelink</path>. 总之最后, 祝你好运!
</p>

</body>
</section>
</chapter>
</guide>
