为什么没有两个只有注释的程序的二进制文件在gcc中完全匹配?
我创build了两个C程序
-
计划1
int main() { }
-
计划2
int main() { //Some Harmless comments }
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
是的,md5sums匹配多个具有相同标志的编译。
BTW我的系统是gcc (GCC) 5.2.0
和Linux 4.2.0-1-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux
这是因为文件名称不同(尽pipestring输出是相同的)。 如果您尝试修改文件本身(而不是有两个文件),您会注意到输出二进制文件不再有所不同。 正如Jens和我所说的那样,这是因为GCC将所有元数据转储到它所build立的二进制文件中, 包括确切的源文件名 (和AFAICS也是如此)。
尝试这个:
$ cp code.c code2.c subdir/code.c $ gcc code.c -oa $ gcc code2.c -ob $ gcc subdir/code.c -o a2 $ diff ab Binary files a and b differ $ diff a2 b Binary files a2 and b differ $ diff -sa a2 Files a and a2 are identical
这就解释了为什么你的md5sum不会在两个版本之间改变,但是它们在不同的文件之间是不同的。 如果你愿意,你可以做什么Jensbuild议和比较每个二进制文件的strings
的输出,你会发现文件名被embedded二进制文件。 如果你想“修复”这个,你可以去除二进制文件,元数据将被删除:
$ strip a a2 b $ diff -sab Files a and b are identical $ diff -s a2 b Files a2 and b are identical $ diff -sa a2 Files a and a2 are identical
最常见的原因是编译器添加的文件名和时间戳(通常在ELF部分的debugging信息部分)。
尝试运行
$ strings -a program > x ...recompile program... $ strings -a program > y $ diff xy
你可能会看到原因。 我曾经用这个来找出为什么在不同的目录下编译相同的代码会导致不同的代码。 发现是__FILE__
macros展开为绝对文件名,在两棵树中都不相同。
注意 :请记住, 源文件名将进入未被分离的二进制文件,所以来自不同名称源文件的两个程序将具有不同的哈希值。
在类似的情况下,如果以上不适用 ,你可以尝试:
- 运行
strip
二进制删除一些脂肪。 如果剥离的二进制文件是相同的,那么它是一些元数据,对于程序操作来说不是必需的。 - 生成汇编中间输出以validation差异不在实际的CPU指令中(或者,为了更好地查明实际差异在哪里)
- 使用
strings
,或将两个程序转储到hex,并在两个hex转储上运行diff。 一旦find差异,你可以试着看看是否有一些韵律或理由(PID,时间戳,源文件时间戳…)。 例如,您可能有一个例程在编译时存储时间戳以用于诊断目的。