前言
在之前的学习中了解到GCC编译Cpp文件生成的目标文件(.o) 中的各个段(section)的含义, 重点实践了代码段,数据段 这些常见的段。对于一个完整的ELF文件,除了各个段之外,还包含了一些其他附属信息等待挖掘。
测试环境
- Ubuntu 20.04
- VSCode
- GCC >= 7.5.0
ELF文件的结构组成
- ELF header: ELF的头文件,包含整个文件的基本信息描述
- 段表(Section Header Table): 包含elf文件各个段的信息
- 符号表(Symbol Table)
ELF文件的查看分析工具: readelf
命令
-a --all Equivalent to: -h -l -S -s -r -d -V -A -I
-h --file-header Display the ELF file header
-l --program-headers Display the program headers
--segments An alias for --program-headers
-S --section-headers Display the sections' header
--sections An alias for --section-headers
-g --section-groups Display the section groups
-t --section-details Display the section details
-e --headers Equivalent to: -h -l -S
-s --syms Display the symbol table
--symbols An alias for --syms
--dyn-syms Display the dynamic symbol table
-n --notes Display the core notes (if present)
-r --relocs Display the relocations (if present)
-u --unwind Display the unwind info (if present)
-d --dynamic Display the dynamic section (if present)
-V --version-info Display the version sections (if present)
-A --arch-specific Display architecture specific information (if any)
-c --archive-index Display the symbol/file index in an archive
继续采用之前的程序: SimpleSection.cpp
/**
* @file SimpleSectipn.cpp
* @author your name (you@domain.com)
* @brief
* @version 0.1
* @date 2021-04-27
*
* @copyright Copyright (c) 2021
*
*/
int printf(const char* format, ... );
int global_init_var = 84;
int global_uninit_var;
void func1(int i){
printf("%d\n", i);
}
// 使用GCC的扩展功能,制定函数到 ABC段
__attribute__((section("ABC"))) void func2(){
printf("Hello,world!\n");
}
__attribute__((section("DEF"))) int g_index = 12345;
int main(){
static int static_var = 85;
static int static_var2;
int a = 1;
int b;
func1(static_var + static_var2 + a + b);
return a;
}
ELF 头文件(ELF Header)
readelf -h xxx.o
读取elf文件的头部信息,主要包含内容:
- ELF 魔术 (就是一些特定数字)
- 数据存储方式: 大端、小端
- ABI 版本信息
- 运行平台: unix, amd64 x86-64
- 段的数量,长度, 17个段
readelf -h SimpleSectipn.o
ELF 头:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
类别: ELF64
数据: 2 补码,小端序 (little endian)
Version: 1 (current)
OS/ABI: UNIX - System V
ABI 版本: 0
类型: REL (可重定位文件)
系统架构: Advanced Micro Devices X86-64
版本: 0x1
入口点地址: 0x0
程序头起点: 0 (bytes into file)
Start of section headers: 1488 (bytes into file)
标志: 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: 17
Section header string table index: 16
段表 (Section Header Table)
段表用于记录各个段的信息,比如段的字节大小,段名称,读写权限等。段表并不是段本身,段本身是指.text, .data, .rodata 等。
readelf -S xxx.o
读取段表信息, 下面读取的结果段的编号从0~16, 总共17个段, 常见的段: .text, .data, .rodata, .bss, .comment, 以及自定义的2个段 ABC, DEF。 标号为0的段大小为NULL, 实际上有效的段为1~16
There are 17 section headers, starting at offset 0x5d0:
节头:
[号] 名称 类型 地址 偏移量
大小 全体大小 旗标 链接 信息 对齐
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
000000000000005f 0000000000000000 AX 0 0 1
[ 2] .rela.text RELA 0000000000000000 00000458
0000000000000078 0000000000000018 I 14 1 8
[ 3] .data PROGBITS 0000000000000000 000000a0
0000000000000008 0000000000000000 WA 0 0 4
[ 4] .bss NOBITS 0000000000000000 000000a8
0000000000000008 0000000000000000 WA 0 0 4
[ 5] .rodata PROGBITS 0000000000000000 000000a8
0000000000000012 0000000000000000 A 0 0 1
[ 6] ABC PROGBITS 0000000000000000 000000ba
000000000000001c 0000000000000000 AX 0 0 1
[ 7] .relaABC RELA 0000000000000000 000004d0
0000000000000030 0000000000000018 I 14 6 8
[ 8] DEF PROGBITS 0000000000000000 000000d8
0000000000000004 0000000000000000 WA 0 0 4
[ 9] .comment PROGBITS 0000000000000000 000000dc
000000000000002b 0000000000000001 MS 0 0 1
[10] .note.GNU-stack PROGBITS 0000000000000000 00000107
0000000000000000 0000000000000000 0 0 1
[11] .note.gnu.propert NOTE 0000000000000000 00000108
0000000000000020 0000000000000000 A 0 0 8
[12] .eh_frame PROGBITS 0000000000000000 00000128
0000000000000078 0000000000000000 A 0 0 8
[13] .rela.eh_frame RELA 0000000000000000 00000500
0000000000000048 0000000000000018 I 14 12 8
[14] .symtab SYMTAB 0000000000000000 000001a0
0000000000000210 0000000000000018 15 14 8
[15] .strtab STRTAB 0000000000000000 000003b0
00000000000000a7 0000000000000000 0 0 1
[16] .shstrtab STRTAB 0000000000000000 00000548
0000000000000081 0000000000000000 0 0 1
重定位表 (Relocation Table)
readelf 输出的结果中, [1] 段的类型为RELA 即重定位
[1] .rela.text RELA
符号表 (Symbol Table)
符号表 对于链接时候比较重要, 经常会遇到链接时候的一些错误undefined reference
错误, 和符号表有很大的关系。
查看目标文件的符号表: nm
命令:
C++代码中的变量名称:g_index, global_init_var, 等 以及函数名称: main, func1, func2, 程序中调用了标准库的函数printf, printf显然不在SimpleSection.cpp中定义, 因此printf为外部符号
nm SimpleSectipn.o
0000000000000000 D g_index
0000000000000000 D global_init_var
U _GLOBAL_OFFSET_TABLE_
0000000000000000 B global_uninit_var
0000000000000028 T main
0000000000000000 T _Z5func1i
0000000000000000 T _Z5func2v
U _Z6printfPKcz
0000000000000004 d _ZZ4mainE10static_var
0000000000000004 b _ZZ4mainE11static_var2
也可以采用 readelf -s xxx.o
查看符号表的信息
readelf -s SimpleSectipn.o
Symbol table '.symtab' contains 22 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS SimpleSectipn.cpp
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: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 8
8: 0000000000000004 4 OBJECT LOCAL DEFAULT 3 _ZZ4mainE10static_var
9: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 _ZZ4mainE11static_var2
10: 0000000000000000 0 SECTION LOCAL DEFAULT 10
11: 0000000000000000 0 SECTION LOCAL DEFAULT 11
12: 0000000000000000 0 SECTION LOCAL DEFAULT 12
13: 0000000000000000 0 SECTION LOCAL DEFAULT 9
14: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 global_init_var
15: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 global_uninit_var
16: 0000000000000000 40 FUNC GLOBAL DEFAULT 1 _Z5func1i
17: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
18: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z6printfPKcz
19: 0000000000000000 28 FUNC GLOBAL DEFAULT 6 _Z5func2v
20: 0000000000000000 4 OBJECT GLOBAL DEFAULT 8 g_index
21: 0000000000000028 55 FUNC GLOBAL DEFAULT 1 main
网友评论