It should work…

Cuando cualquier trasto es útil

It should work… header image 2

CFLAGS y libgcrypt

June 19th, 2009 · 4 Comments · hacking, linux, programming

Ya se sabe, cuando se tiene que “entregar” algo a tal hora, un ratito antes empezarán a salir fallos que hagan que no funcione. Cosas de Murphy. Estaba preparando la prueba 12 del reto cuando me encontré con un marrón que me costó darme cuenta 3horas de rayadas mentales diciendo “no puede ser, ¡si está bien!” Pero antes, una introducción para saber de qué va el asunto: las CFLAGS.

¿Qué son las CFLAGS/CXXFLAGS?

Son unas variables de entorno o unas variables en un Makefile que se le pasan al compilador para que compile el software aplicando un serie de optimizaciones. Herramientas como autoconf las cogerían del entorno para añadirlas a la sentencia que se usa al compilar. Las CFLAGS se usarían en C, y las CXXFLAGS en C++.

Según usemos un set distinto de CFLAGS los binarios de salida que nos dé el compilador podrán ser distintos partiendo de un mismo código fuente. Gracias a ellas podremos adecuar o intentar mejorar características de los binarios, ya sea para que sean más pequeños, más rápidos en ciertas arquitecturas u otras opciones. Para ello se podrán usar instrucciones específicas disponibles un procesador, podremos especificar por ejemplo que se “desenrrollen” bucles, etc.

Un ejemplo del primer caso sería usar instrucciones SSE3 disponibles en procesadores actuales pero no disponibles en un Pentium IV de primera generación. Para ello le pasaremos -msse3

Un ejemplo del segundo caso sería, yo tengo un bucle que se ejecuta 1000 veces. Cogeríamos y, en ensamblador, tenemos un registro que se va decrementando, comprueba si lo ha hecho 1000 veces y si no, hace un salto para ejecutar el bucle de nuevo. Pues vamos a cambiar eso por “pegar” consecutivamente el código de dentro del bucle 1000 veces. Con eso nos ahorramos recodificaciones de punteros y cosas similares pero tendremos como inconvenientes que el binario será más grande. ¿Qué se ejecuta más rápido? ¿El código optimizado por no hacer esas recodificaciones o el código inicial porque se tarda menos en cargarlo al ser más pequeño? Eterna pregunta… pues depende, a veces uno, a veces el otro.

Por comodidad, para que no tener que pasarle 8 lineas de optimizaciones, de las cuales más de una no sabremos lo que hace y que algunas implican o excluyen otras, existen sets de optimizaciones: -O, -O1, -O2, -O3, -Os, etc. Eso es la letro “o” mayúscula seguida de un número, más allá del 3 no existe, se usaría -O3.

Por otro lado, a las arquitecturas existentes se les pone un nombre, para que cuando digamos qué arquitectura tiene nuestra máquina el compilador le aplique automáticamente lo que toca: -march=athlon64, -march=pentium2, -march=pentium4, -march=prescott, -march=core2, … Esta opción dependerá mucho de la versión de GCC que tengamos instalada, ya que dependiendo de lo nueva que sea tendrá soporte para nuevas arquitecturas o no, e incluso para una misma arquitectura dependiendo de si instalas un sistema de 32 o 64bits el nombre cambiará. Además está opción está íntimamente ligada con la variable CHOST que será del estilo: i586-pc-linux-gnu, i686-pc-linux-gnu, x86_64-pc-linux-gnu, etc.

La mayoría de las distribuciones que se usan son precompiladas, Debian/Ubuntu, RedHat, Mandriva, … y esto no es algo de lo que preocuparse pero esto cobra especialmente sentido en distros como Gentoo y LFS donde todo el código es compilado desde cero con las optimizaciones y opciones que se quieran, ajustadas al tipo de máquina que va a ejecutar el código.

Pero ya se sabe, la gente funciona del modo “a ver quien la tiene más larga”. Cuando Gentoo empezó a ganar terreno y adeptos con la versión 1.4  y la 2004 la gente se cascaba unas pedazos de CFLAGS que no tenían ni pies ni cabeza, ¡cuantas más le pase más guay!, ¡más rápido irá! ¡más todo! Estilo pajillero, el foro estaba lleno de hilos de discusión sobre las CFLAGS y que no sé quien se había puesto tales y podía viajar atrás en el tiempo con ellas. En realidad lo único que se consigue es tener como salida un código inestable, que puede funcionar mal y más lento. Por ejemplo, la opción -ffast-math además de no cumplir con el estándar hace que las raices negativas no existan en lugar de devolver números complejos. ¿y si compilamos octave/algo_tipo_matlab con -ffast-math? => fiesta del confeti.

Generalmente se recomienda usar -O2 -pipe -fomit-frame-pointer y poco más. La opción -O3 se considera un poco insegura que ya de uvas a peras puede dar problemas. La opción -pipe en realidad no cambia el código de salida, sólo provoca que el compilador use tuberías entre las distintas etapas de una compilación en lugar de usar ficheros temporales, esto aumenta la velocidad de compilación pero puede provocar que en algunos sistemas donde el código ensamblador no pueda recibir de una tubería falle, algo poco común en realidad. La opción -fomit-frame-pointer reduce el tamaño del código bastante pero provoca que la depuración de código sea infinitamente más complicada, además, para gran parte de las arquitecturas, viene activada en el set -O2 así que no necesitaríamos ni ponerla xD

