调试符号如何影响由GCC编译的Linux可执行文件的性能? [英] How do debug symbols affect performance of a Linux executable compiled by GCC?
问题描述
所有其他因素相同(例如优化级别),在ELF或SO中调试符号如何影响:
- 加载时间。
- 运行时内存占用。
- 运行时间性能
- Load time.
- Runtime memory footprint.
- Runtime performance?
编辑
我已经看到这个问题,但我发现讨论无益,因为代码优化因素混淆了那里的问题。 为什么我的代码运行速度比较慢线程比使用单线程编译时进行性能分析(-pg)?
调试符号是位于与代码/数据部分完全不同的部分。你可以用 objdump
来检查它:
$ b
$ objdump -h a。 out
a.out:文件格式elf64-x86-64
部分:
Idx名称大小VMA LMA File off Algn
0 .interp 0000001c 0000000000400200 0000000000400200 00000200 2 ** 0
目录,ALLOC,LOAD,READONLY,DATA
1 .note.ABI-tag 00000020 000000000040021c 000000000040021c 0000021c 2 ** 2
目录,ALLOC,LOAD,READONLY ,DATA
2 .note.gnu.build-id 00000024 000000000040023c 000000000040023c 0000023c 2 ** 2
目录,ALLOC,LOAD,READONLY,DATA
3.hash 00000018 0000000000400260 0000000000400260 00000260 2 ** 3
目录,ALLOC,LOAD,READONLY,DATA
4 .gnu.hash 0000001c 0000000000400278 0000000000400278 00000278 2 ** 3
目录,ALLOC,LOAD,READONLY,DATA
5。 dynsym 00000 048 0000000000400298 0000000000400298 00000298 2 ** 3
目录,ALLOC,LOAD,READONLY,DATA
6.dynstr 00000038 00000000004002e0 00000000004002e0 000002e0 2 ** 0
目录,ALLOC,LOAD,READONLY,DATA
7 .gnu.version 00000006 0000000000400318 0000000000400318 00000318 2 ** 1
目录,ALLOC,LOAD,READONLY,DATA
8 .gnu.version_r 00000020 0000000000400320 0000000000400320 00000320 2 ** 3
目录,ALLOC,LOAD,READONLY,DATA
9.rela.dyn 00000018 0000000000400340 0000000000400340 00000340 2 ** 3
目录,ALLOC,LOAD,READONLY,DATA
10 .rela.plt 00000018 0000000000400358 0000000000400358 00000358 2 ** 3
目录,ALLOC,LOAD,READONLY,DATA
.init 00000018 0000000000400370 0000000000400370 00000370 2 ** 2
目录,ALLOC,LOAD,READONLY,CODE
12 .pl t 00000020 0000000000400388 0000000000400388 00000388 2 ** 2
目录,ALLOC,LOAD,READONLY,CODE
13 .text 000001c8 00000000004003b0 00000000004003b0 000003b0 2 ** 4
目录,ALLOC,LOAD,READONLY,CODE
14 .fini 0000000e 0000000000400578 0000000000400578 00000578 2 ** 2
目录,ALLOC,LOAD,READONLY,CODE
.rodata 00000004 0000000000400588 0000000000400588 00000588 2 ** 2
目录,ALLOC ,LOAD,READONLY,DATA
16 .eh_frame_hdr 00000024 000000000040058c 000000000040058c 0000058c 2 ** 2
目录,ALLOC,LOAD,READONLY,DATA
17 .eh_frame 0000007c 00000000004005b0 00000000004005b0 000005b0 2 ** 3
目录,ALLOC,LOAD,READONLY,DATA
18 .ctors 00000010 0000000000600630 0000000000600630 00000630 2 ** 3
目录,ALLOC,LOAD,DATA
1 9 .dtors 00000010 0000000000600640 0000000000600640 00000640 2 ** 3
目录,ALLOC,LOAD,DATA
20 .jcr 00000008 0000000000600650 0000000000600650 00000650 2 ** 3
目录,ALLOC,LOAD,DATA
21 .dynamic 000001a0 0000000000600658 0000000000600658 00000658 2 ** 3
目录,ALLOC,LOAD,DATA
22 .got 00000008 00000000006007f8 00000000006007f8 000007f8 2 ** 3
目录,ALLOC,LOAD,DATA
23 .got.plt 00000020 0000000000600800 0000000000600800 00000800 2 ** 3
目录,ALLOC,LOAD,DATA
。数据00000010 0000000000600820 0000000000600820 00000820 2 ** 3
目录,ALLOC ,LOAD,DATA
25 .bss 00000010 0000000000600830 0000000000600830 00000830 2 ** 3
ALLOC
26 .comment 00000039 0000000000000000 0000000000000000 00000830 2 ** 0
CONTENTS,READONLY
27 .debug_aranges 00000030 0000000000000000 0000000000000000 00000869 2 ** 0
内容,READONLY,DEBUGGING
28 .debug_pubnames 0000001b 0000000000000000 0000000000000000 00000899 2 ** 0
目录,READONLY,DEBUGGING
29 .debug_info 00000055 0000000000000000 0000000000000000 000008b4 2 ** 0
目录,只读,调试
30 .debug_abbrev 00000034 0000000000000000 0000000000000000 00000909 2 ** 0
目录, READONLY,DEBUGGING
31 .debug_line 0000003b 0000000000000000 0000000000000000 0000093d 2 ** 0
CONTENTS,READONLY,DEBUGGING
32 .debug_str 00000026 0000000000000000 0000000000000000 00000978 2 ** 0
CONTENTS,READONLY,调试
33 .debug_loc 0000004c 0000000000000000 0000000000000000 0000099e 2 ** 0
目录,READONLY,DEBUGG ING
您可以看到额外的部分(27到33)。这些部分不会在运行时加载,所以不会有任何性能损失。使用 gdb
,您也可以在运行时检查它们
$ gdb。 /a.out
(gdb)break main
(gdb)运行
(gdb)信息文件
//等等等等......
本地exec文件:
`/home/kghost/a.out',文件类型为elf64-x86-64。
入口点:0x4003b0
0x0000000000400200 - 0x000000000040021c是.interp
0x000000000040021c - 0x000000000040023c是.note.ABI-tag
0x000000000040023c - 0x0000000000400260是.note.gnu.build-id
0x0000000000400260 - 0x0000000000400278 is .hash
0x0000000000400278 - 0x0000000000400294 is .gnu.hash
0x0000000000400298 - 0x00000000004002e0 is .dynsym
0x00000000004002e0 - 0x0000000000400318 is .dynstr
0x0000000000400318 - 0x000000000040031e是.gnu .version
0x0000000000400320 - 0x0000000000400340 is .gnu.version_r
0x0000000000400340 - 0x0000000000400358 is .rela.dyn
0x0000000000400358 - 0x0000000000400370 is .rela.plt
0x0000000000400370 - 0x0000000000400388是.init
0x0000000000400388 - 0x00000000004003a8是.plt
0x00000000004003b0 - 0x0000000000400578是.text
0x0000000000400578 - 0x0000000 000400586是.fini
0x0000000000400588 - 0x000000000040058c是.rodata
0x000000000040058c - 0x00000000004005b0是.eh_frame_hdr
0x00000000004005b0 - 0x000000000040062c是.eh_frame
0x0000000000600630 - 0x0000000000600640是.ctors
0x0000000000600640 - 0x0000000000600650 is .dtors
0x0000000000600650 - 0x0000000000600658 is .jcr
0x0000000000600658 - 0x00000000006007f8 is .dynamic
0x00000000006007f8 - 0x0000000000600800 is .got
0x0000000000600800 - 0x0000000000600820 is .got.plt
0x0000000000600820 - 0x0000000000600830 is .data
0x0000000000600830 - 0x0000000000600840 is .bss
// blah blah ....
所以唯一的损失是你需要额外的磁盘空间来存储这些信息。您也可以使用 strip
删除调试信息:
$ strip a.out
使用 objdump
来检查它再次,你会看到区别。
编辑:
文件根据程序头
,这可以通过 objdump -p
来看到。 (以下示例使用不同的elf二进制文件)
$ objdump -p / bin / cat
/ bin / cat:文件格式elf64-x86-64
程序头:
PHDR关闭0x0000000000000040 vaddr 0x0000000000000040 paddr 0x0000000000000040对齐2 ** 3
文件0x00000000000001f8 memsz 0x00000000000001f8标志rx
INTERP off 0x0000000000000238 vaddr 0x0000000000000238 paddr 0x0000000000000238 align 2 ** 0
filesz 0x000000000000001c memsz 0x000000000000001c flags r--
LOAD off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2 ** 21
filesz 0x00000000000078bc memsz 0x00000000000078bc标志rx
LOAD off 0x0000000000007c28 vaddr 0x0000000000207c28 paddr 0x0000000000207c28 align 2 ** 21
filesz 0x0000000000000678 memsz 0x0000000000000818 flags rw-
DYNAMIC off 0x0000000000007dd8 vaddr 0x0000000000207dd8 paddr 0x0000000000207dd8 align 2 ** 3
f ilesz 0x00000000000001e0 memsz 0x00000000000001e0标志rw-
注意off 0x0000000000000254 vaddr 0x0000000000000254 paddr 0x0000000000000254对齐2 ** 2
filesz 0x0000000000000044 memsz 0x0000000000000044标志r--
EH_FRAME关闭0x0000000000006980 vaddr 0x0000000000006980 paddr 0x0000000000006980对齐2 ** 2
filesz 0x0000000000000274 memsz 0x0000000000000274标志r--
堆栈关闭0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000对齐2 ** 4
filesz 0x0000000000000000 memsz 0x0000000000000000标志rw-
RELRO off 0x0000000000007c28 vaddr 0x0000000000207c28 paddr 0x0000000000207c28 align 2 ** 0
filesz 0x00000000000003d8 memsz 0x00000000000003d8 flags r--
程序头文件告诉哪个段将被加载什么rwx标志,具有相同标志的多个段将被合并到单个段。
顺便说一句:
加载程序没有在加载elf文件时不会关注部分,但它会查找几个符号相关部分以在需要时解析符号。
All other factors being equal (eg optimisation level), how does having debug symbols in an ELF or SO affect:
And what could be done to mitigate any negative effects?
EDIT I've seen this question but I find the discussion unhelpful, as the code optimization factor has confused the issue there. Why does my code run slower with multiple threads than with a single thread when it is compiled for profiling (-pg)?
The debug symbols are located in totally different sections from the code/data sections. You can check it with objdump
:
$ objdump -h a.out
a.out: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001c 0000000000400200 0000000000400200 00000200 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 000000000040021c 000000000040021c 0000021c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024 000000000040023c 000000000040023c 0000023c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .hash 00000018 0000000000400260 0000000000400260 00000260 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .gnu.hash 0000001c 0000000000400278 0000000000400278 00000278 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynsym 00000048 0000000000400298 0000000000400298 00000298 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .dynstr 00000038 00000000004002e0 00000000004002e0 000002e0 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version 00000006 0000000000400318 0000000000400318 00000318 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .gnu.version_r 00000020 0000000000400320 0000000000400320 00000320 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.dyn 00000018 0000000000400340 0000000000400340 00000340 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .rela.plt 00000018 0000000000400358 0000000000400358 00000358 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .init 00000018 0000000000400370 0000000000400370 00000370 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .plt 00000020 0000000000400388 0000000000400388 00000388 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .text 000001c8 00000000004003b0 00000000004003b0 000003b0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .fini 0000000e 0000000000400578 0000000000400578 00000578 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
15 .rodata 00000004 0000000000400588 0000000000400588 00000588 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .eh_frame_hdr 00000024 000000000040058c 000000000040058c 0000058c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .eh_frame 0000007c 00000000004005b0 00000000004005b0 000005b0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
18 .ctors 00000010 0000000000600630 0000000000600630 00000630 2**3
CONTENTS, ALLOC, LOAD, DATA
19 .dtors 00000010 0000000000600640 0000000000600640 00000640 2**3
CONTENTS, ALLOC, LOAD, DATA
20 .jcr 00000008 0000000000600650 0000000000600650 00000650 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .dynamic 000001a0 0000000000600658 0000000000600658 00000658 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .got 00000008 00000000006007f8 00000000006007f8 000007f8 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .got.plt 00000020 0000000000600800 0000000000600800 00000800 2**3
CONTENTS, ALLOC, LOAD, DATA
24 .data 00000010 0000000000600820 0000000000600820 00000820 2**3
CONTENTS, ALLOC, LOAD, DATA
25 .bss 00000010 0000000000600830 0000000000600830 00000830 2**3
ALLOC
26 .comment 00000039 0000000000000000 0000000000000000 00000830 2**0
CONTENTS, READONLY
27 .debug_aranges 00000030 0000000000000000 0000000000000000 00000869 2**0
CONTENTS, READONLY, DEBUGGING
28 .debug_pubnames 0000001b 0000000000000000 0000000000000000 00000899 2**0
CONTENTS, READONLY, DEBUGGING
29 .debug_info 00000055 0000000000000000 0000000000000000 000008b4 2**0
CONTENTS, READONLY, DEBUGGING
30 .debug_abbrev 00000034 0000000000000000 0000000000000000 00000909 2**0
CONTENTS, READONLY, DEBUGGING
31 .debug_line 0000003b 0000000000000000 0000000000000000 0000093d 2**0
CONTENTS, READONLY, DEBUGGING
32 .debug_str 00000026 0000000000000000 0000000000000000 00000978 2**0
CONTENTS, READONLY, DEBUGGING
33 .debug_loc 0000004c 0000000000000000 0000000000000000 0000099e 2**0
CONTENTS, READONLY, DEBUGGING
You can see the extra sections (27 through 33). These sections won't be loaded at runtime, so there won't be any performance penalty. Using gdb
, you can also examine them at runtime
$ gdb ./a.out
(gdb) break main
(gdb) run
(gdb) info files
// blah blah ....
Local exec file:
`/home/kghost/a.out', file type elf64-x86-64.
Entry point: 0x4003b0
0x0000000000400200 - 0x000000000040021c is .interp
0x000000000040021c - 0x000000000040023c is .note.ABI-tag
0x000000000040023c - 0x0000000000400260 is .note.gnu.build-id
0x0000000000400260 - 0x0000000000400278 is .hash
0x0000000000400278 - 0x0000000000400294 is .gnu.hash
0x0000000000400298 - 0x00000000004002e0 is .dynsym
0x00000000004002e0 - 0x0000000000400318 is .dynstr
0x0000000000400318 - 0x000000000040031e is .gnu.version
0x0000000000400320 - 0x0000000000400340 is .gnu.version_r
0x0000000000400340 - 0x0000000000400358 is .rela.dyn
0x0000000000400358 - 0x0000000000400370 is .rela.plt
0x0000000000400370 - 0x0000000000400388 is .init
0x0000000000400388 - 0x00000000004003a8 is .plt
0x00000000004003b0 - 0x0000000000400578 is .text
0x0000000000400578 - 0x0000000000400586 is .fini
0x0000000000400588 - 0x000000000040058c is .rodata
0x000000000040058c - 0x00000000004005b0 is .eh_frame_hdr
0x00000000004005b0 - 0x000000000040062c is .eh_frame
0x0000000000600630 - 0x0000000000600640 is .ctors
0x0000000000600640 - 0x0000000000600650 is .dtors
0x0000000000600650 - 0x0000000000600658 is .jcr
0x0000000000600658 - 0x00000000006007f8 is .dynamic
0x00000000006007f8 - 0x0000000000600800 is .got
0x0000000000600800 - 0x0000000000600820 is .got.plt
0x0000000000600820 - 0x0000000000600830 is .data
0x0000000000600830 - 0x0000000000600840 is .bss
// blah blah ....
So the only penalty is that you need extra disk space to store this information. You can also use strip
to remove the debug information:
$ strip a.out
Use objdump
to check it again, you'll see the difference.
EDIT:
Instead looking sections, actually the loader loads elf file according to its Program Header
, which can be seen by objdump -p
. (following example is using a different elf binary)
$ objdump -p /bin/cat
/bin/cat: file format elf64-x86-64
Program Header:
PHDR off 0x0000000000000040 vaddr 0x0000000000000040 paddr 0x0000000000000040 align 2**3
filesz 0x00000000000001f8 memsz 0x00000000000001f8 flags r-x
INTERP off 0x0000000000000238 vaddr 0x0000000000000238 paddr 0x0000000000000238 align 2**0
filesz 0x000000000000001c memsz 0x000000000000001c flags r--
LOAD off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**21
filesz 0x00000000000078bc memsz 0x00000000000078bc flags r-x
LOAD off 0x0000000000007c28 vaddr 0x0000000000207c28 paddr 0x0000000000207c28 align 2**21
filesz 0x0000000000000678 memsz 0x0000000000000818 flags rw-
DYNAMIC off 0x0000000000007dd8 vaddr 0x0000000000207dd8 paddr 0x0000000000207dd8 align 2**3
filesz 0x00000000000001e0 memsz 0x00000000000001e0 flags rw-
NOTE off 0x0000000000000254 vaddr 0x0000000000000254 paddr 0x0000000000000254 align 2**2
filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
EH_FRAME off 0x0000000000006980 vaddr 0x0000000000006980 paddr 0x0000000000006980 align 2**2
filesz 0x0000000000000274 memsz 0x0000000000000274 flags r--
STACK off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
RELRO off 0x0000000000007c28 vaddr 0x0000000000207c28 paddr 0x0000000000207c28 align 2**0
filesz 0x00000000000003d8 memsz 0x00000000000003d8 flags r--
The program headers tell which segment will be loaded with what rwx flags, multiple sections with same flags will be merged to a single segment.
BTW:
The loader doesn't care sections when loading elf file, but it will look several symbol related sections to resolve symbols when needed.
这篇关于调试符号如何影响由GCC编译的Linux可执行文件的性能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!