Activité 2 Les étapes de la compilation
gcc effectue quatre étapes pour produire l'exécutable :
1. passage au pré-processeur (preprocessing)
2. compilation en langage assembleur (compiling)
3. conversion du langage assembleur en code machine (assembling)
4. édition des liens (linking)
gcc bonjour.c
preprocessing
compiling
assembling
linking
bonjour.c
bonjour.i
bonjour.s
bonjour.o
a.out
On note que les fichiers intermédiaires générés n'apparaissent pas dans le répertoire. Une fois
que gcc a fini son exécution, les seuls fichiers qui apparaissent sont celui qui contient
l'exécutable et le fichier source C.
La fonction printf fait partie d'une bibliothèque standard et son prototype est donné dans le
fichier nommé stdio.h . Le prototype fournit les informations qui sont essentielles pour
utiliser la fonction : ce qu'elle retourne et ce qu'elle attend en paramètre.
Pour illustrer la transformation du programme par le compilateur, nous omettrons cette ligne
(pour des raisons de taille de l'exemple).
bonjour.c
int main (void)
{
/ afficher le mot bonjour et sauter une ligne /
printf("bonjour !!!\n");
return 0;
}
Étape 1 : passage au pré-processeur
gcc -E bonjour.c > bonjour.i
preprocessing
compiling
assembling
linking
bonjour.c
bonjour.i
bonjour.s
bonjour.o
a.out
L'option -E de gcc permet d'interrompre la compilation après la première phase. Le > indique
qu'il faut stocker le résultat du preprocessing dans un fichier nommé bonjour.i.
Le pré-processeur réalise plusieurs opérations de substitution sur le code C, notamment :
suppression des commentaires (// et / /) qui sont utiles au programmeur, mais
Publicité
inutiles pour l'ordinateur.
inclusion des fichiers .h dans le fichier .c (#include)
traitement des directives de compilation qui commencent par un caractère #. Ces
directives sont define elif else endif error if ifdef ifndef include line
pragma undef, vous les aborderez dans la suite du cours.
Le fichier qui est produit est un fichier texte en langage C qui est lisible. Voici le fichier
obtenu pour notre programme bonjour.c
bonjour.i
1 "bonjour.c"
int main (void)
{
printf("bonjour !!!\n");
return 0;
}
Le pré-processeur contrôle la syntaxe du programme.
Prenons le fichier bonjour.c ci-dessous dans lequel nous avons oublié de fermer le guillemet à
la fin de la chaîne :
bonjour.c
int main (void)
{
/ afficher le mot bonjour et sauter une ligne /
printf("bonjour !!!\n);
return 0;
}
Lorsque le programme contient des erreurs de syntaxe, gcc affiche la liste des erreurs à la
console et il interrompt la suite des opérations, i.e. il ne passe pas à l'étape 2.
gcc -E bonjour.c > bonjour.i
bonjour.c:5: unterminated string or character constant
Voici un autre exemple de programme erroné, le commentaire ouvrant n'est jamais fermé
bonjour.c
int main (void)
{
/* afficher le mot bonjour et sauter une ligne
printf("bonjour !!!\n");
return 0;
}
> gcc -E bonjour.c > bonjour.i
bonjour.c:4: unterminated comment
>
Les erreurs de compilation sont bloquantes, mais pas les avertissements (warning). Lorsqu'on
compile avec gcc, les avertissements ne sont pas automatiquement affichés sur la console, ils
sont cependant très utiles car ils permettent de résoudre des bugs. Pour les afficher, il faut
utiliser l'option -Wall (W pour Warning).
Dans notre programme bonjour.c, si nous n'incluons pas le fichier qui contient le prototype
de la fonction printf, nous avons un warning qui est affiché :
> gcc -Wall bonjour.c
bonjour.c: In function `main':
bonjour.c:5: warning: implicit declaration of function `printf'
>
Publicité
Étape 2 : Compilation en langage assembleur
gcc -S bonjour.i
preprocessing
compiling
assembling
linking
bonjour.c
bonjour.i
bonjour.s
bonjour.o
a.out
Le code du langage C est transformé en code Assembleur. Il suffit de donner à gcc l'option -S
suivie du nom de fichier qui est issu du preprocessing pour obtenir la transformation en
langage assembleur. Un fichier bonjour.s est automatiquement produit, c'est un fichier texte
qui est lisible, mais difficilement compréhensible si on ne connaît pas l'assembleur.
bonjour.s
.file "bonjour.c"
gcc2_compiled.:
.section ".rodata"
.align 8
.LLC0:
.asciz "bonjour\n"
.section ".text"
.align 4
.global main
.type main,#function
.proc 04
main:
!#PROLOGUE# 0
save %sp, -112, %sp
!#PROLOGUE# 1
sethi %hi(.LLC0), %o1
or %o1, %lo(.LLC0), %o0
call printf, 0
nop
mov 0, %i0
b .LL2
nop
.LL2:
ret
restore
.LLfe1:
.size main,.LLfe1-main
.ident "GCC: (GNU) 2.95.2 19991024 (release)"
Étape 3 : transformation de l'assembleur en code machine
gcc -c bonjour.s
preprocessing
compiling
assembling
Publicité
linking
bonjour.c
bonjour.i
bonjour.s
bonjour.o
a.out
Le code assembleur qui est lisible est transformé en code machine binaire. Il suffit de donner
à gcc l'option -c suivie du nom du fichier qui contient le code assembleur pour obtenir un
fichier objet bonjour.o. Ce fichier binaire ne peut pas être directement édité et lu par un
humain. On peut le rendre lisible en utilisant une commande od -x bonjour.o.
La commande od pour octal dump lit le fichier binaire et affiche sur la sortie standard les
octets en hexadécimal avec l'option -x (base 16, on compte de 0 à 15, les lettre a, b, c, d, e et f
représentent 10, 11, 12, 13, 14, 15).
bonjour.o
> od -x bonjour.o
0000000 7f45 4c46 0102 0100 0000 0000 0000 0000
0000020 0001 0002 0000 0001 0000 0000 0000 0000
0000040 0000 01ac 0000 0000 0034 0000 0000 0028
0000060 0008 0001 002e 7368 7374 7274 6162 002e
0000100 7465 7874 002e 726f 6461 7461 002e 7379
0000120 6d74 6162 002e 7374 7274 6162 002e 7265
0000140 6c61 2e74 6578 7400 2e63 6f6d 6d65 6e74
0000160 0000 0000 9de3 bf90 1300 0000 9012 6000
0000200 4000 0000 0100 0000 b010 2000 1080 0002
0000220 0100 0000 81c7 e008 81e8 0000 0000 0000
0000240 626f 6e6a 6f75 720a 0000 0000 0000 0000
0000260 0000 0000 0000 0000 0000 0000 0000 0001
0000300 0000 0000 0000 0000 0400 fff1 0000 000b
0000320 0000 0000 0000 0000 0000 0002 0000 0000
0000340 0000 0000 0000 0000 0300 0002 0000 0000
0000360 0000 0000 0000 0000 0300 0003 0000 001a
0000400 0000 0000 0000 0000 1000 0000 0000 0021
0000420 0000 0000 0000 0028 1200 0002 0062 6f6e
0000440 6a6f 7572 2e63 0067 6363 325f 636f 6d70
0000460 696c 6564 2e00 7072 696e 7466 006d 6169
0000500 6e00 0000 0000 0004 0000 0409 0000 0000
0000520 0000 0008 0000 040c 0000 0000 0000 000c
0000540 0000 0507 0000 0000 0061 733a 2053 756e
0000560 2057 6f72 6b53 686f 7020 3620 3939 2f30
0000600 382f 3138 0a00 4743 433a 2028 474e 5529
0000620 2032 2e39 352e 3220 3139 3939 3130 3234
0000640 2028 7265 6c65 6173 6529 0000 0000 0000
0000660 0000 0000 0000 0000 0000 0000 0000 0000
0000720 0000 0000 0000 0001 0000 0003 0000 0000
0000740 0000 0000 0000 0034 0000 003d 0000 0000
0000760 0000 0000 0000 0001 0000 0000 0000 000b
0001000 0000 0001 0000 0006 0000 0000 0000 0074
0001020 0000 0028 0000 0000 0000 0000 0000 0004
0001040 0000 0000 0000 0011 0000 0001 0000 0002
Publicité
0001060 0000 0000 0000 00a0 0000 0009 0000 0000
0001100 0000 0000 0000 0008 0000 0000 0000 0019
0001120 0000 0002 0000 0002 0000 0000 0000 00ac
0001140 0000 0070 0000 0005 0000 0005 0000 0004
0001160 0000 0010 0000 0021 0000 0003 0000 0002
0001200 0000 0000 0000 011c 0000 0026 0000 0000
0001220 0000 0000 0000 0001 0000 0000 0000 0029
0001240 0000 0004 0000 0002 0000 0000 0000 0144
0001260 0000 0024 0000 0004 0000 0002 0000 0004
0001300 0000 000c 0000 0034 0000 0001 0000 0000
0001320 0000 0000 0000 0168 0000 0043 0000 0000
0001340 0000 0000 0000 0001 0000 0000
0001354
>
Étape 4 : édition des liens
gcc bonjour.o
preprocessing
compiling
assembling
linking
bonjour.c
bonjour.i
bonjour.s
bonjour.o
a.out
Le fichier bonjour.o produit par l'étape 3 est incomplet, il ne contient pas le code de la
fonction printf. En effet, ce code est dans une bibliothèque. Afin que le programme puisse
être compilé, nous avons inclus son prototype mais le code de la fonction n'est pas présent
dans bonjour.o.
L'édition des liens va réunir le fichier objet et les fonctions contenues dans les bibliothèques,
pour produire le programme complet : l'exécutable a.out dans notre exemple.
Un exécutable est spécifique à un système
Attention, la compilation produit un code spécifique pour l'ordinateur. Un exécutable d'un
ordinateur sous Linux ne pourra pas être exécuté sur une Sun sous Solaris. Il faudra
recompiler le programme pour pouvoir l'exécuter.
Vous avez un compte qui contient vos fichiers sources. Lorsque vous vous connectez sur un
PC sous Linux ou sur une station Sun sous Solaris, vous pouvez lire et modifier vos fichiers
textes. Si vous avez travaillé sur une Sun et que vous avez compilé un fichier, l'exécutable que
vous avez obtenu fonctionnera uniquement sur une des stations Sun. Si vous vous connectez
sur un PC sous Linux, il vous faudra recompiler votre programme afin de pouvoir l'exécuter.
Le programme a.out a été compilé sur un système différent de celui sur lequel on tente
l'exécution :
> ./a.out
> ./a.out: Exec format error. Binary file not executable.