【IoT】ELF 和 AXF 文件分析详解

简介: ELF 和 AXF 文件分析

ELF(Executable and Linking Format)是一个定义了目标文件内部信息如何组成和组织的文件格式。

内核会根据这些信息加载可执行文件,内核根据这些信息可以知道从文件哪里获取代码,从哪里获取初始化数据,在哪里应该加载共享库等信息。

栈的地址是向下生长,堆的地址是向上生长:

20190313093640706.png

1、ELF 文件类型

ELF 文件有下面三种类型:

1)目标文件

$ gcc -c test.c

得到的test.o就是目标文件,目标文件通过链接可生成可执行文件。

静态库其实也算目标文件,静态库是通过ar命令将目标打包为.a文件。

如:ar crv libtest.a test.o

2)可执行文件

$gcc -o test test.c

得到的 test 文件就是可执行的二进制文件。

3)共享库

$ gcc test.c -fPIC -shared -o libtest.so

得到的文件 listtest.so 就是共享库。

可以通过 readelf 来区分上面三种类型的 ELF 文件,每种类型文件的头部信息是不一样的。

2、示例

2.1、test.c 文件

include<stdio.h>

int global_data = 4;
int global_data_2;
int main(int argc, char **argv)
{

int local_data = 3; 

printf("Hello World\n"); 
printf("global_data = %d\n", global_data); 
printf("global_data_2 = %d\n", global_data_2); 
printf("local_data = %d\n", local_data); 

return (0);

}
2.2、目标文件:$readelf -h test.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: 456 (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
在 readelf 的输出中:

第 1 行,ELF Header: 指名 ELF 文件头开始。
第 2 行,Magic 魔数,用来指名该文件是一个 ELF 目标文件。第一个字节 7F 是个固定的数;后面的 3 个字节正是 E, L, F 三个字母的 ASCII 形式。
第 3 行,CLASS 表示文件类型,这里是 64位的 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等。

2.3、可执行文件:$readelf -h test

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: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400420
Start of program headers: 64 (bytes into file)
Start of section headers: 2696 (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: 27
2.3.1、信息详解

1) 根据 Class、Type 和 Machine,可以知道该文件在 X86-64 位机器上生成的 64 位可执行文件;

2) 根据 Entry point address,可以知道当该程序启动时从虚拟地址 0x400420 处开始运行。

这个地址并不是 main 函数的地址,而是 _start 函数的地址,_start 由链接器创建,_start 是为了初始化程序。

通过这个命令可以看到 _start 函数:

objdump -d -j .text test

3) 根据Number of program headers,可以知道该程序有8个段。

4) 根据Number of section headers,可以知道该程序有30个区。

区中存储的信息是用来链接使用的,主要包括:程序代码、程序数据(变量)、重定向信息等。

比如:Code section 保存的是代码,data section 保存的是初始化或未初始化的数据等。

Linux内核无法以区的概念来识别可执行文件。

内核使用包括连续页的VMA(virtual memory area)来识别进程。

在每个VMA中可能映射了一个或多个区,每个VMA代表一个ELF文件的段。

2.3.2、查看区的内容

$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)
.text 区存储的是程序的代码(二进制指令),该区的标志为 X 表示可执行。

2.3.3、使用 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 :
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
2.3.4、使用 objdump 反汇编查看 .data 的内容

$objdump -d -j .data test

.data区保存的是初始化的全局变量。

test: file format elf64-x86-64
Disassembly of section .data:
0000000000600950 <__data_start>:
600950: 00 00 add %al,(%rax)

    ...

0000000000600954 <global_data>:
600954: 04 00 00 00
2.3.5、使用objdump反汇编查看.bss的内容

$objdump -d -j .bss test

.bss区保存的是未初始化的全局变量,linux会默认将未初始化的变量置为0。

test: file format elf64-x86-64

Disassembly of section .bss:

0000000000600958 <completed.6347>:

    ...

0000000000600960 <dtor_idx.6349>:

    ...

0000000000600968 <global_data_2>:
2.4、共享库:$readelf -h libtest.so

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: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x570
Start of program headers: 64 (bytes into file)
Start of section headers: 2768 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 6
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 26
2.5、查看 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

.text:

已编译程序的机器代码;

.rodata:

只读数据,比如printf语句中的格式串和开关(switch)语句的跳转表;

.data:

已初始化的全局C变量。

局部C变量在运行时被保存在栈中,既不出现在.data中,也不出现在.bss节中。

.bss:

未初始化的全局C变量。

在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。

目标文件格式区分初始化和未初始化变量是为了空间效率在:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。

.symtab:

