我创建了两个C程序
计划1
int main()
{
}
Run Code Online (Sandbox Code Playgroud)计划2
int main()
{
//Some Harmless comments
}
Run Code Online (Sandbox Code Playgroud)AFAIK,在编译时,编译器(gcc)应该忽略注释和冗余空白,因此输出必须类似.
但是当我检查输出二进制文件的md5sums时,它们不匹配.我也试图与优化的编译-O3和-Ofast,但他们仍然不匹配.
这里发生了什么?
编辑:确切的命令和md5sums是(t1.c是程序1,t2.c是程序2)
gcc ./t1.c -o aaa
gcc ./t2.c -o bbb
98c1a86e593fd0181383662e68bac22f aaa
c10293cbe6031b13dc6244d01b4d2793 bbb
gcc ./t2.c -Ofast -o bbb
gcc ./t1.c -Ofast -o aaa
2f65a6d5bc9bf1351bdd6919a766fa10 aaa
c0bee139c47183ce62e10c3dbc13c614 bbb
gcc ./t1.c -O3 -o aaa
gcc ./t2.c -O3 -o bbb
564a39d982710b0070bb9349bfc0e2cd aaa
ad89b15e73b26e32026fd0f1dc152cd2 bbb
Run Code Online (Sandbox Code Playgroud)
是的,md5sums匹配多个具有相同标志的编译.
顺便说一句我的系统是gcc (GCC) 5.2.0和Linux 4.2.0-1-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux
我正在使用构建脚本来编译几个C#项目.二进制输出被复制到结果文件夹,覆盖以前版本的文件,然后添加/提交到subversion.
我注意到,即使源或环境没有任何变化,编译的二进制输出也是不同的.这怎么可能?对于相同的输入,二进制结果是否应该完全相等?
我不是故意在任何地方使用任何类型的特殊时间戳,但编译器(Microsoft,.NET 4.0中包含的那个)可能会自己添加时间戳吗?
我问的原因是我将输出提交给subversion,并且由于我们的构建服务器的工作方式,已签入的更改会触发重建,导致再次修改的二进制文件以圆圈形式签入.
c# compiler-construction binaryfiles .net-4.0 binary-reproducibility
有没有人知道比较两个.NET程序集以确定它们是否是从"相同"源文件构建的方法?
我知道有一些差异实用程序可用,例如Reflector的插件,但我对查看GUI中的差异不感兴趣,我只是想要一种自动方式来比较二进制文件的集合,看看它们是否是从相同(或等效)的源文件.我知道多个不同的源文件可以产生相同的IL,并且意识到该过程只对IL的差异敏感,而不是原始源.
仅仅比较两个程序集的字节流的主要障碍是.NET包含一个名为"MVID"(模块版本标识符)的程序集.这似乎对每个编译都有不同的值,因此如果您构建相同的代码两次,则程序集将有所不同.
一个相关的问题是,是否有人知道如何强制MVID为每个编译相同?这将避免我们需要具有对MVID值的差异不敏感的比较过程.一致的MVID将是更可取的,因为这意味着可以使用标准校验和.
这背后的背景是,在我们被允许发布到Production之前,第三方公司负责独立审核和签署我们的版本.这包括查看源代码.他们希望独立确认我们提供的源代码与我们之前构建,测试并且当前计划部署的二进制文件相匹配.我们正在寻找一个允许它们从我们提供的源中独立构建系统的过程,并将校验和与我们测试的二进制文件的校验和进行比较.
BTW.请注意,我们正在使用持续集成,自动构建,源代码控制等.该问题与内部缺乏对源文件进入给定构建的控制无关.问题在于,第三方负责验证我们提供的来源是否与我们测试过并计划投入生产的二进制文件相同.他们不应该信任我们的任何内部系统或控件,包括构建服务器或源代码控制系统.他们所关心的只是获取与构建相关的源,自己执行构建,并验证输出是否与我们所说的部署相匹配.
比较解决方案的运行速度并不是特别重要.
谢谢
我先给你一点背景知道我为什么问这个问题:
我目前正在一个严格监管的行业工作,因此我们的代码由官方测试机构仔细查看.这些测试机构希望能够构建代码并生成.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` ...等.
任何想法或建议将是最受欢迎的!
Roslyn几年前给了我们一些deterministic构建。
通过添加NuGet 锁定文件,我们终于可以保证可重现的构建。
--use-lock-file Bootstraps use of lock file for a project. You can alternatively set RestorePackagesWithLockFile property in the project file
并且在恢复时需要一个锁定文件:
--locked-mode Enables locked mode for restore. This is useful in CI/CD scenarios where you would like to get the repeatable builds. This can be also by setting the RestoreLockedMode MSBuild property to true
我正在通过修改Directory.Build.propsrepo 的根目录来尝试它:
<PropertyGroup>
...
+ <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
Run Code Online (Sandbox Code Playgroud)
当我运行时dotnet restore,我看到 …
每次我们重新编译C#应用程序时,我们都会得到具有不同MD5签名的EXE.我们在相同的机器上重新编译,相隔几分钟.为什么相同的源代码不会产生相同的输出?有没有办法来解决这个问题?
我和我的团队正在开发一个VC++ 6项目.我们都使用相同的代码库(使用版本控制系统),据我们所知,所有编译器/链接器/环境设置(包括包含目录顺序)完全相同.当然,我们使用相同的VC++版本和相同的服务包(VC6 SP6).
问题是我们每个人构建的EXE有点不同.
我知道每次在同一台计算机上构建EXE时,文件中有3个位置,链接器存储时间戳.我不是在谈论这些差异.
虽然我们的EXE文件长度完全相同,但是当我们比较EXE时,有1000个不同的字节.其中许多字节的值相差0x20.
任何想法可能是什么原因?
编辑:调试版本(实际上,我们没有检查发布).
编辑:差异在二进制部分,而不是文本字符串.
编辑:所有开发人员使用相同的驱动器/文件夹名称,源和产品.
在尝试构建使用CMake的项目时,通常会有许多swiches启用/禁用.
如何存储某些用户创建的构建设置,以使构建在另一台机器上可重现?是否有某种导出功能或者您只是复制构建(缓存)文件夹?
我需要比较使用相同编译器/标志编译的2个可执行文件和/或共享对象,并验证它们没有更改.我们在受监管的环境中工作,因此对于测试目的而言,确切地隔离可执行文件的哪些部分已经发生变化非常有用.
由于包含有关文件信息的标头,因此使用MD5Sums/Hashes不起作用.
有没有人知道一个程序或方法来验证2个文件是否在执行上是相同的,即使它们是在不同的时间构建的?
我的雇主有一项业务需求,以使Java构建逐字节可重复。我知道使JAR文件可再现的困难(由于归档顺序和时间戳),但是在这一点上,我正在谈论类文件。
在Mac和Linux上,我都使用Java 8u65构建了相同的代码。类文件在二进制方面有所不同。这两个类都反编译回相同的源。要查看差异,需要使用javap反汇编程序。
源代码似乎是:
final TrustStrategy acceptingTrustStrategy =
(X509Certificate[] chain, String authType) -> true;
Run Code Online (Sandbox Code Playgroud)
在一个版本中,结果是:
private static boolean lambda$restTemplate$38(java.security.cert.X509Certificate[], java.lang.String) throws java.security.cert.CertificateException;
Code:
0: iconst_1
1: ireturn?
Run Code Online (Sandbox Code Playgroud)
另一方面,它是:
private static boolean lambda$restTemplate$15(java.security.cert.X509Certificate[], java.lang.String) throws java.security.cert.CertificateException;
Code:
0: iconst_1
1: ireturn
Run Code Online (Sandbox Code Playgroud)
匿名lambda会在其中获得带有不同数字的名称(lambda$restTemplate$15与lambda$restTemplate$38)。
看来,当我在同一主机上重建时,我得到了相同的字节。当主机不同时,数字也会改变;两台Linux主机产生了不同的字节。
是什么决定这些数字?有没有办法强迫每个编译在该位置使用相同的数字,从而产生相同的类文件?还是Java 8类文件编译不确定?
c# ×3
.net ×2
build ×2
.net-4.0 ×1
assemblies ×1
binaryfiles ×1
c ×1
c++ ×1
checksum ×1
cmake ×1
comparison ×1
executable ×1
gcc ×1
hash ×1
il ×1
java ×1
javac ×1
lambda ×1
linker ×1
msbuild ×1
nuget ×1
optimization ×1
visual-c++ ×1
windows ×1