sections包含所有的信息,除了ELF头、program header table和section header table。sections满足几个条件:
1. 每个section都有唯一的一个section header,但是section header可能没有section。
2. 每个section占用文件中连续的字节。
3. 文件中的section没有重叠。
4. 目标文件可能有不活动的空间。即文件中的一部分字节,可能既不是头,也不是section、也许是无用的填充。
Section header table包含所有section的基本信息,如类型、地址等。通过section header table可以索引所有的section。通过ELF header中的e_shoff可以确定section header table在文件中的位置、e_shnum可以确定section的个数、e_shentsize可以确定section header table一个section条目的大小。
Section header可以用下述结构体表示:
1 2 3 4 5 6 7 8 9 10 11 12 | typedef struct elf32_shdr { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr; |
sh_name,确定section的名字,其值是距section header string table开头的偏移。由于string table中的所有字符串是'\0'结尾的,所以只需要知道字符串首即可。
sh_type,是section的类型。
Name | Value |
SHT_NULL | 0 |
SHT_PROGBITS | 1 |
SHT_SYMTAB | 2 |
SHT_STRTAB | 3 |
SHT_RELA | 4 |
SHT_HASH | 5 |
SHT_DYNAMIC | 6 |
SHT_NOTE | 7 |
SHT_NOBITS | 8 |
SHT_REL | 9 |
SHT_SHLIB | 10 |
SHT_DYNSYM | 11 |
SHT_LOPROC | 0x70000000 |
SHT_HIPROC | 0x7fffffff |
SHT_LOUSER | 0x80000000 |
SHT_HIUSER | 0xffffffff |
sh_flags,section的flags:
Name | Value |
SHF_WRITE | 0x1 |
SHF_ALLOC | 0x2 |
SHF_EXECINSTR | 0x4 |
SHF_MASKPROC | 0xf0000000 |
sh_addr,如果section出现在内存镜像中,表示section第一个字节的地址。否则为0。
sh_offset,给出section距文件开始处的偏移。
sh_size,如果type不是SHT_NOBITS,表示section在文件中的大小。如果type是SHT_NOBITS,section不占文件大小,sh_size表示内存中的大小。
sh_link,根据type确定含义。
sh_info,根据type确定含义。
sh_addralign,section的对齐要求。0和1表示无对齐要求。
sh_entsize,一些section包含固定大小的条目,表示一个条目的大小。0表示无固定大小的条目。
ELF中的一些内容如符号表使用section索引。一些特殊的section索引有特殊的含义,这些索引可能并不存在于section header table中。这些特殊的索引如下:
Name | Value |
SHN_UNDEF | 0 |
SHN_LORESERVE | 0xff00 |
SHN_LOPROC | 0xff00 |
SHN_HIPROC | 0xff1f |
SHN_ABS | oxfff1 |
SHN_COMMON | 0xfff2 |
SHN_HIRESERVE | 0xffff |
SHN_UNDEF,显然这个索引存在于section header table中(如果不存在,那必然与其0号索引冲突)。0号索引的所有成员都是0。
SHN_ABS,表示相关的引用有绝对值。如存储在符号表中的源文件名的section索引为ABS。
SHN_COMMON,相对于这个section索引的符号是公共符号,如c的弱定义符号。
SHT_NULL,section header不活动,没有相关的section。通常,只有0号索引有这个类型。
SHT_PROGBITS,包含程序相关的信息。.text,.data等都是这种类型。
SHT_SYMTAB、SHT_DYNSYM,符号表。
SHT_STRTAB,字符串表。
SHT_REL、SHT_REL,重定向表。
SHT_HASH,字符哈希表。
SHT_DYNAMIC,包含动态链接的信息。
SHT_NOTE,note信息。
SHT_NOBITS,不占用文件空间,其它和PROGBITS类型相似。sh_offset包含概念上的文件偏移。.bss是这种类型。
SHT_SHLIB,保留。
SHF_WRITE,section包含在进程执行期间可写的数据。
SHF_ALLOC,进程执行期间,section占用内存。一些section是控制section,不会加载到内存,此flag被清除。
SHF_EXECINSTR,section包含可执行机器指令。
这两个字段,不同的section type,表示不同的含义,如下:
sh_type | sh_link | sh_info |
SHT_DYNMIC | section条目使用的字符串表的section header索引。 | 0 |
SHT_HASH | 哈希表对应的符号表的索引 | 0 |
SHT_REL SHT_RELA | 相关的符号表的索引。 | 重定向的目标section的索引。 |
SHT_SYMTAB SHT_DYNSYM | 操作系统定义 | 操作系统定义 |
其它 | SHN_UNDEF | 0 |
ELF中的许多section是预定义好的,包含程序和控制信息。这些section被操作系统使用。不同的操作系统可能有不同的类型和属性。
Name | Type | Atrributes |
.bss | SHT_NOBITS | SHF_ALLOC_SHF_WRITE |
.comment | SHT_PROGBITS | none |
.data | SHT_PROGBITS | SHF_ALLOC_SHF_WRITE |
.data1 | SHT_PROGBITS | SHF_ALLOC_SHF_WRITE |
.debug | SHT_PROGBITS | none |
.dynamic | SHT_DYNAMIC | see below |
.hash | SHT_HASH | SHF_ALLOC |
.line | SHT_PROGBITS | none |
.note | SHT_NOTE | none |
.rodata | SHT_PROGBITS | SHF_ALLOC |
.rodata1 | SHT_PROGBITS | SHF_ALLOC |
.shstrtab | SHT_STRTAB | none |
.strtab | SHT_STRTAB | |
.symtab | SHT_STRTAB | |
.text | SHT_PROGBITS | SHF_ALLOC+SHF_EXECINSTR |
这些特殊section的用途如下:
.bss,包含未初始化的数据。程序运行时,系统初始化为0。这个section不占用文件空间。
.comment,包含版本控制信息。
.data与.data1,包含已初始化数据。
.debug,包含符号调试信息。
.dynamic,包含动态链接信息。可以有SHF_ALLOC何SHF_WRITE属性,是否有SHF_WRITE属性是由操作系统和处理器定义的。
.hash,包含符号哈希表。
.line,包含用于符号调试的行号信息。
.note,
.rodata和.rodata1,包含只读数据。
.shstrtab,包含section names。
.strtab,包含字符串,通常表示符号表相关的名字。如果一个文件有一个可加载段包含符号字符串表,这个section的属性将是SHF_ALLOC,否则这个位被关闭。
.symtab,包含符号表。如果有一个可加载段包含符号表,则属性包括SHF_ALLOC。
.text,包含可执行指令。
.开头的section name是保留给系统的。
尽管程序也可使用,但是不建议这样做。