14 elf 文件执行的流程

2025-05-17 23:28:29

14 elf 文件执行的流程

前言

这里我们来探讨一下 elf 文件的执行流程

当然 这也是我很久以前 就想了解的东西了

不过 苦于 缺少各种调试环境, 呵呵 所以 一直搁置于此

调试环境 至关重要

这里主要是走一下 elf 的执行流程, fork, exec, libc_start_main, main

测试用例

root@ubuntu:~/ClionWorkStations/HelloWorld# cat Test01Sum.c

#include "stdio.h"

int main(int argc, char** argv) {

int x = 2;

int y = 3;

int z = x + y;

printf(" x + y = %d\n ", z);

}

readelf 查看 elf 的文件信息

root@ubuntu:~/ClionWorkStations/HelloWorld# readelf -a Test01Sum

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: 0x400480

Start of program headers: 64 (bytes into file)

Start of section headers: 8496 (bytes into file)

Flags: 0x0

Size of this header: 64 (bytes)

Size of program headers: 56 (bytes)

Number of program headers: 9

Size of section headers: 64 (bytes)

Number of section headers: 38

Section header string table index: 35

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 0000000000400238 00000238

0000000000000040 0000000000000000 A 0 0 1

[ 2] .note.ABI-tag NOTE 0000000000400278 00000278

0000000000000020 0000000000000000 A 0 0 4

[ 3] .note.gnu.build-i NOTE 0000000000400298 00000298

0000000000000024 0000000000000000 A 0 0 4

[ 4] .gnu.hash GNU_HASH 00000000004002c0 000002c0

000000000000001c 0000000000000000 A 5 0 8

[ 5] .dynsym DYNSYM 00000000004002e0 000002e0

0000000000000060 0000000000000018 A 6 1 8

[ 6] .dynstr STRTAB 0000000000400340 00000340

000000000000006a 0000000000000000 A 0 0 1

[ 7] .gnu.version VERSYM 00000000004003aa 000003aa

0000000000000008 0000000000000002 A 5 0 2

[ 8] .gnu.version_r VERNEED 00000000004003b8 000003b8

0000000000000020 0000000000000000 A 6 1 8

[ 9] .rela.dyn RELA 00000000004003d8 000003d8

0000000000000018 0000000000000018 A 5 0 8

[10] .rela.plt RELA 00000000004003f0 000003f0

0000000000000030 0000000000000018 AI 5 24 8

[11] .init PROGBITS 0000000000400420 00000420

000000000000001a 0000000000000000 AX 0 0 4

[12] .plt PROGBITS 0000000000400440 00000440

0000000000000030 0000000000000010 AX 0 0 16

[13] .plt.got PROGBITS 0000000000400470 00000470

0000000000000008 0000000000000000 AX 0 0 8

[14] .text PROGBITS 0000000000400480 00000480

00000000000001b2 0000000000000000 AX 0 0 16

[15] .fini PROGBITS 0000000000400634 00000634

0000000000000009 0000000000000000 AX 0 0 4

[16] .rodata PROGBITS 0000000000400640 00000640

0000000000000012 0000000000000000 A 0 0 4

[17] .eh_frame_hdr PROGBITS 0000000000400654 00000654

0000000000000034 0000000000000000 A 0 0 4

[18] .eh_frame PROGBITS 0000000000400688 00000688

00000000000000f4 0000000000000000 A 0 0 8

[19] .init_array INIT_ARRAY 0000000000600e00 00000e00

0000000000000008 0000000000000000 WA 0 0 8

[20] .fini_array FINI_ARRAY 0000000000600e08 00000e08

0000000000000008 0000000000000000 WA 0 0 8

[21] .jcr PROGBITS 0000000000600e10 00000e10

0000000000000008 0000000000000000 WA 0 0 8

[22] .dynamic DYNAMIC 0000000000600e18 00000e18

00000000000001e0 0000000000000010 WA 6 0 8

[23] .got PROGBITS 0000000000600ff8 00000ff8

0000000000000008 0000000000000008 WA 0 0 8

[24] .got.plt PROGBITS 0000000000601000 00001000

0000000000000028 0000000000000008 WA 0 0 8

[25] .data PROGBITS 0000000000601028 00001028

0000000000000010 0000000000000000 WA 0 0 8

[26] .bss NOBITS 0000000000601038 00001038

