2 Compilation en plusieurs phases
C est un langage compilé. Cela signifie qu'un programme C est décrit
par un fichier texte appelé fichier source. Ce fichier n'est pas
exécutable par le microprocesseur, il faut le traduire en langage
machine. Cette opération est effectuée par un programme appelé
compilateur.
La compilation d'un programme C se décompose en 4 phases successives :
-
Le traitement par le préprocesseur : le fichier source
est analysé par un programme appelé préprocesseur qui effectue des
transformations purement textuelles (remplacement de chaînes de
caractères, inclusion d'autres fichiers source, etc.).
- La compilation : au cours de cette étape, le fichier
engendré par le préprocesseur est traduit en assembleur, c'est Ã
dire en une suite d'instructions qui sont chacunes associées à une
fonctionnalité du microprocesseur (faire une addition, une
comparaison, etc.).
- L'assemblage : cette opération transforme le code
assembleur en un fichier binaire, c'est-Ã -dire en instructions
directement compréhensibles par le processeur. Le fichier produit
par l'assemblage est appelé fichier objet .o).
- L'édition de liens : un programme est souvent séparé en
plusieurs fichiers source (ceci permet d'utiliser des librairies
de fonctions standard déjà écrites comme les fonctions d'affichage
par exemple). Une fois le code source assemblé, il faut donc lier
entre eux les différents fichiers objets. L'édition de liens
produit alors un fichier exécutable.
La commande gcc invoque tour à tour ces différentes phases.
Des options de gcc permettent de stopper le processus de
compilation après chaque des phases.
Nous allons illustrer cela sur le programme suivant
(phases.c) :
/* ------------------------------
Mon premier programme
------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#define MAX 12
int foo = 3;
const int bar = 5;
extern int gee;
int
main()
{
int bzu; /* declaration et definition de bzu */
bzu = MAX;
printf("Hello : %d\n", foo + bar + gee + bzu);
exit(EXIT_SUCCESS);
}
Préprocessing
Exercice 3
Vérifiez dans la page de manuel de gcc le sens de
l'option -E.
Exercice 4
Produisez le résultat du prétraitement par le préprocesseur sur le
programme phases.c dans un fichier phases.i.
Reportez vous éventuellement au TP précédent pour vous remémorer
l'utilisation des redirections des entrées/sorties des commandes.
Exercice 5
Comparez le contenu des fichiers phases.c et
phases.i. En particulier
-
Combien de lignes comporte chacun des fichiers
phases.c et phases.i ?
- Qu'est devenu la ligne
#include <stdio.h>
- Que sont devenus les commentaires ?
- Quel traitement a été réalisé sur la ligne
bzu = MAX;
Vous pouvez vérifiez cela en invoquant la commande « Macro
expand region » (C-c C-e) du menu C d'emacs
sur cette ligne.
Génération de code assembleur
Exercice 6
Vérifiez dans la page de manuel de gcc le sens de
l'option -S et produisez le code assembleur correspondant
à phases.c.
Exercice 7
Dans ce code assembleur, identifiez les différentes sections
.data, .rodata, et .text.
-
Quels symboles sont associés à la section .data ?
À quoi correspond cette section ?
Vérifiez en ajoutant une déclaration au programme
phases.c.
- Quels symboles et valeurs sont associés à la section
.rodata ? À quoi correspond cette section ?
Vérifiez en modifiant phases.c pour ajouter un
élément à cette section.
- Quel est le point d'entrée de ce programme ?
Référez vous éventuellement à vos manipulations de l'assembleur
gas vu dans l'UE « Architecture
élémentaire des ordinateurs (info 202) ».
Génération du fichier objet
Exercice 8
Trouvez comment indiquer à gcc de générer le fichier
objet phases.o à partir de phases.c.
Exercice 9
Comparer les résultats de la commande nm sur ce fichier
.o avec ce que vous aviez identifié comme section dans le
code assembleur.
Exercice 10
-
Qu'indique nm pour les symboles printf,
exit, et gee ?
- Où ces symboles sont-ils définis ? Quel programme est en
charge de rechercher ces symboles ?
- Qu'est ce qui change dans le résultat de nm si on
supprime l'utilisation de gee dans l'instruction
printf du fichier phases.c ?
Exercice 11
Comment expliquez vous le résultat de la commande strings
sur ce fichier .o ?
En conclusion
Ces manipulations vous ont permis d'aborder le processus de
compilation d'un programme C.
Ces manipulations sont représentatives de l'activité d'un programmeur
:
-
allers et retours entre un éditeur de textes et un shell ;
- consultation de pages de manuel ;
- consultation de documentation (web...).
Soyez à l'aise et efficaces avec vos outils !
Concernant les différentes phases de compilation :
-
bien souvent on se contente d'appeler gcc qui
enchaîne automatiquement toutes les phases de compilation jusqu'Ã
produire un fichier exécutable ;
- on vérifie parfois le résultat fourni par le préprocesseur
quand on a un doute sur une ligne de code comportant de nombreuses
substitutions de macros ;
- la génération de code assembleur est parfois utilisée pour
comparer le code généré et donc l'efficacité de deux versions de
code C ;
- la production de fichiers objets est, quand à elle, très
courante et forme la base de la compilation séparée. Nous y
reviendrons.