La production de programmes exécutables sur un système d'exploitation passe par plusieurs étapes, et permet de transformer du code écrit dans un langage de haut niveau vers un programme écrit en code machine :
Saisie du programme dans le langage et enregistrement sur le disque : c'est le fichier source
Compilation avec le compilateur du langage (vérification syntaxique et lexicale) : on obtient le fichier objet
Edition de liens (résolution des références externes) : c'est le fichier exécutable
Lorsque l'utilisateur demande l'exécution de son programme, le fichier exécutable est alors monté en mémoire centrale : c'est l'étape de chargement. Le système alloue de la place mémoire pour placer le code et les données du programme. Nous préciserons dans la partie suivante du cours cette dernière étape.
Ces diverses manipulations sont inspirées des exercices donnés par Ivan Boule du CNAM, pour l'enseignement de la SMB137.
Soit le programme suivant écrit en langage C :
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int TAILLE_ALLOC = 1024*1024*1024;
// ======================A==========================
int calcul_trigo( int n)
{
int i, res = 0;
for(i=0; i<=n; i++)
res+=3*sin(i);
return res;
}
// ======================B==========================
int calcul_carre( int n)
{
int i, res = 0;
for(i=0; i<=n; i++)
res+=i*i;
return res;
}
// ======================C==========================
int main(int argn, char *argv[], char *env[])
{
int nb_pas;
int i;
char *zone;
for (i=0; env[i] != NULL; i++)
printf("VARIABLE ENVIRONNEMENT:%s\n", env[i]);
zone = (char *) malloc(TAILLE_ALLOC);
if (argn != 2){
printf("il faut 1 argument : le nb de pas de calcul\n");
exit (-2);
}
sscanf(argv[1], "%d", &nb_pas);
printf("\n\n\n\nnombre de pas = %d \n", nb_pas);
printf("somme trigo = %d\n", calcul_trigo(nb_pas));
printf("somme carre = %d\n", calcul_carre(nb_pas));
printf("Adresse de main = %09lx\n", main);
printf("Adresse de TAILLE_ALLOC = %09lx\n", &TAILLE_ALLOC);
printf("Adresse de nb_pas = %09lx\n", &nb_pas);
printf("Adresse de zone = %09lx\n", zone);
printf("Adresse de argv[1] = %09lx\n", argv[1]);
// ======================D==========================
sleep(5);
exit(nb_pas);
}
Ce programme contient quatres sections :
Les directives d'inclusion qui permettent d'utiliser des codes existants, contenus dans d'autres fichiers.
Les variables globales, visibles dans l'ensemble du programme
Les variables locales, visibles dans le corps du programme où elles sont définies
Les fonctions, unités d'exécution dans le langage C.
La compilation de ce programme est illustrée par la séquence de commandes suivante :
ikare@kaitan:exemples > ls -l total 2 -rw-r--r-- 1 ikare bsd 1393 Feb 18 11:31 exo1.cikare@kaitan:exemples > gcc -c exo1.c
ikare@kaitan:exemples > ls -l total 6 -rw-r--r-- 1 ikare bsd 1393 Feb 18 11:31 exo1.c -rw-r--r-- 1 ikare bsd 2088 Feb 22 15:23 exo1.o
![]()
Le fichier ainsi créé se compose des parties suivantes
Text : ensemble du code, instructions machines.
Data : données du programme.
Rodata : données en lecture seule (Read Only).
Symbol : table des symboles.
Comment : informations sur le compilateur
Chaque fichier objet (ou exécutable) possède une table décrivant les différents symboles qu'il contient. La commande nm [-options] [ref] ... permet de visualiser la table des symboles, en fournissant : son nom, sa valeur, sa classe et son type.
ikare@kaitan:exemples > nm exo1.o 00000000 D TAILLE_ALLOC00000060 T calcul_carre
00000000 T calcul_trigo U exit 000000a0 T main U malloc
U printf U puts U sin U sleep U sscanf
Certains symboles ne sont donc pas "résolus". Il s'agit dans notre cas de fonctions définies dans d'autres librairies.
L'édition de lien permet de constituer un fichier exécutable à partir de bibliothèques et de modules objets compilés séparément. L'éditeur de lien doit donc résoudre pour chacun des modules les références externes non résolues, en extrayant de bilbliothèques les modules correspondant à des fonctions effectivement utilisées.
Historiquement l'édition de lien se faisait de manière statique : chaque code d'une fonction utilisée est recopié dans le fichier binaire. L'exécutable est alors autonome, mais si plusieurs programmes utilisent la même fonction, cette portion de code sera alors autant de fois chargée en mémoire centrale. De plus, la taille de l'exécutable augemente en conséquence. Le changement de version de bibliothèque ne se fera également pas sans souci.
Dans le cas de l'édition de liens dynamique, les références à résoudre vont contenir des informations sur les objets partagés (fichiers .so sous BSD), qui seront chargés si nécessaire à l'exécution du progamme.
ikare@kaitan:exemples > gcc -static exo1.c -lm -o staticikare@kaitan:exemples > gcc exo1.c -lm -o dynamic
ikare@kaitan:exemples > ls -lh total 300 -rwxr-xr-x 1 ikare bsd 5.9K Feb 22 16:40 dynamic
-rw-r--r-- 1 ikare bsd 1.4K Feb 18 11:31 exo1.c -rw-r--r-- 1 ikare bsd 2.0K Feb 22 15:23 exo1.o -rwxr-xr-x 1 ikare bsd 265K Feb 22 16:40 static
ikare@kaitan:exemples > nm dynamic 08049978 D TAILLE_ALLOC 08049980 D _DYNAMIC 08049a4c D _GLOBAL_OFFSET_TABLE_ w _Jv_RegisterClasses 08049a3c d __CTOR_END__ 08049a38 d __CTOR_LIST__ 08049a44 d __DTOR_END__ 08049a40 d __DTOR_LIST__ 0804997c r __FRAME_END__ 08049a48 d __JCR_END__ 08049a48 d __JCR_LIST__ 08049a7c A __bss_start 08048730 t __do_global_ctors_aux 080484c0 t __do_global_dtors_aux 08049970 D __dso_handle 0804996c D __progname 08049a7c A _edata 08049a84 A _end 0804875c T _fini 08048374 T _init U _init_tls@@FBSD_1.0 08048430 T _start 0804810c r abitag U atexit@@FBSD_1.0 08048580 T calcul_carre 08048520 T calcul_trigo 08049a7c b completed.4970 08049a80 B environ U exit@@FBSD_1.0 080484f0 t frame_dummy 080485c0 T main U malloc@@FBSD_1.0 08049974 d p.4968 U printf@@FBSD_1.0
U puts@@FBSD_1.0 U sin@@FBSD_1.0 U sleep@@FBSD_1.0 U sscanf@@FBSD_1.0
1. Edition de lien en statique | |
2. Edition de lien en dynamique | |
3. Fichier exécutable (x) de taille 5.6Ko | |
4. Fichier exécutable (x) de taille 256Ko | |
5. Le lien dynamique |
Le fichier exécutable est maintenant créé. Pour le lancer il suffit sous Unix de faire la commande ./dynamic 4, ce qui donne le résultat suivant :
VARIABLE ENVIRONNEMENT:TERM=rxvt VARIABLE ENVIRONNEMENT:COLORTERM=rxvt-xpm VARIABLE ENVIRONNEMENT:WINDOWID=44040196 VARIABLE ENVIRONNEMENT:DISPLAY=:0.0 VARIABLE ENVIRONNEMENT:COLORFGBG=15;0 VARIABLE ENVIRONNEMENT:SSH_AGENT_PID=1474 VARIABLE ENVIRONNEMENT:SSH_AUTH_SOCK=/tmp/ssh-3Vpzd7LUzB/agent.1457 VARIABLE ENVIRONNEMENT:USER=ikare VARIABLE ENVIRONNEMENT:MACHTYPE=i386 VARIABLE ENVIRONNEMENT:MAIL=/var/mail/ikare VARIABLE ENVIRONNEMENT:VENDOR=intel VARIABLE ENVIRONNEMENT:SHLVL=3 VARIABLE ENVIRONNEMENT:HOME=/home/ikare VARIABLE ENVIRONNEMENT:TEXEDIT=emacs VARIABLE ENVIRONNEMENT:PAGER=more VARIABLE ENVIRONNEMENT:LC_CTYPE=fr_FR.ISO8859-15 VARIABLE ENVIRONNEMENT:SSH_ASKPASS=/usr/local/bin/ssh-askpass VARIABLE ENVIRONNEMENT:GROUP=bsd VARIABLE ENVIRONNEMENT:MM_CHARSET=ISO-8859-15 VARIABLE ENVIRONNEMENT:LOGNAME=ikare VARIABLE ENVIRONNEMENT:MOZILLA_HOME=/usr/local/bin/firefox3 VARIABLE ENVIRONNEMENT:RSYNC_RSH=/usr/bin/ssh VARIABLE ENVIRONNEMENT:PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:/home/ikare/bin VARIABLE ENVIRONNEMENT:LANG=fr_FR.ISO-8859-15 VARIABLE ENVIRONNEMENT:SHELL=/bin/tcsh VARIABLE ENVIRONNEMENT:HOST=kaitan.fremens VARIABLE ENVIRONNEMENT:CPUTYPE=k7 VARIABLE ENVIRONNEMENT:OSTYPE=FreeBSD VARIABLE ENVIRONNEMENT:PWD=/home/ikare/data/travail/Cours/Cnam/SMB137/Cours/Chapitre1/exemples VARIABLE ENVIRONNEMENT:LC_ALL=en_US.ISO8859-1 VARIABLE ENVIRONNEMENT:HOSTTYPE=FreeBSD VARIABLE ENVIRONNEMENT:EDITOR=vi nombre de pas = 4 somme trigo = 1 somme carre = 30 Adresse de main = 0080485c0 Adresse de TAILLE_ALLOC = 008049978 Adresse de nb_pas = 0bfbfe938 Adresse de zone = 028300000 Adresse de argv[1] = 0bfbfebf6
Le programme a simplement affiché les variables d'environnement de son contexte, et exécuté les deux fonctions. Pour son exécution, le système a chargé son code en mémoire, et exécuté les instructions sur le processeur, en mettant à jour les différents registres et le compteur ordinal.
Quelques petits exercices pour revoir les commandes shells et un petit peu de programmation. Vous pouvez consulter les cours disponibles sur www.kurzweg.info.
Soit un fichier
ficcontenant 12 lignes. Donnez la commande composée permettant d'afficher les lignes de 5 à 9.Utilisez la commande find pour supprimer dans votre répertoire de domiciliation (
$HOME) tous les fichiers dont le nom estcore.Ecrivez en C un programme affichant la liste des nombres entiers premiers (divisibles uniquement par 1 et par eux-mêmes).