0000000000000008 0000000000000000 WA 0 0 1

[27] .comment PROGBITS 0000000000000000 00001038

0000000000000035 0000000000000001 MS 0 0 1

[28] .debug_aranges PROGBITS 0000000000000000 0000106d

0000000000000030 0000000000000000 0 0 1

[29] .debug_info PROGBITS 0000000000000000 0000109d

000000000000016a 0000000000000000 0 0 1

[30] .debug_abbrev PROGBITS 0000000000000000 00001207

000000000000010d 0000000000000000 0 0 1

[31] .debug_line PROGBITS 0000000000000000 00001314

0000000000000097 0000000000000000 0 0 1

[32] .debug_str PROGBITS 0000000000000000 000013ab

000000000000016d 0000000000000001 MS 0 0 1

[33] .debug_loc PROGBITS 0000000000000000 00001518

000000000000011b 0000000000000000 0 0 1

[34] .debug_ranges PROGBITS 0000000000000000 00001633

0000000000000060 0000000000000000 0 0 1

[35] .shstrtab STRTAB 0000000000000000 00001fc5

0000000000000165 0000000000000000 0 0 1

[36] .symtab SYMTAB 0000000000000000 00001698

0000000000000708 0000000000000018 37 55 8

[37] .strtab STRTAB 0000000000000000 00001da0

0000000000000225 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)

There are no section groups in this file.

Program Headers:

Type Offset VirtAddr PhysAddr

FileSiz MemSiz Flags Align

PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040

0x00000000000001f8 0x00000000000001f8 R E 8

INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238

0x0000000000000040 0x0000000000000040 R 1

[Requesting program interpreter: /root/Desktop/linux/glibc-2.23/install/lib/ld-linux-x86-64.so.2]

LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000

0x000000000000077c 0x000000000000077c R E 200000

LOAD 0x0000000000000e00 0x0000000000600e00 0x0000000000600e00

0x0000000000000238 0x0000000000000240 RW 200000

DYNAMIC 0x0000000000000e18 0x0000000000600e18 0x0000000000600e18

0x00000000000001e0 0x00000000000001e0 RW 8

NOTE 0x0000000000000278 0x0000000000400278 0x0000000000400278

0x0000000000000044 0x0000000000000044 R 4

GNU_EH_FRAME 0x0000000000000654 0x0000000000400654 0x0000000000400654

0x0000000000000034 0x0000000000000034 R 4

GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000

0x0000000000000000 0x0000000000000000 RW 10

GNU_RELRO 0x0000000000000e00 0x0000000000600e00 0x0000000000600e00

0x0000000000000200 0x0000000000000200 R 1

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 .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame

03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss

04 .dynamic

05 .note.ABI-tag .note.gnu.build-id

06 .eh_frame_hdr

07

08 .init_array .fini_array .jcr .dynamic .got

Dynamic section at offset 0xe18 contains 25 entries:

Tag Type Name/Value

0x0000000000000001 (NEEDED) Shared library: [libc.so.6]

0x000000000000000f (RPATH) Library rpath: [/root/Desktop/linux/glibc-2.23/install/lib]

0x000000000000000c (INIT) 0x400420

0x000000000000000d (FINI) 0x400634

0x0000000000000019 (INIT_ARRAY) 0x600e00

0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)

0x000000000000001a (FINI_ARRAY) 0x600e08

0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)

0x000000006ffffef5 (GNU_HASH) 0x4002c0

0x0000000000000005 (STRTAB) 0x400340

0x0000000000000006 (SYMTAB) 0x4002e0

0x000000000000000a (STRSZ) 106 (bytes)

0x000000000000000b (SYMENT) 24 (bytes)

0x0000000000000015 (DEBUG) 0x0

0x0000000000000003 (PLTGOT) 0x601000

0x0000000000000002 (PLTRELSZ) 48 (bytes)

0x0000000000000014 (PLTREL) RELA

0x0000000000000017 (JMPREL) 0x4003f0

0x0000000000000007 (RELA) 0x4003d8

0x0000000000000008 (RELASZ) 24 (bytes)

0x0000000000000009 (RELAENT) 24 (bytes)

0x000000006ffffffe (VERNEED) 0x4003b8

0x000000006fffffff (VERNEEDNUM) 1

