ELF(Executable and Linking Format)是一种对象文件的格式。他用于描述下列三种文件:
可重定向对象文件
典型的是gcc -c main.c main.o 其中main.o就是可重定向对象文件
可执行对象文件
典型的gcc main.o -o main main文件就是可执行对象文件
可动态链接共享对象文件
常用的pthread.so等就是可动态链接共享对象文件
上面都是对象文件,利用连接器,可重定向对象文件可以生成可执行对象文件或者可动态链接共享对象文件。
整个ELF分为4个部分:
ELF header
program header table
sections/segments
section header table
以下面程序为例:
.section .data
data_items:
.long 3,4,5,6,7,8
hellostring:
.ascii "hello world"
.section .text
.globl _start
_start:
movl $1,eax
movl $4,ebx
int $0x80
可生成对象文件和可执行文件
as main.s -o main.o
ld main.o -o main
使用工具readelf可以查看这两个文件的结构
可重定向对象文件
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: 144 (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: 7
Section header string table index: 4
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 00000c 00 AX 0 0 4
[ 2] .data PROGBITS 00000000 000040 000023 00 WA 0 0 4
[ 3] .bss NOBITS 00000000 000064 000000 00 WA 0 0 4
[ 4] .shstrtab STRTAB 00000000 000064 00002c 00 0 0 1
[ 5] .symtab SYMTAB 00000000 0001a8 000070 10 6 6 4
[ 6] .strtab STRTAB 00000000 000218 00001f 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There are no relocations in this file.
There are no unwind sections in this file.
Symbol table '.symtab' contains 7 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000000 0 SECTION LOCAL DEFAULT 2
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 NOTYPE LOCAL DEFAULT 2 data_items
5: 00000018 0 NOTYPE LOCAL DEFAULT 2 hellostring
6: 00000000 0 NOTYPE GLOBAL DEFAULT 1 _start
分析ELF Headers:
Entry point address: 0x0
这里表明入口地址为0,因此可以用作重定向。
Start of program headers: 0 (bytes into file)
Start of section headers: 144 (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: 7
00000040 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 |................|
00000050 07 00 00 00 08 00 00 00 68 65 6c 6c 6f 20 77 6f |........hello wo|
00000060 72 6c 64 00 00 2e 73 79 6d 74 61 62 00 2e 73 74 |rld...symtab..st|
对应之前看到的.data段信息:起始地址0x40,长度为0x23。可以看到所有的被初始化的全局数据。
readelf -a main.o最后输出了.symtab符号表。每个符号代表着程序中的函数名称或者变量名。可以看到是否全局/局部以及所属段ID。
例如hellostring为局部变量,所在段序号为2,代表.data段。
可在偏移144找到section headers,大小为40字节<p>program headers为空,这是因为program header只在可执行文件中生成。
分析Section可以看到7个secions:
.text 程序段
.data 被初始化的全局数据
.bsss 未被初始化的全局数据
.shstrtab 段表字符串表段(Section Header String Table)
.symtab 符号表段(变量、函数)
.strtab 字符串段(变量名,函数名字符串)
每个段列出了一些信息:
Name: 名称
Type:类型
Addr:虚拟地址
Off:段内偏移
Size:此段大小
ES:有些段有,例如.symtab存储了程序符号表,ES为10代表符号表中每行占用10字节
Flg:标志位输出有说明,一般来说W代表数据,X代表程序,A代表程序运行时需要分配内存。可以看到.data为WA,说明这是个数据区,且程序加载时必须分配内存存储初始化数据。.bss为W说明是数据区,但程序加载时不用分配内存。
Lk/inf:和特定Section相关
Al:段内地址对齐
使用HexDump可以查看对应段内的数据,例如:hexdump -C main.o
可执行对象文件
htm@htm:~/test/testassemble$ readelf -a main
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: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048074
Start of program headers: 52 (bytes into file)
Start of section headers: 204 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 2
Size of section headers: 40 (bytes)
Number of section headers: 6
Section header string table index: 3
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 08048074 000074 00000c 00 AX 0 0 4
[ 2] .data PROGBITS 08049080 000080 000023 00 WA 0 0 4
[ 3] .shstrtab STRTAB 00000000 0000a3 000027 00 0 0 1
[ 4] .symtab SYMTAB 00000000 0001bc 000090 10 5 5 4
[ 5] .strtab STRTAB 00000000 00024c 000037 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x08048000 0x08048000 0x00080 0x00080 R E 0x1000
LOAD 0x000080 0x08049080 0x08049080 0x00023 0x00023 RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .text
01 .data
There is no dynamic section in this file.
There are no relocations in this file.
There are no unwind sections in this file.
Symbol table '.symtab' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048074 0 SECTION LOCAL DEFAULT 1
2: 08049080 0 SECTION LOCAL DEFAULT 2
3: 08049080 0 NOTYPE LOCAL DEFAULT 2 data_items
4: 08049098 0 NOTYPE LOCAL DEFAULT 2 hellostring
5: 08048074 0 NOTYPE GLOBAL DEFAULT 1 _start
6: 080490a3 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
7: 080490a3 0 NOTYPE GLOBAL DEFAULT ABS _edata
8: 080490a4 0 NOTYPE GLOBAL DEFAULT ABS _end
No version information found in this file.
比较之前的可重定向对象文件:
Entry point address: 0x8048074
这里可执行入口变为了一个有效的虚拟地址。
Size of program headers: 32 (bytes)
Number of program headers: 2
因为这是可执行文件,所以需要有program headers,它描述了两个Segments
Seg1:0x08048000->0x08048000+0x80 可读可执行(里面放置了.text段)
Seg2:0x08049080->0x08049080+0x23 可读可写 (里面放置了.data段)
(这里的Segments是具有共同属性的Sections的集合,如RE/RW等)
从上面还可以看到虽然整个main文件大小不到1k,但占用的内存范围确是0x08048000->0x08049080+0x23。原因是,Segments是基于页存储的,因此必须是4K字节对齐(MMU的限制,从Segments的Align信息也可以看出)。
bss段被去掉了,因为这个段的长度为0
其他的段的加载地址也变为了有效的虚拟地址。