Linker

Android Linker:程序员

          http://geek.csdn.net/news/detail/104860?locationNum=11&fps=1数组

关于load_bias_: SO 能够指定加载基址,可是 SO 指定的加载基址可能不是页对齐的,这种状况会致使实际映射地址和指定的加载地址有一个误差,这个误差即是 load_bias_,以后在针对虚拟地址进行计算时须要使用 load_bias_ 修正。普通的 SO 都不会指定加载基址,这时min_vaddr = 0,则 load_bias_ = load_start_,即load_bias_ 等于加载基址,下文会将 load_bias_ 直接称为基址。函数

 

Section Header:测试

  • .text:已编译程序的机器代码。
  • .rodata:只读数据,好比printf语句中的格式串和开关(switch)语句的跳转表。
  • .data:已初始化的全局C变量。局部C变量在运行时被保存在栈中,既不出如今.data中,也不出如今.bss节中。
  • .bss:未初始化的全局C变量。在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。目标文件格式区分初始化未初始化变量是为了空间效率在:在目标文件中,未初始化变量不须要占据任何实际的磁盘空间。
  • .symtab:一个符号表(symbol table),它存放在程序中被定义和引用的函数和全局变量的信息。一些程序员错误地认为必须经过-g选项来编译一个程序,获得符号表信息。实际上,每一个可重定位目标文件在.symtab中都有一张符号表。然而和编译器中的符号表不一样,.symtab符号表不包含局部变量的表目。
  • .rel.text:当连接噐把这个目标文件和其余文件结合时,.text节中的许多位置都须要修改。通常而言,任何调用外部函数或者引用全局变量的指令都须要修改。另外一方面调用本地函数的指令则不须要修改。注意,可执行目标文件中并不须要重定位信息,所以一般省略,除非使用者显式地指示连接器包含这些信息。
  • .rel.data:被模块定义或引用的任何全局变量的信息。通常而言,任何已初始化全局变量的初始值是全局变量或者外部定义函数的地址都须要被修改
  • .debug:一个调试符号表,其有些表目是程序中定义的局部变量和类型定义,有些表目是程序中定义和引用的全局变量,有些是原始的C源文件。只有以-g选项调用编译驱动程序时,才会获得这张表。
  • .line:原始C源程序中的行号和.text节中机器指令之间的映射。只有以-g选项调用编译驱动程序时,才会获得这张表。
  • .strtab:一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。字符串表就是以null结尾的字符串序列。

 

.data保存初始化过的数据,这是普通程序数据的一部分,能够在程序运行期间修改。spa

 

.rodata保存了只读数据,能够读取但不能修改,例如printf语句中的全部静态字符串封装到该节。.net

.init.fini保存了进程初始化和结束所用的代码,这一般是由编译器自动添加的。debug

.hash是一个散列表,容许在不对全表元素进行线性搜索的状况下,快速访问全部符号表项。指针

 

符号表机制radelf调试

符号表保存了程序实现或使用的全部全局变量和函数;若是程序引用一个自身代码未定义的符号,则称之为未定义符号,这类引用必须在静态连接期间用其余目标模块或库解决,或在加载时经过动态连接过程解决。code

实现:

.symtab肯定符号的名称与其值之间的关联,其中名称不是直接以字符串形式出现的,而是表示为某一字符串数组(.strtab)的索引。

.strtab保存了字符串数组(.shstrtab包含了节名称字符串表)。

.hash保存了一个散列表,以帮助快速查找符号。

 

Symbol table:

上图对应下面的结构:

Num Value SIze Type Bind Vis Ndx Name
  ELF64_sym.st_value ELF64_sym.st_size ELF64_sym.st_info ELF64_sym.st_info   ELF64_sym.st_shndx strtab[ELF64_sym.st_name]

 

 

typedef struct elf64_sym {

Elf64_Word st_name;            // 符号名称,字符串表中的索引

unsigned char st_info;         // 类型:NOTYPE,OBJECT,FUNC和绑定属性:STB_LOCAL/STB_GLOBAL/STB_WEAK;

unsigned char st_other;        // 语义未定义,0

Elf64_Half st_shndx;           // section header index 相关节的索引,符号将绑定到该节,此外SHN_ABS指定符号是绝对值,不因重定位而改变,SHN_UNDEF标识未定义符号。

Elf64_Addr st_value;           // 符号的值

Elf64_Xword st_size;           // 符号的长度,如一个指针的长度或struct对象中包含的字节数。

}Elf64_Sym;

 

dlopen RTLD_XXX 解析:

RTLD_LAZY:在dlopen返回前,对于动态库中的未定义的符号不执行解析(只对函数引用有效,对于变量引用老是当即解析)。

RTLD_NOW: 须要在dlopen返回前,解析出全部未定义符号,若是解析不出来,在dlopen会返回NULL,错误为:: undefined symbol: xxxx.......

二、做用范围,可与解析方式经过“|”组合使用。

RTLD_GLOBAL:动态库中定义的符号可被其后打开的其它库解析。

RTLD_LOCAL: 与RTLD_GLOBAL做用相反,动态库中定义的符号不能被其后打开的其它库重定位。若是没有指明是RTLD_GLOBAL仍是RTLD_LOCAL,则缺省为RTLD_LOCAL。

三、做用方式

RTLD_NODELETE: 在dlclose()期间不卸载库,而且在之后使用dlopen()从新加载库时不初始化库中的静态变量。这个flag不是POSIX-2001标准。

RTLD_NOLOAD: 不加载库。可用于测试库是否已加载(dlopen()返回NULL说明未加载,不然说明已加载),也可用于改变已加载库的flag,如:先前加载库的flag为RTLD_LOCAL,用dlopen(RTLD_NOLOAD|RTLD_GLOBAL)后flag将变成RTLD_GLOBAL。这个flag不是POSIX-2001标准。

 

一、解析方式

RTLD_LAZY:在dlopen返回前,对于动态库中的未定义的符号不执行解析(只对函数引用有效,对于变量引用老是当即解析)。

RTLD_NOW: 须要在dlopen返回前,解析出全部未定义符号,若是解析不出来,在dlopen会返回NULL,错误为:: undefined symbol: xxxx.......

二、做用范围,可与解析方式经过“|”组合使用。

RTLD_GLOBAL:动态库中定义的符号可被其后打开的其它库解析。

RTLD_LOCAL: 与RTLD_GLOBAL做用相反,动态库中定义的符号不能被其后打开的其它库重定位。若是没有指明是RTLD_GLOBAL仍是RTLD_LOCAL,则缺省为RTLD_LOCAL。

三、做用方式

RTLD_NODELETE: 在dlclose()期间不卸载库,而且在之后使用dlopen()从新加载库时不初始化库中的静态变量。这个flag不是POSIX-2001标准。

RTLD_NOLOAD: 不加载库。可用于测试库是否已加载(dlopen()返回NULL说明未加载,不然说明已加载),也可用于改变已加载库的flag,如:先前加载库的flag为RTLD_LOCAL,用dlopen(RTLD_NOLOAD|RTLD_GLOBAL)后flag将变成RTLD_GLOBAL。这个flag不是POSIX-2001标准。

相关文章
相关标签/搜索