GNU tool chain

  • ar
  • strings
  • strip
  • nm
  • size
  • readelf
  • objdump

cmd

1
gcc -g -c hello.c

-g用于生成调试信息以便gdb使用,-c只激活预处理编译汇编,生成后缀名.o的obj文件

1
2
$ file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), with debug_info, not stripped
1
2
3
$ gcc -o hello hello.o
$ file hello
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bb407a3b5053469c8d7e7f27ef5e67e216a82bd4, for GNU/Linux 3.2.0, with debug_info, not stripped

链接

使用ldd查看helloworld链接了哪些共享库

1
2
3
4
$ ldd hello
linux-vdso.so.1 (0x00007ffc703ec000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1ae3600000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1ae3844000)

libc.so.6glibc,实现了printf这类标准C的函数

ld-linux-x86-64.so.2ELF可执行文件的解释器,Linux内核在执行ELF可执行文件时,其实是执行ld-linux-x86-64.so.2,然后由ld-linux-x86-64.so.2去加载可执行文件及依赖的共享库。

ld-linux-x86-64.so.2是共享库,又是可执行的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
$ ./lib64/ld-linux-x86-64.so.2 --help
Usage: ./lib64/ld-linux-x86-64.so.2 [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]
You have invoked 'ld.so', the program interpreter for dynamically-linked
ELF programs. Usually, the program interpreter is invoked automatically
when a dynamically-linked executable is started.

You may invoke the program interpreter program directly from the command
line to load and run an ELF executable file; this is like executing that
file itself, but always uses the program interpreter you invoked,
instead of the program interpreter specified in the executable file you
run. Invoking the program interpreter directly provides access to
additional diagnostics, and changing the dynamic linker behavior without
setting environment variables (which would be inherited by subprocesses).

--list list all dependencies and how they are resolved
--verify verify that given object really is a dynamically linked
object we can handle
--inhibit-cache Do not use /etc/ld.so.cache
--library-path PATH use given PATH instead of content of the environment
variable LD_LIBRARY_PATH
--glibc-hwcaps-prepend LIST
search glibc-hwcaps subdirectories in LIST
--glibc-hwcaps-mask LIST
only search built-in subdirectories if in LIST
--inhibit-rpath LIST ignore RUNPATH and RPATH information in object names
in LIST
--audit LIST use objects named in LIST as auditors
--preload LIST preload objects named in LIST
--argv0 STRING set argv[0] to STRING before running
--list-tunables list all tunables with minimum and maximum values
--list-diagnostics list diagnostics information
--help display this help and exit
--version output version information and exit

This program interpreter self-identifies as: /lib64/ld-linux-x86-64.so.2

Shared library search path:
(libraries located via /etc/ld.so.cache)
/lib/x86_64-linux-gnu (system search path)
/usr/lib/x86_64-linux-gnu (system search path)
/lib (system search path)
/usr/lib (system search path)

Subdirectories of glibc-hwcaps directories, in priority order:
x86-64-v4 (supported, searched)
x86-64-v3 (supported, searched)
x86-64-v2 (supported, searched)

Legacy HWCAP subdirectories under library search path directories:
haswell (AT_PLATFORM; supported, searched)
tls (supported, searched)
avx512_1 (supported, searched)
x86_64 (supported, searched)

从它的的参数来看,它可以直接执行ELF文件:

1
2
$ ./lib64/ld-linux-x86-64.so.2 ~/Downloads/prog/hello1/hello
Hello World! via be0606f0

linux-vdso.so.1没有指向任何文件,而是指向一个地址0x00007ffc703ec000。vdso的意思是虚拟动态共享库。Linux内核根据CPU类型,动态决定使用哪个共享库。它的功能主要是加速系统调用(syscall)

objdump反汇编

显示文件中的text段的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ objdump --section=.text -s helloworld 

helloworld: file format elf64-x86-64

