***************************************************************************************************************************
作者:EasyWave 时间:2013.03.24

类别:Android系统源码分析 声明:转载,请保留链接

注意:如有错误,欢迎指正。这些是我学习的日志文章......

***************************************************************************************************************************

跟普通的linux基本一样,不过android是采用了自己的glibc,也就是在bionic这个文件中,在这个文件夹中它有libc、libdl、libm、libstdc++、libthread_db以及linker,如下图所示:

1):libc

libc是Android下的C的函数库。
bionic libc是基本的C语言函数库,包含了C语言最基本的库函数。这个库可以根据 头文件划分为几个 个部分,包括:字符类型、错误码、 浮点常数、数学常数、标准定义 、 标准 I/O、工具函数、字符串操作 等等。如下图所示:

2):libdl
这个一个跟动态库链接有关的一个库,也就是说,所有libxxx.so都是由它来打开。它提供了如下的函数供应用开发者动态的打开和加载动态库,如下:

void *dlopen(const char *filename, int flag) { return 0; }const char *dlerror(void) { return 0; }void *dlsym(void *handle, const char *symbol) { return 0; }int dladdr(void *addr, Dl_info *info) { return 0; }int dlclose(void *handle) { return 0; }


不过需要注意的是,上面函数的具体实现,却是在bionic/linker/Dlfcn.c中实现的。如下所示:

3):libm

这个是andriod下的标准数学库

4):libstdc++

这个是G++相关的库

5):libthread_db

这是跟线程相关的库函数。

6):linker

linker 主要用于实现共享库的加载与链接。它支持应用程序对库函数的隐式和显式调用。对于隐式调用,应用程序的编译与静态库大致相同,只是在静态链接的时候通过--dynamic-linker /system/bin/linker 指定动态链接器,(该信息将被存放在ELF文件的.interp节中,内核执行目标映像文件前将通过该信息加载并运行相应的解释器程序linker.)并链接相应的共享库。与ld.so不同的是,Linker目前没有提供Lazy Binding机制,所有外部过程引用都在映像执行之前解析。对于显式调用,可以同过linker中提供的接口dlopen,dlsym,dlerror和dlclose来动态加载和链接共享库。

在说到linker时,不得不提PreLinker机制,Prelink即预链接技术是利用事先链接以代替运行时链接的技术,以加快共享库的加载速度,它不仅能加快程序启动时间,还可以减少部分内存开销(它能使KDE的启动时间减少50%)。每次程序执行时,进行的链接动作都是一样的,链接相对来说开销很大,尤其是嵌入式系统。

Android的Prelink的机制:
Android源码中有一组map文件,其中定义了需要预连接的动态库,其Prelink信息以及对应的逻辑地址(4G地址空间中位置),在动态库编译时,预处理程序apriori根据map文件中的定义,生成预链接信息重定向信息,并加入这些二进制文件lib*.so的末尾。它主要节约了查询函数地址等工作所用的时间,动态库重定位的开销。在运行程序,动态库加载时,加载程序linker判断动态库是否为Prelink的,如果是的话,就在首次使用时将其加载到指定的内存空间,直接使用预编译信息。如果要打开prelinker的话,需要进行一些配置,在Android.mk中设置该库是否需要Prelink,默认是使用Prelink的,也可设置成否,方法如下:
LOCAL_PRELINK_MODULE := false
在android中它是以build/core/prelink_linux_arm.map文件为基础,来分配动态库的地址的,如下所示:

也就是说,如果想自己添加第三方动态库的话,就需要在build/core/prelink-linux-arm.map 中加入形如libxxx.so 0xxx000000。
手工指定某个库相应的prelink地址范围,库应用对齐1M边界,注意库与库之间的间隔数,如果指定不好编译的时候会提示说地址空间冲突的问题。另外,注意排序,这里要把数大的放到前面去,按照大小降序排序。
而在andriod中,以apriori中的prelinkmap.c它用根据整个系统设置BoardConfig.mk的内存分配规则(3G/1G, 2G/2G)来判断map中指定地址是否符合Prelink的地址空间范围,如果正常,则在so的末尾加入prelink信息和标识(文件以PRE结束),apriori可以预先为若干共享库确定加载地址,并为有依赖关系的共享库做静态重定位和连接, 该命令加入参数--verbose,即可显示出prelink的细节。

以下为网络摘取:
linker是Android的专用动态链接库键接器,Linker和传统Linux使用的linker(ld.so,ld-linux.so.2,ld-linux.so.3)有所不同。库的编译参数-dynamic-linker指定了键接器为/system/bin/linker(也可以手动换成别的),该信息将被存放在ELF文件的.interp节中,内核执行目标映像文件前将通过该信息加载并运行相应的解释器程序linker,并链接相应的共享库,共享库以ELF文件的形式保存在文件系统中。核心的load_elf_binary会首先将其映像文件映射到内存,然后映射并执行其解释器也就是linker的代码。linker的代码段是进程间共享的,但数据段为各进程私有。
所有外部过程引用都在映像执行之前解析, Android中的共享库和可执行映像都默认采用ELF格式的文件. 程序头表包含了加载到内存中的各种段的索引及属性信息,它将告诉加载器如何加载映像,初始化时,动态链接器首先解析出外部过程引用的绝对地址,一次性的修改所有相应的GOT表项。
linker会在共享库加载时,调用is_prelinked查看该库是否是prelink的,并在alloc_mem_region中检查目的地址是否被占用。如果该库不是prelink的,则库加载的起始地址为零。

更多相关文章

  1. Android(安卓)可执行文件结构的分析
  2. Chaquopy读取Android项目python目录下的文件
  3. Android(安卓)Studio的应用与快捷键
  4. android lint的使用
  5. NDK 开发指南---Android(安卓)NDK概览
  6. Android中ListView,SQLite,BaseAdapter的结合
  7. Android(安卓)studio for mac 的一些常用快捷键
  8. Android提高篇之自定义dialog实现processDialog“正在加载”效果
  9. Android启动后,加载的2类service (Native 系统Service, Java 系统

随机推荐

  1. Android进度条样式
  2. Android 之retrofit2 之 @body上传服务器
  3. 16个最热门的 Android Apps 推荐下载
  4. Android 之listview \gridview 属性设置
  5. Android点击返回按钮两次退出系统
  6. 在Android程序中使用MQTT
  7. Android Studio 插件之 Android ButterKn
  8. 如何使用Android(安卓)Studio把自己的And
  9. Android 之 自定义标签 和 自定义组件
  10. Android(安卓)利用soap协议与服务端进行