2015-04-17 15 views
96

Ho appreso dal mio collega che uno può scrivere ed eseguire un programma C senza scrivere una funzione main(). Si può fare come inQual è l'uso di _start() in C?

withoutMain.c

// Compile it with gcc -nostartfiles 

void _start() { 
    int ret = my_main(); 
    exit(ret); 
} 

int my_main() { 
    puts("This is a program without main!\n"); 
    return 0; 
} 

compilarlo come: gcc -o withoutMain withoutMain.c –nostartfiles

Esegui come: ./ withoutMain

La mia domanda è quando uno avrebbe bisogno di fare questo genere di cose? Qualche scenario del mondo reale?

+1

correlato in remoto: http://stackoverflow.com/questions/2548486/compiling-without-libc –

+6

Articolo classico che dimostra alcuni dei meccanismi interni di avvio dei programmi: [Un tutorial Whirlwind sulla creazione di file eseguibili ELF really Teensy per Linux] (http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html). Questa è una buona lettura che discute alcuni dei punti migliori di '_start()' e altre cose al di fuori di 'main()'. –

+0

Il linguaggio C di per sé non dice nulla su '_start', o su qualsiasi punto di ingresso diverso da' main' (tranne che il nome del punto di ingresso è definito dall'implementazione per le implementazioni indipendenti (incorporate)). –

risposta

78

Il simbolo _start è punto di ingresso del programma. Cioè, l'indirizzo di quel simbolo è l'indirizzo saltato all'avvio del programma. Normalmente, la funzione con il nome _start viene fornita da un file denominato crt0.o che contiene il codice di avvio per l'ambiente di runtime C. Imposta alcune cose, popola l'array argomento argv, conta quanti argomenti ci sono, e quindi chiama main. Dopo i ritorni main, viene chiamato exit.

Se un programma non desidera utilizzare l'ambiente di runtime C, deve fornire il proprio codice per _start. Ad esempio, l'implementazione di riferimento del linguaggio di programmazione Go lo fa perché hanno bisogno di un modello di threading non standard che richiede un po 'di magia con lo stack. È anche utile fornire il proprio _start quando si desidera scrivere programmi o programmi veramente piccoli che fanno cose non convenzionali.

+2

Un altro esempio è il linker/loader dinamico di Linux che ha il proprio nome _start. –

+2

@BlueMoon Ma quello'_start' deriva anche dal file oggetto 'crt0.o'. – fuz

+0

Questo comportamento è nella lingua standard? L'ho visto usato con molti compilatori di sistemi embedded (che non usano Linux). –

35

Mentre main è il punto di ingresso per il vostro programma dal punto di vista dei programmatori, _start è il solito punto di ingresso dal punto di vista del sistema operativo (la prima istruzione che viene eseguita dopo che il programma è stato avviato dal sistema operativo)

In un tipico C e in particolare il programma C++, è stato fatto molto lavoro prima che l'esecuzione entrasse nel main. Soprattutto cose come l'inizializzazione delle variabili globali. Here è possibile trovare una buona spiegazione di tutto ciò che accade tra _start() e main() e anche dopo che il main è uscito di nuovo (vedere il commento di seguito).
Il codice necessario viene solitamente fornito dagli scrittori del compilatore in un file di avvio, ma con il flag –nostartfiles si dice essenzialmente al compilatore: "Non preoccupatevi di darmi il file di avvio standard, darmi il controllo completo su ciò che sta accadendo sin dall'inizio".

Talvolta è necessario e spesso utilizzato su sistemi embedded. Per esempio. se non hai un sistema operativo e devi abilitare manualmente alcune parti del tuo sistema di memoria (ad es. cache) prima dell'inizializzazione dei tuoi oggetti globali.

+0

I vars globali fanno parte della sezione dati e quindi vengono impostati durante il caricamento del programma (se sono costanti fanno parte della sezione di testo, stessa trama). La funzione _start non è completamente correlata a ciò. – Cheiron

+0

@Cheiron: scusa, il mio errore In C++, le variabili globali sono spesso inizializzate da un costruttore che viene eseguito in '_start()' (o in realtà un'altra funzione chiamata da esso) e in molti programmi Bare-Metal, si copia esplicitamente tutto dati globali da flash a RAM, cosa che accade anche in '_start()', ma questa domanda non riguardava né il C++ né il codice bare-metal. – MikeMB

+1

Si noti che in un programma che fornisce il proprio '_start', la libreria C non verrà inizializzata a meno che non si adottino misure speciali per farlo da soli - potrebbe non essere sicuro utilizzare una funzione non async-signal-safe da un tale programma. (Non esiste alcuna garanzia ufficiale che * qualsiasi * funzione della libreria funzioni, ma le funzioni sicure del segnale asincrono non possono riferirsi a nessun dato globale, quindi dovrebbero fare in modo di non funzionare correttamente.) – zwol

Problemi correlati