程序的基本处理过程
从源代码开始到形成可执行文件,需要经过预处理、编译、汇编、链接几个步骤。(这里主要是针对c语言程序)编译器主要是把源代码翻译成中间语言,这里是汇编语言,然后用汇编成目标文件,最后目标文件被链接器处理生成可执行文件。
ELF文件格式
编译器生成的文件叫目标文件,当前常见的是windows下的PE格式文件和Linux下的ELF格式文件。
ELF文件分类
其中ELF目标文件可以分为如下三类:
- 可重定位文件
这种文件可以作为链接器的输入,用来生成可执行文件或是共享文件。
- 可执行文件
- 共享文件
这种文件可以被可执行那个文件或其他共享文件调用。
ELF文件作用
由上面分类可知,ELF文件主要参与程序的链接和程序的执行过程。在链接过程中,ELF文件被看做是节(section)的集合,所有的节由节头表描述。在程序执行过程中,ELF文件被看成是段的集合,由程序头表描述。
ELF文件结构
ELF文件主要由以下4部分组成:
- ELF Header
指明该文件的属性信息,如该文件的类型,节头表和段头表在该文件的位置等信息。
- Program Header table
段头表和创建进程有关,描述了连续的几个节在文件中的位置、大小以及放到内存后的位置和大小。用于构建进程映像的目标文件必须有段头表,而可重定向的目标文件不需要段头表。
- Section
编译后的目标文件至少有3个节区:
.text
代码段,存放程序执行代码的一块区域;
.data
数据段,存放程序中已经初始化的全局变量的区域;
.bss
bbs段,存放程序中未初始化的全局变量的区域;
- Section header table
节头表描述了该文件中各个节区的名称,大小以及在文件的位置等信息。用于链接的文件必须要有节头表,其他的目标文件可以不要节头表。
链接脚本
链接过程
链接过程主要完成两件事:符号解析和重定位。
符号解析
找到当前文件中未定义符号在共享文件中的位置。
重定位
确定各个函数加载到内存中的运行地址。
链接脚本的功能
程序的链接过程是由链接脚本控制的,基本上只完成两个操作:
- 输入文件中的section如何映射到输出文件;
- 控制输出文件的内存分布;
默认情况下,链接器会使用默认的链接脚本,用参数-T参数可以指定自己的链接脚本。通常链接器的输入是编译器或汇编器输出的.o目标文件,在Linux平台输出的是ELF格式的目标文件或可执行文件。
链接脚本基础
关键字ENTRY
将某个符号的地址作为该可执行文件的入口地址,使用方式如下:
ENTRY(symbol_name)
关键字SECTIONS
SECTIONS命令告诉链接器如何把输入文件中的节映射到输出文件中。下面是一个简单的例子
SECTIONS
{
. = 0x10000;
.text : { *(.text) }
}
其中,花括号中的第一行表示把定位器设置在某个地址位置,使得后续的内容从这个地址开始存放。第二行是把所有输入文件中的.text代码段都合并放到输出文件的.text代码段中。