一个符号表(symbol table),它存放在程序中被定义和引用的函数和全局变量的信息。

一些程序员错误地认为必须通过-g选项来编译一个程序,得到符号表信息。

实际上,每个可重定位目标文件在.symtab中都有一张符号表。然而,和编译器中的符号表不同,.symtab符号表不包含局部变量的表目。

.rel.text:

当链接噐把这个目标文件和其他文件结合时,.text节中的许多位置都需要修改。

一般而言,任何调用外部函数或者引用全局变量的指令都需要修改。

另一方面调用本地函数的指令则不需要修改。

注意,可执行目标文件中并不需要重定位信息,因此通常省略,除非使用者显式地指示链接器包含这些信息。

.rel.data:

被模块定义或引用的任何全局变量的信息。一般而言,任何已初始化全局变量的初始值是全局变量或者外部定义函数的地址都需要被修改。

.debug:

一个调试符号表,其有些表目是程序中定义的局部变量和类型定义,有些表目是程序中定义和引用的全局变量,有些是原始的C源文件。

只有以-g选项调用编译驱动程序时,才会得到这张表。

.line:

原始C源程序中的行号和.text节中机器指令之间的映射。只有以-g选项调用编译驱动程序时,才会得到这张表。

.strtab:

一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。字符串表就是以null结尾的字符串序列。

PROGBITS(程序必须解释的信息,如二进制代码),STRTAB用于存储与ELF格式有关的字符串,但与程序没有直接关联,如各个节的名称(.text, .comment)

.data保存初始化过的数据,这是普通程序数据的一部分,可以在程序运行期间修改。

.rodata保存了只读数据,可以读取但不能修改,例如printf语句中的所有静态字符串封装到该节。

.init和.fini保存了进程初始化和结束所用的代码,这通常是由编译器自动添加的。

.hash是一个散列表,允许在不对全表元素进行线性搜索的情况下,快速访问所有符号表项。

2.6、查看文件的段信息

$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段中指定的解释器)使用的信息。

段有多种类型,下面介绍LOAD类型:

LOAD:该段的内容从可执行文件中获取。Offset标识内核从文件读取的位置。FileSiz标识读取多少字节。

那么,执行test之后的进程的段布局是如何呢?
可以通过cat /proc/pid/maps来查看。pid是进程的pid。
但是该test运行时间很短,可以使用gdb加断点来运行,或者在return语句之前加上sleep()。

下面使用gdb加断点的形式:

