编写C / C ++代码时,为了调试二进制可执行文件,必须在编译器/链接器上启用debug选项。对于GCC,该选项为-g。启用调试选项后,对二进制可执行文件有何影响?文件中还存储哪些其他数据,以允许调试器功能正常运行?
Answers:
-g告诉编译器将符号表信息存储在可执行文件中。除其他外,这包括:
调试器使用此信息为符号输出有意义的名称,并将指令与源代码中的特定行相关联。
对于某些编译器,提供-g将禁用某些优化。例如,除非您明确指示-O [123],否则icc会使用-g将默认优化级别设置为-O0。同样,即使您确实提供了-O [123],仍将禁用阻止堆栈跟踪的优化(例如,从堆栈帧中删除帧指针。这仅会对性能产生很小的影响)。
对于某些编译器,-g将禁用可能混淆符号来源的优化(指令重新排序,循环展开,内联等)。如果要通过优化进行调试,可以将-g3与gcc一起使用以解决某些问题。额外的调试信息将包含有关可能已内联的宏,扩展和功能的信息。这可以使调试器和性能工具将优化的代码映射到原始源,但这是最大的努力。一些优化确实使代码混乱。
有关更多信息,请查看DWARF,它最初是与ELF一起使用的调试格式(Linux和其他OS的二进制格式)。
将符号表添加到可执行文件中,该表将函数/变量名称映射到数据位置,以便调试器可以报告回有意义的信息,而不仅仅是指针。这不会影响程序的速度,您可以使用“ strip”命令删除符号表。
除了调试和符号信息外,
Google DWARF(ELF上的一个开发者笑话)
默认情况下,启用调试后,大多数编译器优化功能均处于关闭状态。
因此,代码是源代码到机器代码的纯翻译,而不是应用于发行二进制文件的许多高度专业化转换的结果。
但是,最重要的区别(在我看来)
是Debug构建中的内存通常会初始化为某些编译器特定的值,以利于调试。在发行版本中,除非应用程序代码明确进行初始化,否则不会初始化内存。
查看您的编译器文档以获取更多信息:
但是DevStudio的示例是:
- 0xCDCDCDCD分配在堆中,但未初始化
- 0xDDDDDDDD释放的堆内存。
- 0xFDFDFDFD“ NoMansLand”围栏自动放置在堆内存的边界。永远不应该被覆盖。如果您确实要覆盖一个,则可能是走到了数组的末尾。
- 0xCCCCCCCC分配在堆栈上,但未初始化