Contents of section .text:
1060 f30f1efa 31ed4989 d15e4889 e24883e4 ....1.I..^H..H..
1070 f0505445 31c031c9 488d3dca 000000ff .PTE1.1.H.=.....
1080 15532f00 00f4662e 0f1f8400 00000000 .S/...f.........
1090 488d3d79 2f000048 8d05722f 00004839 H.=y/..H..r/..H9
10a0 f8741548 8b05362f 00004885 c07409ff .t.H..6/..H..t..
10b0 e00f1f80 00000000 c30f1f80 00000000 ................
10c0 488d3d49 2f000048 8d35422f 00004829 H.=I/..H.5B/..H)
10d0 fe4889f0 48c1ee3f 48c1f803 4801c648 .H..H..?H...H..H
10e0 d1fe7414 488b0505 2f000048 85c07408 ..t.H.../..H..t.
10f0 ffe0660f 1f440000 c30f1f80 00000000 ..f..D..........
1100 f30f1efa 803d052f 00000075 2b554883 .....=./...u+UH.
1110 3de22e00 00004889 e5740c48 8b3de62e =.....H..t.H.=..
1120 0000e819 ffffffe8 64ffffff c605dd2e ........d.......
1130 0000015d c30f1f00 c30f1f80 00000000 ...]............
1140 f30f1efa e977ffff fff30f1e fa554889 .....w.......UH.
1150 e5488d05 ac0e0000 4889c7e8 f0feffff .H......H.......
1160 b8000000 005dc3 .....].

反汇编程序中的text段内容,并尽可能用源代码形式表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
$ objdump -j .text -S helloworld 

helloworld: file format elf64-x86-64


Disassembly of section .text:

0000000000001060 <_start>:
1060: f3 0f 1e fa endbr64
1064: 31 ed xor %ebp,%ebp
1066: 49 89 d1 mov %rdx,%r9
1069: 5e pop %rsi
106a: 48 89 e2 mov %rsp,%rdx
106d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
1071: 50 push %rax
1072: 54 push %rsp
1073: 45 31 c0 xor %r8d,%r8d
1076: 31 c9 xor %ecx,%ecx
1078: 48 8d 3d ca 00 00 00 lea 0xca(%rip),%rdi # 1149 <main>
107f: ff 15 53 2f 00 00 call *0x2f53(%rip) # 3fd8 <__libc_start_main@GLIBC_2.34>
1085: f4 hlt
1086: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
108d: 00 00 00

0000000000001090 <deregister_tm_clones>:
1090: 48 8d 3d 79 2f 00 00 lea 0x2f79(%rip),%rdi # 4010 <__TMC_END__>
1097: 48 8d 05 72 2f 00 00 lea 0x2f72(%rip),%rax # 4010 <__TMC_END__>
109e: 48 39 f8 cmp %rdi,%rax
10a1: 74 15 je 10b8 <deregister_tm_clones+0x28>
10a3: 48 8b 05 36 2f 00 00 mov 0x2f36(%rip),%rax # 3fe0 <_ITM_deregisterTMCloneTable@Base>
10aa: 48 85 c0 test %rax,%rax
10ad: 74 09 je 10b8 <deregister_tm_clones+0x28>
10af: ff e0 jmp *%rax
10b1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
10b8: c3 ret
10b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)

00000000000010c0 <register_tm_clones>:
10c0: 48 8d 3d 49 2f 00 00 lea 0x2f49(%rip),%rdi # 4010 <__TMC_END__>
10c7: 48 8d 35 42 2f 00 00 lea 0x2f42(%rip),%rsi # 4010 <__TMC_END__>
10ce: 48 29 fe sub %rdi,%rsi
10d1: 48 89 f0 mov %rsi,%rax
10d4: 48 c1 ee 3f shr $0x3f,%rsi
10d8: 48 c1 f8 03 sar $0x3,%rax
10dc: 48 01 c6 add %rax,%rsi
10df: 48 d1 fe sar %rsi
10e2: 74 14 je 10f8 <register_tm_clones+0x38>
10e4: 48 8b 05 05 2f 00 00 mov 0x2f05(%rip),%rax # 3ff0 <_ITM_registerTMCloneTable@Base>
10eb: 48 85 c0 test %rax,%rax
10ee: 74 08 je 10f8 <register_tm_clones+0x38>
10f0: ff e0 jmp *%rax
10f2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
10f8: c3 ret
10f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)

