Cours de Compilation
Maîtrise d'Informatique
Paris VII
Paris VII
Roberto Di Cosmo
PPS
Université de Paris VII
Paris
e-mail: roberto@dicosmo.org
WWW: http://www.dicosmo.org~dicosmo
PPS
Université de Paris VII
Paris
e-mail: roberto@dicosmo.org
WWW: http://www.dicosmo.org~dicosmo
Généralités
Le terme
compilation :
compilateur''</FONT></DIV><FONT SIZE=5>
</FONT><DL COMPACT=compact>
<DT><FONT SIZE=5>
</FONT><FONT SIZE=5>compilateur</FONT><DD><FONT SIZE=5>: </FONT><FONT SIZE=5><EM>
Personne qui reunit des documents dispersés'' (Le Petit Robert)Rassemblement de documents''</EM></FONT><FONT SIZE=5> (Le Petit Robert)<BR></FONT></DL><FONT SIZE=5>Mais le programme qui
reunit des bouts de code dispersés'' s'appelle aujourd'hui un Editeur de Liens,
et l'on appelle ``compilateur'' une autre chose:com·pil·er (Webster)1: one that compiles 2:
a computer program that translates an entire set of instructions written in a higher-level symbolic language (as COBOL) into machine language before the instructions can be executed
Notions (abstraites) de base
- les machines virtuelles
-
une machine
virtuelle'' est une machine qui reconnait un certain nombre d'instructions qui ne sont pas forcément
native'' pour la machine hardware.
Ex: le compilateur C produit du code assembleur qui suppose l'existence d'un ensemble de fonctions système (ex.: les E/S). Donc il produit du code pour la machine virtuelle définie par les instructions hardware, plus les appels système.
On rencontre souvent les machines virtuelles suivantes-
programmes d'application
- Langage de programmation evolué
- Langage d'assemblage
- Noyau du système d'exploitation
- Langage machine
-
programmes d'application
Qu'est-ce qu'un interpreteur?
-
C'est un programme qui prend en entrée un autre programme, écrit pour une
quelque machine virtuelle, et l'execute sans le traduire.
- l'interpréteur VisualBasic,
- le toplevel Ocaml,
- l'interpreteur PERL,
- etc.
Qu'est-ce qu'un compilateur?
-
C'est un traducteur, en général d'un langage évolué vers un langage moins expressif.
Quelques exemples:- Compilation des expressions régulières (utilisées dans le shell Unix, les outils sed, awk, l'éditeur Emacs et les bibliothèques des langages C, Perl et Ocaml)
- Minimisation des automates (compilation d'un automate vers un automate plus efficace)
- De LaTex vers Postscript ou HTML (latex2html/Hevea)
- De C vers l'assembleur x86 plus les appels de système Unix/Linux
- De C vers l'assembleur x86 plus les appels de système Win32
La décompilation: on va dans le sens inverse, d'un langage moins structuré vers un langage évolué. Ex: retrouver le source C à partir d'un code compilé (d'un programme C). Applications: piratage, récupération de vieux logiciels.
On peut ``compiler'' vers une machine... interpretée (ex: bytecode Java, bytecode Ocaml)
Notions (abstraites) de base, II
Il ne faut pas tricher... un compilateur ne doit pas faire de l'interprétation...
Pourtant, dans certains cas, il est inevitable de retrouver du code interprété dans le code compilé
-
printf("I vaut %d\n",i);
serait à la limite compilable
s="I vaut %d\n"; printf(s,i);
est plus dur
- alors que
void error(char *s) { printf(s,i);}
devient infaisable
Structure logique d'un compilateur
-
analyse lexicale (flot de lexemes)
théorie: langages réguliers
outils: automates finis
logiciels: Lex (et similaires)
- analyse syntaxique (flot de reductions)
théorie: langages algébriques
outils: automates à pile
logiciels: Yacc (et similaires)
Structure logique d'un compilateur (suite)
-
actions sémantiques (contruction de l'arbre de syntaxe abstrait)
outils: grammaires attribuées
logiciels: encore Yacc
- analyse sémantique (coherence sémantique: vérification de types, d'usage après définition,
mise en place des tables des symboles, gestion des environnements etc.) rend l'arbre
de syntaxe abstraite décoré et les tables
outils: on peut utiliser des gramamires attribuées, ou à la main
- traduction en code intermédiaire (souvent un arbre, independant de l'architecture cible)
- linéarisation du code (transformation en liste d'instructions du code intermediaire)
- séléction d'instructions (passage du code intermédiaire à l'assembleur de la machine cible, eventuellement abstrait par rapport aux noms des registres)
Structure logique d'un compilateur: suite
-
diffèrentes optimisations
- analyse de vie des variables et allocation des registres
- optimisation des boucles (déplacement des invariants, transformations affines)
- function inlining
- depliement des boucles
- etc.
- émission du code (production d'un fichier écrit dans l'assembleur de la machine cible)
- assemblage (production de fichiers contenant le code machine)
- édition des liens (production d'un seul fichier executable)
Les phases cachées d'un compilateur: l'apparence
ranger> cat callfact.cinclude <stdio.h>
int fact(int i)
if (i==0) return(1); else return(i*fact(i-1));;main()
printf ("%d",fact(3)); return(0);
ranger> gcc -o callfact callfact.c ranger> ls -l callfact -rwxr-xr-x 1 dicosmo 50784 Oct 5 15:43 callfact -rw-r--r-- 1 dicosmo 139 Oct 5 15:42 callfact.c
Les phases cachées d'un compilateur: la réalité
ranger> gcc -o callfact -v -save-temps callfact.c Reading specs from /lib/i386/specs NeXT Computer, Inc. version cc-437.2.6, gcc version 2.5.8 /lib/i386/cpp-precomp ... callfact.c callfact.i NeXT DevKit-based CPP 3.1 /lib/i386/cc1obj callfact.i -o callfact.s GNU Objective-C version 2.5.8 (80386, BSD syntax) compiled by GNU C version 2.5.8. /lib/i386/as -arch i386 -o callfact-callfact.o callfact.s ld -o callfact -lcrt0.o -L/lib/i386 callfact-callfact.o -lsys_sranger> ls -l callfact -rwxr-xr-x 1 dicosmo 50784 Oct 5 15:43 callfact -rw-r--r-- 1 dicosmo 139 Oct 5 15:42 callfact.c -rw-r--r-- 1 dicosmo 4524 Oct 5 15:48 callfact.i -rw-r--r-- 1 dicosmo 634 Oct 5 15:48 callfact.s
4 étapes:
- preprocesseur: cpp traduit callfact.c en callfact.i
- compilateur: cc1obj traduit callfact.i en callfact.s
- assembleur: as traduit callfact.s en callfact-callfact.o
- éditeur de liens: ld transforme callfact-callfact.o en executable, en résolvant les liens externes
Un exemple simple
Produit:include <stdio.h>
main ()
int i=0; int j=0; for (i=0;i<10;i++) j=6*i; ; printf("Resultat: %d", j); exit(0);
ranger> gcc -o callfact -v -save-temps simplaffine.c
Un exemple simple: preprocesseur
1 "simpleaffine.c"
1 "/NextDeveloper/Headers/ansi/stdio.h" 1
... extern int printf ( const char * format , ... ) ; ...
1 "simpleaffine.c" 2
main ( )
int i = 0 ; int j = 0 ; for ( i = 0 ; i < 10 ; i ++ ) j = 6 * i ; ; printf ( "Resultat: %d" , j ) ; exit ( 0 ) ;
Un exemple simple: compilation vers assembleur
.cstring LC0: .ascii "Resultat: %d" .text .align 2,0x90 .globl main main: pushl %ebp movl %esp,%ebp subl $8,%esp pushl %ebx movl $0,-4(%ebp) movl $0,-8(%ebp) movl $0,-4(%ebp) L2: cmpl $9,-4(%ebp) jg L3 movl -4(%ebp),%eax movl %eax,%ecx movl %ecx,%edx addl %ecx,%edx addl %eax,%edx movl %edx,%eax addl %edx,%eax movl %eax,-8(%ebp) L4: incl -4(%ebp) jmp L2 .align 2,0x90
Un exemple simple: suite
L3: movl -8(%ebp),%ebx pushl %ebx pushl $LC0 call printf addl $8,%esp pushl $0 call exit addl $4,%esp .align 2,0x90 L1: movl -12(%ebp),%ebx movl %ebp,%esp popl %ebp ret
Notez bien que l'execution de printf est interpretee
Un exemple simple: optimisations I
Le compilateur arrive a faire tenire tout dans des registres, et trouve une façon plus efficace pour multiplier par 6.
.cstring LC0: .ascii "Resultat: %d" .text .align 2,0x90 .globl main main: pushl %ebp movl %esp,%ebp xorl %edx,%edx .align 2,0x90 L5: leal (%edx,%edx,2),%eax addl %eax,%eax incl %edx cmpl $9,%edx jle L5 pushl %eax pushl $LC0 call printf pushl $0 call exit .align 2,0x90
Un exemple simple: optimisations II
Le compilateur decouvre que j est une fonction affine de i.
.cstring LC0: .ascii "Resultat: %d" .text .align 2,0x90 .globl main main: pushl %ebp movl %esp,%ebp xorl %eax,%eax xorl %ecx,%ecx .align 2,0x90 L5: movl %ecx,%edx leal 6(%edx),%ecx incl %eax cmpl $9,%eax jle L5 pushl %edx pushl $LC0 call printf pushl $0 call exit .align 2,0x90
Organisation du cours
- analyse lexicale, usage de (Ocaml)Lex
- analyse syntaxique, usage de (Ocaml)Yacc
- generation de l'arbre de syntaxe abstraite
- analyse semantique
- blocs d'activation pour fonctions/variables locales
- traduction en code intermediaire
- optimisations
- emission de code
Détails pratiques
- TD
- : Antonio Bucciarelli, buccia@pps.jussieu.fr
- Contrôle continu
- : partiel sous forme de projet à rendre pour le 15 decembre
- Langage utilisé
- : Ocaml 2.04 ou plus recent (disponible librement par ftp depuis l'Inria ftp.inria.fr)
- Machine cible
- : à decider, soit le 486, utilisé en mode RISC, soit un emulateur MIPS;
ce choix n'est pas essentiel pour la première partie du cours.
Bibliographie
- Modern Compiler Implementation in ML, Andrew W. Appel, Cambridge University Press, 1998 (disponible en bibliotheque)
- Notes de cours: Compilers: Principles, Techniques, and Tools, Addison-Wesley, Reading, Mass. 1986
- Manuel Ocaml en ligne.
- Livre "Développement d'applications avec Objective Caml" sur Ocaml: (disponible en bibliotheque)
This document was translated from LATEX by HEVEA et modifié à la main.