有没有办法列出两个可执行二进制文件之间哪些函数发生了变化?

Is there a way to list which functions have changed between two executable binaries?

TLDR/summary: 有没有办法,给定两个可执行文件(都是从 C++ 编译的,带有调试-信息存在,并且来自相同或几乎相同的源代码)以仅列出其中一个相对于另一个不同的功能?

background/motivation:在每个冲刺结束时,我们的工程团队都会提交一个 "hero" 构建交给我们的 QA 团队作为发布候选。然后,SQA 团队会花费数周的时间来测试发布候选版本,以确保其正常工作。 (他们已经尽可能多地自动化了测试,但有些部分不容易自动化,因此需要费力的手册 testing/verification)。他们不可避免地会在候选发布版中遇到一个或多个错误,此时会提交错误报告,工程人员会修复这些错误并生成新的候选发布版。

在这一点上,SQA 团队必须做出决定:他们是从头开始重新开始所有测试,还是假设新的候选发布版本与之前的候选发布版本相同,除了请求的修复 - - 即在程序的其他部分没有引入回归?

首选 ("restart from scratch") 更安全,但成本高,并且会导致严重的进度延误。第二种选择 ("just continue testing as before, but with the new build") 更快,但如果在已经使用旧版本测试过的程序部分出现任何新引入的错误,则存在让用户退化的风险。

因此,当 SQA 就此决定征求我的意见时,我目前在两个构建日期之间执行 "svn diff" 以检查两个构建之间究竟更改了哪些 C++ 代码,并使用它来估计风险不做全面复试的水平。然而,我们的一些 SQA 人员并不像我一样信任我们的构建过程,他们不愿意做出这样的假设,即仅仅因为源代码几乎没有改变,就意味着可执行文件几乎没有改变。 (即他们说 "but what if some setting has been changed on the build machine that we don't know about?";对此我只能诉诸他们对人性的信念,即没有人会做这样的事情)

因此,为了减轻 SQA(和我自己)的恐惧,如果我可以采用新的候选发布可执行文件并对其执行 "diff"(与 old/partially-tested release-candidate executable) 并准确查看哪些功能不同,哪些功能保持不变。 (显然,我可以只使用二进制差异或 MD5 校验和来执行此操作,但它们只会告诉我这两个可执行文件是不同的;它们不会告诉我哪些函数不同,这是我真正想知道的——例如,在我修复了“关于”框中的拼写错误后,可执行文件中的核心业务逻辑功能相对于之前的测试没有改变)

我意识到这个问题的答案很可能是 OS 特定的;但是我们在 Linux、MacOS/X 和 Linux 下编译,因此欢迎对这三个 OS 中的任何一个有任何见解。

这个问题的答案似乎是不,不存在任何此类工具(至少,在反恶意软件社区之外)。

因此,为了看看它是否可以完成,我编写了一个简单的概念验证 executable_diff 实用程序,它或多或少地完成了我正在寻找的事情。它在 Linux 和 MacOS/X 下运行,当被调用时,它通过反汇编程序运行两个可执行文件中的每一个("otool" 在 MacOS/X 下,"objdump" 在 [=28= 下=]), 然后扫描反汇编文本以查看文本段中的哪些函数(或 .rodata 段中的字符串)在一个可执行文件和下一个可执行文件之间是不同的。

然后它打印出一个列表,其中列出了哪些函数与另一个可执行文件中的对应函数不相同,并且还写出一个包含实际差异的文件,以防用户希望看到如何功能不同

实现该程序的主要复杂因素是,当您更改程序中一个函数的大小时,该更改会波及程序的其余部分,因为所有函数的地址都在文本后面-段变化也是如此。因此该程序还包含过滤误报的逻辑(通过在执行 diff 之前将程序集中的绝对地址转换回它们相应的函数名称)

正如这个问题的评论者所指出的,区分可执行文件并不能替代使用版本控制和跟踪与每个构建的可执行文件关联的存储库修订号,这样您就可以在源代码上进行差异水平代替。我写这个只是为了看看它是否可以完成,并且作为一个学习练习来教会自己更多关于源代码的更改如何反映在生成的二进制文件中。 executable_diff 仅应被视为粗略的启发式方法,因为它无疑会在某些情况下产生误报,并错误地忽略其他情况下有意义的变化。