2013-10-19 13 views
5

Il mio modo di capire il processo di compilazione:Come funziona esattamente il collegamento?

1) Pre-elaborazione: Tutti i tuoi macro vengono sostituiti con i loro valori reali, tutti i commenti sono stati rimossi, ecc Sostituisce le sue dichiarazioni #include con il testo letterale dei file che si' ve incluso.

2) Compilation: non eseguirà il drill down troppo in profondità, ma il risultato è un file assembly per qualsiasi architettura su cui ci si trova.

3) Assemblaggio: prende il file di assieme e lo converte in istruzioni binarie, cioè codice macchina.

4) Collegamento: è qui che sono confuso. A questo punto hai un eseguibile. Ma se esegui effettivamente quell'eseguibile, cosa succede? Il problema è che potresti aver incluso i file * .h, e questi contengono solo prototipi di funzioni? Quindi se chiamate effettivamente una delle funzioni da quei file, non avrà una definizione e il vostro programma andrà in crash?

Se è questo il caso, cosa fa esattamente il collegamento , sotto il cofano? Come trova il file .c associato al file .h che hai incluso e come lo inserisce nel tuo codice macchina? Non deve ripetere l'intero processo di compilazione per quel file?

Ora, ho capito che esistono due tipi di collegamento, dinamico e statico. È statico quando si ricompila effettivamente la fonte della libreria per ogni eseguibile che si crea? Non capisco come funzionerebbe il collegamento dinamico. Quindi compili una libreria eseguibile che è condivisa da tutti i tuoi processi che la usano? Com'è possibile, esattamente? Non sarebbe al di fuori dello spazio degli indirizzi dei processi che cercano di accedervi? Inoltre, per il collegamento dinamico, non hai ancora bisogno di compilare la libreria in un momento preciso? E 'solo seduto lì costantemente in memoria in attesa di essere utilizzato? Quando è compilato?

Potete passare attraverso quanto sopra e chiarire tutti i fraintendimenti, le assunzioni sbagliate lì e sostituire la vostra spiegazione corretta?

+0

possibile duplicato di [Come funziona il collegamento C++ in pratica?] (Http://stackoverflow.com/questions/12122446/how-does-c-linking-work-in-practice) –

risposta

11

At this point you have an executable.

No. A questo punto, si dispone di file oggetto, che non sono, di per sé, eseguibili.

But if you actually run that executable what happens?

Qualcosa di simile a questo:

h2co3-macbook:~ h2co3$ clang -Wall -o quirk.o quirk.c -c 
h2co3-macbook:~ h2co3$ chmod +x quirk.o 
h2co3-macbook:~ h2co3$ ./quirk.o 
-bash: ./quirk.o: Malformed Mach-o file 

ho detto voi che non era un eseguibile.

Is the problem that you may have included *.h files, and those only contain function prototypes?

Abbastanza vicino, in realtà. Un'unità di traduzione (file .c) viene (generalmente) trasformata in codice assembly/macchina che rappresenta ciò che fa. Se chiama una funzione, allora ci sarà un riferimento a quella funzione nel file, ma nessuna definizione.

So if you actually call one of the functions from those files, it won't have a definition and your program will crash?

Come ho già detto, non funzionerà nemmeno. Permettetemi di ripetere: un file oggetto è non eseguibile.

what exactly does linking do, under the hood? How does it find the .c file associated with the .h that you included [...]

E non lo fa. Cerca altri file oggetto generati da file .c e infine librerie (che sono essenzialmente solo raccolte di altri file oggetto).

E li trova perché gli dici cosa cercare. Supponendo di avere un progetto che si compone di due file .c che richiedono funzioni di ogni altro, questo non funzionerà:

gcc -c file1.c -o file1.o 
gcc -c file2.c -o file2.o 
gcc -o my_prog file1.o 

fallirà con un errore di linker: il linker non troverà la definizione del funzioni implementate in file2.c (e file2.o). Ma questo funzionerà: i file

gcc -c file1.c -o file1.o 
gcc -c file2.c -o file2.o 
gcc -o my_prog file1.o file2.o 

[...] and how does it inject that into your machine code?

Object contengono riferimenti stub (di solito sotto forma di indirizzi punto di ingresso di funzione o esplicite, nomi leggibili) alle funzioni che chiamano. Quindi, il linker esamina ciascuna libreria e il file oggetto, trova i riferimenti (, genera un errore se non è possibile trovare una definizione di funzione), quindi sostituisce i riferimenti stub con le istruzioni del codice macchina "chiama questa funzione". (Sì, questo è in gran parte semplificata, ma senza che ti chiede di una specifica architettura e uno specifico compilatore/linker, è difficile dire più precisamente ...)

Is static when you actually recompile the source of the library for every executable you create?

No. legame statico significa che il codice macchina i file oggetto di una libreria vengono effettivamente copiati/uniti nell'eseguibile finale. Collegamento dinamico significa che una libreria viene caricata in memoria una volta, quindi i riferimenti delle funzioni di stub di cui sopra vengono risolti dal sistema operativo all'avvio del file eseguibile. Nessun codice macchina dalla libreria verrà copiato nel file eseguibile finale. (Quindi qui, il linker nella toolchain fa solo parte del lavoro.)

Quanto segue può aiutarti a raggiungere l'illuminazione: se si collega staticamente un eseguibile, esso sarà autonomo. Funzionerà ovunque (comunque su un'architettura compatibile). Se lo si collega dinamicamente, verrà eseguito solo su una macchina se quella particolare macchina ha tutte le librerie installate a cui fa riferimento il programma.

So you compile one executable library that is shared by all of your processes that use it? How is that possible, exactly? Wouldn't it be outside of the address space of the processes trying to access it?

Il componente linker/loader dinamico del sistema operativo si occupa di tutto ciò.

Also, for dynamic linking, don't you still need to compile the library at some juncture in time?

Come ho già detto: sì, è già compilato. Quindi viene caricato in un punto (in genere quando viene utilizzato per la prima volta) in memoria.

When is it compiled?

Un po 'di tempo prima che potesse essere utilizzato. In genere, una libreria viene compilata, quindi installata in una posizione del sistema in modo che il sistema operativo e il compilatore/linker siano a conoscenza della sua esistenza, quindi è possibile iniziare la compilazione (um, che collega i programmi) che utilizzano quella libreria. Non prima.

+0

Risposta brillante! Grazie. Ovviamente ora ho delle domande di follow-up se lo farai: - Hai detto che se chiama una funzione, ci sarà un riferimento a una funzione. Quindi il file oggetto contiene letteralmente una sorta di simbolo che può essere risolto al momento del collegamento? Non è un'istruzione di macchina reale? Come dice solo "printf" o qualcosa del genere? Perché non può sapere prima mano dove in memoria quella funzione sarà ... – ordinary

+0

- Nel paradigma di collegamento dinamico, dalla tua spiegazione sembra che l'eseguibile finale avrà simboli irrisolti.Quindi, quando si carica il programma in memoria, vuol dire che c'è un passaggio intermedio da parte del sistema operativo prima che il programma sia effettivamente caricato, nel quale guarda tutti i simboli non risolti e fornisce loro gli indirizzi letterali per quelle funzioni? Che succede se chiami una funzione che non esiste? Dov'è il punto di fallimento? – ordinary

+1

@ordinario Sì, contiene i simboli stub ("simbolo" - è esattamente quello che sono chiamati). Questo è in parte il motivo per cui questi file non sono effettivamente eseguibili. –

Problemi correlati