编译链接基本素养笔记(一)ELF文件结构
来源:互联网 发布:数据透视表行标签重复 编辑:程序博客网 时间:2024/06/05 00:55
源代码:
int printf(const char * format,...);int global_init_var=84;int global_uninit_var;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;}
头文件结构:
karl@ubuntu:~/c/static$ objdump -h SimpleSection.o SimpleSection.o: file format elf32-i386Sections:Idx Name Size VMA LMA File off Algn 0 .text 00000053 00000000 00000000 00000034 2**0 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE 1 .data 00000008 00000000 00000000 00000088 2**2 CONTENTS, ALLOC, LOAD, DATA 2 .bss 00000004 00000000 00000000 00000090 2**2 ALLOC 3 .rodata 00000004 00000000 00000000 00000090 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .comment 0000002a 00000000 00000000 00000094 2**0 CONTENTS, READONLY 5 .note.GNU-stack 00000000 00000000 00000000 000000be 2**0 CONTENTS, READONLY 6 .eh_frame 00000058 00000000 00000000 000000c0 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
生成的汇编语言和代码段内容:
karl@ubuntu:~/c/static$ objdump -s -d SimpleSection.oSimpleSection.o: file format elf32-i386Contents of section .text: 0000 5589e583 ec188b45 08894424 04c70424 U......E..D$...$ 0010 00000000 e8fcffff ffc9c355 89e583e4 ...........U.... 0020 f083ec20 c7442418 01000000 8b150400 ... .D$......... 0030 0000a100 00000001 c28b4424 1801c28b ..........D$.... 0040 44241c01 d0890424 e8fcffff ff8b4424 D$.....$......D$ 0050 18c9c3 ... Contents of section .data: 0000 54000000 55000000 T...U... Contents of section .rodata: 0000 25640a00 %d.. Contents of section .comment: 0000 00474343 3a202855 62756e74 7520342e .GCC: (Ubuntu 4. 0010 382e342d 32756275 6e747531 7e31342e 8.4-2ubuntu1~14. 0020 30342920 342e382e 3400 04) 4.8.4. Contents of section .eh_frame: 0000 14000000 00000000 017a5200 017c0801 .........zR..|.. 0010 1b0c0404 88010000 1c000000 1c000000 ................ 0020 00000000 1b000000 00410e08 8502420d .........A....B. 0030 0557c50c 04040000 1c000000 3c000000 .W..........<... 0040 1b000000 38000000 00410e08 8502420d ....8....A....B. 0050 0574c50c 04040000 .t...... Disassembly of section .text:00000000 <func1>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 ec 18 sub $0x18,%esp 6: 8b 45 08 mov 0x8(%ebp),%eax 9: 89 44 24 04 mov %eax,0x4(%esp) d: c7 04 24 00 00 00 00 movl $0x0,(%esp) 14: e8 fc ff ff ff call 15 <func1+0x15> 19: c9 leave 1a: c3 ret 0000001b <main>: 1b: 55 push %ebp 1c: 89 e5 mov %esp,%ebp 1e: 83 e4 f0 and $0xfffffff0,%esp 21: 83 ec 20 sub $0x20,%esp 24: c7 44 24 18 01 00 00 movl $0x1,0x18(%esp) 2b: 00 2c: 8b 15 04 00 00 00 mov 0x4,%edx 32: a1 00 00 00 00 mov 0x0,%eax 37: 01 c2 add %eax,%edx 39: 8b 44 24 18 mov 0x18(%esp),%eax 3d: 01 c2 add %eax,%edx 3f: 8b 44 24 1c mov 0x1c(%esp),%eax 43: 01 d0 add %edx,%eax 45: 89 04 24 mov %eax,(%esp) 48: e8 fc ff ff ff call 49 <main+0x2e> 4d: 8b 44 24 18 mov 0x18(%esp),%eax 51: c9 leave 52: c3 ret
段说明:
- 代码段第一列为偏移量,中间代码段中的内容(16进制),往下为代码段的汇编指令。可以看到代码段中的内容和会汇编指令的序列一样。代码段的长度也和头文件结构中的长度(0x53)相同。
- 数据段(data)保存的是初始化了的全局变量和局部静态变量。程序中有两个变量,
global_init_var
和static_var
,共八个字节。和头文件结构中的data段大小一样。 - rodata段存放的是只读数据,const修饰的变量和字符串常量(
%d\n
)。 - bss段存放的是未初始化的全局变量和局部静态变量。
观察文件头:
karl@ubuntu:~/c/static$ readelf -h SimpleSection.oELF 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: 376 (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: 13 Section header string table index: 10
32位文件头数据结构:/usr/include/elf.h
#define EI_NIDENT (16)typedef struct{ unsigned char e_ident[EI_NIDENT]; 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;
- Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 ,这个16字节魔术数对应了ELF文件的平台属性,字长,字节序,版本等。操作系统在加载的时候会确认魔术数是否正确,如果不正确,会拒绝加载。
- e_type ELF文件类型。
/* Legal values for e_type (object file type). */#define ET_NONE 0 /* No file type */#define ET_REL 1 /* Relocatable file */#define ET_EXEC 2 /* Executable file */#define ET_DYN 3 /* Shared object file */#define ET_CORE 4 /* Core file */
段表
karl@ubuntu:~/c/static$ readelf -S SimpleSection.oThere are 13 section headers, starting at offset 0x178://注意在文件头中,Start of section headers的值为十进制。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 000053 00 AX 0 0 1 [ 2] .rel.text REL 00000000 0004e8 000028 08 11 1 4 [ 3] .data PROGBITS 00000000 000088 000008 00 WA 0 0 4 [ 4] .bss NOBITS 00000000 000090 000004 00 WA 0 0 4 [ 5] .rodata PROGBITS 00000000 000090 000004 00 A 0 0 1 [ 6] .comment PROGBITS 00000000 000094 00002a 01 MS 0 0 1 [ 7] .note.GNU-stack PROGBITS 00000000 0000be 000000 00 0 0 1 [ 8] .eh_frame PROGBITS 00000000 0000c0 000058 00 A 0 0 4 [ 9] .rel.eh_frame REL 00000000 000510 000010 08 11 8 4 [10] .shstrtab STRTAB 00000000 000118 00005f 00 0 0 1 [11] .symtab SYMTAB 00000000 000380 000100 10 12 11 4 [12] .strtab STRTAB 00000000 000480 000066 00 0 0 1Key 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)
- 段表其实是一个段结构体的数组。
- 段表描述符结构:
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;
对于编译器和链接器来说,主要决定段的属性的是段的类型(
sh_type
)和段的标志位(sh_flags
).段类型:
/* Legal values for sh_type (section type). */#define SHT_NULL 0 /* Section header table entry unused */#define SHT_PROGBITS 1 /* Program data */#define SHT_SYMTAB 2 /* Symbol table */#define SHT_STRTAB 3 /* String table */#define SHT_RELA 4 /* Relocation entries with addends */#define SHT_HASH 5 /* Symbol hash table */#define SHT_DYNAMIC 6 /* Dynamic linking information */#define SHT_NOTE 7 /* Notes */#define SHT_NOBITS 8 /* Program space with no data (bss) */#define SHT_REL 9 /* Relocation entries, no addends */#define SHT_SHLIB 10 /* Reserved */#define SHT_DYNSYM 11 /* Dynamic linker symbol table */#define SHT_INIT_ARRAY 14 /* Array of constructors */#define SHT_FINI_ARRAY 15 /* Array of destructors */#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */#define SHT_GROUP 17 /* Section group */#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */#define SHT_NUM 19 /* Number of defined types. */
- 段标志:段的标志位(
sh_flag
) 段的标志位表示该段在进程虚拟地址空间中的属性,比如是否可写,是否可执行等。
/* Legal values for sh_flags (section flags). */#define SHF_WRITE (1 << 0) /* Writable */#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */#define SHF_EXECINSTR (1 << 2) /* Executable */#define SHF_MERGE (1 << 4) /* Might be merged */#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
- 分析文件头,能够得到短表和短表字符串表的位置,从而了解整个ELF文件。
符号表
- 查看目标文件的符号表:ELF文件中的符号表往往是文件中的一个段,段名一般叫”.symtab”。
karl@ubuntu:~/c/static$ nm SimpleSection.o00000000 T func100000000 D global_init_var00000004 C global_uninit_var0000001b T main U printf00000004 d static_var.137800000000 b static_var2.1379
- 符号表的结构很简单,它是一个
Elf32_Sym
结构(32位ELF文件)的数组,每个Elf32_Sym
结构对应一个符号。
/* Symbol table entry. */typedef struct{ Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility */ Elf32_Section st_shndx; /* Section index */} Elf32_Sym;
- 符号类型和绑定信息(
st_info
) 该成员低4位表示符号的类型(Symbol Type),高28位表示符号绑定信息(Symbol Binding) - 绑定信息:
/* Legal values for ST_BIND subfield of st_info (symbol binding). */#define STB_LOCAL 0 /* Local symbol 局部符号,对于目标文件的外部不可见*/#define STB_GLOBAL 1 /* Global symbol 全局符号,外部可见*/#define STB_WEAK 2 /* Weak symbol 弱引用*/#define STB_NUM 3 /* Number of defined types. */#define STB_LOOS 10 /* Start of OS-specific */#define STB_GNU_UNIQUE 10 /* Unique symbol. */#define STB_HIOS 12 /* End of OS-specific */#define STB_LOPROC 13 /* Start of processor-specific */#define STB_HIPROC 15 /* End of processor-specific */
- 符号的类型
/* Legal values for ST_TYPE subfield of st_info (symbol type). */#define STT_NOTYPE 0 /* Symbol type is unspecified 未知类型符号*/#define STT_OBJECT 1 /* Symbol is a data object 该符号是个数据对象,比如变量、数组等*/#define STT_FUNC 2 /* Symbol is a code object 该符号是个函数或其他可执行代码*/#define STT_SECTION 3 /* Symbol associated with a section 该符号表示一个段,这种符号必须是STB_LOCAL的*/#define STT_FILE 4 /* Symbol's name is file name 该符号表示文件名,一般都是该目标文件所对应的源文件名,它一定是STB_LOCAL类型的,并且它的st_shndx一定是SHN_ABS*/#define STT_COMMON 5 /* Symbol is a common data object */#define STT_TLS 6 /* Symbol is thread-local data object*/#define STT_NUM 7 /* Number of defined types. */#define STT_LOOS 10 /* Start of OS-specific */#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */#define STT_HIOS 12 /* End of OS-specific */#define STT_LOPROC 13 /* Start of processor-specific */#define STT_HIPROC 15 /* End of processor-specific */
- 符号所在段
st_shndx
)如果符号定义在本目标文件中,那么这个成员表示符号所在的段在段表中的下标,但是如果符号不是定义在本目标文件中,或者对于有些特殊符号,sh_shndx的值有些特殊。
#define SHN_UNDEF 0 /* Undefined section符号块未定义,在本目标文件被引用到,但是定义在其他目标文件中*/#define SHN_ABS 0xfff1 /* Associated symbol is absolute 表示该符号包含了一个绝对的值。比如表示文件名的符号就属于这种类型的*/#define SHN_COMMON 0xfff2 /* Associated symbol is common 表示该符号是一个“COMMON块”类型的符号,一般来说,未初始化的全局符号定义就是这种类型的*/
查看SimpleSection.o中的符号表详细信息
karl@ubuntu:~/c/static$ readelf -s SimpleSection.oSymbol table '.symtab' contains 16 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 FILE LOCAL DEFAULT ABS SimpleSection.c 2: 00000000 0 SECTION LOCAL DEFAULT 1 3: 00000000 0 SECTION LOCAL DEFAULT 3 4: 00000000 0 SECTION LOCAL DEFAULT 4 5: 00000000 0 SECTION LOCAL DEFAULT 5 6: 00000004 4 OBJECT LOCAL DEFAULT 3 static_var.1378 7: 00000000 4 OBJECT LOCAL DEFAULT 4 static_var2.1379 8: 00000000 0 SECTION LOCAL DEFAULT 7 9: 00000000 0 SECTION LOCAL DEFAULT 8 10: 00000000 0 SECTION LOCAL DEFAULT 6 11: 00000000 4 OBJECT GLOBAL DEFAULT 3 global_init_var 12: 00000004 4 OBJECT GLOBAL DEFAULT COM global_uninit_var 13: 00000000 27 FUNC GLOBAL DEFAULT 1 func1 14: 00000000 0 NOTYPE GLOBAL DEFAULT UND printf 15: 0000001b 56 FUNC GLOBAL DEFAULT 1 main
0 0
- 编译链接基本素养笔记(一)ELF文件结构
- Linux下ELF文件的基本结构
- ELF文件格式(一)--ELF文件头
- 网络素养公开课笔记(一)
- PE文件结构(一) 基本结构
- 编译、链接学习笔记(一)简述编译链接过程
- 编译 链接 加载 ELF 文件 相关 工具 和 命令
- Linux中ELF文件动态链接的加载、解析及实例分析(一): 加载
- ELF文件结构描述(1)
- ELF文件结构描述(2)
- ELF文件结构描述
- ELF文件结构
- elf文件结构描述
- ELF 文件结构
- ELF文件结构
- ELF文件结构
- ELF文件结构
- ELF文件结构
- 同余与乘法逆元
- JAVA 的垃圾回收机制
- 6个Java项目UML反向工程工具
- HTTP请求和响应
- Java程序员修炼之道 之 Logging(2/3) - 怎么写Log
- 编译链接基本素养笔记(一)ELF文件结构
- 最大子段和
- NGUIkeng
- SQL学习笔记(一)
- jquery $.trim()方法使用介绍
- Android Lollipop (5.0) 屏幕录制实现
- deep learning---利用caffe在vgg-face上finetuing自己的人脸数据
- usaco contest 2008.11 gold 安慰奶牛
- java 实现发送邮件