Hace unos meses, a raíz de un correo de Jesús Sanz comentando la mítica entrevista a BJarne Stroustrup , hicimos una pequeña prueba de cuánto podría engordar un «Hola, mundo!» en función del compilador y lenguaje de programación que utilices. De la exageración -casi irreal hoy en día- de 2.1 MB de ejecutable que prácticamente no hace nada (digo «casi irreal» porque he visto ejecutables que no hacían prácticamente nada más que lanzarse a ejecución con lorzas de bytes similares a esas), llegamos a los 177 bytes de «Hola, mundo!» (aunque estoy convencido de que se puede rebajar bastante más, y no me refiero a usar el formato COM, lenguajes interpretados o trucos similares :-D).
Veamos cómo fue la «operación bikini» con nuestros programas…
Todo comenzó con una frase de neo2001 que decía incrédulo: «De todas maneras… por morbo y porque me parecía una pasada, he compilado un helloWorld con el gcc 4.0 (creo) de Xcode y ocupa 38.796 bytes el binario… no 2.1 MB como dice este señor… vamos, no se a que se referirá…. pero creo que no se sostiene«.
Es una broma… que da qué pensar, ¿eh?
¿38.796 bytes un helloWorld y te parece poco? El mundo está loco.
Lo mismo en C ocupa…
$ echo 'main() { printf("Hello, world\n"); }' > helloC.c $ make helloC cc helloC.c -o helloC $ ls -l helloC -rwxr-xr-x 1 txipi txipi 6922 2006-05-28 00:19 helloC
6922 bytes, 6 veces menos!!
Pero es que si lo hacemos en ASM…
$ cat helloASM.asm extern printf, exit section .text global _start _start: push dword formatstring call printf push 0 call exit section .data formatstring: db "Hello, world",10,0
Lo ensamblamos…
$ nasm -f elf helloASM.asm -o helloASM.o $ ld -s --dynamic-linker /lib/ld-linux.so.2 -lc helloASM.o -o helloASM
Y lo ejecutamos…
$ ./helloASM Hello, world
Miramos cuanto ocupa…
$ ls -l helloASM -rwxr-xr-x 1 txipi txipi 1412 2006-05-28 00:25 helloASM
Ocupa 1412 bytes, unas 5 veces menos que en C y unas 30 veces menos que en C++.
Pero si es que en lugar de usar funciones de C como printf usamos las llamadas al sistema, nos ahorramos algo de espacio…
$ cat helloSyscalls.asm section .text global _start _start: mov eax, 04h mov ebx, 01h mov ecx, formatstring mov edx, 13 int 80h mov eax, 01h mov ebx, 00h int 80h section .data formatstring: db "Hello, world",10,0
Lo ensamblamos, enlazamos y ejecutamos…
$ nasm -f elf helloSyscalls.asm -o helloSyscalls.o $ ld helloSyscalls.o -o helloSyscalls $ ./helloSyscalls Hello, world
Miramos cuanto ocupa…
$ ls -l helloSyscalls -rwxr-xr-x 1 txipi txipi 811 2006-05-28 00:30 helloSyscalls
¡Aproximadamente la mitad que antes!
Pero aún hay más, si le pasamos el sstrip, para quitar secciones y strings que no sirven en tiempo de ejecución…
$ sstrip helloSyscalls $ ls -l helloSyscalls -rwxr-xr-x 1 txipi txipi 177 2006-05-28 00:35 helloSyscalls
177 bytes!!!
Frente a los 39 KB de C++, hay diferencia 😀
Posteriormente, entre los contertulios del hilo de correos, hicimos una recopilación de nuestras indagaciones, bastante reveladoras:
- Windows Borland C++ Builder: 311.296 bytes
- g++ 4.0 de Xcode (C++): 38.796 bytes
- Borland 3.1 con cout (C++): 23.798 bytes
- Borland 3.1 con printf (C): 8.992 bytes
- gcc 4.0 (C): 6.922 bytes
- nasm con printf: 1.412 bytes
- nasm con syscalls: 811 bytes
- nasm con syscalls, stripped: 177 bytes
311296 frente a 177 bytes, ¡¡¡un factor de «compresión» de 1758 a 1!!! (ya, ya, es un ejemplo farsa, pero me gusta poner voz de vendedor de teletienda 😉 ).
Hombre, yo acabo de hacer pruebilla, y el de c tambien solo con strippearlo pierde mas de la mitad!
saladino@Marley:~$ ls -al helloC
-rwxr-xr-x 1 saladino saladino 6894 2006-09-02 00:25 helloC
saladino@Marley:~$ strip helloC
saladino@Marley:~$ ls -al helloC
-rwxr-xr-x 1 saladino saladino 2960 2006-09-02 00:25 helloC
Ñi
Sí, está claro que un strip-tease del binario lo reduce bastante, pero yo creo que esa reducción no es proporcional, sino que siempre está en torno a un valor, que tendrá que ver con la cantidad de información supérflua del binario y que crece a mucho menor ritmo que el propio binario. Por eso al strippear el binario de 811 bytes se notó un cambio tan espectacular (a menos de la 4ª parte).
Muchas gracias por compartir tus pruebas 😉
hey txipi 😀 jejejeje me mola me mola cada dia mas .. lo se … es un comentario demasiado estupido … he intentado leer algo … lo juro … pero es q me parece q leo chino macho … esta claro q no es lo mio … pero esta todo muy bonito 😀
Pués a mi con el GNU C++ 4.0.1 en Mandriva 2006 me da:
$ g++ -o hola CPP-hola.cpp
$ gcc -o holaC C-hola.c
$ ls -all hola*
-rwxrwxr-x 1 xavier xavier 6973 oct 8 16:22 hola*
-rwxrwxr-x 1 xavier xavier 6572 oct 8 16:30 holaC*
O sea no demasiado lejos de C pero un poco superior. Lo que si veo és que ‘strip’ les hace un lifting parecido
$ ls -all hola*
-rwxrwxr-x 1 xavier xavier 3452 oct 8 16:28 hola*
-rwxrwxr-x 1 xavier xavier 3120 oct 8 16:28 holaC*
I añado otra prueba, esta vez Microsoft only, con Visual Studio 2005 Express Edition en versión Release: 5.632 bytes
@Xavier: gracias por aportar más datos al asunto 😉
using System;
namespace H {
class Program {
static void Main( string [] args ) {
Console.WriteLine( «Hello World!» );
}
}
}
$csc /platform:x86 /debug- /checked- /nostdlib- Program.cs
12/05/2010 12:03 3.584 Program.exe