Cours Architecture des Systèmes Informatiques Jean-Jacques Girardot girardot@emse.fr http://kiwi.emse.fr/ASI Quatrième séance Introduction à la Compilation
Plan Concepts des processeurs : la pile Le simulateur pédagogique, suite… Langage machine, langage d’assemblage Compilation et génération de code Expressions arithmétiques, boucles, sous-programmes Module objet, exécutable Allocation des variables Statique, automatique, dynamique Utilisation de la pile Notion de cadre
Terminologie Source (code, programme) : texte rédigé par le programmeur dans un langage de programmation “évolué” Objet (code, programme) : traduction en langage de la machine d’un texte source Exécutable : programme obtenu en assemblant un programme objet et l’ensemble des sous-programmes nécessaires à son exécution Assembleur : génère du code objet à partir d’un programme en langage d’assemblage (source) Compilateur : génère du code objet à partir d’un programme source en langage de haut niveau (Pascal, C…) Éditeur de liens : rassemble des modules objets pour constituer un programme exécutable Chargeur : installe en mémoire centrale un programme en vue de son exécution
La pile du processeur Qu’est-ce, à quoi sert-elle ? Portion de la mémoire centrale Référencée par un registre spécifique, le “pointeur de pile”, stack pointer “Empiler” une valeur : a: déplacer le pointeur de pile de ± un mot b: écrire la valeur dans le mot désigné par le pointeur de pile Note: certaines machines font b, puis a… “Dépiler” une valeur : effectuer les opérations inverses : b: lire le mot pointé par le registre de pile a: déplacer le pointeur de pile en sens inverse
La pile : outil des sous-programmes Gestion des appels et retour de sous-programmes 2 instructions : Appel de sous-programme : Empiler la valeur du pointeur programme (PC) Se brancher à l’adresse du sous-programme Retour de sous-programme : Dépiler une valeur [le pointeur programme sauvegardé avant l’appel] Affecter cette valeur au pointeur programme
La machine mac : opérations sur la pile Tout registre peut servir de pointeur de pile Empiler : PUSH, 0x0D Rx <- [Rx] - 2 MemW[[Rx]] <- valeur Formats : court/long, immédiat/direct/indirect-indexé Dépiler : POP, 0x0E destination <- MemW[[Rx]] Rx <- [Rx] + 2 Formats : court/long, direct/indirect-indexé [pas de mode immédiat]
La machine mac : appels et retour de sous-programme Appel : JSR, Jump to SubRoutine, 0x0C Rx <- [Rx] - 2 MemW[[Rx]] <- PC PC <- adresse-du-sous-programme Formats : pas de mode court immédiat Retour : RET, Return, 0x1C PC <- MemW[[Rx]] Rx <- [Rx] + 2 Format : court immédiat : 0 00 11100 xxxx 0000
La machine mac : autres opérations Appel du superviseur : TRAP, 0x1A Format court immédiat : 0 00 11010 xxxx yyyy Appel niveau X, sous-niveau Y. c.f. manuel pour les différentes fonctions… Opération ineffective : NOP, No OPération, 0x1B Format court immédiat : 0 00 11011 0000 0000 Ne modifie ni la mémoire, ni les registres Arrêt : HALT, 0x1E Format court immédiat : 0 00 11110 0000 0000 Arrêt du calculateur, lève l’exception ErrHalt
Le simulateur sim Modèle logiciel de la machine mac Émulateur de la machine virtuelle : Simule registres et mémoire centrale Interprète les codes instructions Gère les erreurs/exceptions Metteur au point Visualise et modifie mémoire et registres Lance et interrompt la machine virtuelle Trace les instructions Visualise les registres modifiés en cours d’exécution
Les commandes du simulateur Syntaxe des commandes Mot clef: /xxx suivi de compléments éventuels Ex : /R2 impression du contenu du registre R2 /PSW impression des drapeaux et de PC /run 2FC0 exécuter le programme débutant en 0x2FC0 /dm 1000 20 imprimer le contenu de la zone de mémoire de 32 octets débutant en 4096 /R2=237 affectation de la valeur 567 à R2 c.f. manuel pour l’ensemble des commandes
Exemples Placer la valeur 3 dans le registre R5 Note : constantes en hexadécimal… Écrire un programme qui place 3 dans R5 ld r5,#3 code : 0 00 00001 0101 0011 Placer l'instruction en mémoire, par exemple en 0 /addr 0 /sw 0153 Exécuter l'instruction /step 0 Vérifier /r5
Exemple d'utilisation : calcul du PGCD de deux nombres Programme chargé à l'adresse 1000 TEST: CMP R2,R3 1000 2523 JEQ FIN 1002 8F10 1016 JL SUITE 1006 8F40 1010 LD R0,R3 100A 2103 LD R3,R2 100C 2132 LD R2,R0 100E 2120 SUITE: SUB R3,R2 1010 2432 JMP TEST 1012 8F00 1000 FIN: HALT 1016 1E00
Exemple d'utilisation : calcul du PGCD de deux nombres Mise en mémoire du programme /addr 1000 /sw 2523 8f10 1016 8f40 1010 /sw 2103 2132 2120 2432 8f00 1000 1e00 Positionnement des registres /r2=+7953 /r3=+12291 Lancement de l'exécution /run 1000 réponse : psw = 0502 1018 Consultation du résultat /r2 réponse : r2 = 0x02D3 723/723 2,-45 ‘ ‘
Tests sous sim Créer sous un éditeur le fichier de commandes Utilisation directe du simulateur sim < pgcd.sim Utilisation interactive sim /rd "pgcd.sim" /run 0 Mise au point /db 1 : trace des registres modifiés /db 2 : trace des instructions
Langage d’assemblage Représentation symbolique des instructions Syntaxe : [étiquette:] opération [opérandes] Symboles : registres, ex : R1, R2, R15, étiquettes, variables… opérations LD, ADD, SUB, ST… nombres (décimal, hexadécimal, octal, binaire, caractère) Sémantique : combinaison code opération et des opérandes Une instruction assembleur = une instruction machine
Assembleur Outil permettant le passage du langage d’assemblage au langage machine ; “machine dependent” Instructions Commentaires Directives ou “pseudo-instructions” DATA, ORG, BSS, START… Fournit : Binaire “absolu”/“core image”/“exécutable” ; ex l’assembleur ASM Binaire “translatable”, ou programme objet.
L'assembleur asm Programme réalisant la transformation d'instructions exprimées en assembleur en code chargeable par le simulateur Syntaxe Toutes les instructions de la machine (c.f. manuel) Commentaires : * … Directives : ORG : nouvelle adresse d'implantation des instructions suivantes BSS : réservation d'une zone de mémoire DATA : création d'une donnée initialisée occupant un mot START : définition de l'adresse de début du programme
Transformation de PGCD en un programme assembleur ORG 0x1000 PGCD: CMP R2,R3 JEQ FIN JLT SUITE LD R0,R3 LD R3,R2 LD R2,R0 SUITE: SUB R3,R2 JMP PGCD FIN: RET R15 MAIN: LA.L R15,PILE LD.L R2,#1144 LD.L R3,#858 JSR R15,PGCD LD.L R3,#1287 HALT BSS 16 PILE: DATA 0 START MAIN
Le code généré et l’exécution /addr 1000 /w 2523 8f10 1016 8f40 1010 2103 2132 2120 /w 2432 8f00 1000 1cf0 abf0 1042 8120 0478 /w 8130 035a 8cf0 1000 8130 0507 8cf0 1000 /w 1e00 /addr 1042 /w 0000 /run 1018 /rd “pgcd.sim” /run 1018 psw = 0501 1032 /r2 r2 = 0x008f 143/143 0,-113 ‘ ‘
Langages de “haut niveau” Langages compilés Un outil (compilateur) transforme le programme source en un programme objet, ou un programme “core image” Exemples : C, C++, Pascal, FORTRAN, ADA, COBOL, etc. Langage interprété Un outil (interprète) lit le programme source et (après transformations diverses) l’exécute directement. Exemples : APL, LISP, Perl, CAML, etc. Approches intermédiaires - ex: SIM Source ® code machine virtuelle, interprétation du code
Étapes de l’exécution d’un programme Compilation : traduction d’un langage source vers un langage objet Assemblage : traduction d’un programme source en assembleur vers un langage objet Édition de liens : création d’un programme exécutable, rassemblant des modules objets et les sous-programmes de bibliothèque nécessaires à l’exécution Exécution : chargement en mémoire centrale du programme exécutable ; le “chargeur” lui “donne la main”
Compilateur Lit un programme en un langage dit “de haut niveau” C, C++, Pascal, Fortran, Ada : langage source Convertit les instructions du programme en commandes pour la machine : langage machine, dit langage cible A une instruction du langage source correspondent en général plusieurs instructions du langage cible.
Module objet Résultat d’une compilation ou d’un assemblage Structure de données segments de code machine valeurs d’initialisation données liste des “externes” et “points d’entrée” informations de contrôle / mise au point Format d’entrée pour l’éditeur de liens
Module exécutable Résultat d’une édition de liens Structure de données segments de code machine valeurs d’initialisation des données liste des “externes” et “points d’entrée” les externes sont “résolus” informations de contrôle / mise au point Format d’entrée du chargeur Peut contenir des “externes” non résolus chargement dynamique
Traduction Comment réalise-t-on sur la machine la représentation des éléments du langage source ? Variables TP 4 variables globales statiques, variables locales automatiques Sous-programmes Représentation Appel et retour.
Un langage et son compilateur : mcc mcc : “mini C compiler” Sous-ensemble du langage C type de données unique : entier 16 bits pas de structures de données Compilateur minimal pas de pré processeur pas d'optimisation du code généré fournit de l'assembleur en format source Utilisation compilation => assemblage => simulation
Compilation - 1 Expressions arithmétiques int a,b,c; a = 2; b = 5; c = (a+3)*(b-1); ld r2,#2 st.l r2,@a ld r2,#5 st.l r2,@b ld.l r2,@a add r2,#3 ld.l r3,@b sub r3,#1 ld r0,r2 mul r3 ld r2,r1 st.l r2,@c ... @a: data 0 @b: data 0 @c: data 0
Compilation - 2 Boucles int i; i=0; while (i<10) i=i+1; ld r2,#0 st.l r2,@i @1002: ld.l r2,@i ld r3,#10 cmp r2,r3 jlt @1004 jmp @1005 @1004: ld r2,#1 @1005: jeq.l @1003 ld.l r2,@i add r2,#1 st.l r2,@i jmp @1002 @1003: ... @i: data 0
Un exemple : PGCD de 2 nombres Le programme C int x, y, z; main() { x = 7953; y = 12291; while (x != y) if (x > y) { z=x; x=y; y=z; } y = y-x; } // out (x);
Le code assembleur (presque complet) @main: ld.l r2,#7953 st.l r2,@x ld.l r2,#12291 st.l r2,@y @1003: ld.l r2,@x ld.l r3,@y cmp r2,r3 jne @1005 ld r2,#0 jmp @1006 @1005: ld r2,#1 @1006: jeq.l @1004 jgt @1007 jmp @1008 @1007: ld r2,#1 @1008: jeq.l @1002 ld.l r2,@x st.l r2,@z ld.l r2,@y st.l r2,@x ld.l r2,@z st.l r2,@y @1002: ld.l r3,@x sub r2,r3 jmp.l @1003 @1004: halt start @main @a: data 0 @b: data 0 @c: data 0
Compilation : sous-programmes Passer des paramètres aux sous-programmes Valeurs transmises dans les registres R2, R3, R4, R5… Que fait le compilateur ? Le registre R14 est sauvegardé dans la pile Le registre R14 pointe sur la pile à l’entrée du sous-programme Les registres R2, R3, R4… sont empilés Les paramètres sont désignés par -2(R14), -4(R14)… Les valeurs des registres sont restaurées à la sortie du sous-programme Le résultat de la fonction est rendu dans R0 Les sous-programmes peuvent être récursifs.
Compilation - 3 Sous-programmes int incr(int x) { return x+1; } main(){ incr(3); } @1000: ld.l r2,-2(r14) add r2,#1 ld r0,r2 jmp.l @1001 @1001: pop r15,r2 ld r15,r14 pop r15,r14 ret r15 @incr: push r15,r14 ld r14,r15 push r15,r2 jmp.l @1000 @1002: ld r2,#3 jsr.l r15,incr ld r2,r0 halt main: ld r14,#0 ld r15,#0 jmp.l @1002 start main