0000000000001100 <__do_global_dtors_aux>:
1100: f3 0f 1e fa endbr64
1104: 80 3d 05 2f 00 00 00 cmpb $0x0,0x2f05(%rip) # 4010 <__TMC_END__>
110b: 75 2b jne 1138 <__do_global_dtors_aux+0x38>
110d: 55 push %rbp
110e: 48 83 3d e2 2e 00 00 cmpq $0x0,0x2ee2(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
1115: 00
1116: 48 89 e5 mov %rsp,%rbp
1119: 74 0c je 1127 <__do_global_dtors_aux+0x27>
111b: 48 8b 3d e6 2e 00 00 mov 0x2ee6(%rip),%rdi # 4008 <__dso_handle>
1122: e8 19 ff ff ff call 1040 <__cxa_finalize@plt>
1127: e8 64 ff ff ff call 1090 <deregister_tm_clones>
112c: c6 05 dd 2e 00 00 01 movb $0x1,0x2edd(%rip) # 4010 <__TMC_END__>
1133: 5d pop %rbp
1134: c3 ret
1135: 0f 1f 00 nopl (%rax)
1138: c3 ret
1139: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)

0000000000001140 <frame_dummy>:
1140: f3 0f 1e fa endbr64
1144: e9 77 ff ff ff jmp 10c0 <register_tm_clones>

0000000000001149 <main>:
#include <stdio.h>

int main()
{
1149: f3 0f 1e fa endbr64
114d: 55 push %rbp
114e: 48 89 e5 mov %rsp,%rbp
printf("hello world\n");
1151: 48 8d 05 ac 0e 00 00 lea 0xeac(%rip),%rax # 2004 <_IO_stdin_used+0x4>
1158: 48 89 c7 mov %rax,%rdi
115b: e8 f0 fe ff ff call 1050 <puts@plt>
return 0;
1160: b8 00 00 00 00 mov $0x0,%eax
}
1165: 5d pop %rbp
1166: c3 ret

显示文件的符号表入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$ objdump -t helloworld 

helloworld: file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 Scrt1.o
000000000000038c l O .note.ABI-tag 0000000000000020 __abi_tag
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000001090 l F .text 0000000000000000 deregister_tm_clones
00000000000010c0 l F .text 0000000000000000 register_tm_clones
0000000000001100 l F .text 0000000000000000 __do_global_dtors_aux
0000000000004010 l O .bss 0000000000000001 completed.0
0000000000003dc0 l O .fini_array 0000000000000000 __do_global_dtors_aux_fini_array_entry
0000000000001140 l F .text 0000000000000000 frame_dummy
0000000000003db8 l O .init_array 0000000000000000 __frame_dummy_init_array_entry
0000000000000000 l df *ABS* 0000000000000000 hello.c
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
00000000000020f0 l O .eh_frame 0000000000000000 __FRAME_END__
0000000000000000 l df *ABS* 0000000000000000
0000000000003dc8 l O .dynamic 0000000000000000 _DYNAMIC
0000000000002010 l .eh_frame_hdr 0000000000000000 __GNU_EH_FRAME_HDR
0000000000003fb8 l O .got 0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000 F *UND* 0000000000000000 __libc_start_main@GLIBC_2.34
0000000000000000 w *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000004000 w .data 0000000000000000 data_start
0000000000000000 F *UND* 0000000000000000 puts@GLIBC_2.2.5
0000000000004010 g .data 0000000000000000 _edata
0000000000001168 g F .fini 0000000000000000 .hidden _fini
0000000000004000 g .data 0000000000000000 __data_start
0000000000000000 w *UND* 0000000000000000 __gmon_start__
0000000000004008 g O .data 0000000000000000 .hidden __dso_handle
0000000000002000 g O .rodata 0000000000000004 _IO_stdin_used
0000000000004018 g .bss 0000000000000000 _end
0000000000001060 g F .text 0000000000000026 _start
0000000000004010 g .bss 0000000000000000 __bss_start
0000000000001149 g F .text 000000000000001e main
0000000000004010 g O .data 0000000000000000 .hidden __TMC_END__
0000000000000000 w *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 w F *UND* 0000000000000000 __cxa_finalize@GLIBC_2.2.5
0000000000001000 g F .init 0000000000000000 .hidden _init

显示目标文件各个段的头部摘要信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
$ objdump -h helloworld 