GNU gdb (GDB) Red Hat Enterprise Linux (7.2-50.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
http://www.gnu.org/software/gdb/bugs/...
Reading symbols from /data/readyao/qqlive_zb_prj/server/cgi_push_post_replay/lib/test...(no debugging symbols found)...done.
(gdb) b main
Breakpoint 1 at 0x400508
(gdb) r
Starting program: /data/readyao/qqlive_zb_prj/server/cgi_push_post_replay/lib/test
[Thread debugging using libthread_db enabled]

Breakpoint 1, 0x0000000000400508 in main ()
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.49.tl1.x86_64

$cat /proc/6929/maps

00400000-00401000 r-xp 00000000 ca:11 8626925 /test
00600000-00601000 rw-p 00000000 ca:11 8626925 /test
7ffff762d000-7ffff7644000 r-xp 00000000 ca:01 332328 /lib64/libpthread-2.12.so
7ffff7644000-7ffff7843000 ---p 00017000 ca:01 332328 /lib64/libpthread-2.12.so
7ffff7843000-7ffff7844000 r--p 00016000 ca:01 332328 /lib64/libpthread-2.12.so
7ffff7844000-7ffff7845000 rw-p 00017000 ca:01 332328 /lib64/libpthread-2.12.so
7ffff7845000-7ffff7849000 rw-p 00000000 00:00 0
7ffff7849000-7ffff784b000 r-xp 00000000 ca:01 332237 /lib64/libdl-2.12.so
7ffff784b000-7ffff7a4b000 ---p 00002000 ca:01 332237 /lib64/libdl-2.12.so
7ffff7a4b000-7ffff7a4c000 r--p 00002000 ca:01 332237 /lib64/libdl-2.12.so
7ffff7a4c000-7ffff7a4d000 rw-p 00003000 ca:01 332237 /lib64/libdl-2.12.so
7ffff7a4d000-7ffff7bd3000 r-xp 00000000 ca:01 332102 /lib64/libc-2.12.so
7ffff7bd3000-7ffff7dd3000 ---p 00186000 ca:01 332102 /lib64/libc-2.12.so
7ffff7dd3000-7ffff7dd7000 r--p 00186000 ca:01 332102 /lib64/libc-2.12.so
7ffff7dd7000-7ffff7dd8000 rw-p 0018a000 ca:01 332102 /lib64/libc-2.12.so
7ffff7dd8000-7ffff7ddd000 rw-p 00000000 00:00 0
7ffff7ddd000-7ffff7dfd000 r-xp 00000000 ca:01 332126 /lib64/ld-2.12.so
7ffff7ed9000-7ffff7edc000 rw-p 00000000 00:00 0
7ffff7eeb000-7ffff7eee000 r-xp 00000000 ca:01 336319 /lib64/libonion_security.so.1.0.13
7ffff7eee000-7ffff7fee000 ---p 00003000 ca:01 336319 /lib64/libonion_security.so.1.0.13
7ffff7fee000-7ffff7fef000 rw-p 00003000 ca:01 336319 /lib64/libonion_security.so.1.0.13
7ffff7fef000-7ffff7ffb000 rw-p 00000000 00:00 0
7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 0001f000 ca:01 332126 /lib64/ld-2.12.so
7ffff7ffd000-7ffff7ffe000 rw-p 00020000 ca:01 332126 /lib64/ld-2.12.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffea000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
前面一部分是VMA的起始地址和结束地址,最后一部分是该区域内容所属文件。

在32位系统中,进程地址空间为4G,分为用户空间和内核空间。

卫朋

人人都是产品经理受邀专栏作家,CSDN 嵌入式领域新星创作者、资深技术博主。2020 年 8 月开始写产品相关内容,截至目前,人人都是产品经理单渠道阅读 56 万+,鸟哥笔记单渠道阅读200 万+,CSDN 单渠道阅读 210 万+,51CTO单渠道阅读 180 万+。

卫朋入围2021/2022年人人都是产品经理平台年度作者,光环国际学习社区首批原创者、知识合作伙伴,商业新知 2021 年度产品十佳创作者,腾讯调研云2022年达人榜第三名。

文章被人人都是产品经理、CSDN、华为云、运营派、产品壹佰、鸟哥笔记、光环国际、商业新知、腾讯调研云等头部垂直类媒体转载。文章见仁见智,各位看官可策略性选择对于自己有用的部分。

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
关系型数据库 物联网 PostgreSQL
沉浸式学习PostgreSQL|PolarDB 11: 物联网(IoT)、监控系统、应用日志、用户行为记录等场景 - 时序数据高吞吐存取分析
物联网场景, 通常有大量的传感器(例如水质监控、气象监测、新能源汽车上的大量传感器)不断探测最新数据并上报到数据库. 监控系统, 通常也会有采集程序不断的读取被监控指标(例如CPU、网络数据包转发、磁盘的IOPS和BW占用情况、内存的使用率等等), 同时将监控数据上报到数据库. 应用日志、用户行为日志, 也就有同样的特征, 不断产生并上报到数据库. 以上数据具有时序特征, 对数据库的关键能力要求如下: 数据高速写入 高速按时间区间读取和分析, 目的是发现异常, 分析规律. 尽量节省存储空间
788 1
|
7月前
|
网络协议 物联网 5G
K3S 系列文章 -5G IoT 网关设备 POD 访问报错 DNS 'i/o timeout' 分析与解决
K3S 系列文章 -5G IoT 网关设备 POD 访问报错 DNS 'i/o timeout' 分析与解决
|
物联网 网络协议 网络性能优化
使用抓包工具Wireshark分析IoT设备网络行为
使用抓包工具Wireshark分析IoT设备网络行为
4385 0
|
1月前
|
SQL 监控 物联网
ClickHouse在物联网(IoT)中的应用:实时监控与分析
【10月更文挑战第27天】随着物联网(IoT)技术的快速发展,越来越多的设备被连接到互联网上,产生了海量的数据。这些数据不仅包含了设备的状态信息,还包括用户的使用习惯、环境参数等。如何高效地处理和分析这些数据,成为了一个重要的挑战。作为一位数据工程师,我在一个物联网项目中深入使用了ClickHouse,以下是我的经验和思考。
107 0
|
存储 NoSQL 安全
【MongoDB行业案例】Bosch IoT 和应用程序驱动型分析的重要性
将运营和分析工作负载整合到一处的数据平台
|
传感器 编解码 安全
|
网络协议 物联网 数据安全/隐私保护
NB-IoT 之 M5310-A 模块介绍及应用场景分析 | 学习笔记
快速学习 NB-IoT 之 M5310-A 模块介绍及应用场景分析
NB-IoT 之 M5310-A 模块介绍及应用场景分析 | 学习笔记