ELF目标文件结构
来源:互联网 发布:诺基亚n8刷windows 编辑:程序博客网 时间:2024/06/04 18:51
目标文件结构
编译C/C++源文件会产生目标文件,目标文件是链接的基础。常见的目标文件后缀名是.o、.obj。在Windows下,目标文件(.obj)按照PE-COFF格式存储;在Linux下,目标文件按照ELF格式存储。PE-COFF、ELF格式都是Unix的COFF变种,COFF主要贡献是在目标文件中引入的“段”的机制。 下面以Linux下gcc编译产生的目标文件为主,介绍目标文件结构。
实验代码
首先编写如下代码的源文件,在Linux环境下,使用gcc编译器编译产生目标文件SimpleSection.o。以SimpleSection.o为例,分析目标文件结构。
// SimpleSection.c 源文件int printf(const char* format, ...);int global_init_var = 255;int global_uninit_var;void func1 (int i){ printf("%d\n", i);}int main(void){ static int static_var = 256; static int static_var2; int a = 1; int b; func1(static_var + static_var2 + a + b); return a;}
编译产生目标文件,无需链接:gcc -c SimpleSection.c。
ELF目标文件总体结构
ELF目标文件的总体结构如上图所示。不同操作系统下不同编译器生成的目标文件结构可能会稍有不同。
首先是ELF文件头(ELF Header)。像其他文件的文件头一下,ELF文件头保存了ELF文件的基本信息。根据文件头可以读取解析整个目标文件。文件头以下是各个段,主要包括代码段(.text)、数据段(.data)、bss段(.bss)等。之后还有段表(Section header table)、字符串表(String Tables)、符号表(Symbol Tables)等信息。
ELF文件头
文件头将目标文件基本信息保存在一个结构体中,如下:
typedef struct { unsigned char e_ident[16]; // Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; // 段表偏移 Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; // 段描述符大小 Elf32_Half e_shnum; // 段的数量 Elf32_Half e_shstrndx; // 段字符串表在段表中的下标} Elf32_Ehdr;
在终端输入readelf -h SimpleSection.o,可以查看SimpleSection.o文件头:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2’s complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 1056 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 13
Section header string table index: 10
段表结构
typedef struct { 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;
查看段表readelf -S SimpleSection.o :
There are 13 section headers, starting at offset 0x420:
Section Headers:
[Nr] Name Type Address Offset Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040 0000000000000054 0000000000000000 AX 0 0 1
[ 2] .rela.text RELA 0000000000000000 00000378 0000000000000078 0000000000000018 I 11 1 8
[ 3] .data PROGBITS 0000000000000000 00000094 0000000000000008 0000000000000000 WA 0 0 4
[ 4] .bss NOBITS 0000000000000000 0000009c 0000000000000004 0000000000000000 WA 0 0 4
[ 5] .rodata PROGBITS 0000000000000000 0000009c 0000000000000004 0000000000000000 A 0 0 1
[ 6] .comment PROGBITS 0000000000000000 000000a0 000000000000002e 0000000000000001 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 0000000000000000 000000ce 0000000000000000 0000000000000000 0 0 1
[ 8] .eh_frame PROGBITS 0000000000000000 000000d0 0000000000000058 0000000000000000 A 0 0 8
[ 9] .rela.eh_frame RELA 0000000000000000 000003f0 0000000000000030 0000000000000018 I 11 8 8
[10] .shstrtab STRTAB 0000000000000000 00000128 0000000000000061 0000000000000000 0 0 1
[11] .symtab SYMTAB 0000000000000000 00000190 0000000000000180 0000000000000018 12 11 8
[12] .strtab STRTAB 0000000000000000 00000310 0000000000000066 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
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 st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; // Elf32_Half st_shndx; // 符号所在的段} Elf32_Sym;
查看符号表readelf -s SimpleSection.o :
Symbol table ‘.symtab’ contains 16 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS SimpleSection.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000004 4 OBJECT LOCAL DEFAULT 3 static_var.1731
7: 0000000000000000 4 OBJECT LOCAL DEFAULT 4 static_var2.1732
8: 0000000000000000 0 SECTION LOCAL DEFAULT 7
9: 0000000000000000 0 SECTION LOCAL DEFAULT 8
10: 0000000000000000 0 SECTION LOCAL DEFAULT 6
11: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 global_init_var
12: 0000000000000004 4 OBJECT GLOBAL DEFAULT COM global_uninit_var
13: 0000000000000000 33 FUNC GLOBAL DEFAULT 1 func1
14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf
15: 0000000000000021 51 FUNC GLOBAL DEFAULT 1 main
SimpleSection.o结构
根据文件头、段表、字符串表信息,可以分析出整个目标文件的结构,如上图所示。整个文件的大小0x00000760 = 1888 Byte。注意到,由于对齐的原因,.symtab、.rela.text的起始地址与前面的段并不连续。根据段表可以知道,.symtab、.rela.text段都要求起始地址能被8整除。
变量在ELF文件中的存储
已初始化全局变量 ——〉 .data
已初始化局部静态变量 ——〉 .data
未初始化全局变量 ——〉 .bss
未初始化局部静态变量 ——〉 .bss
只读数据 ——〉 .rodata
局部变量 ——〉 .text
对于C++程序
- 段表:group段;
- C++符号修饰:C构造函数,D析构函数,C/D0默认构造/析构函数;
- 构造/析构函数:只要我们定义了构造函数,系统不再生成默认的构造函数;不论我们有没有定义析构函数,系统都会生成默认的析构函数;
- 每个被明确调用成员函数都是一个段;
- 数据段:类的初始化静态非const变量放在.data段,类的初始化静态const变量放在.rodata段。
待完善…
- ELF目标文件结构
- 目标文件--ELF目标文件
- 目标文件ELF
- ELF二进制目标文件详解
- 目标文件ELF中的内容
- ELF二进制目标文件详解
- ELF文件结构描述
- ELF文件结构
- elf文件结构描述
- ELF 文件结构
- ELF文件结构
- ELF文件结构
- ELF文件结构
- ELF文件结构
- ELF文件结构
- ELF文件结构描述
- ELF文件头结构
- ELF文件结构详解
- 通过API文档查询Math的方法打印近似圆
- redis模糊查询scan
- XSL常见问题及解决(二)有关Xpath
- 隐马尔科夫模型(HMM)
- windows下的navicat的安装、激活、汉化
- ELF目标文件结构
- HDU 题目1198 Farm Irrigation 并查集
- 2--理解并学习javascript中的面向对象(OOP)(续)
- 微机原理期中考试
- tortoisegit使用教程 --- 修改提交简易图文教程
- 算法概论 习题8.20
- jq insertBefore 的返回值
- tomcat版本换了报错:报错:The Apache Tomcat installation at this directory is version 8.5.6. A Tomcat 8.0 ins
- 今天研究jquery源码的收获