Che cosa è l’uso di _start() in C?

Ho imparato da un mio collega, che si può scrivere ed eseguire un programma in C, senza scrivere una main() funzione. Esso può essere fatto come questo:

my_main.c

/* Compile this with gcc -nostartfiles */

#include <stdlib.h>

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

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

Compilarlo con il comando:

gcc -o my_main my_main.c nostartfiles

Con questo comando:

./my_main

Quando sarebbe bisogno di fare questo tipo di cosa? C’è qualche scenario reale in cui questo sarebbe utile?

InformationsquelleAutor SimpleGuy | 2015-04-17



3 Replies
  1. 90

    Il simbolo _start è il punto di ingresso del programma. Che è, l’indirizzo di questo simbolo è l’indirizzo saltò all’avvio del programma. Normalmente, la funzione con il nome _start viene fornito con un file chiamato crt0.o che contiene il codice di avvio per il C runtime environment. Imposta un po ‘ di roba, popola l’argomento array argv, conta quanti argomenti ci sono, e quindi chiama main. Dopo main restituisce, exit è chiamato.

    Se un programma non si desidera utilizzare il C ambiente di runtime, è necessario fornire il proprio codice per _start. Per esempio, l’implementazione di riferimento del linguaggio di programmazione Go fa perché hanno bisogno di un non-standard modello di threading che richiede un po ‘ di magia con la pila. E ‘ anche utile per fornire il proprio _start quando si desidera scrivere molto piccoli programmi o programmi che fanno cose non convenzionali.

    • Un altro esempio è Linux linker dinamico/caricatore che ha il suo _start definito.
    • Ma che_start proviene dal file oggetto crt0.o, troppo.
    • È questo comportamento in lingua standard? L’ho visto utilizzato con molti sistemi embedded compilatori (che non uso Linux).
    • La norma non specifica _start; esso, infatti, non specifica cosa succede prima di main è chiamato a tutti, è solo specifica quali condizioni devono essere soddisfatte quando main è chiamato. È più una convenzione per il punto di ingresso per essere _start che risale ai vecchi tempi.
    • “l’implementazione di riferimento del linguaggio di programmazione Go fa perché hanno bisogno di un non-standard modello di threading” crt0.o è C specifiche (crt->C runtime). Non c’è ragione di aspettare di essere utilizzato per qualsiasi altra lingua. E Vai il modello di threading è completamente compatibile con gli standard
    • Molte linguaggio di programmazione sono costruiti sulla cima di runtime C perché è più facile da implementare le lingue in questo modo. Go non utilizzare il normale modello di threading. Si utilizzano piccoli, con allocazione heap stack e propria pianificazione. Questa non è certamente una filettatura standard per modello.
    • rilevanti: muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux (or, "Size Is Everything")
    • Ti sarei grato se poteste chiarire che la voce del programma ambiente specifico e soprattutto per gli ambienti di hosting. Non fa parte dello standard (commentato che già, sembra essere una buona idea per aggiungere la tua risposta – i commenti sono spesso ignorati). Per freestanding ambienti C standard permette anche più rilassato comportamento e non mandato main o una firma specifica.
    • Tutta questa risposta riguarda un dettaglio di implementazione di certo C runtime. Forse devo chiarire che.
    • Hmm, penso che l’essenza del mio commento. Tanto per “pensare prima, quindi scrivere”. Appena si prega di essere precisi su freestanding ambienti (e nulla di “normale”/”non normale”. che fa male un po’; -)

  2. 42

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

    In una tipica C e, soprattutto, programma in C++, un sacco di lavoro è stato fatto prima dell’esecuzione entra principale. Soprattutto roba come l’inizializzazione di variabili globali. Qui è possibile trovare una buona spiegazione di tutto quello che sta succedendo tra _start() e main() e anche dopo che è uscito di nuovo (vedi commento sotto).

    Il codice che di solito è fornito dal compilatore scrittori in un file di avvio, ma con la bandiera –nostartfiles ci si limita a dire al compilatore: “non mi dà fastidio lo standard per i file di avvio, mi danno il pieno controllo su ciò che sta accadendo dall’inizio”.

    Questo a volte è necessario e spesso utilizzato su sistemi embedded. E. g. se non si dispone di un sistema operativo e devi attivare manualmente alcune parti del tuo sistema di memoria (ad esempio, la cache) prima dell’inizializzazione dei vostri oggetti globali.

    • Le variabili globali sono parte della sezione di dati e, quindi, sono il programma di installazione durante la fase di caricamento del programma (se sono const fanno parte della sezione di testo, stessa storia). Il _start funzione è completamente estraneo a quello.
    • Scusa, il mio emistake In c++, le variabili globali sono spesso inizializzata da un costruttore che viene eseguito all’interno di _start() (o un’altra funzione chiamata da esso) e in molte Bare-Metal-Programmi, in modo esplicito copia globale di tutti i dati da flash RAM di prima, cosa che avviene anche in _start(), ma a questa domanda non è stata né su c++ né nudo-metallo codice.
    • Nota che in un programma che fornisce la sua _start, la libreria C non inizializzati a meno che non si prendono dei provvedimenti speciali per do it yourself-può ben essere a rischio per l’uso di qualsiasi non-async-segnale-funzione di sicurezza da un tale programma. (Non c’è la garanzia ufficiale che qualsiasi funzione di libreria, ma async-segnale-funzionalità di sicurezza non può riferirsi a qualsiasi di dati globali, quindi dovrebbe andare fuori del loro modo di malfunzionamento.)
    • questo è solo parzialmente corretta. Per esempio, tale funzione potrebbe allocare la memoria. L’allocazione di memoria è problematico quando le strutture dati interne per malloc non inizializzate.
    • Async-segnale-funzionalità di sicurezza sono non permesso di chiamare malloc. Questo non è esplicitamente specificato in standard, ma deriva direttamente da malloc stesso di non essere in async-segnale-safe list.
    • Questo non è corretto. L’elenco è solo il minimo garantito. Una piattaforma in grado di fornire un async-segnale-cassetta di sicurezza malloc e l’attuazione può utilizzare. Infatti, credo che la glibc fornisce un malloc.
    • Detto questo, ho notato che async-segnale-funzionalità di sicurezza sono hanno il permesso di modificare errno (es. read e write sono async-segnale-cassetta di sicurezza e possibilità di impostare errno) e che potrebbero essere un problema a seconda esattamente quando il per-thread errno posizione è assegnata.
    • So per certo che glibc del malloc è non async-segnale-safe, ma accetto la correzione, come astratto caso.
    • Se dici così, sto solo cercando di indovinare.
    • Io non credo che sia raro che i compilatori C, in particolare quelli rivolti sistemi embedded, per avere il codice dell’immagine contenere i dati inizializzati in una “compressa” forma e avere il codice di avvio decomprimerla. Io non ho visto nulla di particolarmente fantasia in questo senso, ma ho visto che i compilatori generano una sequenza di concatenata {unsigned char *dest; unsigned short n; unsigned char data[n]; } strutture. Questo può essere un po ‘ utile in molti casi, e molto utile in pochi, e non deve costare molto, anche quando non è di grande aiuto.

  3. -1

    _start() è una funzione a cui punta l’intestazione speciale , solo per essere capito dal computer. Ma è importante perché dobbiamo imparare che cosa sta andando accadere al retro del computer.

Lascia un commento