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

h22fl7wq  于 2023-03-30  发布在  其他
关注(0)|答案(7)|浏览(165)

编写C/C++代码时,为了调试二进制可执行文件,必须在编译器/链接器上启用调试选项。对于GCC,该选项为-g。启用调试选项后,会对二进制可执行文件产生什么影响?文件中存储了哪些附加数据,使调试器能够正常工作?

ki1q1bka

ki1q1bka1#

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

  • 符号名
  • 符号的类型信息
  • 文件和符号来源的行号

调试器使用此信息为符号输出有意义的名称,并将指令与源代码中的特定行相关联。
对于某些编译器,提供-g将禁用某些优化。例如,除非您显式指定-O[123],否则icc会使用-g将默认优化级别设置为-O 0。此外,即使您提供了-O[123],阻止堆栈跟踪的优化仍将被禁用(例如,从堆栈帧中剥离帧指针。这对性能的影响很小)。
对于某些编译器,-g将禁用可能混淆符号来源的优化(指令重新排序,循环展开,内联等)。如果你想用优化来调试,你可以使用-g3和gcc来解决一些问题。额外的调试信息将包括关于宏,扩展,以及可能已内联的函数。这可以允许调试器和性能工具将优化的代码Map到原始源代码,但这是最大的努力。一些优化确实会破坏代码。
有关更多信息,请查看DWARF,这是最初设计用于ELF(Linux和其他操作系统的二进制格式)的调试格式。

piztneat

piztneat2#

符号表被添加到可执行文件中,它将函数/变量名Map到数据位置,这样调试器就可以报告有意义的信息,而不仅仅是指针。这不会影响程序的速度,你可以用'strip'命令删除符号表。

yebdmbv4

yebdmbv43#

除了调试和符号信息之外
Google DWARF(ELF上的一个开发者笑话)
默认情况下,在启用调试时,大多数编译器优化都处于关闭状态。
因此,代码是源代码到机器代码的纯粹转换,而不是应用于发布二进制文件的许多高度专业化转换的结果。
但最重要的区别(在我看来)
调试版本中的内存通常被初始化为一些编译器特定的值以便于调试。在发布版本中,除非应用程序代码显式地初始化内存,否则不会初始化内存。
有关详细信息,请查看编译器文档:
DevStudio的一个例子是:

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

cyvaqqii4#

-g在可执行文件中添加调试信息,如变量名、函数名和行号。这允许调试器(如gdb)逐行遍历代码,设置断点,并检查变量的值。由于这些附加信息,使用-g会增加可执行文件的大小。
此外,gcc允许将-g与-O标志一起使用,这会打开优化。调试优化的可执行文件可能非常棘手,因为变量可能会被优化掉,或者指令可能会以不同的顺序执行。通常,在使用-g时关闭优化是一个好主意,即使它会导致代码变慢。

0pizxfdo

0pizxfdo5#

作为一个有趣的事情,你可以打开一个十六进制编辑器,看看一个用-g和一个没有-g生成的可执行文件。你可以看到添加的符号和东西。它也可能改变程序集(-S),但我不确定。

wa7juj8i

wa7juj8i6#

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

sr4lhrrt

sr4lhrrt7#

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

相关问题