두 개의 C 프로그램을 만들었습니다.
-
프로그램 1
int main() { }
-
프로그램 2
int main() { //Some Harmless comments }
AFAIK, 컴파일 할 때 컴파일러 (gcc)는 주석과 중복 된 공백을 무시해야하므로 출력이 유사해야합니다.
그러나 출력 바이너리의 md5sum을 확인했을 때 일치하지 않습니다. 또한 최적화 컴파일 시도 -O3
하고 -Ofast
있지만 아직 일치하지 않습니다.
여기서 무슨 일이 일어나고 있습니까?
편집 : 정확한 명령과 md5sum이 있습니다 (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
답변
파일 이름이 다르기 때문입니다 (문자열 출력은 동일하지만). 두 개의 파일이 아닌 파일 자체를 수정하려고하면 출력 바이너리가 더 이상 다르지 않음을 알 수 있습니다. 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__
매크로 는 두 트리에서 다른 절대 파일 이름 으로 확장되었습니다 .
답변
참고 : 소스 파일 이름 은 스트리핑되지 않은 바이너리로 이동하므로 이름이 다른 소스 파일에서 오는 두 프로그램은 다른 해시를 갖게됩니다.
유사한 상황에서 위의 내용이 적용되지 않는 경우 다음을 시도 할 수 있습니다.
strip
일부 지방을 제거하기 위해 바이너리에 대해 실행 합니다. 제거 된 바이너리가 같으면 프로그램 작업에 필수적이지 않은 일부 메타 데이터입니다.- (차이가 실제로 어디에서보다 정확히 파악할 그러나, 또는 어셈블리 중간 출력을 생성하는 차분 실제 CPU의 지시에 없는지를 확인하는 것이다 )
- 을 사용
strings
하거나 두 프로그램을 모두 16 진으로 덤프하고 두 개의 16 진 덤프에서 diff를 실행하십시오. 차이점을 찾으면 운율이나 이유 (PID, 타임 스탬프, 소스 파일 타임 스탬프 …)가 있는지 확인할 수 있습니다. 예를 들어 , 진단 목적으로 컴파일 타임에 타임 스탬프를 저장 하는 루틴이있을 수 있습니다 .