编写C/C++代码时,为了调试二进制可执行文件,必须在编译器/链接器上启用调试选项。对于GCC,该选项为-g。启用调试选项后,会对二进制可执行文件产生什么影响?文件中存储了哪些附加数据,使调试器能够正常工作?
ki1q1bka1#
-g告诉编译器在可执行文件中存储符号表信息。这包括:
调试器使用此信息为符号输出有意义的名称,并将指令与源代码中的特定行相关联。对于某些编译器,提供-g将禁用某些优化。例如,除非您显式指定-O[123],否则icc会使用-g将默认优化级别设置为-O 0。此外,即使您提供了-O[123],阻止堆栈跟踪的优化仍将被禁用(例如,从堆栈帧中剥离帧指针。这对性能的影响很小)。对于某些编译器,-g将禁用可能混淆符号来源的优化(指令重新排序,循环展开,内联等)。如果你想用优化来调试,你可以使用-g3和gcc来解决一些问题。额外的调试信息将包括关于宏,扩展,以及可能已内联的函数。这可以允许调试器和性能工具将优化的代码Map到原始源代码,但这是最大的努力。一些优化确实会破坏代码。有关更多信息,请查看DWARF,这是最初设计用于ELF(Linux和其他操作系统的二进制格式)的调试格式。
piztneat2#
符号表被添加到可执行文件中,它将函数/变量名Map到数据位置,这样调试器就可以报告有意义的信息,而不仅仅是指针。这不会影响程序的速度,你可以用'strip'命令删除符号表。
yebdmbv43#
除了调试和符号信息之外Google DWARF(ELF上的一个开发者笑话)默认情况下,在启用调试时,大多数编译器优化都处于关闭状态。因此,代码是源代码到机器代码的纯粹转换,而不是应用于发布二进制文件的许多高度专业化转换的结果。但最重要的区别(在我看来)调试版本中的内存通常被初始化为一些编译器特定的值以便于调试。在发布版本中,除非应用程序代码显式地初始化内存,否则不会初始化内存。有关详细信息,请查看编译器文档:DevStudio的一个例子是:
cyvaqqii4#
-g在可执行文件中添加调试信息,如变量名、函数名和行号。这允许调试器(如gdb)逐行遍历代码,设置断点,并检查变量的值。由于这些附加信息,使用-g会增加可执行文件的大小。此外,gcc允许将-g与-O标志一起使用,这会打开优化。调试优化的可执行文件可能非常棘手,因为变量可能会被优化掉,或者指令可能会以不同的顺序执行。通常,在使用-g时关闭优化是一个好主意,即使它会导致代码变慢。
0pizxfdo5#
作为一个有趣的事情,你可以打开一个十六进制编辑器,看看一个用-g和一个没有-g生成的可执行文件。你可以看到添加的符号和东西。它也可能改变程序集(-S),但我不确定。
-g
-S
wa7juj8i6#
这一问题与从另一个方面涵盖问题的问题有些重叠。
sr4lhrrt7#
一些操作系统(如z/OS)会产生一个包含调试符号的“副文件”,这有助于避免额外信息使可执行文件膨胀。
7条答案
按热度按时间ki1q1bka1#
-g告诉编译器在可执行文件中存储符号表信息。这包括:
调试器使用此信息为符号输出有意义的名称,并将指令与源代码中的特定行相关联。
对于某些编译器,提供-g将禁用某些优化。例如,除非您显式指定-O[123],否则icc会使用-g将默认优化级别设置为-O 0。此外,即使您提供了-O[123],阻止堆栈跟踪的优化仍将被禁用(例如,从堆栈帧中剥离帧指针。这对性能的影响很小)。
对于某些编译器,-g将禁用可能混淆符号来源的优化(指令重新排序,循环展开,内联等)。如果你想用优化来调试,你可以使用-g3和gcc来解决一些问题。额外的调试信息将包括关于宏,扩展,以及可能已内联的函数。这可以允许调试器和性能工具将优化的代码Map到原始源代码,但这是最大的努力。一些优化确实会破坏代码。
有关更多信息,请查看DWARF,这是最初设计用于ELF(Linux和其他操作系统的二进制格式)的调试格式。
piztneat2#
符号表被添加到可执行文件中,它将函数/变量名Map到数据位置,这样调试器就可以报告有意义的信息,而不仅仅是指针。这不会影响程序的速度,你可以用'strip'命令删除符号表。
yebdmbv43#
除了调试和符号信息之外
Google DWARF(ELF上的一个开发者笑话)
默认情况下,在启用调试时,大多数编译器优化都处于关闭状态。
因此,代码是源代码到机器代码的纯粹转换,而不是应用于发布二进制文件的许多高度专业化转换的结果。
但最重要的区别(在我看来)
调试版本中的内存通常被初始化为一些编译器特定的值以便于调试。在发布版本中,除非应用程序代码显式地初始化内存,否则不会初始化内存。
有关详细信息,请查看编译器文档:
DevStudio的一个例子是:
cyvaqqii4#
-g在可执行文件中添加调试信息,如变量名、函数名和行号。这允许调试器(如gdb)逐行遍历代码,设置断点,并检查变量的值。由于这些附加信息,使用-g会增加可执行文件的大小。
此外,gcc允许将-g与-O标志一起使用,这会打开优化。调试优化的可执行文件可能非常棘手,因为变量可能会被优化掉,或者指令可能会以不同的顺序执行。通常,在使用-g时关闭优化是一个好主意,即使它会导致代码变慢。
0pizxfdo5#
作为一个有趣的事情,你可以打开一个十六进制编辑器,看看一个用
-g
和一个没有-g
生成的可执行文件。你可以看到添加的符号和东西。它也可能改变程序集(-S
),但我不确定。wa7juj8i6#
这一问题与从另一个方面涵盖问题的问题有些重叠。
sr4lhrrt7#
一些操作系统(如z/OS)会产生一个包含调试符号的“副文件”,这有助于避免额外信息使可执行文件膨胀。