Prelink是Red Hat 开发者 Jakub Jelinek 所设计的工具,正如其名字所示,Prelink利用事先链接代替运行时链接的方法来加速共享库的加载,它不仅可以加快起动速度,还可以减少部分内存开销,是各种Linux架构上用于减少程序加载时间、缩短系统启动时间和加快应用程序启动的很受欢迎的一个工具。
我们在上一章中详细介绍了动态链接和加载的过程,这种运行时的动态链接尤其是重定位(relocation)的开销对于大型系统来说是很大的。相比之下,早期UNIX下的a.out格式的老式链接方法在速度和占用内存方面有明显的优势(但不如ELF格式更灵活,能方便的构建动态共享库)。Prelink工具是试图在保持一部分灵活性的基础上,借鉴a.out格式在速度和占用内存方面的优点,对ELF文件进行一些改进。
事实上,Prelink工具的原理主要基于这样一个事实:动态链接和加载的过程开销很大,并且在大多数的系统上, 函数库并不会常常被更动, 每次程序被执行时所进行的链接动作都是完全相同的,对于嵌入式系统来说尤其如此。因此,这一过程可以改在运行时之前就可以预先处理好,即花一些时间利用Prelink工具对动态共享库和可执行文件进行处理,修改这些二进制文件并加入相应的重定位等信息,节约了本来在程序启动时的比较耗时的查询函数地址等工作,这样可以减少程序启动的时间,同时也减少了内存的耗用。
Prelink的这种做法当然也有代价:我们每次更新动态共享库时,相关的可执行文件都需要重新执行一遍Prelink才能保证有效,因为新的共享库中的符号信息、地址等很可能与原来的已经不同了。这种代价对于嵌入式系统的开发者来说可能稍微带来一些复杂度,不过好在对用户来说几乎是可以忽略的。
更多有关Prelink的具体做法和细节读者可以参考Prelink的开发者 Jakub Jelinek的专文介绍:http://people.redhat.com/jakub/prelink/prelink.pdf。
很多Linux的发行版上已经预装了或者已经使用了Prelink工具,不过我们需要专门的针对嵌入式体系,比如ARM的版本,这样我们需要到Red Hat的网站下载源代码并重新编译。下载地址是:http://people.redhat.com/jakub/prelink/
编译时主要是configure时设定--host参数,注意它是一个用于主机而不是开发板上的工具,不要用arm-linux-gcc编译它,如下所示:
# ./configure --prefix=/opt/tools/arm/prelink --host=arm-linux # make # make install |
Prelink工具的使用非常简单,对一个系统来说可能要花几分钟或者十几分钟。一般来说我们不用在命令行中直接指定ELF文件的方式,而是将需要Prelink的文件写到配置文件/etc/prelink.conf中,然后使用下面的命令即可:
# prelink -avmR |
如果你要取消已经做了的Prelink也非常简单,运行:
# prelink -au |
Prelink常用的选项含义如下:
-a 对所有的文件进行Prelink,包括/etc/prelink.conf文件中指定目录下的所有程序
-m节省虚拟定址分配,在有许多程序需要连接时使用
-f 重新强制预连接已经连接的程序,主要用于更新连接数据时使用
-R 在给库指定地址时,使用随机地址,这有利于提高系统安全以防缓冲区溢出
-u 取消已做的预连接
下面是一份/etc/prelink.conf文件的示例:
# This config file contains a list of directories both with binaries # and libraries prelink should consider by default. # If a directory name is prefixed with `-l ', the directory hierarchy # will be walked as long as filesystem boundaries are not crossed. # If a directory name is prefixed with `-h ', symbolic links in a # directory hierarchy are followed. # Blacklist specification should be prefixed by -b # and optionally also -l or -h if needed. -l /opt/lib -l /opt/bin -l /opt/qte/lib |
其中以”#”开头的行为注释,正如注释中所解释的,下面列出的文件目录分别可以有”-l”, “-h”和”-b”开头,”-l”和“-h”区分是否包括符号连接类型的目录,”-b”指黑名单,即应该排除出去的部分。
你可能会在Prelink时遇到类似这样的错误:"Cannot prelink against non-PIC shared library" 。 这是因为有些库没有使用 -fPIC gcc 选项编译。PIC指Postion Independent Code,即位置无关代码,是动态链接的一项技术,也是Prelink的前提条件。这种问题只需要用-fPIC重新编译代码就可以了。
根据笔者的经验,如果你的嵌入式系统中动态库过多过慢是系统性能的瓶颈之一,推荐你试试 Prelink 的方法。在笔者工作的平台上,它是非常行之有效的,让大多数应用的启动时间及系统启动时间都有了显著的提升。