【问题标题】:How can I tell if two source files produce functionally identical code?如何判断两个源文件是否生成功能相同的代码?
【发布时间】:2016-10-29 12:04:49
【问题描述】:

我正在使用 uncrustify 来格式化一个充满 C 和 C++ 代码的目录。我需要确保 uncrustify 不会更改生成的代码;我无法对目标文件或二进制文件进行比较,因为目标文件具有时间戳,因此永远不会相同。我不能一一检查文件的来源,因为我会在这里多年。

该项目使用 make 进行构建过程,所以我想知道是否有某种方法可以输出可以检查的内容。

我搜索了 SO 和 Google 均无济于事,所以如果这是重复的,我深表歉意。

编辑:我正在使用 gcc/g++ 并为 32 位编译。

【问题讨论】:

  • 您可以使用objdump 之类的命令反汇编二进制文件并进行比较。
  • “我无法对目标文件或二进制文件进行比较,因为目标文件有时间戳,因此永远不会相同。” .o 文件是否有嵌入的时间戳?我不知道。
  • 时间戳是如何嵌入到目标文件中的?它可以以某种方式剥离吗?也许有二进制比较实用程序可以跳过或忽略它比较的文件中的某些字节范围,您是否尝试过寻找这样的实用程序?
  • 实际上,在从目标文件中清除时间戳之后,您可以进行二进制比较。一个处理 PE/PDB 文件的示例程序是 zap_timestamps
  • 过去,我不得不比较应该相同的生成二进制文件(尽管出于不同的原因)。在这种情况下,我使用objcopy 从elf 文件中提取相关部分——.text、.data 等——并进行比较。诚然很乏味,但在这种情况下那行不通吗?

标签: c++ c format diff uncrustify


【解决方案1】:

一种可能性是使用 CLang 编译它们,并将输出作为 LLVM IR。如果没记错,这应该是-S -emit-llvm 的命令行参数。

要对 gcc/g++ 做同样的事情,您可以使用它的一个标志来生成一个文件,其中包含它在某个编译阶段的中间表示。早期阶段仍会显示与空白等变化的差异,但快速测试表明,到 SSA 阶段,此类非操作性变化已从 IR 中消失。

g++ -c -fdump-tree-ssa foo.cpp

除了正常的目标文件之外,这将生成一个名为 foo.cpp.018t.ssa 的文件,它代表源文件中的语义操作。

如上所述,虽然我还没有测试过这么广泛的东西——在这个阶段,一些非操作性的改变可能仍然会产生不同的输出文件(虽然我有点怀疑) .如有必要,您可以使用-fdump-tree-all 获取所有编译阶段的输出1。作为一个简单的经验法则,我希望后期阶段更能不受格式等变化的影响,所以如果 ssa 阶段不起作用,我的下一个选择可能是optimized 阶段,它是其中之一最后阶段(注意:生成的文件按生成每个文件的阶段顺序编号,因此当您转储所有阶段时,很明显哪些是早期阶段产生的,哪些是后期阶段产生的)。


1. 请注意,这会产生相当多的文件,其中许多都非常大。第一次执行此操作时,您可能希望单独对目录中的单个源文件执行此操作,以防止淹没在文件中,可以这么说。此外,当以这种方式编译需要比正常时间更长的时间时,不要感到惊讶。

【讨论】:

  • 我生成了 ssa 文件,将来自 crusty 源的文件放到一个文件夹中,将外壳源文件放到另一个文件夹中。将它们与diff -rq crusty crustfree 进行比较表明它们都不同(某些文件仅存在于硬壳输出中)。这是否表明去壳进程已经实际上以某种方式改变了代码的功能?
  • @AlexMeuer:困难在于:如果文件相同,我们很容易得出结论,这些更改对生成的代码没有影响。它们的不同意味着含义的变化是可能的,但不确定(不幸的是,我怀疑你可以轻松产生的任何其他东西也能提供更强大的保证)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-07
  • 1970-01-01
  • 2023-04-07
  • 2018-05-14
  • 1970-01-01
相关资源
最近更新 更多