๐ Retour au Sommaire
Dans la section prรฉcรฉdente, nous avons dรฉcouvert les 4 รฉtapes de la chaรฎne de compilation. Maintenant, nous allons visualiser concrรจtement ce pipeline en action. Voir les transformations de votre code ร chaque รฉtape vous aidera ร mieux comprendre ce qui se passe ยซ sous le capot ยป quand vous compilez un programme.
Voici une reprรฉsentation visuelle complรจte du chemin parcouru par votre code :
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PIPELINE DE COMPILATION GCC โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
VOUS รCRIVEZ VOUS EXรCUTEZ
โ โ
โผ โผ
โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ hello.c โโโโโถโ hello.i โโโโโถโ hello.s โโโโโถโ hello.o โโโโโถโ hello โ
โ โ โ โ โ โ โ โ โ (exรฉcutable)โ
โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ โ โ โ โ
Code C Code C Code Code Programme
source prรฉtraitรฉ assembleur machine prรชt !
(รฉtendu) (textuel) (binaire)
โ โ โ โ โ
โโโโโโโโฌโโโโโโโโดโโโโโโโฌโโโโโโโโดโโโโโโโฌโโโโโโโโดโโโโโโโโฌโโโโโโโโ
โ โ โ โ
โผ โผ โผ โผ
PRรPROCESSEUR COMPILATEUR ASSEMBLEUR LINKER
(cpp) (cc1) (as) (ld)
Chaque outil transforme le fichier dโentrรฉe en un format diffรฉrent, jusquโร obtenir lโexรฉcutable final.
Prenons un programme simple et observons sa transformation ร travers le pipeline.
#include <stdio.h>
#define AUTEUR "Alice"
#define ANNEE 2025
// Fonction principale
int main(void) {
printf("Programme crรฉรฉ par %s en %d\n", AUTEUR, ANNEE);
return 0;
}
Ce fichier fait environ 15 lignes. Voyons comment il รฉvolue.
gcc -E hello.c -o hello.i
Taille approximative : ~800 lignes (oui, vraiment !)
Le fichier hello.i ressemble ร ceci (version trรจs simplifiรฉe) :
# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4
/* ... des centaines de lignes de stdio.h et ses dรฉpendances ... */
typedef struct _IO_FILE FILE;
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
extern int printf (const char *__format, ...);
extern int scanf (const char *__format, ...);
/* ... encore beaucoup de dรฉclarations ... */
# 2 "hello.c" 2
int main(void) {
printf("Programme crรฉรฉ par %s en %d\n", "Alice", 2025);
return 0;
}
Ce qui a changรฉ :
| Avant | Aprรจs |
|---|---|
#include <stdio.h> |
~700 lignes de dรฉclarations |
AUTEUR |
"Alice" |
ANNEE |
2025 |
// Fonction principale |
(supprimรฉ) |
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ VISUALISATION DE L'EXPANSION โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ hello.c (15 lignes) โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ #include <stdio>โ โโโโโโโ โ
โ โ #define AUTEUR โ โ โ
โ โ #define ANNEE โ โ PRรPROCESSEUR โ
โ โ int main() { โ โ โ
โ โ printf(...) โ โผ โ
โ โ } โ โโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโ โ /* stdio.h */ โ โ
โ โ typedef ... โ โ
โ โ extern printf โ โ
โ โ /* ~700 lignes*/โ โ
โ โ โโโโโโโโโโโโโโโ โ โ
โ โ int main() { โ โ
โ โ printf("Alice",โ โ
โ โ 2025) โ โ
โ โ } โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ hello.i (~800 lignes) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
gcc -S hello.c -o hello.s
Taille approximative : ~30 lignes
Le fichier hello.s contient du code assembleur :
.file "hello.c"
.text
.section .rodata
.LC0:
.string "Programme cr\303\251\303\251 par %s en %d\n"
.LC1:
.string "Alice"
.text
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
movl $2025, %edx
leaq .LC1(%rip), %rax
movq %rax, %rsi
leaq .LC0(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
popq %rbp
ret
.size main, .-main
Dรฉcryptage pour dรฉbutants :
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ STRUCTURE DU CODE ASSEMBLEUR โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ .section .rodata โโโ Section des donnรฉes โ
โ .LC0: en lecture seule โ
โ .string "Programme..." (nos chaรฎnes de caractรจres) โ
โ .LC1: โ
โ .string "Alice" โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ .text โโโ Section du code exรฉcutable โ
โ main: โ
โ pushq %rbp โโโ Sauvegarde du contexte โ
โ movq %rsp, %rbp โ
โ โ
โ movl $2025, %edx โโโ Prรฉpare l'argument "2025" โ
โ leaq .LC1, %rsi โโโ Prรฉpare l'argument "Alice" โ
โ leaq .LC0, %rdi โโโ Prรฉpare le format string โ
โ โ
โ call printf@PLT โโโ Appelle printf โ
โ โ
โ movl $0, %eax โโโ Prรฉpare return 0 โ
โ ret โโโ Retourne โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Le code C a รฉtรฉ traduit en instructions que le processeur peut comprendre (aprรจs une derniรจre transformation).
gcc -c hello.c -o hello.o
Taille approximative : ~1.5 Ko
Le fichier .o est binaire. Vous ne pouvez pas le lire avec un รฉditeur de texte :
cat hello.o
# Affiche des caractรจres illisibles : ELF>๏ฟฝ@@...
Mais vous pouvez lโinspecter avec des outils spรฉcialisรฉs :
# Voir la structure du fichier
file hello.o
# Rรฉsultat : hello.o: ELF 64-bit LSB relocatable, x86-64, ...
# Voir les symboles dรฉfinis
nm hello.o
# Rรฉsultat :
# U printf
# 0000000000000000 T main
# Voir le dรฉsassemblage
objdump -d hello.o
Signification des symboles :
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ TABLE DES SYMBOLES (nm hello.o) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ SYMBOLE TYPE SIGNIFICATION โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ main T Dรฉfini ici (T = Text/Code) โ
โ C'est notre fonction main() โ
โ โ
โ printf U Non dรฉfini (U = Undefined) โ
โ Utilisรฉ mais pas encore trouvรฉ โ
โ โ Sera rรฉsolu par le linker โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Le fichier objet contient le code machine de main, mais lโadresse de printf est encore inconnue (marquรฉe U). Cโest le linker qui va rรฉsoudre ce mystรจre.
gcc hello.o -o hello
# ou directement : gcc hello.c -o hello
Taille approximative : ~16 Ko
Lโexรฉcutable final est prรชt :
file hello
# Rรฉsultat : hello: ELF 64-bit LSB executable, x86-64, dynamically linked, ...
./hello
# Rรฉsultat : Programme crรฉรฉ par Alice en 2025
Ce que le linker a fait :
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ RรSOLUTION DES SYMBOLES PAR LE LINKER โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ hello.o libc.so (bibliothรจque C) โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ main: T โ โ printf: T โ โ
โ โ printf: U โโโผโโโโโโโโโโโโโโโผโโถ (code de printf) โ โ
โ โโโโโโโโโโโโโโโ โ scanf: T โ โ
โ โ malloc: T โ โ
โ โ โ ... โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ hello (exรฉcutable) โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ main: appelle printf ร l'adresse X โ โ โ
โ โ โ printf: rรฉfรฉrence vers libc.so โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Un aspect frappant du pipeline est lโรฉvolution de la taille des fichiers :
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ รVOLUTION DE LA TAILLE DES FICHIERS โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Fichier Taille Reprรฉsentation โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ hello.c ~200 o โโ โ
โ (votre code compact) โ
โ โ
โ hello.i ~20 Ko โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ (explosion due aux #include) โ
โ โ
โ hello.s ~800 o โโโโ โ
โ (assembleur, plus compact) โ
โ โ
โ hello.o ~1.5 Ko โโโโโโโ โ
โ (code machine + mรฉtadonnรฉes) โ
โ โ
โ hello ~16 Ko โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโ โ
โ (exรฉcutable complet avec en-tรชtes) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Pourquoi ces variations ?
#include <stdio.h> inclut des milliers de lignes.Dans un vrai projet, vous avez souvent plusieurs fichiers .c. Voici comment le pipeline sโorganise :
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PIPELINE MULTI-FICHIERS โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ main.c โโโถ main.i โโโถ main.s โโโถ main.o โโโ โ
โ โ โ
โ utils.c โโถ utils.i โโถ utils.s โโถ utils.o โโผโโโถ LINKER โโโถ programme โ
โ โ โ
โ calc.c โโโถ calc.i โโโถ calc.s โโโถ calc.o โโโ โ
โ โ โ
โ libc.so โโโโ โ
โ (bibliothรจque) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Chaque fichier .c traverse indรฉpendamment les 3 premiรจres รฉtapes (prรฉprocesseur, compilation, assemblage). Cโest seulement ร la fin que le linker les rassemble tous.
Commandes correspondantes :
# Compilation sรฉparรฉe de chaque fichier
gcc -c main.c -o main.o
gcc -c utils.c -o utils.o
gcc -c calc.c -o calc.o
# รdition de liens finale
gcc main.o utils.o calc.o -o programme
GCC propose une option pour voir les commandes exรฉcutรฉes ร chaque รฉtape :
gcc -v hello.c -o hello
Lโoption -v (verbose) affiche tout ce qui se passe :
Using built-in specs.
COLLECT_GCC=gcc
...
/usr/lib/gcc/x86_64-linux-gnu/11/cc1 -quiet hello.c -o /tmp/ccXXXXXX.s
as -v --64 -o /tmp/ccYYYYYY.o /tmp/ccXXXXXX.s
/usr/lib/gcc/x86_64-linux-gnu/11/collect2 -o hello /tmp/ccYYYYYY.o -lc ...
Vous pouvez identifier :
cc1 : le compilateur (รฉtapes 1-2)as : lโassembleur (รฉtape 3)collect2/ld : le linker (รฉtape 4)Voici un schรฉma qui rรฉsume tout le pipeline avec les outils, fichiers et commandes :
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PIPELINE COMPLET DE COMPILATION โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ SOURCE OUTIL RรSULTAT COMMANDE GCC โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโ โ
โ โ hello.c โ Votre code C (texte lisible) โ
โ โโโโโโฌโโโโโ โ
โ โ โ
โ โ โโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโถโ Prรฉprocesseurโ cpp โ
โ โ โ (cpp) โ gcc -E hello.c -o hello.i
โ โ โโโโโโโโฌโโโโโโโ โ
โ โ โ โ
โ โ โผ โ
โ โ โโโโโโโโโโโ โ
โ โ โ hello.i โ Code prรฉtraitรฉ (texte, ~800 lignes) โ
โ โ โโโโโโฌโโโโโ โ
โ โ โ โ
โ โ โ โโโโโโโโโโโโโโโ โ
โ โ โโโถโ Compilateur โ cc1 โ
โ โ โ (cc1) โ gcc -S hello.c -o hello.s
โ โ โโโโโโโโฌโโโโโโโ โ
โ โ โ โ
โ โ โผ โ
โ โ โโโโโโโโโโโ โ
โ โ โ hello.s โ Code assembleur (texte, ~30 lignes) โ
โ โ โโโโโโฌโโโโโ โ
โ โ โ โ
โ โ โ โโโโโโโโโโโโโโโ โ
โ โ โโโถโ Assembleur โ as โ
โ โ โ (as) โ gcc -c hello.c -o hello.o
โ โ โโโโโโโโฌโโโโโโโ โ
โ โ โ โ
โ โ โผ โ
โ โ โโโโโโโโโโโ โ
โ โ โ hello.o โ Fichier objet (binaire) โ
โ โ โโโโโโฌโโโโโ โ
โ โ โ โ
โ โ โ โโโโโโโโโโโโโโโ โโโโโโโโโโโ โ
โ โ โโโถโ Linker โโโโค libc.so โ โ
โ โ โ (ld/lld) โ โโโโโโโโโโโ โ
โ โ โโโโโโโโฌโโโโโโโ gcc hello.o -o hello
โ โ โ โ
โ โ โผ โ
โ โ โโโโโโโโโโโโโ โ
โ โ โ hello โ Exรฉcutable final โ
โ โ โโโโโโโโโโโโโ โ
โ โ โ โ
โ โ โผ โ
โ โ ./hello โ
โ โ "Programme crรฉรฉ par โ
โ โ Alice en 2025" โ
โ โ โ
โ โโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ RACCOURCI : gcc hello.c -o hello (fait tout en une seule commande) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Quand vous utilisez gcc hello.c -o hello sans options intermรฉdiaires, GCC crรฉe quand mรชme tous les fichiers intermรฉdiaires, mais dans un rรฉpertoire temporaire (/tmp/). Ils sont automatiquement supprimรฉs aprรจs la compilation.
Pour les conserver et les examiner :
gcc -save-temps hello.c -o hello
Cette commande garde tous les fichiers intermรฉdiaires dans le rรฉpertoire courant :
hello.i (prรฉprocessรฉ)hello.s (assembleur)hello.o (objet)hello (exรฉcutable)Visualiser le pipeline de compilation vous permet de comprendre que la ยซ compilation ยป nโest pas une opรฉration magique, mais une sรฉrie de transformations bien dรฉfinies :
Chaque รฉtape a ses propres outils, formats de fichiers et types dโerreurs. En comprenant ce pipeline, vous serez capable de diagnostiquer plus rapidement les problรจmes et de mieux organiser vos projets C.
Dans la section suivante, nous dรฉcouvrirons les options de compilation GCC essentielles pour contrรดler ce pipeline selon vos besoins.