调试选项-g如何更改二进制可执行文件?

时间:2020-03-06 14:19:48  来源:igfitidea点击:

在编写C / C ++代码时,为了调试二进制可执行文件,必须在编译器/链接器上启用debug选项。对于GCC,该选项为-g。启用调试选项后,对二进制可执行文件有何影响?文件中还存储哪些其他数据,以允许调试器功能正常运行?

解决方案

-g告诉编译器将符号表信息存储在可执行文件中。除其他外,这包括:

  • 符号名称
  • 输入符号信息
  • 符号来自的文件和行号

调试器使用此信息来输出符号的有意义的名称,并将指令与源代码中的特定行相关联。

对于某些编译器,提供-g将禁用某些优化。例如,除非我们明确指示-O [123],否则icc会使用-g将默认优化级别设置为-O0。此外,即使我们确实提供了-O [123],仍将禁用阻止堆栈跟踪的优化(例如,从堆栈帧中删除帧指针。这对性能影响很小)。

对于某些编译器,-g将禁用可能混淆符号来源的优化(指令重新排序,循环展开,内联等)。如果要通过优化进行调试,则可以将-g3与gcc配合使用以解决某些问题。将包括有关可能已内联的宏,扩展和功能的其他调试信息。这可以使调试器和性能工具将优化的代码映射到原始源,但这是最大的努力。一些优化确实使代码混乱。

有关更多信息,请查看DWARF,它最初是与ELF一起设计的调试格式(Linux和其他OS的二进制格式)。

将符号表添加到可执行文件中,该表将函数/变量名称映射到数据位置,以便调试器可以报告回有意义的信息,而不仅仅是指针。这不会影响程序的速度,我们可以使用" strip"命令删除符号表。

这个问题有些重叠,从另一个方面涵盖了这个问题。

出于兴趣,我们可以打开一个hexeditor并查看使用-g生成的可执行文件和不使用-g生成的可执行文件。我们可以看到符号和添加的内容。它也可能会更改程序集(-S),但是我不确定。

-g在可执行文件中添加调试信息,例如变量名,函数名和行号。这使调试器(例如gdb)可以逐行逐步执行代码,设置断点并检查变量值。由于存在这些添加信息,因此-g会增加可执行文件的大小。

同样,gcc允许将-g与-O标志一起使用,这将打开优化。调试优化的可执行文件可能非常棘手,因为可能会优化掉变量或者以不同的顺序执行指令。通常,最好使用-g时关闭优化,即使这样做会导致代码慢得多。

除了调试和符号信息
Google DWARF(有关ELF的开发人员笑话)

默认情况下,启用调试后,大多数编译器优化功能均处于关闭状态。
因此,代码是源代码到机器代码的纯翻译,而不是应用于发行二进制文件的许多高度专业化转换的结果。

但是最重​​要的区别(在我看来)
通常将Debug构建中的内存初始化为某些编译器特定的值,以利于调试。在发行版中,除非应用程序代码明确进行初始化,否则不会初始化内存。

检查编译器文档以获取更多信息:
但是DevStudio的示例是:

0xCDCDCDCD  Allocated in heap, but not initialized
  0xDDDDDDDD  Released heap memory.
  0xFDFDFDFD  "NoMansLand" fences automatically placed at boundary of heap memory. Should never be overwritten. If you do overwrite one, you're probably walking off the end of an array.
  0xCCCCCCCC  Allocated on stack, but not initialized

某些操作系统(如z / OS)会生成一个包含调试符号的"辅助文件"。这有助于避免使用额外信息使可执行文件膨胀。