ikare@kaitan:exemples > gcc -c exo1.c
ikare@kaitan:exemples > ls -l
total 6
-rw-r--r-- 1 ikare bsd 1393 Feb 18 11:31 exo1.c
-rw-r--r-- 1 ikare bsd 2088 Feb 22 15:23 exo1.o
ikare@kaitan:exemples > nm dynamic
08049978 D TAILLE_ALLOC
08049980 D _DYNAMIC
08049a4c D _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
08049a3c d __CTOR_END__
08049a38 d __CTOR_LIST__
08049a44 d __DTOR_END__
08049a40 d __DTOR_LIST__
0804997c r __FRAME_END__
08049a48 d __JCR_END__
08049a48 d __JCR_LIST__
08049a7c A __bss_start
08048730 t __do_global_ctors_aux
080484c0 t __do_global_dtors_aux
08049970 D __dso_handle
0804996c D __progname
08049a7c A _edata
08049a84 A _end
0804875c T _fini
08048374 T _init
U _init_tls@@FBSD_1.0
08048430 T _start
0804810c r abitag
U atexit@@FBSD_1.0
08048580 T calcul_carre
08048520 T calcul_trigo
08049a7c b completed.4970
08049a80 B environ
U exit@@FBSD_1.0
080484f0 t frame_dummy
080485c0 T main
U malloc@@FBSD_1.0
08049974 d p.4968
U printf@@FBSD_1.0
U puts@@FBSD_1.0
U sin@@FBSD_1.0
U sleep@@FBSD_1.0
U sscanf@@FBSD_1.0