2011-07-21 11 views
12

Sé que hay una opción "-Os" para "Optimizar el tamaño", pero tiene poco efecto, o incluso aumentar el tamaño en alguna ocasión :(Cómo disminuir el tamaño de los binarios generados?

tira (o la opción "-s") quita depuración tabla de símbolos, que funciona bien;.? pero sólo puede disminuir sólo una pequeña propotion del tamaño

¿hay alguna otra manera de ir furthur

+0

¿Qué te hace pensar que es demasiado grande? – bdonlan

+3

En algunos dispositivos incrustados como enrutadores que funcionan con OpenWrt con solo almacenamiento flash de 4MB ... – felix021

Respuesta

10

Aparte de lo obvio (-Os -s), alinear las funciones al valor más pequeño posible que no se bloquee (no conozco los requisitos de alineación de ARM) podría exprimir algunos bytes por función.
-Osdebe desactivar las funciones de alineación, pero esto aún puede tener un valor predeterminado de 4 u 8. Si se alinea, p. a 1 es posible con ARM, que podría salvar algunos bytes.

-ffast-math (o el menos abrasivo -fno-math-errno) no establecerá errno y evitará algunas comprobaciones, lo que reduce el tamaño del código. Si, como la mayoría de las personas, no lee errno de todos modos, esa es una opción.

El uso correcto de __restrict (o restrict) y const elimina las cargas redundantes, haciendo que el código sea más rápido y más pequeño (y más correcto). Marcar correctamente las funciones puras como tal, elemina las llamadas de función.

Activación LTO puede ayudar, y si eso no está disponible, la compilación de todos los archivos de origen en un sistema binario de una sola vez (gcc foo.c bar.c baz.c -o program en lugar de compilar foo.c, bar.c y baz.c a los ficheros objeto primero y luego vincular) tendrá un efecto similar . Hace que todo sea visible para el optimizador a la vez, posiblemente permitiendo que funcione mejor.

-fdelete-null-pointer-checks puede ser una opción (tenga en cuenta que esto normalmente está activado con cualquier "O", pero no de objetivos embebidos).

Poniendo globales estáticos (esperemos que no tenga tantos, pero aún así) en una estructura puede eleminar un montón de sobrecarga inicializándolos. Aprendí eso al escribir mi primer cargador OpenGL. Tener todos los punteros de función en una estructura e inicializar la estructura con = {} genera una llamada a memset, mientras que inicializar los punteros de la "forma normal" genera cien kilobytes de código para establecer cada uno a cero individualmente.

Evitar no trivial-constructor estático locales variables como el diablo (POD tipos no son un problema). Gcc inicializará locales no estáticos constructores triviales threadsafe a menos que compile con -fno-threadsafe-statics, que vincula mucho de código adicional (incluso si no usa subprocesos en absoluto).

Usando algo como libowfat en lugar del crt normal puede enormemente reducir su tamaño binario.

5

Suponiendo que también se permite otra herramienta ;-)

Luego considere UPX: the Ultimate Packer for Binaries que usa descompresión en tiempo de ejecución.

Happy coding.

+0

Muchas gracias ... Pensé que era solo Windows ... – felix021

+2

Tenga en cuenta que esto puede aumentar el consumo de RAM, especialmente cuando se usa en bibliotecas compartidas. – bdonlan

+0

Hace que el intercambio sea menos efectivo. Al intercambiar una página mapeada desde un binario ELF, simplemente descarta el contenido de la página sin tener que escribir la página en el archivo de intercambio. Cuando la página no tiene una asignación de archivos, primero debe guardar la página en el archivo de intercambio. –

6

You can also use-nostartfiles y/o -nodefaultlibs o la combinación de ambos -nostdlib. En caso de que no desee un archivo de inicio estándar, debe escribir su propia función _start luego. Ver también this thread en ompf:

(citando Perrin)

# man syscalls 
# cat phat.cc 
extern "C" void _start() { 
     asm("int $0x80" :: "a"(1), "b"(42)); 
} 
# g++ -fno-exceptions -Os -c phat.cc 
# objdump -d phat.o 

phat.o:  file format elf64-x86-64 

Disassembly of section .text: 

0000000000000000 <_start>: 
    0: 53      push %rbx 
    1: b8 01 00 00 00   mov $0x1,%eax 
    6: bb 2a 00 00 00   mov $0x2a,%ebx 
    b: cd 80     int $0x80 
    d: 5b      pop %rbx 
    e: c3      retq 
# ld -nostdlib -nostartfiles phat.o -o phat 
# sstrip phat 
# ls -l phat 
-rwxr-xr-x 1 tbp src 294 2007-04-11 22:47 phat 
# ./phat; echo $? 
42 

Resumen: Por encima produjo un fragmento binaria de 294 bytes, cada byte de 8 bits.

+1

Gracias, me diste la respuesta a la vida, el universo y todo, jaja. – felix021

4

También depende de la arquitectura que esté utilizando.

En el brazo, tiene el conjunto de instrucciones Thumb que está aquí para reducir el tamaño del código generado.

También puede evitar los enlaces dinámicos y prefiere los enlaces estáticos para libs que solo usa su programa o muy pocos programas en su sistema. Esto no disminuirá el tamaño del binario generado per se, pero en general, usará menos espacio en su sistema para este programa.

2

Al usar tira (1), querrá asegurarse de usar todas las opciones relevantes. Por alguna razón, --strip-all no siempre tira todo. Eliminar secciones innecesarias puede ser útil.

En última instancia, sin embargo, la mejor manera de reducir el tamaño del binario es eliminar el código y los datos estáticos del programa. Haga que haga menos, o seleccione construcciones de programación que den como resultado menos instrucciones. Por ejemplo, puede construir estructuras de datos en tiempo de ejecución, o cargarlos desde un archivo, bajo demanda, en lugar de tener una matriz inicializada estáticamente.

+0

Gracias, solución muy práctica^^. – felix021

2

Puede intentar jugar con -fdata-sections, -ffunction-sections y -Wl,--gc-sections, pero esto no es seguro, así que asegúrese de entender cómo funcionan antes de usarlos.

Cuestiones relacionadas