最终目标是在完全相同的环境中比较从完全相同的源构建的2个二进制文件,并且能够告诉它们确实在功能上是等效的.
一个应用程序就是将QA时间集中在发布之间实际发生变化的事情上,以及一般的变更监控.
MSVC与PE格式串联自然使得这很难做到.
到目前为止,我发现并中和了这些事情:
我解析PE,找到所有这些东西的偏移量和大小,并在比较二进制文件时忽略字节范围.像魅力一样工作(好吧,我运行它的少数测试).我可以说,只要编译器版本和所有源和头都相同,在Win Server 2008上构建的版本1.0.2.0的已签名可执行文件等于版本10.6.6.6的无符号版本,在我的Win XP开发框上构建.这似乎适用于VC 7.1 - 9.0.(适用于发布版本)
有一点需要注意.
两个绝对路径建立 必须是相同的 ,必须具有相同的长度.
cl.exe将相对路径转换为绝对路径,并将它们与编译器标志一起放入对象中,依此类推.这对整个二进制文件具有不成比例的影响.路径中的一个字符更改将导致在此处更改一个字节,并且在整个.text部分上有几次(但是我怀疑链接了很多对象).改变路径的长度会导致明显更多的差异.在obj文件和链接二进制文件中.
感觉像带有编译标志的文件路径被用作某种哈希,这使得它成为链接二进制或甚至影响不相关的编译代码片段的放置顺序.
所以这是三部分的问题(总结为"现在是什么?"):
我是否应该放弃整个项目并回家,因为我想要做的事情违反了物理法则和MS的公司政策?
假设我处理绝对路径问题(在策略级别或通过查找神奇的编译器标志),还有其他我应该注意的事项吗?(之类的东西__TIME__ 做意味着改变的代码,所以我不介意那些没有被忽略)
有没有办法强制编译器使用相对路径,或欺骗它认为路径不是它是什么?
最后一个的原因是令人讨厌的Windows文件系统.你永远都不知道什么时候删除几个有价值的源和对象,并且svn元数据会因为流氓文件锁而失败.至少创建新根总是成功,而剩下空间.一次运行多个构建也是一个问题.运行一堆虚拟机虽然是一个解决方案,但却是一个相当繁重的虚拟机.
我想知道是否有办法为进程及其子进程设置虚拟文件系统,以便多个进程树将看到不同的 "C:\ build"目录,仅对它们是私有的,所有这些都是同时...重量级的虚拟化......
更新:我们最近在GitHub上开源了这个工具.请参阅文档中的比较部分.
我先给你一点背景知道我为什么问这个问题:
我目前正在一个严格监管的行业工作,因此我们的代码由官方测试机构仔细查看.这些测试机构希望能够构建代码并生成.exe或.dll,每次都完全相同(显然不会更改任何代码!).他们检查MD5和他们创建的可执行文件的SHA1以确保这一点.
到目前为止,我主要使用C++进行编码,其中(经过一些项目设置调整后)我设法让项目能够相同地重建到相同的MD5/SHA1.我现在正在一个项目中使用C#,并且在重建之后很难让MD5匹配.我知道文件的PE头中有"Time-Stamps",它们已经被清除为0.我也知道.exe有一个GUID,它再次被清除为00 00 00 ......等但是文件仍然不匹配.
我正在使用CFF资源管理器查看和编辑PE标头以删除时间和日期戳.使用二进制比较工具后,.exe中只有2个字节块不同(都非常小).
其中不一致的块的出现只是之前的一些二进制代码,这在ASCII详细介绍了路径*Project*\obj\Release\xxx.pdb文件.
编辑:现在已知这是*.pdb文件的GUID,但我仍然不知道是否可以修改它而不会导致任何错误!?
另一个块出现在看起来是函数名称的中间,即.(典型的部分)AssemblyName.GetName.Version.get_Version.System.IO.Ports.SerialPort.Parity.Byte.<PrivateImplementationDetails>{
那么不同的代码块:
4A134ACE-D6A0-461B-A47C-3A4232D90816
其次是:
"} .ValueType .__ StaticArrayInitTypeSize = 7. $$ method0x60000ab-1.RuntimeFieldHandle.InitializeArray` ...等.
任何想法或建议将是最受欢迎的!
有没有办法强制相同的代码在Visual C++中生成相同的二进制文件?关闭PE中的时间戳或强制PE中的时间戳为某个固定值,换句话说?
c++ portable-executable visual-studio visual-c++ binary-reproducibility