Linux下面,目标文件、共享对象文件、可执行文件都是使用ELF文件格式来存储的。程序经过编译之后会输出目标文件,然后经过链接可以产生可执行文件或者共享对象文件。Linux下面使用的ELF文件和Windows操作系统使用的PE文件都是从Unix系统的COFF文件格式演化来的。
我们先来了解一些基本的想法。
首先,最重要的思路是一个程序从人能读懂的格式转换为供操作系统执行的二进制格式之后,代码和数据是分开存放的,之所以这样设计有这么几个原因:
1、程序执行之后,代码和数据可以被映射到不同属性的虚拟内存中。因为代码一般是只读的,而数据是可读可写的;
2、现代CPU有强大的缓存体系。程序和代码分离可以提高程序的局部性,增加缓存命中的概率;
3、还有最重要的一个原因是当有多个程序副本在运行的时候,只读部分可以只在内存中保留一份,这样大大节省了内存。
在ELF的定义中,把他们分开存放的地方称为一个 Section ,就是一个段。
一个ELF文件中重要的段包括:
.text 段:存储 只读程序
.data 段:存储 已经初始化的全局变量和静态变量
.bss 段:存储 未初始化的全局变量和静态变量,因为这些变量的值为0,所以这个段在文件当中不占据空间
.rodata 段:存储 只读数据,比如字符串常量
我们用一个例子来看一下ELF文件的格式到底是什么。首先,在Linux下编写一个C程序:SimpleSection.c
int printf(const char *format, ... );
int global_init_var = 16;
int global_unint_var;
void func1 (int );
int main()
{
static int static_var = -32;
static int static_var_uninit;
int a = 1;
int b;
func1(static_var + global_init_var + a + b);
return a;
}
void func1 (int i)
{
printf("%d\n", i);
}
然后,产生目标文件:
[root@-CentOS Program]# gcc -c SimpleSection.c
[root@-centos Program]# file SimpleSection.o
SimpleSection.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
file命令的结果也告诉我们,这是一个32位ELF的文件,类型是 relocatable ,就是可重定位。所以目标文件又叫做可重定位文件。
elf文件的最开始是elf文件头信息,32位有52个字节组成。我们可以使用 readelf 工具来查看一下:
[root@-centos Program]# readelf -h SimpleSection.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 224 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 11
Section header string table index: 8