《程序员的自我修养》- ELF文件预备知识
基本工具与ELF文件基本结构
基本工具包括radare2,objdump,readelf
ELF文件的基本结构由文件头(Header)和段(section)组成
sections 与 segments
在维基百科中,对这两个概念的区分如下:
The segments contain information that is necessary for runtime execution of the file, while sections contain important data for linking and relocation. Any byte in the entire file can be owned by at most one section, and there can be orphan bytes which are not owned by any section.
可以看到,sections和segments最大的区别在于前者所包含的是链接所需要的信息,用于和链接器互动;而后者所包含的则是运行时所需要的数据,与操作系统互动。注意这里的链接可以是可执行文件产生之前就已经完成了的静态链接,也可以是运行时的动态链接。因此sections和segments并不冲突,只是概念上有不同之处。为了避免歧义,本文中对于这类概念使用英文表示。 我们使用readelf工具来探索一下/bin/sh程序的sections和segments:
1 |
|
1 |
|
注意两者输出中的Sections Headers和Program
Headers,其中前者是指sections的入口,而后者则是segments的入口。从readelf -l
的输出中同样可以看到一个segment可以包含多个section。其实正是在链接期间,链接器将一个或多个sections放进了一个segment。
同时在readelf -S
的输出中我们可以看到表头同时存在Address和Offset,要了解这两者的区别需要先了解在内核中,Section
Headers的信息是如何被存储的。
Section Header Table
Section Headers是由一种特定的数据结构组成的数组,称为section header
table,用于索引文件中所有sections的位置。这个数组的下标被称为section
header table
index。这个数据的详细信息保存在ELF文件的文件头中,可以使用readelf -h
查看:
1 |
|
有一些section header table index是被保留的,其中比较重要的是以下几个:
Value
Name
Explanation
0x0000
SHN_UNDEF
Marks a meaningless section reference
0xfff1
SHN_ABS
Specifies absolute values for the corresponding reference
0xfff2
SHN_COMMON
Symbols defined relative to it are common symbols
注意:common symbols仅存在于relocatable object file中 到这里为止,我们已经简单了解了section的相关数据在ELF文件中是如何被组织起来的。下面是一个简单的示意图:
Section Header 的数据结构
在内核中,组成section header数据结构的代码如下:
1 |
|
下面的/bin/sh的section header table可以让我们直观地看到这一点:
sh_type的值有以下几种:
Value
Name
Explanation
0
SHT_NULL
The Section Header is inactive
1
SHT_PROGBITS
Information defined completely by the program
2
SHT_SYMTAB
All symbols needed during linking and some unnecessary ones
3
SHT_STRTAB
A string table (can be mutiple)
4
SHT_RELA
Relocation entries with explict addends (can be mutiple)
9
SHT_REL
Relocation entries without explict addends (can be mutiple)
5
SHT_HASH
A symbol hash table used in dynamic linking
6
SHT_DYNAMIC
Information for dynamic linking
11
SHT_DYNSYM
Only the symbols needed during linking
7
SHT_NOTE
Information that marks the file in some way
8
SHT_NOBITS
Looks like SHT_PROGBITS but occupies no space
10
SHT_SHLIB
(Reserved but semantics not specified)
0x70000000
SHT_LOPROC
Reserved for processor-specific semantics
0x7fffffff
SHT_HIPROC
Reserved for processor-specific semantics
0x80000000
SHT_LOUSER
The lower bound of the range of index reserved for application programs
0xffffffff
SHT_HIUSER
The upper bound of the range of index reserved for application programs
sh_flag的值如下所示:
Nama
Value
Explanation
SHF_WRITE
0x1
Data in this section should be writable during process execution
SHF_ALLOC
0x2
The section occupies memory during process execution
SHF_EXECINSTR
0x4
This section contains executable machine instructions
SHF_MASKPROC
0xf0000000
Reserved section
sh_link与sh_info的值取决于sh_type:
sh_type
sh_link
sh_info
SHT_DYNAMIC
The section header index of the string table used by entries in the section
0
SHT_HASH
The section header index of the symbol table to which the hash table applies
0
SHT_REL
SHT_RELA
The section header index of the associated symbol table
The section header index of the section to which the relocation applies
SHT_SYMTAB
SHT_DYNSYM
The section header index of the associated string table
One greater than the symbol table index of the last local symbol (binding STB_LOCAL).
other
SHN_UNDEF
0
可以看到,sh_link的作用在于告诉特定类型的section需要的信息的位置。
有了上面的知识,我们最后来看一下sh_addr与sh_offset的区别
sh_addr为0时,代表这个section不会出现在程序运行时的地址空间中(也就是说不会出现),否则它的值就是程序运行时这个section的地址。
而sh_offset指的是在这个ELF文件中该section的位置相对于文件首的偏移。上面sh_type的可能取值告诉我们,SHT_NOBITS类型的section并不占实际的空间,这时sh_offset指的是一个概念性的位置。即这个section理论上的偏移。
下面截取的一部分readelf -S
的输出结果有助于我们理解上面的区别:
1 |
|
.bss段的类型是NOBITS,Flags中包含A(Alloc),这意味着这个段在ELF文件中不占空间,但是在程序运行时却需要为它分配空间,它的Address便是程序运行时该section的地址,后面的Offset便是ELF文件中的概念性的偏移地址。 下面的三个段都有一个共同特点:不具有A的Flag,也就是说不会出现在文件执行时的地址空间中,因此Address的值都为0,而Offset存在。 以上便是了解ELF文件的section的预备知识,下次将详细讲解ELF文件中的section