0x000000006ffffff0 (VERSYM) 0x4003aa

0x0000000000000000 (NULL) 0x0

Relocation section '.rela.dyn' at offset 0x3d8 contains 1 entries:

Offset Info Type Sym. Value Sym. Name + Addend

000000600ff8 000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0

Relocation section '.rela.plt' at offset 0x3f0 contains 2 entries:

Offset Info Type Sym. Value Sym. Name + Addend

000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0

000000601020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

Symbol table '.dynsym' contains 4 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 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)

3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__

Symbol table '.symtab' contains 75 entries:

Num: Value Size Type Bind Vis Ndx Name

0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND

1: 0000000000400238 0 SECTION LOCAL DEFAULT 1

2: 0000000000400278 0 SECTION LOCAL DEFAULT 2

3: 0000000000400298 0 SECTION LOCAL DEFAULT 3

4: 00000000004002c0 0 SECTION LOCAL DEFAULT 4

5: 00000000004002e0 0 SECTION LOCAL DEFAULT 5

6: 0000000000400340 0 SECTION LOCAL DEFAULT 6

7: 00000000004003aa 0 SECTION LOCAL DEFAULT 7

8: 00000000004003b8 0 SECTION LOCAL DEFAULT 8

9: 00000000004003d8 0 SECTION LOCAL DEFAULT 9

10: 00000000004003f0 0 SECTION LOCAL DEFAULT 10

11: 0000000000400420 0 SECTION LOCAL DEFAULT 11

12: 0000000000400440 0 SECTION LOCAL DEFAULT 12

13: 0000000000400470 0 SECTION LOCAL DEFAULT 13

14: 0000000000400480 0 SECTION LOCAL DEFAULT 14

15: 0000000000400634 0 SECTION LOCAL DEFAULT 15

16: 0000000000400640 0 SECTION LOCAL DEFAULT 16

17: 0000000000400654 0 SECTION LOCAL DEFAULT 17

18: 0000000000400688 0 SECTION LOCAL DEFAULT 18

19: 0000000000600e00 0 SECTION LOCAL DEFAULT 19

20: 0000000000600e08 0 SECTION LOCAL DEFAULT 20

21: 0000000000600e10 0 SECTION LOCAL DEFAULT 21

22: 0000000000600e18 0 SECTION LOCAL DEFAULT 22

23: 0000000000600ff8 0 SECTION LOCAL DEFAULT 23

24: 0000000000601000 0 SECTION LOCAL DEFAULT 24

25: 0000000000601028 0 SECTION LOCAL DEFAULT 25

26: 0000000000601038 0 SECTION LOCAL DEFAULT 26

27: 0000000000000000 0 SECTION LOCAL DEFAULT 27

28: 0000000000000000 0 SECTION LOCAL DEFAULT 28

29: 0000000000000000 0 SECTION LOCAL DEFAULT 29

30: 0000000000000000 0 SECTION LOCAL DEFAULT 30

31: 0000000000000000 0 SECTION LOCAL DEFAULT 31

32: 0000000000000000 0 SECTION LOCAL DEFAULT 32

33: 0000000000000000 0 SECTION LOCAL DEFAULT 33

34: 0000000000000000 0 SECTION LOCAL DEFAULT 34

35: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c

36: 0000000000600e10 0 OBJECT LOCAL DEFAULT 21 __JCR_LIST__

37: 00000000004004b0 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones

38: 00000000004004f0 0 FUNC LOCAL DEFAULT 14 register_tm_clones

39: 0000000000400530 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux

40: 0000000000601038 1 OBJECT LOCAL DEFAULT 26 completed.7594

41: 0000000000600e08 0 OBJECT LOCAL DEFAULT 20 __do_global_dtors_aux_fin

42: 0000000000400550 0 FUNC LOCAL DEFAULT 14 frame_dummy

43: 0000000000600e00 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_init_array_

44: 0000000000000000 0 FILE LOCAL DEFAULT ABS elf-init.c

45: 0000000000000000 0 FILE LOCAL DEFAULT ABS Test01Sum.c

46: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c

47: 0000000000400778 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__

48: 0000000000600e10 0 OBJECT LOCAL DEFAULT 21 __JCR_END__

49: 0000000000000000 0 FILE LOCAL DEFAULT ABS

