2010-03-30 23 views
42

Voglio compilare il mio codice C senza la (g) libc. Come posso disattivarlo e quali funzioni dipendono da questo?Compilare senza libc

ho cercato -nostdlib ma non aiuta: Il codice è compilabile e corre, ma posso ancora trovare il nome della libc nel hexdump della mia eseguibile.

+1

'-nostdlib' dovrebbe farlo, quale versione della piattaforma/compilatore stai usando? –

+0

"non aiuta" dato che in questo non è stata disabilitata la libreria, oppure non è stato possibile compilare nulla con quella bandiera? –

+3

Probabilmente vorrai anche -nostartuperare file. –

risposta

53

Se si compila il codice con -nostdlib, non sarà possibile chiamare alcuna funzione di libreria C (ovviamente), ma non si ottiene il normale codice di bootst C. In particolare, il vero punto di ingresso di un programma su linux non è main(), ma piuttosto una funzione chiamata _start(). Normalmente le librerie standard forniscono una versione di questo che esegue un codice di inizializzazione, quindi chiama main().

provare a compilare questo 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 funzione _start() deve sempre terminare con una chiamata per uscire (o altre chiamate non-ritorno sistema come exec). L'esempio precedente richiama la chiamata di sistema direttamente con l'assembly inline poiché la solita exit() non è disponibile.

+3

Per 64 bit, il codice assembly deve apparire come segue: 'asm (" mov rax, 60; mov rdi, 0; syscall ")'. – sigalor

+3

Aggiungendo al commento di @ sigalor, per compilare con 'gcc' è necessario utilizzare la sintassi AT & T in modo che questo assomigli al seguente:' asm (mov $ 60,% rax; mov $ 0,% rdi; syscall) ' – lanoxx

+0

@ataylor: perché la funzione _start() dovrebbe sempre terminare con call to exit()? Cosa succede se non scrivo exit() nella funzione start()? – Destructor

6

Il modo più semplice per è compilare il codice C di opporsi file (gcc -c per ottenere alcuni *.o file) e quindi collegare direttamente con il linker (ld). Dovrai collegare i tuoi file oggetto con alcuni file oggetto aggiuntivi come /usr/lib/crt1.o per ottenere un file eseguibile funzionante (tra il punto di ingresso, come visto dal kernel, e la funzione main(), c'è un po 'di lavoro da fare) . Per sapere con cosa collegare, prova a collegarti con glibc, usando gcc -v: questo dovrebbe mostrarti cosa succede normalmente nell'eseguibile.

Troverete che gcc genera codice che può avere alcune dipendenze da alcune funzioni nascoste. La maggior parte di questi sono in libgcc.a. Potrebbero esserci anche chiamate nascoste a memcpy(), memmove(), memset() e, che si trovano nella libc, quindi potrebbe essere necessario fornire le proprie versioni (che non è difficile, almeno finché non si è troppo esigenti per le prestazioni).

Le cose possono risultare più chiare a volte se si guarda l'assemblaggio prodotto (utilizzare il flag -S).

+0

Devo usare _start invece di main, ma quando provo a chiamare una funzione di libc gcc non si lamenta. Il collegamento a libc scompare se rimuovo tutte le chiamate libc? – dkreuter

+2

Non direttamente. Se provate 'gcc -v', vedrete che' gcc' fornisce alcuni file oggetto al linker (il '* .o'). Il linker include tutti i file oggetto che gli vengono dati. "Scomparsa" si verifica solo con le librerie ('*.a') perché sono repository di file oggetto che il linker è libero di usare o non usare. –