Structure d`un programme
Transcription
Structure d`un programme
Structure d’un programme Entrées/Sorties Sous-programmes Exemple Structure d’un programme Entrées/Sorties Sous-programmes Exemple Architecture des ordinateurs Structure d’un programme Cours 6 3 décembre 2012 Archi Structure d’un programme Entrées/Sorties 1/30 Sous-programmes Exemple Programme en Assembleur Archi Structure d’un programme 2/30 Entrées/Sorties Sous-programmes Exemple Sections de données B Données initialisées : SECTION .data programme en assembleur = fichier texte (extension .asm) déclarer des données initialisées avec la directive : dX organisé en plusieurs SECTIONS (= segments) X = b (1 octet), w (2 octets) ou d (4 octets = 1 mot). exemples : sections différentes pour les données et le code l1: db db dw dw l2: dw l3: dw directives pour NASM 6= instructions pour le processeur une seule instruction par ligne, séparateur = chgt de ligne 1 ligne de code = 4 champs (certains optionnels) : étiquette: instruction opérandes ; commentaire ; ; ; ; ; ; l’octet 0x55 3 octets successifs 0x34 0x12 (little endian) 0x61 0x00 0x61 0x62 (caractères) 0x61 0x62 0x63 0x00 (string) définir des constantes non modifiables avec la directive : equ exemple : Archi 0x55 0x55,0x66,0x77 0x1234 ’a’ ’ab’ ’abc’ 3/30 nb lettres: Archi equ 26 4/30 Structure d’un programme Entrées/Sorties Sous-programmes Exemple Sections de données - suite SECTION .text global main déclarer des données non initialisées avec la directive : resX main: ... X = b (1 octet), w (2 octets) ou d (4 octets = 1 mot). exemples (étiquettes obligatoires) : 100 1 1 Exemple commencer par déclarer global l’étiquette de début de programme (main) pour qu’elle soit visible : db 0 ; 100 fois l’octet 0x00 dd 0xffffffff ; 28 fois le m^ eme mot resb resw resd Sous-programmes B Corps du programme : SECTION .text B Données non initialisées : SECTION .bss input1: input2: input3: Entrées/Sorties Section de code répéter une déclaration avec la directive : times exemples : p0: times 100 p1: times 28 Structure d’un programme ; réserve 100 octets ; réserve 2 octets ; réserve 1 mot (4 octets) fin de fichier : mov mov int ebx, 0 eax, 1 0x80 ; code de sortie, 0 = normal ; numéro de la commande exit ; interruption 80 hex, appel au noyau ! ! ! Étiquette = adresse de la donnée. Archi Structure d’un programme Entrées/Sorties Archi 5/30 Sous-programmes Exemple Fichier squelette Structure d’un programme Entrées/Sorties 6/30 Sous-programmes Exemple Assembler un programme Assemblage : créer un fichier objet (transformer le programme écrit en langage d’assemblage en instructions machine) %include "asm_io.inc" SECTION .data ; données initialisées ; nasm -g -f <format> <fichier> [-o <sortie>] Exemples : SECTION .bss ; données non initialisées ; nasm -g -f coff toto.asm nasm -g -f elf toto.asm -o toto.o Produire un listing des instructions machine : SECTION .text global main ; rend l’étiquette visible de l’extérieur nasm -g -f elf toto.asm -l toto.lst Édition de lien : main: ; programmme ; mov ebx,0 mov eax,1 int 0x80 ld -e main toto.o -o toto En utilisant des bibliothèques C ou écrites en C (par exemple, asm io de P. Carter, pour les E/S) : ; code de sortie, 0 = normal ; numéro de la commande exit ; interruption 80 hex, appel au noyau Archi nasm -g -f elf toto.asm gcc toto.o asm_io.o -o toto 7/30 Archi 8/30 Structure d’un programme Entrées/Sorties Sous-programmes Exemple Structure d’un programme Entrées/Sorties Sous-programmes Exemple Interruptions Le flot ordinaire d’un programme doit pouvoir être interrompu pour traiter des évènements nécessitant une réponse rapide. Mécanisme d’interruptions (ex : lorsque la souris est déplacée, le programme en cours est interrompu pour gérer ce déplacement). Entrées/Sorties Passage du contrôle à un gestionnaire d’interruptions. Certaine interruptions sont externes (ex : la souris). D’autres sont soulevées par le processeur, à cause d’une erreur (traps) ou d’une instruction spécifique (interruption logicielle). En général, le gestionnaire d’interruptions redonne le contrôle au programme interrompu, une fois l’interrupion traitée. Il restaure tous les registres (sauf eax). Le programme interrompu s’exécute comme si rien n’était arrivé. Les traps arrêtent généralement le programme. Archi Structure d’un programme Entrées/Sorties 9/30 Sous-programmes Exemple Entrées/sorties Archi Structure d’un programme Entrées/Sorties 10/30 Sous-programmes Exemple Affichage par interruption Entrées-sorties (I/O) : échanges d’informations entre le processeur et les périphériques. Entrées : données envoyées par un périphérique (disque, réseau, clavier...) à destination de l’unité centrale. Sorties : données émises par l’unité centrale à destination d’un périphérique (disque, réseau, écran...). Gestion par interruptions : permet de réagir rapidement à un changement en entrée. le périphérique prévient le processeur par une interruption, le processeur interrompt la tâche en cours, effectue l’action prévue pour cette interruption et reprend l’exécution du programme principal là où il l’avait laissée. SECTION .text global main main: Gestion “haut-niveau” : Bibliothèques standards en C pour les E/S (pas en assembleur). MAIS, les conventions d’appels utilisées par C sont complexes... Archi SECTION .data msg1:db "message 1",10 lg1: equ $-msg1 11/30 ... mov mov mov mov int ... edx, ecx, ebx, eax, 0x80 lg1 msg1 1 ; stdout 4 ; write Archi 12/30 Structure d’un programme Entrées/Sorties Sous-programmes Exemple Affichage en utilisant printf Structure d’un programme Entrées/Sorties %include "asm_io.inc" SECTION .data msg2: db "msg 2", 10, 0 SECTION .data msg3: db "msg 3", 10, 0 SECTION .text global main SECTION .text global main main: main: Sous-programmes Exemple ... mov eax, msg3 call print_string ... msg2 printf Archi Structure d’un programme Exemple Affichage avec ams io.inc extern printf ... push call ... Sous-programmes Entrées/Sorties 13/30 Sous-programmes Exemple Archi Structure d’un programme Entrées/Sorties 14/30 Routines d’E/S de P. Carter print int print char print string print nl read int read char affiche à l’écran la valeur de l’entier stocké dans eax affiche à l’écran le caractère dont le code ASCII est stocké dans al affiche à l’écran le contenu de la chaı̂ne de caractères à l’adresse stockée dans eax. La chaı̂ne doit être une chaı̂ne de type C (terminée par 0) affiche à l’écran un caractère de nouvelle ligne lit un entier au clavier et le stocke dans le registre eax lit un caractère au clavier et stocke son code ASCII dans le registre eax Sous-programmes %include "asm io.inc" Pour chaque fonction d’affichage, il faut charger eax avec la valeur correcte, utiliser une instruction call pour l’invoquer. ces fonctions préservent les valeurs de tous les registres, sauf les deux read qui modifient eax. Archi 15/30 Archi 16/30 Structure d’un programme Entrées/Sorties Sous-programmes Exemple Sous-programmes Structure d’un programme Entrées/Sorties Exemple Exemple, sans sous-programme Les sous-programmes servent à mutualiser du code (éviter les copier-coller) %include "asm_io.inc" Exemple : les fonctions des langages haut niveau. cmp jl Le code appelant le sous-programme et le sous-programme lui-même doivent se mettre d’accord sur la façon de se passer les données (conventions d’appel). SECTION .data msg1: db "entier <10 ?",10,0 msg2: db "bravo",10,0 msg3: db "perdu",10,0 Un saut peut être utilisé pour appeler le sous-programme, mais le retour pose problème. Le sous-programme peut être utilisé par différentes parties du programme B il doit revenir au point où il a été appelé ! Donc, le retour du sous-programme ne peut pas être codé “en dur” par un saut vers une étiquette. L’étiquette de retour doit être un paramètre du sous-programme. Archi Structure d’un programme Sous-programmes rate: mov call jmp eax, msg3 print_string fin SECTION .text global main ok: mov call eax, msg2 print_string main: mov call fin: mov mov int ebx, 0 eax, 1 0x80 call eax, msg1 print_string read_int Archi 17/30 Entrées/Sorties Sous-programmes Exemple Sous-programme “à la main” eax, 10 ok Structure d’un programme Entrées/Sorties 18/30 Sous-programmes Exemple Instructions call et ret Problèmes : %include "asm_io.inc" SECTION .data msg1: db "entier <10 ?",10,0 msg2: db "bravo",10,0 msg3: db "perdu",10,0 SECTION .text global main main: mov call eax, msg1 print_string mov jmp ret_sb: call read_int Un peu compliqué Besoin d’autant d’étiquettes que d’appels du sous-programme. Solution : call et ret fin: mov mov int ebx, 0 eax, 1 0x80 sb: cmp jl mov jmp mov jmp eax, 10 ok eax, msg3 ecx eax, msg2 ecx rate: ok: call ecx, ret_sb sb print_string L’instruction call effectue un saut inconditionnel vers un sousprogramme après avoir empilé l’adresse de l’instruction suivante l1: call fonction push l2 l2: ... jmp fonction L’instruction ret dépile une adresse et saute à cette adresse : ret pop reg. jmp reg. Lors de l’utilisation de ces instructions, il est très important de gérer la pile correctement (dépiler tout ce qu’on a empilé) afin que l’adresse dépilée par l’instruction ret soit correcte. Permet d’imbriquer des appels de sous-programmes facilement. Archi 19/30 Archi 20/30 Structure d’un programme Entrées/Sorties Sous-programmes Exemple Sous-programme avec call et ret %include "asm_io.inc" SECTION .data msg1: db "entier <10 ?",10,0 msg2: db "bravo",10,0 msg3: db "perdu",10,0 fin: Structure d’un programme Entrées/Sorties Sous-programmes Exemple Passage des paramètres call call sb print_string mov mov int ebx, 0 eax, 1 0x80 cmp jl mov ret mov ret eax, 10 ok eax, msg3 ! ! Il est très important de dépiler toute donnée qui a été empilée dans le corps du sous-programme. Exemple : plus2: add push ret eax, 2 eax ; dépile la valeur de eax !! Ce code ne reviendra pas correctement ! SECTION .text global main sb: rate: main: mov call call eax, msg1 print_string ok: Autre problème : passage des paramètres par registres limite le nombre de paramètres ; eax, msg2 mobilise les registres pour les conserver. read_int Solution : passer les paramètres par la pile (convention de C). Archi Structure d’un programme Entrées/Sorties 21/30 Sous-programmes Exemple Passer les paramètres par la pile Entrées/Sorties 22/30 Sous-programmes Exemple Passer les paramètres par la pile - suite Les paramètres passés par la pile sont empilés avant le call. Si le paramètre doit être modifié par le sous-programme, c’est son adresse qui doit être passée. Les paramètres sur la pile ne sont pas dépilés par le sous-programme mais accédés depuis la pile elle-même : Sinon, comme ils sont empilés avant le call, l’adresse de retour devrait être dépilée avant tout (puis ré-empilée ensuite). Si les paramètres sont utilisés à plusieurs endroits : B ça évite de les conserver dans un registre ; B les laisser sur la pile permet de conserver une copie de la donnée en mémoire accessible à n’importe quel moment. Lors d’un appel de sous-programme : la pile ressemble à ... esp adresse de retour esp+4 paramètre Si la pile est également utilisée dans le sous-programme pour stocker des données, le nombre à ajouter à esp change. Par exemple, après un push la pile ressemble à : ... esp donnée du sous-programme esp+4 adresse de retour esp+8 paramètre Maintenant, le paramètre est en esp+8, et non plus en esp+4. esp pour faire référence aux paramètres ⇒ erreurs possibles. Pour résoudre ce problème, utiliser ebp (base de la pile). La convention de C est qu’un sous-programme commence par empiler la valeur de ebp puis affecte à ebp la valeur de esp. Permet à esp de changer sans modifier ebp. A la fin du programme, la valeur originale de ebp est restaurée. Accès au paramètre par adressage indirect : [esp+4] Archi Archi Structure d’un programme 23/30 Archi 24/30 Structure d’un programme Entrées/Sorties Sous-programmes Exemple Passer les paramètres par la pile - suite etiquette sousprogramme: push ebp ; empile la valeur originale de ebp mov ebp, esp ; ebp = esp ; code du sous-programme pop ebp ; restaure l’ancienne valeur de ebp ret Exemple Archi Une fois le sous-programme terminé, les paramètres qui ont été empilés doivent être retirés. Un sous-programme utilisant cette convention peut être appelé comme suit : Le paramètre est accessible avec [ebp+8] depuis n’importe quel endroit du sous-programme. push call add param fnc esp, 4 Exemple ; passe un paramètre ; retire le paramètre de la pile La 3ème ligne retire le paramètre de la pile en manipulant directement l’adresse du sommet de la pile. Une instruction pop pourrait également être utilisée, mais le paramètre n’a pas besoin d’être stocké dans un registre. 25/30 Sous-programmes Sous-programmes La convention d’appel C spécifie que c’est au code appelant de le faire (convention différente en Pascal, par exemple). La pile au début du code du sous-programme ressemble à ... ... esp donnée esp ebp ebp prec. esp+4 ebp ebp prec. esp+4 ebp+4 adr. de retour esp+8 ebp+4 adr. de retour esp+8 ebp+8 paramètre esp+12 ebp+8 paramètre Entrées/Sorties Entrées/Sorties Passer les paramètres par la pile - fin Forme générale d’un sous-programme qui suit ces conventions : Structure d’un programme Structure d’un programme Archi Structure d’un programme Entrées/Sorties 26/30 Sous-programmes Exemple Exemple de passage de paramètre par la pile %include "asm_io.inc" SECTION .data msg1: db "entier <10 ?",10,0 msg2: db "bravo",10,0 msg3: db "perdu",10,0 fin: sb: print_string mov mov int ebx,0 eax,1 0x80 push mov cmp jl rate: mov pop ret ok: mov pop ret SECTION .text global main main: mov eax,msg1 call print_string call read_int push call add call eax sb esp, 4 Archi ebp ebp, esp dword [ebp+8], 10 ok eax, msg3 ebp Exemple complet eax, msg2 ebp 27/30 Archi 28/30 Structure d’un programme Entrées/Sorties Sous-programmes Exemple Afficher des rayures Structure d’un programme Entrées/Sorties Sous-programmes Exemple Programme On souhaite écrire un programme qui affiche k rayures verticales sur n lignes. Les rayures doivent être dessinées en utilisant un caractère choisi par l’utilisateur. %include "asm_io.inc" SECTION .data msg1:db msg2:db msg3:db blanc: "nb bandes?",10,0 "nb lignes?",10,0 "caractere?",10,0 db " ",0 SECTION .bss nbb: resd 1 nbl: resd 1 SECTION .text global main mov call call mov eax, msg2 print_string read_int [nbl], eax mov call call call mov eax,msg3 print_string read_char read_char ecx, [nbl] ligne: push ebp mov ebp, esp push ecx nxt:push push call add pop eax dword [nbb] ligne esp, 4 eax mov sv: mov call mov call loop ecx, [ebp+8] eax, [ebp+12] print_char eax, blanc print_string sv call print_nl pop ecx main: mov call call mov Archi 29/30 loop nxt eax, msg1 print_string read_int [nbb], eax fin:mov ebx, 0 mov eax, 1 int 0x80 Archi pop ret ebp 30/30