2010-03-30 11 views
42

Quiero compilar mi código C sin la (g) libc. ¿Cómo puedo desactivarlo y qué funciones dependen de él?Compilación sin libc

Probé -nostdlib pero no ayuda: el código es compilable y se ejecuta, pero todavía puedo encontrar el nombre de la libc en el hexdump de mi ejecutable.

+1

'-nostdlib' debería hacerlo, lo que versión de la plataforma/compilador está usando? –

+0

"no ayuda", ya que no deshabilitó la biblioteca, o no se pudo compilar nada con esa marca? –

+3

Probablemente también quiera -nostartupfiles. –

Respuesta

53

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().

tratar de compilar esto con -nostdlib gcc:

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 terminar con una llamada a salir (u otra llamada no regresar sistema como el ejecutivo). El ejemplo anterior invoca la llamada al sistema directamente con el ensamblaje en línea, ya que la salida usual() no está disponible.

+3

Para 64 bits, el código de ensamblado debe tener el siguiente aspecto: 'asm (" mov rax, 60; mov rdi, 0; syscall ")'. – sigalor

+3

Añadiendo al comentario de @signalor, para compilar con 'gcc' necesitará usar la sintaxis de AT & T así que esto debería verse así:' asm (mov $ 60,% rax; mov $ 0,% rdi; syscall) ' – lanoxx

+0

@ataylor: ¿Por qué la función _start() siempre debe finalizar con la llamada a exit()? ¿Qué ocurre si no escribo exit() en la función start()? – Destructor

6

La manera más simple es compilar el código C para archivos de objeto (gcc -c para obtener algunos archivos *.o) y luego vincularlos directamente con el vinculador (ld). Deberá vincular los archivos de objeto con unos pocos archivos de objetos adicionales, como /usr/lib/crt1.o, para obtener un ejecutable que funcione (entre el punto de entrada, como lo ve el núcleo, 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 mientras no sea demasiado quisquilloso con el rendimiento).

Las cosas pueden obtener más claras a veces si nos fijamos en el conjunto producido (utilice la bandera -S).

+0

Tengo que usar _start en lugar de main, pero cuando intento llamar a una función libc, gcc no se queja. ¿Desaparece el enlace libc si elimino todas las llamadas libc? – dkreuter

+2

No directamente. Si prueba 'gcc -v', verá que' gcc' le da algunos archivos de objetos al enlazador (el '* .o'). El enlazador incluye todos los archivos de objeto que se le da. La "desaparición" ocurre solo con las bibliotecas ('*.a') porque son repositorios de archivos de objeto que el enlazador es libre de usar o no usar. –

20

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 trata con la configuración del enlazador para eliminar la pelusa innecesaria de los archivos.

+0

+1, enlace muy informativo. –

+0

Me pregunto dónde está la parte 3 – navigaid

Cuestiones relacionadas