Android学习之--prelink
最近移植一些既存的c程序到android中,不可避免的需要了解ndk,jni之类的东西,编译体系,toolchain之类的东西。偶尔,发现了Android中的src中有一个叫做“LOCAL_PRELINK_MODULE”的参数,它是Android采用的加快一些系统的函数库加载速度的手段。
因为对这个比较感兴趣,就稍微去了解了一下。
首先,需要了解一下什么是prelink
由RedHat的大牛Jakub Jelínek所发布的开源程序。通过修改ELF的可执行文件预先计算出函数库的relocation的信息,来加速系统对于被prelink处理过后的函数库的加载速度。
详细可以参考一下资源:
http://people.redhat.com/jakub/prelink/prelink.pdf
http://jserv.blogspot.com/2010/10/android.html这篇是台湾同胞写的,本文最后贴出来方便大家查看。
接着,就看看Android中什么地方使用到了
以下是Android的开发这David Turner在邮件列表中对于一个开发者的疑问的回答(原文链接):
Android使用了一个定制的prelinker tool来降低系统库的大小和加载速度(通过预先指定可执行文件使用到的动态库的location地址配合定制的linker来完成)。它的回答中提到了,Android中使用的linker也是定制过的,没有完全实现一些ELF所规定的relocations相关的功能。这就会导致如果用其它的toolchain编译出的动态库如果用了一些Android的linker所不支持的特性,有可能就会出奇怪的问题。如果你用了其它的toolchain编译了一些动态库,导致在android上链接失败,最好还是使用android提供的toolchain。(从linker和两个prelink工具的代码看,默认的android执行的linker是在/system/bin/linker)
grep了一下android源代码,发现只有编译dalvik时会根据是否是模拟器来显示开启这个选项,而其它的库都默认是打开prelink的。
mydroid/bionic/linker/README.TXT文件中对Android中的prelink做了一些描述:android默认对所有系统的库都会进行prelink,一旦有新的库被加入或者更改时,需要重新更新prelink-linux-xxx.map的文件,android提供了定制的apriori和soslim(在使用)两个工具在build的时候进行相应的prelink动作。
dalvik/vm/Android.mk: LOCAL_PRELINK_MODULE := true
同时,build/core/prelink-linux-arm.map是关键的一个配置文件。
查看dalvik的代码,在Native.c的注释中,有关于dalvik中使用dynamic library的一些注意事项
最后,作为开发者我们可以如何使用它
适用于Android的系统开发者,用来定制系统级的动态库,加速定制的android的系统的启动及加载速度。
由于嵌入式设备尤其是android设备,目前的升级比较频繁,一旦prelink过的库函数修改过了,要求所有引用该库函数的可执行文件也要被重新编译。这就要求系统开发者谨慎的修改系统代码,毕竟每次OTA升级的代价还是很大的。
例子:
让我们以系统的一个可执行文件,service为例(mydroid/out/target/product/generic/system/bin/service)
使用readelf dump出该可执行elf文件的信息,可以看到.interp这个section,并发现它是指向/system/bin/linker这个定制化的android的连接器。为什么这里会有.interp这个section,主要是因为它的Dynamic Setction明确用到了一些库函数,而这些库函数是被prelink过的。
Section Headers:
[Nr] Name Type Addr Off Size ES 易做图 Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00008114 000114 000013 00 A 0 0 1
[ 2] .hash HASH 00008128 000128 00022c 04 A 3 0 4
Dynamic section at offset 0x2068 contains 27 entries:
Tag Type Name/Value
...
0x00000004 (HASH) 0x8128
0x00000001 (NEEDED) Shared library: [liblog.so]
0x00000001 (NEEDED) Shared library: [libutils.so]
0x00000001 (NEEDED) Shared library: [libbinder.so]
0x00000001 (NEEDED) Shared library: [libc.so]
0x00000001 (NEEDED) Shared library: [libstdc++.so]
0x00000001 (NEEDED) Shared library: [libm.so]
0x00000020 (PREINIT_ARRAY) 0xa000
...
再来看看作为动态库的文件中prelink和不prelink的区别,以liblog.so为例(mydroid/system/core/liblog/xxx)
两者的编译命令如下:
target Prelink: liblog (out/target/product/generic/symbols/system/lib/liblog.so)
out/host/linux-x86/bin/apriori --prelinkmap build/core/prelink-linux-arm.map --locals-only --quiet out/target/product/generic/obj/SHARED_LIBRARIES/liblog_intermediates/LINKED/liblog.so --output out/target/product/generic/symbols/system/lib/liblog.so
target Strip: liblog (out/target/product/generic/obj/lib/liblog.so)
out/host/linux-x86/bin/soslim --strip --shady --quiet out/target/product/generic/symbols/system/lib/liblog.so --outfile out/target/product/generic/obj/lib/liblog.so
Install: out/target/product/generic/system/lib/liblog.so
out/host/linux-x86/bin/acp -fpt out/target/product/generic/obj/lib/liblog.so out/target/product/generic/system/lib/liblog.so
target Non-prelinked: liblog (out/target/product/generic/symbols/system/lib/liblog.so)
out/host/linux-x86/bin/acp -fpt out/target/product/generic/obj/SHARED_LIBRARIES/liblog_intermediates/LINKED/liblog.so out/target/product/generic/symbols/system/lib/liblog.so
target Strip: liblog (out/target/product/generic/obj/lib/liblog.so)
out/host/linux-x86/bin/soslim --strip --shady --quiet out/target/product/generic/symbols/system/lib/liblog.so --outfile out/target/product/generic/obj/lib/liblog.so
Install: out/target/product/generic/system/lib/liblog.so
out/host/linux-x86/bin/acp -fpt out/target/product/generic/
补充:移动开发 , Android ,