《程序员的自我修养》PAGE77 图3-6理解
/*
*SimpleSection.c
*
*
*/
int printf(const char * format, ...);
int global_init_var = 84;
int static global_uninit_var;
__attribute__((section("yl"))) int gobal = 42;
void func1 (int i)
{
printf( "%d\n", i );
}
int main(void)
{
static int static_var = 85;
static int static_var2;
int a = 1;
int b;
func1( static_var + static_var2 + a + b);
return a;
}
命令:
root@ubuntu:/usr# gcc -c SimpleSection.c
root@ubuntu:/usr# readelf -h SimpleSection.o
ubuntu系统得出表1:
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: 272 (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: 12
Section header string table index: 9
根据Start of section headers: 272 (bytes into file)
由Size of this header: 52 (bytes)可知ELF Header长度为0x34。
注:typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;
该结构体定义了ELF文件头格式。
其中Elf32_Half e_shstrndx; Section header string table index: 9
e_shstrndx表示".shstrtab"在段表中的下标为9。如表2所示。
.shstrtab用来保存段表中用到的字符串。
所以我们知道,通过分析ELF文件头,就可以得到段表和段表字符串表的位置,从而解析出整个ELF文件。
命令:
There are 12 section headers, starting at offset 0x110:
ubuntu系统得出表2:
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 000050 00 AX 0 0 4
[ 2] .rel.text REL 00000000 00046c 000028 08 10 1 4
[ 3] .data PROGBITS 00000000 000084 000008 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 00008c 000008 00 WA 0 0 4
[ 5] yl PROGBITS 00000000 00008c 000004 00 WA 0 0 4
[ 6] .rodata PROGBITS 00000000 000090 000004 00 A 0 0 1
[ 7] .comment PROGBITS 00000000 000094 000026 01 MS 0 0 1
[ 8] .note.GNU-stack PROGBITS 00000000 0000ba 000000 00 0 0 1
[ 9] .shstrtab STRTAB 00000000 0000ba 000054 00 0 0 1
[10] .symtab SYMTAB 00000000 0002f0 000110 10 11 12 4
[11] .strtab STRTAB 00000000 000400 00006c 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
注:.yl段由"__attribute__((section("yl"))) int gobal = 42;"自定义出。
[ 2] .rel.text REL 00000000 00046c 000028 08 10 1 4
.rel.text段是一个重定位表,是SHT_REL类型的,他的”sh_link"表示符号表的下标,它的"sh_info”表示它作用于哪个段。这里.rel.text作用于.text段,.text段的下标为1。
由表2可知.text段由ox04开始长度为0x50以0x84结束;.data段由0x84开始长度为0x08以0x8c结束;.yl段由0x8c开始长度为0x04以0x90结束(.bss段也是有0x8c开始的,但长度为0);.rodata段由0x90开始长度为0x04以0x94结束;.comment段由0x94开始长度为0x26以0ba结束;.shstrtab段由0xba开始长度为0x54以0x10e结束;由表1可知SectionTable的偏移量为0x110,一共12个段,每段大小为40byte,这个长度正好等于sizeof(Elf32_Shdr)。Elf32_Shdr是/usr/include/elf.h 中定义的段表中描述段内容的结构体:
/* Section header. */typedef struct
{
Elf32_Word sh_name; /* Section name (string tbl index) */
Elf32_Word sh_type; /* Section type */
Elf32_Word sh_flags; /* Section flags */
Elf32_Addr sh_addr; /* Section virtual addr at execution */
Elf32_Off sh_offset; /* Section file offset */
Elf32_Word sh_size; /* Section size in bytes */
Elf32_Word sh_link; /* Link to another section */
Elf32_Word sh_info; /* Additional section information */
Elf32_Word sh_addralign; /* Section alignment */
Elf32_Word sh_entsize; /* Entry size if section holds table */
} Elf32_Shdr;
所以SectionTable由0x110开始,长度为480byte即0x1e0以0x2f0结束;.symtab由0x2f0开始长度为0x110以0x400结束;.strtab由0x400开始长度为0x6c以0x46c结束;.reltext段由0x46c开始长度为0x28以0x494结束。0x494为1172字节的。正好就是SimpleSection.o的大小。