参数解释
-a --all 显示全部信息,等价于 -h -l -S -s -r -d -V -A -I.
-h --file-header 显示elf文件开始的文件头信息.
-l --program-headers --segments 显示程序头(段头)信息(如果有的话)。
-S --section-headers --sections 显示节头信息(如果有的话)。
-g --section-groups 显示节组信息(如果有的话)。
-t --section-details 显示节的详细信息(-S的)。
-s --syms --symbols 显示符号表段中的项(如果有的话)。
-e --headers 显示全部头信息,等价于: -h -l -S -n --notes 显示note段(内核注释)的信息。
-r --relocs 显示可重定位段的信息。
-u --unwind 显示unwind段信息。当前只支持IA64 ELF的unwind段信息。
-d --dynamic 显示动态段的信息。
-V --version-info 显示版本段的信息。
-A --arch-specific 显示CPU构架信息。
-D --use-dynamic 使用动态段中的符号表显示符号,而不是使用符号段。
-x --hex-dump= 以16进制方式显示指定段内内容。number指定段表中段的索引,或字符串指定文件中的段名。
-w[liaprmfFsoR] or --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges] 显示调试段中指定的内容。
-I --histogram 显示符号的时候,显示bucket list长度的柱状图。
-v --version 显示readelf的版本信息。
-H --help 显示readelf所支持的命令行选项。
-W --wide 宽行输出。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
readelf -h test
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: EXEC (Executable file)(.so文件DYN (Shared object file)、.o文件REL (Relocatable file)、Core dump文件(CORE))
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400510
Start of program headers: 64 (bytes into file)
Start of section headers: 3072 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 28
在 readelf 的输出中:
第 1 行,ELF Header: 指名 ELF 文件头开始。
第 2 行,Magic 魔数,用来指名该文件是一个 ELF 目标文件。第一个字节 7F 是个固定的数;后面的 3 个字节正是 E, L, F 三个字母的 ASCII 形式。
第 3 行,CLASS 表示文件类型,这里是 32位的 ELF 格式。
第 4 行,Data 表示文件中的数据是按照什么格式组织(大端或小端)的,不同处理器平台数据组织格式可能就不同,如x86平台为小端存储格式。
第 5 行,当前 ELF 文件头版本号,这里版本号为 1 。
第 6 行,OS/ABI ,指出操作系统类型,ABI 是 Application Binary Interface 的缩写。
第 7 行,ABI 版本号,当前为 0 。
第 8 行,Type 表示文件类型。ELF 文件有 3 种类型,一种是如上所示的 Relocatable file 可重定位目标文件,一种是可执行文件(Executable),另外一种是共享库(Shared Library) 。
第 9 行,机器平台类型。
第 10 行,当前目标文件的版本号。
第 11 行,程序的虚拟地址入口点,因为这还不是可运行的程序,故而这里为零。
第 12 行,与 11 行同理,这个目标文件没有 Program Headers。
第 13 行,sections 头开始处,这里 208 是十进制,表示从地址偏移 0xD0 处开始。
第 14 行,是一个与处理器相关联的标志,x86 平台上该处为 0 。
第 15 行,ELF 文件头的字节数。
第 16 行,因为这个不是可执行程序,故此处大小为 0。
第 17 行,同理于第 16 行。
第 18 行,sections header 的大小,这里每个 section 头大小为 40 个字节。
第 19 行,一共有多少个 section 头,这里是 8 个。
第 20 行,section 头字符串表索引号,从 Section Headers 输出部分可以看到其内容的偏移在 0xa0 处,从此处开始到0xcf 结束保存着各个 sections 的名字,如 .data,.text,.bss等。
根据Number of program headers,可以知道该程序有8个段。
根据Number of section headers,可以知道该程序有30个区。
区中存储的信息是用来链接使用的,主要包括:程序代码、程序数据(变量)、重定向信息等。比如:Code section保存的是代码,data section保存的是初始化或未初始化的数据,等等。
Linux内核无法以区的概念来识别可执行文件。内核使用包括连续页的VMA(virtual memory area)来识别进程。在每个VMA中可能映射了一个或多个区。每个VMA代表一个ELF文件的段。
那么,内核如何知道哪个区属于某个VMA(段)?映射关系保存在Program Header Table(PHT)中
$readelf -S test
There are 30 section headers, starting at offset 0xa88:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000400200 00000200
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.ABI-tag NOTE 000000000040021c 0000021c
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.build-i NOTE 000000000040023c 0000023c
0000000000000024 0000000000000000 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000400260 00000260
000000000000001c 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 0000000000400280 00000280
0000000000000078 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 00000000004002f8 000002f8
0000000000000044 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 000000000040033c 0000033c
000000000000000a 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000400348 00000348
0000000000000020 0000000000000000 A 6 1 8
[ 9] .rela.dyn RELA 0000000000400368 00000368
0000000000000018 0000000000000018 A 5 0 8
[10] .rela.plt RELA 0000000000400380 00000380
0000000000000048 0000000000000018 A 5 12 8
[11] .init PROGBITS 00000000004003c8 000003c8
0000000000000018 0000000000000000 AX 0 0 4
[12] .plt PROGBITS 00000000004003e0 000003e0
0000000000000040 0000000000000010 AX 0 0 4
[13] .text PROGBITS 0000000000400420 00000420
0000000000000238 0000000000000000 AX 0 0 16
[14] .fini PROGBITS 0000000000400658 00000658
000000000000000e 0000000000000000 AX 0 0 4
[15] .rodata PROGBITS 0000000000400668 00000668
0000000000000053 0000000000000000 A 0 0 8
[16] .eh_frame_hdr PROGBITS 00000000004006bc 000006bc
0000000000000024 0000000000000000 A 0 0 4
[17] .eh_frame PROGBITS 00000000004006e0 000006e0
000000000000007c 0000000000000000 A 0 0 8
[18] .ctors PROGBITS 0000000000600760 00000760
0000000000000010 0000000000000000 WA 0 0 8
[19] .dtors PROGBITS 0000000000600770 00000770
0000000000000010 0000000000000000 WA 0 0 8
[20] .jcr PROGBITS 0000000000600780 00000780
0000000000000008 0000000000000000 WA 0 0 8
[21] .dynamic DYNAMIC 0000000000600788 00000788
0000000000000190 0000000000000010 WA 6 0 8
[22] .got PROGBITS 0000000000600918 00000918
0000000000000008 0000000000000008 WA 0 0 8
[23] .got.plt PROGBITS 0000000000600920 00000920
0000000000000030 0000000000000008 WA 0 0 8
[24] .data PROGBITS 0000000000600950 00000950
0000000000000008 0000000000000000 WA 0 0 4
[25] .bss NOBITS 0000000000600958 00000958
0000000000000018 0000000000000000 WA 0 0 8
[26] .comment PROGBITS 0000000000000000 00000958
000000000000002c 0000000000000001 MS 0 0 1
[27] .shstrtab STRTAB 0000000000000000 00000984
00000000000000fe 0000000000000000 0 0 1
[28] .symtab SYMTAB 0000000000000000 00001208
0000000000000648 0000000000000018 29 46 8
[29] .strtab STRTAB 0000000000000000 00001850
000000000000021e 0000000000000000 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)
PROGBITS(程序必须解释的信息,如二进制代码),STRTAB用于存储与ELF格式有关的字符串,但与程序没有直接关联,如各个节的名称(.text, .comment)
.text区存储的是程序的代码(二进制指令),该区的标志为X表示可执行。
.data保存初始化过的数据,这是普通程序数据的一部分,可以在程序运行期间修改。
.rodata保存了只读数据,可以读取但不能修改,例如printf语句中的所有静态字符串封装到该节。
.init和.fini保存了进程初始化和结束所用的代码,这通常是由编译器自动添加的。
.hash是一个散列表,允许在不对全表元素进行线性搜索的情况下,快速访问所有符号表项。
下面使用objdump反汇编查看.text的内容:
$objdump -d -j .text test
-d选项告诉objdump反汇编机器码,-j选项告诉objdump只关心.text区。
test: file format elf64-x86-64
Disassembly of section .text:
0000000000400420 <_start>:
400420: 31 ed xor %ebp,%ebp
400422: 49 89 d1 mov %rdx,%r9
400425: 5e pop %rsi
400426: 48 89 e2 mov %rsp,%rdx
400429: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40042d: 50 push %rax
40042e: 54 push %rsp
40042f: 49 c7 c0 80 05 40 00 mov $0x400580,%r8
400436: 48 c7 c1 90 05 40 00 mov $0x400590,%rcx
40043d: 48 c7 c7 04 05 40 00 mov $0x400504,%rdi
400444: e8 c7 ff ff ff callq 400410 <__libc_start_main@plt>
400449: f4 hlt
40044a: 90 nop
40044b: 90 nop
000000000040044c <call_gmon_start>:
40044c: 48 83 ec 08 sub $0x8,%rsp
400450: 48 8b 05 c1 04 20 00 mov 0x2004c1(%rip),%rax # 600918 <_DYNAMIC+0x190>
400457: 48 85 c0 test %rax,%rax
40045a: 74 02 je 40045e <call_gmon_start+0x12>
40045c: ff d0 callq *%rax
40045e: 48 83 c4 08 add $0x8,%rsp
400462: c3 retq
400463: 90 nop
400464: 90 nop
400465: 90 nop
400466: 90 nop
400467: 90 nop
400468: 90 nop
400469: 90 nop
40046a: 90 nop
40046b: 90 nop
40046c: 90 nop
40046d: 90 nop
40046e: 90 nop
40046f: 90 nop
0000000000400470 <__do_global_dtors_aux>:
400470: 55 push %rbp
400471: 48 89 e5 mov %rsp,%rbp
400474: 53 push %rbx
400475: 48 83 ec 08 sub $0x8,%rsp
400479: 80 3d d8 04 20 00 00 cmpb $0x0,0x2004d8(%rip) # 600958 <__bss_start>
400480: 75 4b jne 4004cd <__do_global_dtors_aux+0x5d>
400482: bb 78 07 60 00 mov $0x600778,%ebx
400487: 48 8b 05 d2 04 20 00 mov 0x2004d2(%rip),%rax # 600960 <dtor_idx.6349>
40048e: 48 81 eb 70 07 60 00 sub $0x600770,%rbx
400495: 48 c1 fb 03 sar $0x3,%rbx
400499: 48 83 eb 01 sub $0x1,%rbx
40049d: 48 39 d8 cmp %rbx,%rax
4004a0: 73 24 jae 4004c6 <__do_global_dtors_aux+0x56>
4004a2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
4004a8: 48 83 c0 01 add $0x1,%rax
4004ac: 48 89 05 ad 04 20 00 mov %rax,0x2004ad(%rip) # 600960 <dtor_idx.6349>
4004b3: ff 14 c5 70 07 60 00 callq *0x600770(,%rax,8)
4004ba: 48 8b 05 9f 04 20 00 mov 0x20049f(%rip),%rax # 600960 <dtor_idx.6349>
4004c1: 48 39 d8 cmp %rbx,%rax
4004c4: 72 e2 jb 4004a8 <__do_global_dtors_aux+0x38>
4004c6: c6 05 8b 04 20 00 01 movb $0x1,0x20048b(%rip) # 600958 <__bss_start>
4004cd: 48 83 c4 08 add $0x8,%rsp
4004d1: 5b pop %rbx
4004d2: c9 leaveq
4004d3: c3 retq
4004d4: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1)
4004db: 00 00 00 00 00
00000000004004e0 <frame_dummy>:
4004e0: 48 83 3d 98 02 20 00 cmpq $0x0,0x200298(%rip) # 600780 <__JCR_END__>
4004e7: 00
4004e8: 55 push %rbp
4004e9: 48 89 e5 mov %rsp,%rbp
4004ec: 74 12 je 400500 <frame_dummy+0x20>
4004ee: b8 00 00 00 00 mov $0x0,%eax
4004f3: 48 85 c0 test %rax,%rax
4004f6: 74 08 je 400500 <frame_dummy+0x20>
4004f8: bf 80 07 60 00 mov $0x600780,%edi
4004fd: c9 leaveq
4004fe: ff e0 jmpq *%rax
400500: c9 leaveq
400501: c3 retq
400502: 90 nop
400503: 90 nop
0000000000400504 <main>:
400504: 55 push %rbp
400505: 48 89 e5 mov %rsp,%rbp
400508: 48 83 ec 20 sub $0x20,%rsp
40050c: 89 7d ec mov %edi,-0x14(%rbp)
40050f: 48 89 75 e0 mov %rsi,-0x20(%rbp)
400513: c7 45 fc 03 00 00 00 movl $0x3,-0x4(%rbp)
40051a: bf 78 06 40 00 mov $0x400678,%edi
40051f: e8 dc fe ff ff callq 400400 <puts@plt>
400524: 8b 15 2a 04 20 00 mov 0x20042a(%rip),%edx # 600954 <global_data>
40052a: b8 84 06 40 00 mov $0x400684,%eax
40052f: 89 d6 mov %edx,%esi
400531: 48 89 c7 mov %rax,%rdi
400534: b8 00 00 00 00 mov $0x0,%eax
400539: e8 b2 fe ff ff callq 4003f0 <printf@plt>
40053e: 8b 15 24 04 20 00 mov 0x200424(%rip),%edx # 600968 <global_data_2>
400544: b8 96 06 40 00 mov $0x400696,%eax
400549: 89 d6 mov %edx,%esi
40054b: 48 89 c7 mov %rax,%rdi
40054e: b8 00 00 00 00 mov $0x0,%eax
400553: e8 98 fe ff ff callq 4003f0 <printf@plt>
400558: b8 aa 06 40 00 mov $0x4006aa,%eax
40055d: 8b 55 fc mov -0x4(%rbp),%edx
400560: 89 d6 mov %edx,%esi
400562: 48 89 c7 mov %rax,%rdi
400565: b8 00 00 00 00 mov $0x0,%eax
40056a: e8 81 fe ff ff callq 4003f0 <printf@plt>
40056f: b8 00 00 00 00 mov $0x0,%eax
400574: c9 leaveq
400575: c3 retq
400576: 90 nop
400577: 90 nop
400578: 90 nop
400579: 90 nop
40057a: 90 nop
40057b: 90 nop
40057c: 90 nop
40057d: 90 nop
40057e: 90 nop
40057f: 90 nop
0000000000400580 <__libc_csu_fini>:
400580: f3 c3 repz retq
400582: 66 66 66 66 66 2e 0f data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
400589: 1f 84 00 00 00 00 00
0000000000400590 <__libc_csu_init>:
400590: 48 89 6c 24 d8 mov %rbp,-0x28(%rsp)
400595: 4c 89 64 24 e0 mov %r12,-0x20(%rsp)
40059a: 48 8d 2d bb 01 20 00 lea 0x2001bb(%rip),%rbp # 60075c <__init_array_end>
4005a1: 4c 8d 25 b4 01 20 00 lea 0x2001b4(%rip),%r12 # 60075c <__init_array_end>
4005a8: 4c 89 6c 24 e8 mov %r13,-0x18(%rsp)
4005ad: 4c 89 74 24 f0 mov %r14,-0x10(%rsp)
4005b2: 4c 89 7c 24 f8 mov %r15,-0x8(%rsp)
4005b7: 48 89 5c 24 d0 mov %rbx,-0x30(%rsp)
4005bc: 48 83 ec 38 sub $0x38,%rsp
4005c0: 4c 29 e5 sub %r12,%rbp
4005c3: 41 89 fd mov %edi,%r13d
4005c6: 49 89 f6 mov %rsi,%r14
4005c9: 48 c1 fd 03 sar $0x3,%rbp
4005cd: 49 89 d7 mov %rdx,%r15
4005d0: e8 f3 fd ff ff callq 4003c8 <_init>
4005d5: 48 85 ed test %rbp,%rbp
4005d8: 74 1c je 4005f6 <__libc_csu_init+0x66>
4005da: 31 db xor %ebx,%ebx
4005dc: 0f 1f 40 00 nopl 0x0(%rax)
4005e0: 4c 89 fa mov %r15,%rdx
4005e3: 4c 89 f6 mov %r14,%rsi
4005e6: 44 89 ef mov %r13d,%edi
4005e9: 41 ff 14 dc callq *(%r12,%rbx,8)
4005ed: 48 83 c3 01 add $0x1,%rbx
4005f1: 48 39 eb cmp %rbp,%rbx
4005f4: 72 ea jb 4005e0 <__libc_csu_init+0x50>
4005f6: 48 8b 5c 24 08 mov 0x8(%rsp),%rbx
4005fb: 48 8b 6c 24 10 mov 0x10(%rsp),%rbp
400600: 4c 8b 64 24 18 mov 0x18(%rsp),%r12
400605: 4c 8b 6c 24 20 mov 0x20(%rsp),%r13
40060a: 4c 8b 74 24 28 mov 0x28(%rsp),%r14
40060f: 4c 8b 7c 24 30 mov 0x30(%rsp),%r15
400614: 48 83 c4 38 add $0x38,%rsp
400618: c3 retq
400619: 90 nop
40061a: 90 nop
40061b: 90 nop
40061c: 90 nop
40061d: 90 nop
40061e: 90 nop
40061f: 90 nop
0000000000400620 <__do_global_ctors_aux>:
400620: 55 push %rbp
400621: 48 89 e5 mov %rsp,%rbp
400624: 53 push %rbx
400625: 48 83 ec 08 sub $0x8,%rsp
400629: 48 8b 05 30 01 20 00 mov 0x200130(%rip),%rax # 600760 <__CTOR_LIST__>
400630: 48 83 f8 ff cmp $0xffffffffffffffff,%rax
400634: 74 19 je 40064f <__do_global_ctors_aux+0x2f>
400636: bb 60 07 60 00 mov $0x600760,%ebx
40063b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
400640: 48 83 eb 08 sub $0x8,%rbx
400644: ff d0 callq *%rax
400646: 48 8b 03 mov (%rbx),%rax
400649: 48 83 f8 ff cmp $0xffffffffffffffff,%rax
40064d: 75 f1 jne 400640 <__do_global_ctors_aux+0x20>
40064f: 48 83 c4 08 add $0x8,%rsp
400653: 5b pop %rbx
400654: c9 leaveq
400655: c3 retq
400656: 90 nop
400657: 90 nop
下面命令可以看到test文件中所有的符号:
$readelf -s test
Value的值是符号的地址。
Symbol table '.dynsym' contains 5 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
Symbol table '.symtab' contains 67 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400200 0 SECTION LOCAL DEFAULT 1
2: 000000000040021c 0 SECTION LOCAL DEFAULT 2
3: 000000000040023c 0 SECTION LOCAL DEFAULT 3
4: 0000000000400260 0 SECTION LOCAL DEFAULT 4
5: 0000000000400280 0 SECTION LOCAL DEFAULT 5
6: 00000000004002f8 0 SECTION LOCAL DEFAULT 6
7: 000000000040033c 0 SECTION LOCAL DEFAULT 7
8: 0000000000400348 0 SECTION LOCAL DEFAULT 8
9: 0000000000400368 0 SECTION LOCAL DEFAULT 9
10: 0000000000400380 0 SECTION LOCAL DEFAULT 10
11: 00000000004003c8 0 SECTION LOCAL DEFAULT 11
12: 00000000004003e0 0 SECTION LOCAL DEFAULT 12
13: 0000000000400420 0 SECTION LOCAL DEFAULT 13
14: 0000000000400658 0 SECTION LOCAL DEFAULT 14
15: 0000000000400668 0 SECTION LOCAL DEFAULT 15
16: 00000000004006bc 0 SECTION LOCAL DEFAULT 16
17: 00000000004006e0 0 SECTION LOCAL DEFAULT 17
18: 0000000000600760 0 SECTION LOCAL DEFAULT 18
19: 0000000000600770 0 SECTION LOCAL DEFAULT 19
20: 0000000000600780 0 SECTION LOCAL DEFAULT 20
21: 0000000000600788 0 SECTION LOCAL DEFAULT 21
22: 0000000000600918 0 SECTION LOCAL DEFAULT 22
23: 0000000000600920 0 SECTION LOCAL DEFAULT 23
24: 0000000000600950 0 SECTION LOCAL DEFAULT 24
25: 0000000000600958 0 SECTION LOCAL DEFAULT 25
26: 0000000000000000 0 SECTION LOCAL DEFAULT 26
27: 000000000040044c 0 FUNC LOCAL DEFAULT 13 call_gmon_start
28: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
29: 0000000000600760 0 OBJECT LOCAL DEFAULT 18 __CTOR_LIST__
30: 0000000000600770 0 OBJECT LOCAL DEFAULT 19 __DTOR_LIST__
31: 0000000000600780 0 OBJECT LOCAL DEFAULT 20 __JCR_LIST__
32: 0000000000400470 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux
33: 0000000000600958 1 OBJECT LOCAL DEFAULT 25 completed.6347
34: 0000000000600960 8 OBJECT LOCAL DEFAULT 25 dtor_idx.6349
35: 00000000004004e0 0 FUNC LOCAL DEFAULT 13 frame_dummy
36: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
37: 0000000000600768 0 OBJECT LOCAL DEFAULT 18 __CTOR_END__
38: 0000000000400758 0 OBJECT LOCAL DEFAULT 17 __FRAME_END__
39: 0000000000600780 0 OBJECT LOCAL DEFAULT 20 __JCR_END__
40: 0000000000400620 0 FUNC LOCAL DEFAULT 13 __do_global_ctors_aux
41: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c
42: 0000000000600920 0 OBJECT LOCAL DEFAULT 23 _GLOBAL_OFFSET_TABLE_
43: 000000000060075c 0 NOTYPE LOCAL DEFAULT 18 __init_array_end
44: 000000000060075c 0 NOTYPE LOCAL DEFAULT 18 __init_array_start
45: 0000000000600788 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
46: 0000000000600950 0 NOTYPE WEAK DEFAULT 24 data_start
47: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.2.5
48: 0000000000400580 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
49: 0000000000400420 0 FUNC GLOBAL DEFAULT 13 _start
50: 0000000000600968 4 OBJECT GLOBAL DEFAULT 25 global_data_2
51: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
52: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5
54: 0000000000400658 0 FUNC GLOBAL DEFAULT 14 _fini
55: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
56: 0000000000400668 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
57: 0000000000600950 0 NOTYPE GLOBAL DEFAULT 24 __data_start
58: 0000000000400670 0 OBJECT GLOBAL HIDDEN 15 __dso_handle
59: 0000000000600778 0 OBJECT GLOBAL HIDDEN 19 __DTOR_END__
60: 0000000000400590 137 FUNC GLOBAL DEFAULT 13 __libc_csu_init
61: 0000000000600958 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
62: 0000000000600970 0 NOTYPE GLOBAL DEFAULT ABS _end
63: 0000000000600958 0 NOTYPE GLOBAL DEFAULT ABS _edata
64: 0000000000600954 4 OBJECT GLOBAL DEFAULT 24 global_data
65: 0000000000400504 114 FUNC GLOBAL DEFAULT 13 main
66: 00000000004003c8 0 FUNC GLOBAL DEFAULT 11 _init
符号表保存了程序实现或使用的所有全局变量和函数,如果程序引用一个自身代码未定义的符号,则称之为未定义符号,这类引用必须在静态链接期间用其他目标模块或库解决,或在加载时通过动态链接解决。
实现:
.symtab确定符号的名称与其值之间的关联,其中名称不是直接以字符串形式出现的,而是表示为某一字符串数组(.strtab)的索引。
.strtab保存了字符串数组(.shstrtab包含了节名称字符串表)。
.hash保存了一个散列表,以帮助快速查找符号。
typedef struct elf64_sym {
Elf64_Word st_name; // 符号名称,字符串表中的索引
// STT_OBJECT表示符号关联到一个数据对象,如变量、数组或指针;
// STT_FUNC表示符号关联到一个函数;
// STT_NOTYPE表示符号类型未指定,用于未定义引用
unsigned char st_info; // 类型和绑定属性:STB_LOCAL/STB_GLOBAL/STB_WEAK;
unsigned char st_other; // 语义未定义,0
Elf64_Half st_shndx; // 相关节的索引,符号将绑定到该节,此外SHN_ABS指定符号是绝对值,不因重定位而改变,SHN_UNDEF标识未定义符号。
Elf64_Addr st_value; // 符号的值
Elf64_Xword st_size; // 符号的长度,如一个指针的长度或struct对象中包含的字节数。
}Elf64_Sym;
$readelf -l test
显示程序头表(段信息)
区到段的映射,基本上是按照区的顺序进行映射。
如果Flags为R和E,表示该段可读和可执行。
如果Flags为W,表示该段可写。
VirtAddr是每个段的虚拟起始地址。这个地址并不是位于真正内存上的地址(物理地址)。
Elf file type is EXEC (Executable file)
Entry point 0x400420
There are 8 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001c0 0x00000000000001c0 R E 8
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000075c 0x000000000000075c R E 200000
LOAD 0x0000000000000760 0x0000000000600760 0x0000000000600760
0x00000000000001f8 0x0000000000000210 RW 200000
DYNAMIC 0x0000000000000788 0x0000000000600788 0x0000000000600788
0x0000000000000190 0x0000000000000190 RW 8
NOTE 0x000000000000021c 0x000000000040021c 0x000000000040021c
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x00000000000006bc 0x00000000004006bc 0x00000000004006bc
0x0000000000000024 0x0000000000000024 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
上述各段组成了最终在内存中执行的程序,其还提供了各段在虚拟地址空间和物理地址空间中的大小、位置、标志、访问授权和对齐方面的信息。各段语义如下:
PHDR保存程序头表
INTERP指定程序从可行性文件映射到内存之后,必须调用的解释器,它是通过链接其他库来满足未解析的引用,用于在虚拟地址空间中插入程序运行所需的动态库。
LOAD表示一个需要从二进制文件映射到虚拟地址空间的段,其中保存了常量数据(如字符串),程序目标代码等。
DYNAMIC段保存了由动态连接器(即INTERP段中指定的解释器)使用的信息。
转:https://www.xuebuyuan.com/2039547.html
转:https://blog.csdn.net/Linux_ever/article/details/78210089?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase