2つのCプログラムを作成しました
プログラム1
_int main()
{
}
_
プログラム2
_int main()
{
//Some Harmless comments
}
_
私の知る限り、コンパイル時に、compiler(gcc)はコメントと冗長なホワイトペースを無視する必要があります。したがって、出力は同様でなければなりません。
しかし、出力バイナリのmd5sumをチェックしたとき、それらは一致しません。また、最適化_-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は同じフラグを持つ複数のコンパイルで一致します。
ところで私のシステムはgcc (GCC) 5.2.0
と_Linux 4.2.0-1-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux
_です
ファイル名が異なるためです(ただし、文字列の出力は同じです)。 (2つのファイルを持つのではなく)ファイル自体を変更しようとすると、出力バイナリがもはや変わらないことがわかります。 Jensと私が言ったように、それはGCCが作成したバイナリにメタデータの全負荷をダンプするためです。 正確なソースファイル名を含む (およびAFAICSはclangも同様)。
これを試して:
$ cp code.c code2.c subdir/code.c
$ gcc code.c -o a
$ gcc code2.c -o b
$ gcc subdir/code.c -o a2
$ diff a b
Binary files a and b differ
$ diff a2 b
Binary files a2 and b differ
$ diff -s a a2
Files a and a2 are identical
これは、ビルド間でmd5sumが変わらないのに、ファイルごとに異なる理由を説明しています。必要に応じて、Jensが提案したことを実行し、各バイナリのstrings
の出力を比較して、ファイル名がバイナリに埋め込まれていることがわかります。これを「修正」したい場合は、バイナリをstrip
できます。メタデータは削除されます:
$ strip a a2 b
$ diff -s a b
Files a and b are identical
$ diff -s a2 b
Files a2 and b are identical
$ diff -s a a2
Files a and a2 are identical
最も一般的な理由は、コンパイラによって追加されたファイル名とタイムスタンプです(通常はELFセクションのデバッグ情報部分にあります)。
実行してみてください
$ strings -a program > x
...recompile program...
$ strings -a program > y
$ diff x y
理由がわかるかもしれません。私はかつてこれを使用して、同じソースが異なるディレクトリでコンパイルされたときに異なるコードを引き起こす理由を見つけました。発見は、__FILE__
マクロはabsoluteファイル名に展開され、両方のツリーで異なります。
注:ソースファイル名がストリップされていないバイナリになることに注意してください、そのため、異なる名前のソースファイルからの2つのプログラムは異なるハッシュを持ちます。
同様の状況で、上記が当てはまらない場合、試すことができます:
strip
を実行して、脂肪を除去します。除去されたバイナリが同じ場合、プログラム操作に不可欠ではないメタデータがいくつかありました。strings
を使用するか、両方のプログラムを16進数にダンプし、2つの16進数ダンプで差分を実行します。違いを見つけたら、韻や理由(PID、タイムスタンプ、ソースファイルのタイムスタンプなど)があるかどうかを確認します。たとえば、診断のためにルーチン コンパイル時にタイムスタンプを保存する を使用できます。