调试符号如何影响由GCC编译的Linux可执行文件的性能? [英] How do debug symbols affect performance of a Linux executable compiled by GCC?

查看:128
本文介绍了调试符号如何影响由GCC编译的Linux可执行文件的性能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所有其他因素相同(例如优化级别),在ELF或SO中调试符号如何影响:


  1. 加载时间。
  2. 运行时内存占用。

  3. 运行时间性能





  4. 编辑
    我已经看到这个问题,但我发现讨论无益,因为代码优化因素混淆了那里的问题。 为什么我的代码运行速度比较慢线程比使用单线程编译时进行性能分析(-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:

    1. Load time.
    2. Runtime memory footprint.
    3. Runtime performance?

    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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