How to prelink?
1. Prelink 的交叉编译
1.1 获取源码
原版的 prelink 不适用于嵌入式平台;需要使用 Yocto Project 下的 prelink-cross 版本:
也可以通过 git 获取最新的源码:
$ git clone https://git.yoctoproject.org/git/prelink-cross
$ cd prelink-cross
$ git checkout 20151030_cross
注意,需要切换到 cross 分支。
1.2.交叉编译
prelink 工具类似于 gcc 等工具链,如果处理的 ELF 文件所属系统架构不同于宿主系统架构(也就是当前的操作系统),则需要指定交叉编译参数。例如,如果目标软件运行的平台为 arm,需要将 -target 参数指定为 arm-linux。
此外,还需要加上 –without-sysroot 参数,使得我们编译出来的 prelink 工具可以在运行时指定 sysroot 路径。
2. Prelink 的使用详解
针对目标程序 target_bin 的 prelink 过程如下:
对于上述 prelink 过程所用到的重要参数解释如下:
–root 选项指定包含目标程序和系统共享库的 sysroot 路径,也就是嵌入式系统的根目录拷贝到宿主操作系统上的路径;后续所有路径都可指定为 sysroot 的相对路径。上述操作中,–root 参数指定的目录,其层级结构应与板子上根目录层级结构一致:
–cache-file 参数用于指定prelink 建立索引过程中的 cache 文件;
–config_file 参数用于指定 prelink 的配置文件,默认为 /etc/prelink.conf 。里面是所有需要进行 prelink 的 ELF 文件路径;如果 prelink 后加 -a 选项,则会处理此文件中所有的目录或文件;
–ld-library-path 参数用于指定目标可执行文件运行时的共享库搜索路径。由于我们需要从 target_bin 开始进行 prelink,因此指定其运行时的 LD_LIBRARY_PATH。
-h 和 -l 参数用于指定对目录为目录的软连接的不同处理方式;加 -h 参数时,会处理软链接文件指向的目标目录;加 -l 参数时,如果目标目录跨文件系统,则会忽略。
-b 参数用于添加黑名单,所有用 –b 参数指定的目标都不会处理。
-a 参数表示会处理配置文件中所有添加的路径或文件。
-m 节省虚拟定址分配;如果有大量的共享库需要 prelink 就会需要这个选项。
-R 参数会为共享库选择随机的基址;这个是为安全考虑。
-f 强制重新 prelink 已经做过 prelink 的 ELF 文件。prelink 默认会忽略之前已经被 prelink 的 ELF 文件。
-v 参数表示会输出中间的详细处理过程。
其他参数的解释请参考 man 手册。
单个可执行文件的 prelink 处理时间在秒级,如果对整个系统进行 prelink,可能要花几分钟或者十几分钟。
这里需要注意,使用 prelink 处理多个可执行文件时,如果每个文件运行时的动态库搜索路径不同,建议通过指定 LD_LIBRARY_PATH 来分别处理,而非通过 -a 参数一次性处理,否则可能会 prelink 错误的共享库,导致运行时 prelink 机制并没能发挥作用。
如果需要取消已经做过 Prelink 的 ELF 文件的,也非常简单:
1$ prelink -au
警告:在对本机的 ELF 文件进行 prelink 处理过程中,如果被强制中断,可能会将整个系统弄崩掉。