stallman sistema richard que proyecto meaning license introduccion informatica general codigo binario c gcc optimization binary-reproducibility

sistema - ¿Por qué no coinciden exactamente dos binarios de programas con solo comentarios modificados en gcc?



sistema binario (3)

Creé dos programas en C

  1. Programa 1

    int main() { }

  2. Programa 2

    int main() { //Some Harmless comments }

AFAIK, al compilar, el compilador (gcc) debe ignorar los comentarios y espacios en blanco redundantes, y por lo tanto la salida debe ser similar.

Pero cuando revisé las sumas md5 de los binarios de salida, no coinciden. También intenté compilar con la optimización -Ofast y -Ofast pero todavía no coincidían.

¿Que está sucediendo aquí?

EDITAR: los comandos exactos y md5sums son (t1.c es el programa 1 y t2.c es el programa 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

Y sí, md5sums coincide con múltiples compilaciones con las mismas banderas.

Por cierto, mi sistema es gcc (GCC) 5.2.0 y Linux 4.2.0-1-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux


Es porque los nombres de los archivos son diferentes (aunque la salida de las cadenas es la misma). Si intenta modificar el archivo en sí (en lugar de tener dos archivos), notará que los binarios de salida ya no son diferentes. Como dijimos Jens y yo, es porque GCC volca una carga completa de metadatos en los binarios que crea, incluido el nombre de archivo fuente exacto (y AFAICS también lo hace).

Prueba esto:

$ 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

Esto explica por qué sus md5sums no cambian entre compilaciones, pero son diferentes entre diferentes archivos. Si lo desea, puede hacer lo que Jens sugirió y comparar la salida de strings para cada binario, notará que los nombres de los archivos están incrustados en el binario. Si desea "arreglar" esto, puede strip los binarios y se eliminarán los metadatos:

$ 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


La razón más común son los nombres de archivo y las marcas de tiempo agregadas por el compilador (generalmente en la parte de información de depuración de las secciones ELF).

Intenta correr

$ strings -a program > x ...recompile program... $ strings -a program > y $ diff x y

y puedes ver la razón. Una vez usé esto para encontrar por qué la misma fuente causaría un código diferente cuando se compila en diferentes directorios. El hallazgo fue que la macro __FILE__ expandió a un nombre de archivo absoluto , diferente en ambos árboles.


Nota : recuerde que el nombre del archivo fuente va al binario sin tirar, por lo que dos programas que provienen de archivos fuente con nombres diferentes tendrán hashes diferentes.

En situaciones similares, si lo anterior no se aplica , puede intentar:

  • strip correr contra el binario para eliminar algo de grasa. Si los binarios eliminados son los mismos, se trata de metadatos que no son esenciales para la operación del programa.
  • generar una salida intermedia de ensamblaje para verificar que la diferencia no esté en las instrucciones reales de la CPU (o, sin embargo, para determinar mejor dónde está realmente la diferencia)
  • use strings o descargue ambos programas en hexadecimal y ejecute un diff en los dos volcados hexadecimales. Una vez localizadas las diferencias, puede intentar ver si hay alguna rima o razón para ellas (PID, marcas de tiempo, marca de tiempo del archivo fuente ...). Por ejemplo, puede tener una rutina que almacene la marca de tiempo en tiempo de compilación para fines de diagnóstico.