为什么普通的C编译器会在输出中包含源文件名?

10

我从最近的这个答案中了解到,即使在未启用调试功能的情况下,gccclang仍会将源文件名作为元数据包含在二进制文件中。

我真的不明白为什么这是一个好主意。除了微小的隐私风险外,当人们优化生成的二进制文件的大小(-Os)时,这也看起来效率低下。

编译器为什么要包含此信息?


2
不仅仅是GCC,Clang也可以实现(任何生成遵循规范的ELF二进制文件的编译器工具链都可以)。 - cyphar
1
@cyphar 我承认我只是在其中进行了grep而没有阅读所有的60页,但我发现该文档仅在第25页提到了FILE,并且它并没有说这是强制性的(“通常,符号的名称给出与目标文件相关联的源文件的名称”)。 - Federico Poloni
我也没有读完所有的60页。但是,当涉及到标准时,“传统上”意味着“你应该这样做,因为人们可能会依赖它”。归根结底,如果你得到了一个规范,最好就按照规范的要求去做(考虑到你的用户可能会使用标准中表达的最奇特的功能),而不是试图回避你不必实现的东西。毕竟,GNU是拥有大量额外功能的领域。 - cyphar
1
然而,声称“任何”编译器工具链都将实现STT_FILE可能过于强硬,只是因为一些程序员需要该功能,所以大多数流行的编译器似乎会实现它。 - cyphar
@cyphar讲得很有道理--感谢您的解释和答案。 - Federico Poloni
2个回答

6
GCC包括文件名的原因主要是为了调试目的,因为它允许程序员确定给定符号来自哪个源文件(简述)详见ELF规范p1-17一些Oracle链接文档中进一步展开。使用STT_FILE部分的示例由此SO问题提供。
我仍然困惑的是,即使指定了-g0,GCC和Clang仍然都包括它,但您可以使用-s停止包括STT_FILE。我没有找到这方面的任何解释,也没有找到STT_FILE被包含在ELF规范中的“正式原因”(非常简洁)。

5
我从最近的回答中了解到,即使没有启用调试功能,gcc还是会将源文件名作为元数据包含在二进制文件中。
在现代ELF目标文件中,文件名确实是类型为FILE的符号:
$ readelf bignum.o    # Source bignum.c
[...]
Symbol table (.symtab) contains 36 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS bignum.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    7
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    8
     9: 00000000000003f0   172 FUNC    GLOBAL DEFAULT    1 add
    10: 00000000000004a0   104 FUNC    GLOBAL DEFAULT    1 copy

然而,一旦去掉,符号就不见了:
$ strip bignum.o
$ readelf -all bignum.o | grep bignum.c
$

为了保护您的隐私,请去除可执行文件,或者使用-s进行编译/链接。

1
为什么说“不完全”?虽然你正确地指出它是以一种易于移除的方式嵌入的,但我仍然认为这被视为“包含在二进制文件中”。无论如何,我的问题是关于动机的。 - Federico Poloni
1
@FedericoPoloni,“不太”只有一个非常微妙的原因:符号表是元数据吗?它对于成功链接是*必需的。然而,调试数据不是必需的,它有自己的ELF部分并且可以被删除。这不是一个很大的问题,不应该妨碍理解。 - Jens
1
尽管符号表通常用于链接,但这个特定的符号并不需要。因此,它实际上是将符号表用作保存一些元数据的地方。 - Barmar
剥离所有符号似乎不是一个有效的解决方案,因为那样目标文件就无法链接。我也尝试过使用 --as-needed,但它仍然保留了特定带有文件名的符号。我认为更好的解决方案是找到一种方法防止它们最初进入 .o 文件。 - Trevor Hickey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接