helloworld: file format elf64-x86-64

Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001c 0000000000000318 0000000000000318 00000318 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.gnu.property 00000030 0000000000000338 0000000000000338 00000338 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024 0000000000000368 0000000000000368 00000368 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .note.ABI-tag 00000020 000000000000038c 000000000000038c 0000038c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .gnu.hash 00000024 00000000000003b0 00000000000003b0 000003b0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynsym 000000a8 00000000000003d8 00000000000003d8 000003d8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .dynstr 0000008d 0000000000000480 0000000000000480 00000480 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version 0000000e 000000000000050e 000000000000050e 0000050e 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .gnu.version_r 00000030 0000000000000520 0000000000000520 00000520 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.dyn 000000c0 0000000000000550 0000000000000550 00000550 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .rela.plt 00000018 0000000000000610 0000000000000610 00000610 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .init 0000001b 0000000000001000 0000000000001000 00001000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .plt 00000020 0000000000001020 0000000000001020 00001020 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .plt.got 00000010 0000000000001040 0000000000001040 00001040 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .plt.sec 00000010 0000000000001050 0000000000001050 00001050 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
15 .text 00000107 0000000000001060 0000000000001060 00001060 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
16 .fini 0000000d 0000000000001168 0000000000001168 00001168 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
17 .rodata 00000010 0000000000002000 0000000000002000 00002000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
18 .eh_frame_hdr 00000034 0000000000002010 0000000000002010 00002010 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
19 .eh_frame 000000ac 0000000000002048 0000000000002048 00002048 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
20 .init_array 00000008 0000000000003db8 0000000000003db8 00002db8 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .fini_array 00000008 0000000000003dc0 0000000000003dc0 00002dc0 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .dynamic 000001f0 0000000000003dc8 0000000000003dc8 00002dc8 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .got 00000048 0000000000003fb8 0000000000003fb8 00002fb8 2**3
CONTENTS, ALLOC, LOAD, DATA
24 .data 00000010 0000000000004000 0000000000004000 00003000 2**3
CONTENTS, ALLOC, LOAD, DATA
25 .bss 00000008 0000000000004010 0000000000004010 00003010 2**0
ALLOC
26 .comment 0000002b 0000000000000000 0000000000000000 00003010 2**0
CONTENTS, READONLY
27 .debug_aranges 00000030 0000000000000000 0000000000000000 0000303b 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
28 .debug_info 0000008c 0000000000000000 0000000000000000 0000306b 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
29 .debug_abbrev 00000043 0000000000000000 0000000000000000 000030f7 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
30 .debug_line 00000052 0000000000000000 0000000000000000 0000313a 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
31 .debug_str 000000d9 0000000000000000 0000000000000000 0000318c 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
32 .debug_line_str 00000024 0000000000000000 0000000000000000 00003265 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS

strace

这里使用-static选项禁用动态库,以便查看系统调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ gcc -static -o hello hello.c
$ strace ./hello
execve("./hello", ["./hello"], 0x7ffffb3c6560 /* 59 vars */) = 0
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe40261b40) = -1 EINVAL (Invalid argument)
brk(NULL) = 0x240f000
brk(0x240fdc0) = 0x240fdc0
arch_prctl(ARCH_SET_FS, 0x240f3c0) = 0
set_tid_address(0x240f690) = 4214
set_robust_list(0x240f6a0, 24) = 0
rseq(0x240fd60, 0x20, 0, 0x53053053) = 0
uname({sysname="Linux", nodename="xiaoma-virtual-machine", ...}) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
readlink("/proc/self/exe", "/home/xiaoma/Downloads/prog/hell"..., 4096) = 33
getrandom("\xac\xd3\x2e\xda\x3f\x46\xb2\x94", 8, GRND_NONBLOCK) = 8
brk(0x2430dc0) = 0x2430dc0
brk(0x2431000) = 0x2431000
mprotect(0x4c1000, 16384, PROT_READ) = 0
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0
write(1, "hello world\n", 12hello world
) = 12
exit_group(0) = ?
+++ exited with 0 +++

可以看到有非常多的系统调用。在前面一系列的构建和准备工作后,最后执行了write()系统调用,这也是在屏幕上打印hello world的直接原因。

系统调用统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ strace -c ./helloworld 
hello world
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0.00 0.000000 0 1 read
0.00 0.000000 0 1 write
0.00 0.000000 0 2 close
0.00 0.000000 0 8 mmap
0.00 0.000000 0 4 mprotect
0.00 0.000000 0 1 munmap
0.00 0.000000 0 3 brk
0.00 0.000000 0 4 pread64
0.00 0.000000 0 1 1 access
0.00 0.000000 0 1 execve
0.00 0.000000 0 2 1 arch_prctl
0.00 0.000000 0 1 set_tid_address
0.00 0.000000 0 2 openat
0.00 0.000000 0 3 newfstatat
0.00 0.000000 0 1 set_robust_list
0.00 0.000000 0 1 prlimit64
0.00 0.000000 0 1 getrandom
0.00 0.000000 0 1 rseq
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 0 38 2 total