1. 各种UNIX系统的可执行文件都是采用ELF格式,其有三种不同的类型:
可重定位的目标文件(Relocatable)
可执行文件(Executable)
共享库(Shared Object或Shared Library)
2. 程序的汇编、链接、运行过程:
A. 写一个汇编程序保存为文本文件max.s
B. 汇编器读取这个文本文件转换为目标文件max.o,目标文件由若干个Section组成,在汇编程序中声明的.section也会成为其中的一个section,同时汇编器会添加一些section。
C. 然后,链接器把目标文件中的Section合并成几个segment,生成可执行文件max.
D.最后加载器根据可执行文件中的Segment信息加载运行这个程序。
3. 可重定位的目标文件的粗略布局:
ELF Header |
………………Section……………………… ………… ………… |
Section Header Table Program Header Table(可有可无) Section Header Table保存了所有的Section的描述信息,通过Section Header Table可以找到每个Section的具体位置 |
…………………Section……………………… ………… ………… |
4. 可重定位的目标文件内容概括:
ELF Header描述了该ELF文件的文件类型,ELF Header自身的偏移量,操作系统类型,cpu体系结构,SectionHeaderTable的偏移位置,section header table中有多少个section header,每个Section Header的大小,还附加一些基本信息。
通过ELF定位到Section Header Table,就可以从Section Header Table定位每个Section在本文件的具体位置。
ELFrelocatable文件的示例布局:
起始文件地址 |
Section或Header |
0 |
ELF Header |
0x34 |
.text |
0x60 |
.data |
0x98 |
.bss(此段为空) |
0x98 |
.shstrtab(section header string name tab) |
0xc8 |
Section Header Table |
0x208 |
.symtab |
0x288 |
.strtab(sym string name table) |
0x2b0 |
.rel.text |
.text section:
代码段,把所有的指令全部译为二进制,所有的符号都被替换为地址(相对地址)。
.data section:
数据段,将原封不动地加载到内存中。
.shstrtab section:
段头名字段,存放的都是二进制ascii码,保存着各个section的名字,每个名字都以Null结尾的字符串。通过Section Header Table来本段定位该段的名字。
.strtab section:
符号名字段,存放的都是二进制ascii码,保存着程序中用到的符号名字,每个名字都以Null结尾的字符串。通过symtab来本段定位该符号的名字 。
.bss section:
全局变量未被手动初始化,而被加载器用0初始化的变量将存放.bss段,在加载时和.data段一样都是可读写的数据,但在ELF文件中.data段需要部分空间保存初始值,而.bss段则不需要。即.bss段在文件中只占一个section header而没有对应的section,程序加载时.bss段要多大内存空间,在section header中有描述。
.symtab section
符号表,包括全局符号和局部符号。描述各个符号所处的section的偏移量,各个符号所代表的地址,该地址是相对于符号所处的section的偏移地址。而符号本身的符号名字则存放于strtab section中。
.rel.text section:
重定位代码段,即提供给链接器用的重定位信息,指出在该目标文件中的某一地址需要重新定位。
Section Header Table:
存放每个段的相关信息,包括段的位置,段的大小,查找段的名字的偏移量,及其其他相关信息。
5. 可执行文件粗略布局:
ELF Header |
………………Section……………………… ………… ………… |
Text Segment |
Data Segment |
Section Header Table Program Header Table(可有可无) Section Header Table保存了所有的Section的描述信息,通过Section Header Table可以找到每个Section的具体位置 |
Program Header Table Program Header Table保存了两个Segment的描述信息,那两个Segment是分别通过N个目标文件的data section和text section合并而成 |
…………………Section……………………… ………… ………… |
6. 可执行文件的内容概括:
在从可重定位目标文件链接到可执行文件时,链接器修改了ELF文件的一些内容和布局。主要修改有:
A. 在ELF Header中,Type改成了EXEC,由目标文件变为可执行文件,Entry point address改为真正的虚拟地址,即为汇编_start符号地址。
B. 增加了两个Segment,少了几个section。在增添的Data segment 中,数据原封不动地从.data section中搬过来,而在Text segment中,是由每个目标文件的.text section,ELF Header,Program Header Table一起组成。
C. 增加了Align(指定加载器把文件分为若干页,),增加了Flag,指定两个Segment的访问权限。
D.删除rel.text section。
E. 把代码的相对地址改为绝对地址(虚拟地址)。
F. 可能删除(在.bss段没有任何符号时).bss段,同时添加一些加载器所需的脚本。
G.使用命令strip –a max 可以删除一些不必要的符号表里的符号,这样对可执行文件没有什么影响的同时减小了文件的尺寸。
说明:以上只属于本人观点,更详细准确地内容,请用hexdump -C 文件名 命令去直接读取目标文件或可执行文件,再分析十六进制数据。
参考文献:《Linux C一站式学习》.宋劲杉