c - near - seo optimized images
Compilando sin libc (4)
Quiero compilar mi código C sin la (g) libc. ¿Cómo puedo desactivarlo y qué funciones dependen de él?
Intenté -nostdlib pero no me ayudó: el código es compilable y se ejecuta, pero aún puedo encontrar el nombre de la libc en el hexdump de mi ejecutable.
Aquí hay un excelente artículo sobre la optimización de los binarios de los elfos que cubre la eliminación de stdlib de los ejecutables: Un tutorial de Whirlwind sobre la creación de ejecutables ELF verdaderamente teensy para Linux
La forma más simple es compilar el código C para objetos ( gcc -c
para obtener algunos archivos *.o
) y luego vincularlos directamente con el enlazador ( ld
). Deberá vincular los archivos de objeto con algunos archivos de objetos adicionales, como /usr/lib/crt1.o
, para obtener un ejecutable que funcione (entre el punto de entrada, como lo ve el kernel, y la función main()
, hay un poco de trabajo por hacer). Para saber con qué vincular, intente vincular con glibc, usando gcc -v
: esto debería mostrarle lo que normalmente entra en el ejecutable.
Encontrará que gcc genera código que puede tener algunas dependencias con algunas funciones ocultas. La mayoría de ellos están en libgcc.a
. También puede haber llamadas ocultas a memcpy()
, memmove()
, memset()
y memcmp()
, que están en la libc, por lo que es posible que deba proporcionar sus propias versiones (lo cual no es difícil, al menos tanto tiempo como no son muy exigentes con el rendimiento).
Las cosas pueden aclararse a veces si observa el ensamblaje producido (use la bandera -S
).
Si compila su código con -nostdlib, no podrá llamar a ninguna función de la biblioteca C (por supuesto), pero tampoco obtendrá el código de arranque C normal. En particular, el punto de entrada real de un programa en Linux no es main (), sino más bien una función llamada _start (). Las bibliotecas estándar normalmente proporcionan una versión de esto que ejecuta algún código de inicialización, luego llama a main ().
Intenta compilar esto con gcc -nostdlib:
void _start() {
/* main body of program: call main(), etc */
/* exit system call */
asm("movl $1,%eax;"
"xorl %ebx,%ebx;"
"int $0x80"
);
}
La función _start () siempre debe finalizar con una llamada para salir (u otra llamada al sistema no recurrente como exec). El ejemplo anterior invoca la llamada al sistema directamente con el ensamblaje en línea, ya que la salida usual () no está disponible.
http://blog.ksplice.com/2010/03/libc-free-world/ tiene una muy buena descripción del control preciso de la salida de programación de gcc.
Editar: Ellos (ksplice) acaban de publicar la parte 2 del tutorial / guía anterior. Véalo aquí: http://blog.ksplice.com/2010/04/libc-free-world-2/ Esto principalmente se ocupa de la configuración del enlazador para eliminar la pelusa innecesaria de los archivos.