Por poner algunos ejemplos en las máquinas que tengo a mano uso:

AMD Ahtlon 3200+ (2GHz)
CHOST="x86_64-pc-linux-gnu"
CFLAGS="-O2 -march=athlon64 -pipe -fomit-frame-pointer -msse3"

Intel Core Duo T2500 (2GHz)
CHOST="i686-pc-linux-gnu"
CFLAGS="-march=prescott -O2 -pipe -fomit-frame-pointer -msse3"

Intel Pentium4 (3.2GHz)
CHOST="i686-pc-linux-gnu"
CFLAGS="-march=prescott -O2 -pipe -fomit-frame-pointer -msse3"

Intel Pentium4 Celeron (2GHz)
CHOST="i686-pc-linux-gnu"
CFLAGS="-O2 -march=i686 -pipe -fomit-frame-pointer"

Vamos, más simple y pobre imposible jejeje. Y ahora viene el tema, resulta que en el Athlon 3200+ de 64bits tenía -O3… yo ni me acordaba.

Quien no tenga ni amigos ni cosas que hacer que acuda al man gcc y se las estudie todas.

El problema con libgcrypt

Para la prueba 12, creé en mi portátil una par de pares de claves GPG para cifrar con clave asimétrica un mensaje, el objetivo de la prueba era recuperar la clave privada y la passphrase y a continuación descifrarlo. Al principio pensé hacerla más larga y que luego no estuviese enviado por quien decía ser y hubiera que encontrar más cosas pero bueno, lo deje en el primer stage, así que la clave pública del emisor ya no era ni necesaria.

Una vez creadas las clave y cifrado el mensaje procedí a probar que funcionaba…claro. Así que exporté las claves y las importé en el sobremesa (el Athlon). Procedo a descifrar y:
...
AES-128 test encryption failed.
...

Premio, ¿qué habré hecho mal? Venga a probar a importar de nuevo, crear de nuevo las claves, … Resulta que tenía versiones distintas de GnuPG en cada máquina, ¿afectará? O_o, no debería en absoluto pero bueno, compilo la misma versión, sigue fallando, creo otra vez la claves, me empiezo a desesperar, busco por internet, no encuentro nada, me bajo el código fuente donde sale esa cadena para ser mostrada, me lo empiezo a mirar para ver cuando y por qué sale. No veo nada raro, cambio a otra versión de libgcrypt, recompilo, más de lo mismo, sólo puede ser una cosa, que el algoritmo de AES no esté haciendo lo que toca, pero ¡el mismo código funciona en otra máquina!

Ya desesperadísimo a falta de 20 minutos para que demos comienzo el reto, la prueba 12 no funciona xD, genial. Asumiendo que el código es correcto sin bugs me meto en el make.conf y veo “-O3“, uhm, no me jodas, lo cambio por “-O2” y recompilo libgcrypt, que es el paquete que contiene la función con dicho código tocapelotas, y recompilo GnuPG, pruebo a descifrar, a la primera ¬¬

De normal cuando un paquete es propenso a funcionar mal por estas razones en el proceso de compilación te avisan de que no uses alguna optimización, éste no era el caso aunque después de lo visto quizá deberían avisarlo. O cambiarlo por -O2 sin decir nada.

Así que ya sabéis, KISS (efe eeeeeeeeeeeeeeeeeeeeeeeeemeeeeeeee), Keep It Simple, Stupid!


Fuente original en http://vierito.es/wordpress

Similar Posts:

CFLAGS y libgcrypt

Tags: ·······

4 responses so far ↓

  • 1 Cortex Linux Mozilla Firefox 3.0.11 // Jun 19, 2009 at 10:33 pm

    ¡Que buen post vierito! Té confieso que tenía muchas incognitas con las CFLAGS pero con esto han quedado resueltas ;)

    Y como dices, para el que no tenga amigos ni nada que hacer: man gcc XDDD

  • 2 Death Master Ubuntu Linux Mozilla Firefox 3.0.11 // Jun 19, 2009 at 11:56 pm

    Jajajaja… ¡me acuerdo de esa conversación!

  • 3 vierito5 Gentoo Linux Mozilla Firefox 3.0.11 // Jun 20, 2009 at 8:24 pm

    Jajaja cuando estaba ya desesperado le escribí a Death_Master a ver si es que la estaba cagando yo en alguna chorrada exportando las claves.

  • 4 Solucionar crashes inesperados de Firefox 3.5 | La Comunidad DragonJAR WordPress 2.8.4 // Aug 14, 2009 at 3:35 pm

    [...] importante tener bien las CFLAGS, sino puede que los programas no tenga el funcionamiento esperado, como nos explica Javi. Aquí encuentras CFLAGS para tu arquitectura que está comprobado su buen [...]

Leave a Comment