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


75

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

Answers:


73

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

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

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

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

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

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


1
只是添加它,它也可能降低可执行文件的速度。我正在用Sun Studio编译器测试一些OpenMP代码,并且在调试信息的情况下,代码的运行速度慢得多。只是要记住一点。
Mike

6
除非Sun编译器中的-g标志禁用某些优化,否则调试信息不​​应减慢您的代码的速度。
Todd Gamblin

这是OpenMP代码,它的确降低了速度。我在玩分形,并致力于使用OpenMP编译器扩展。单线程上的代码运行速度比单线程上的非OpenMP代码慢。我禁用了调试功能并且速度保持平衡。
迈克”

注意。这实际上很有趣。也许它在那里放了一些额外的东西来告诉调试器有关并行区域的信息……他们在这里(docs.sun.com/source/819-3683/OpenMP.html)表示,您可以将主线程映射回源,但不能奴隶,这似乎也很奇怪。
托德·盖布林

我认为是这样,当然不影响GCC,当单线程代码从11秒变为22时,肯定给了我一个惊喜::/禁用了调试和4个线程(我有Q6600),它下降到了大约3秒。
Mike

10

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


8

除了调试和符号信息外,
Google DWARF(ELF上的一个开发者笑话)

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

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

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

  • 0xCDCDCDCD分配在堆中,但未初始化
  • 0xDDDDDDDD释放的堆内存。
  • 0xFDFDFDFD“ NoMansLand”围栏自动放置在堆内存的边界。永远不应该被覆盖。如果您确实要覆盖一个,则可能是走到了数组的末尾。
  • 0xCCCCCCCC分配在堆栈上,但未初始化

7

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

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



3

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


3

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.