Aparte de lo obvio (-Os -s
), la alineación de funciones al valor más pequeño posible que no fallará (no conozco los requisitos de alineación de ARM) podría exprimir algunos bytes por función.
-Os
debería ya deshabilite las funciones de alineación, pero esto aún podría tener un valor predeterminado como 4 u 8. Si se alinea, p. a 1 es posible con ARM, eso podría ahorrar 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.
Uso correcto de __restrict
(o restrict
) y const
elimina las cargas redundantes, lo que hace que el código sea más rápido y más pequeño (y más correcto). Marcar correctamente las funciones puras como tales elimina las llamadas a funciones.
Habilitar LTO puede ayudar y, si no está disponible, compilar todos los archivos fuente en un 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
primero a los archivos objeto y luego a la vinculación) tendrá un efecto similar. Hace que todo sea visible para el optimizador al mismo tiempo, lo que posiblemente le permita funcionar mejor.
-fdelete-null-pointer-checks
puede ser una opción (tenga en cuenta que esto normalmente está habilitado con cualquier "O", pero no en objetivos incrustados).
Poner globales estáticos (es de esperar que no tenga tantos, pero aun así) en una estructura puede eliminar muchos gastos generales inicializándolos. Aprendí eso cuando escribí 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 "manera normal" genera cien kilobytes de código solo para poner a cero cada uno individualmente.
Evite local estático de constructores no triviales variables como el diablo (los tipos de POD no son problema). Gcc inicializará locales estáticos de constructores no triviales seguros para subprocesos a menos que compile con -fno-threadsafe-statics
, que enlaza mucho de código adicional (incluso si no usa subprocesos en absoluto).
Usar algo como libowfat en lugar del crt normal puede mucho reduce tu tamaño binario.
Si desea exprimir hasta la última gota de espacio de sus archivos binarios, probablemente tendrá que aprender a ensamblar. Para una introducción muy interesante (y entretenida), vea este enlace:
Un tutorial torbellino sobre la creación de ejecutables ELF realmente pequeños para Linux
También puedes usar -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. Ver también este hilo (archivado) en oompf:
(citando a 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:el fragmento anterior produjo un binario de 294 bytes , cada byte 8 bits.
Suponiendo que también se permita otra herramienta;-)
Entonces considere UPX:Ultimate Packer for Binaries que usa descompresión en tiempo de ejecución.
Codificación feliz.