有没有理由不从可执行文件中删除符号?

Jan*_*roň 8 c c++ mingw compilation

几年前,我问了一个如何减少可执行文件大小的问题.使用MinGW编译器,剥离符号(-s选项)有助于减少50%+的大小.

为什么剥离不是默认的 - 有什么理由不在某些情况下剥离符号呢?我想更深入地理解它:今天,我只是模糊地知道链接库中涉及符号.它们是否需要可执行文件,它们是否会影响执行速度?

Kei*_*all 8

MinGW是"Minimalist GNU for Windows"的首字母缩写; 因此,编译器套件是GCC ...... GNU编译器集合.当然,这个编译器套件倾向于遵守GNU编码标准,它要求每个构建都应该是"调试版本"......即它应包括调试符号和链接所需的符号.(这是合乎逻辑的,因为"调试版本"对于应用程序开发人员而言比对所谓的"版本构建"更有用.此外,区分"调试构建"和"发布构建"模式的构建系统比仅关注"调试构建"的构建系统更复杂 - 可能更加复杂.

在GNU构建模型中,无论如何都不需要"发布版本".在构建时不会创建"发布"; 它是在安装时创建的 - 通常作为"分阶段"安装,从中创建发布.GNU工具链包括一个strip命令和一个install命令,它可以动态地剥离"调试版本",当创建一个分段安装作为发布包装时(或者如果你愿意的话,就到位),所以真的不需要使用"发布版本"细节使构建系统混乱; 只需在前面创建一个"调试版本",然后在事件之后将其删除,以便在需要时将其转换为有效的"版本构建".

由于你的MinGW工具链基本上是一个GNU工具链,它完全支持这个GNU构建模型.


Lig*_*ica 7

我无法想象他们影响了执行速度在任何明显的方式虽然,在理论上,你可以有一个微小的高速缓存未命中的过程映像中的量.

您希望在调试时将符号保留在文件中,以便您可以查看您所在的函数,检查变量的值等等.

但符号使文件较大:可能,一个很多大.因此,您不希望将二进制文件中的符号放在小型嵌入式设备上.(我说的是一个真正的嵌入式设备,而不是21世纪的Raspberry Pi,拥有9,000GB的存储空间!)

我通常剥离所有发布版本,不剥离任何调试版本.这使得来自客户的核心转储变得不那么有用,但是您可以随时保留未经剥离的发布版本的副本,并针对此调试您的核心.

我确实听说过一家公司,即使在发布版本中也有从不剥离符号的策略,因此他们可以将核心直接加载到调试器中.这看起来像是一个抽象泄漏给我,但无论如何.他们的电话.

当然,如果你真的想要,你可以在没有它们的情况下自己分析装配.但那太疯狂了......

  • @Olaf,那里有非常不同的环境.例如,有些情况下开发人员访问他们的客户环境并在那里进行故障排除.;) (3认同)
  • 对于非平凡的系统,尤其是分布式/联网系统,在 alpha 测试期间未发现的客户配置/环境中几乎不可避免地会出现错误。发生这种情况时,您将需要从调试器和记录器中获得的所有帮助。我经常保留一个调试版本,(所有符号,范围检查等,优化关闭等),方便交换。 (2认同)

Ser*_*eyA 5

没有充分的理由去掉符号。例如,通过剥离符号,您将消除收集进程堆栈的可能性-一种非常有用的功能。

编辑。这里的一些人似乎对调试符号和“通用”符号之间的区别感到困惑。只有在为编译器提供-g(或类似选项)选项时才生成第一个,并且通常仅在调试版本中使用(尽管也可以与优化版本一起使用)。常规符号是诸如函数名之类的东西,它们是由编译器生成的,以便可以链接目标文件或加载.so文件。有几种非常有用的非侵入性工具,可用于非调试运行的可执行文件,这取决于未剥离的符号。

  • 这是一个不平衡的答案,没有争论,只有一个好战的主张。 (3认同)
  • 一个很好的理由可能是阻碍逆向工程,这是公司的政策,尤其是在商业产品中可能需要这样做。 (3认同)
  • 当然可以。它使可执行文件更小。您可能无法在目标平台上安装带有调试符号的可执行文件。 (2认同)
  • 调试符号和符号之间是有区别的。不要混淆他们。 (2认同)
  • 有一些命令可以获取正在运行的进程的堆栈跟踪。Solaris/Linux 上的 pstack,AIX 上的 procstack。我相信,任何现代 Unix 都有它们的味道。当您需要解决运行过程中的问题时,它们会非常方便,与 truss/proctruss/d-truss/... 没有符号它们就无法工作。 (2认同)