elf格式分析和动态库的链接过程
ELF格式, Linux上的可执行可链接的文件格式,一般有四种:可执行文件,共享目标文件也就是库文件,可重定位文件也就是.O文件,coredump文件,程序终止时,进程的地址空间及一些堆栈信息。
ELF的文件结构由ELF文件头,ELF段表,ELF的段组成。
ELF文件头:文件类型,版本号,入口地址,段表的偏移地址,段表的大小,段表的数量等。
段表:由段表头和程序头组成
程序头: 记录了多段的简介信息以及每一个段的偏移量,物理地址,虚拟地址,权限,内存大小,标志等。
段表头:相当于每个段的表头构成了一张表。记录了段的名字,段的类型,段的标志,段的类型,段的大小,段的偏移量等。
段的名字记录在字符串表中,所以这里只记录下偏移量即可。
段的类型包括十几种,这个是可以扩展的。
0:无效段,1:程序段(代码段(text segment),初始数据段(data segment), 未初始数据段(bss)) 2:符号表段 3:重定位表段 4:.dynamic动态链接信息段 3.动态链接的符号表段等。
程序段记录了当前程序文件的代码,变量等。
.sysmbol符号表等记录当程序中引用的其他库的代码的函数,变量等。
.dynamic动态链接信息段:记录了当前链接器的路径,用来链接其他共享对象的段。
重定位表段记录了符号重定位的一些偏移值。
上面只是一个简介,实际情况可能复杂得多
实际的段表头:
实际的程序头:
符号表(symbol table):
每一个elf文件想要用到其他的elf文件时候就要用到符号表(symbol table)中的symbol entry , 一个symbol entry是一个sym结构体,描述了symbol的名字和值。
名字被写到dynamic string段中了,这里记录的偏移索引。值记录了在对应的elf文件中该符号的地址,不过这个地址需要被重定位,如何重定位呢:需要加上该elf文件加载到内存的基地址(base load address),构成了该symbol在内存中的绝对地址。
GOT(global offset table)
GOT是一个数组,存放编译时还没有确定下来地址符号地址。动态连接器会重新修改他们的地址。
PLT(procedure linkage table)
用来辅助连接器重复为符号的一个表,和GOT配合使用。
哈希表和链(hash table and chain)
帮助链接更容易地找到目标符号
动态库地链接过程其实主要分为两个部分,一是动态库加载到内存地过程,二是动态库引用了其他库所涉及到地一个链接的过程,需要对一些动态的符号进行地址重定位计算,再加载到内存中去。
强符号和弱符号:两个强符号重复了,编译器直接报错。一个强符号一个弱符号,编译器先引用强符号,两个弱符号,编译器看哪个弱符号的内存大,引用哪一个。通过_attrabite_(weak)可以声明弱符号。