50: 0000000000600e08 0 NOTYPE LOCAL DEFAULT 19 __init_array_end

51: 0000000000600e18 0 OBJECT LOCAL DEFAULT 22 _DYNAMIC

52: 0000000000600e00 0 NOTYPE LOCAL DEFAULT 19 __init_array_start

53: 0000000000400654 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR

54: 0000000000601000 0 OBJECT LOCAL DEFAULT 24 _GLOBAL_OFFSET_TABLE_

55: 0000000000400630 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini

56: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab

57: 0000000000601028 0 NOTYPE WEAK DEFAULT 25 data_start

58: 0000000000601038 0 NOTYPE GLOBAL DEFAULT 25 _edata

59: 0000000000400634 0 FUNC GLOBAL DEFAULT 15 _fini

60: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.2.5

61: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_

62: 0000000000601028 0 NOTYPE GLOBAL DEFAULT 25 __data_start

63: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__

64: 0000000000601030 0 OBJECT GLOBAL HIDDEN 25 __dso_handle

65: 0000000000400640 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used

66: 00000000004005c0 101 FUNC GLOBAL DEFAULT 14 __libc_csu_init

67: 0000000000601040 0 NOTYPE GLOBAL DEFAULT 26 _end

68: 0000000000400480 42 FUNC GLOBAL DEFAULT 14 _start

69: 0000000000601038 0 NOTYPE GLOBAL DEFAULT 26 __bss_start

70: 0000000000400576 67 FUNC GLOBAL DEFAULT 14 main

71: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses

72: 0000000000601038 0 OBJECT GLOBAL HIDDEN 25 __TMC_END__

73: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable

74: 0000000000400420 0 FUNC GLOBAL DEFAULT 11 _init

Version symbols section '.gnu.version' contains 4 entries:

Addr: 00000000004003aa Offset: 0x0003aa Link: 5 (.dynsym)

000: 0 (*local*) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 0 (*local*)

Version needs section '.gnu.version_r' contains 1 entries:

Addr: 0x00000000004003b8 Offset: 0x0003b8 Link: 6 (.dynstr)

000000: Version: 1 File: libc.so.6 Cnt: 1

0x0010: Name: GLIBC_2.2.5 Flags: none Version: 2

Displaying notes found at file offset 0x00000278 with length 0x00000020:

Owner Data size Description

GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag)

OS: Linux, ABI: 2.6.32

Displaying notes found at file offset 0x00000298 with length 0x00000024:

Owner Data size Description

GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)

Build ID: 40a7a5576d0c3e9280e8fd00051f817befc922c6

linux 层面的 elf 的执行

在这一个层面主要是包含两个部分, fork + exec

1. fork 当前进程

2. 然后更新 子进程的执行文件为待执行 elf

3. 然后 之后执行 elf 的相关业务

执行 "./Test01Sum"

首先是 fork, 可以看到执行 Test01Sum 的进程是 275

然后是 exec 更新子进程待执行的 elf

这里可以看到待执行文件为 "./Test01Sum"

然后 核心业务处理是在 binfmt_elf. load_elf_binary

主要包含了读取 elfHeader, programHeaders, 加载 interpreter, 加载 interpreter 的 elfHeader, programHeaders, mmap LOAD 的 segment, 更新 bss, data, code 的相关偏移, 初始化执行程序的栈帧, 更新子进程的入口, 子进程开始处理业务

这里的 elf_entry, 如果是静态链接, 则为 elf 的 entry_point, 否则为 interpreter 的 entry_point

glibc 的 libc_start_main

我们看一下 elf 的 entry_point 的代码

主要是构造了 libc_start_main 的参数, 传入了诸如 main, init, fini, argc, argv 等等相关参数

main, 就是用户代码的 main 编译好了之后生成的代码

在 libc_start_main 中调用了 main

main 的代码地址为 0x400576, 对应于 elf 中的 main

然后 这时候我们的 main 才开始跑起来

main 的执行

然后就是 用户代码中的 main 的代码的执行了

上面的这部分代码段时属于 LOAD 的 segment 的一部分, 被完全 mmap 进来, 因此是一样的

当然 以上仅仅是一个 大体的脉络

实际上有很多有意思的细节, 在其中

最新发表
友情链接

Copyright © 2022 日本世界杯_林高远世界杯 - edenyn.com All Rights Reserved.