Langage C et algorithmique
© Magali Contensin ;
2002 - 2004
 

Environnement de programmation

Compilation : gcc

Produire un exécutable

Prenons un fichier bonjour.c qui contient un programme C très simple. Pour que l'ordinateur puisse exécuter ce programme, on utilise une application gratuite nommée gcc, cette application ou compilateur va produire un exécutable.

fichierbonjour.c
 
#include <stdio.h>

int main (void)
{

  /* afficher le mot bonjour et sauter une ligne */
  printf("bonjour !!!\n");

  return 0;
}

Par défaut, lorsqu'on demande à gcc de compiler un fichier, il produit en sortie un exécutable nommé a.out.

> ls
bonjour.c
> gcc bonjour.c
> ls
a.out  bonjour.c
>

Exécuter

Lorsqu'on tape gcc sur une ligne de la console, l'application gcc est exécutée. Donc, pour que l'ordinateur exécute le programme que vous venez de compiler, il suffit de donner le nom de votre application sur la ligne de commande, précédé d'un ./ pour indiquer que c'est dans le répertoire courant que cet exécutable se trouve.
> a.out: Command not found.
> ./a.out
bonjour !!!
>

Nommer un exécutable

Si on compile plusieurs programmes, le a.out sera celui du dernier programme compilé, de plus le nom de l'exécutable n'est pas très explicite, l'option -o de gcc permet de nommer l'exécutable. Le o signifiant output (sortie).
> ls
bonjour.c
> gcc bonjour.c -o appli_bonjour
> ls
appli_bonjour  bonjour.c
> ./appli_bonjour
bonjour !!!
>

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
fichier fleche fichier fleche fichier fleche fichier fleche fichier
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).

fichierbonjour.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
fichier fleche fichier fleche fichier fleche fichier fleche fichier
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 :

Le fichier qui est produit est un fichier texte en langage C qui est lisible. Voici le fichier obtenu pour notre programme bonjour.c

fichierbonjour.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 :

fichierbonjour.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é

fichierbonjour.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'
>

Étape 2 : Compilation en langage assembleur

gcc -S bonjour.i
preprocessing compiling assembling linking
fichier fleche fichier fleche fichier fleche fichier fleche fichier
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.

fichierbonjour.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 linking
fichier fleche fichier fleche fichier fleche fichier fleche fichier
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).

fichierbonjour.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
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
fichier fleche fichier fleche fichier fleche fichier fleche fichier
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.
haut
css html