Architecture d’Ordinateurs Introduction Pratique Assembleur Introduction L’objectif de ce document est de donner les détails pratiques pour écrire, compiler et exécuter les premiers programmes en Assembleur. On va travailler sur la machine sirius où on dispose du compilateur nasm. Pour se connecter à sirius, démarrer l’ordinateur sous Linux. Dans la fenêtre “Gestionnaire de bureaux GNOME” il faut choisir Action et après “Connexion distante via XDMCP”. Choisir sirius comme hôte et se connecter. D’abord, il faut créer un répertoire TP1_NOM_PRENOM où on peut créer le fichier bonjour.nasm dans lequel on va écrire nos programmes. Je vous conseille d’utiliser l’éditeur Kate car il permet de faire la coloration syntaxique (si besoin, il faut sélectionner Tools→Highlighting→Assembler→ Intel X86 nasm). Voici un premier exemple de programme qui affiche la chaı̂ne Bonjour ! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 g l o b a l main ; c e c i e s t un commentaire extern p r i n t f SECTION .data bonjour : db ”Bonjour ! ” , 1 0 , 0 ; 10 =c a r a c t è r e ASCI Line Feed ( l e s a u t de l i g n e ”\ n ” en C) ; 0 = c a r a c t è r e pour marquer l a f i n de c h aı̂ n e ( pour p r i n t f ) SECTION . t e x t g l o b a l main main : push ebp mov ebp , esp pushad pushad push call popad add popad xor mov pop ret dword b o n j o u r printf ; on mets l ’ a d r e s s e de l a c h aı̂ n e dans l a p i l e esp , 4 ; pop s t a c k ( d é p i l e r ) une f o i s eax , eax esp , ebp ebp ; return value = 0 Notons que les lignes 1-3, 6-11 et 19-23 ne doivent pas être modifiées dans les programmes que vous écrivez ensuite. Pour compiler ce programme, on va créer dans le même répertoire un fichier Makefile qui contient : all : [TAB] nasm −f e l f −g b o n j o u r . nasm [TAB] g c c −ggdb −o b o n j o u r b o n j o u r . o Dans ce fichier Makefile, [TAB] fait référence à la touche Tabulation. Ouvrez une console (terminal) est aller dans le répertoire TP1_NOM_PRENOM qui contient ces deux fichiers (Makefile et bonjour.nasm). Tapez make pour compiler et ./bonjour pour exécuter. Modifier le fichier bonjour.nasm afin de résoudre les exercices de TP1. Indications : Pour l’exercice 1 du TP1, on utilise l’instruction mov (pour mettre les valeurs de a et b dans les registres EAX et EBX), suivie par cmp (cet instruction compare deux registres – EAX et EBX – et mets le résultat dans le registre flags), suivi par une instruction jle (Jump if Lower or Equal – au cas où le résultat stocké dans le registre flags indique que la valeur de EAX est inférieure à celle de EBX, le programme effectue un saut). Pour avoir des renseignements sur une instruction, vous pourriez consulter le cours, ainsi que des matériaux sur Internet, e.g. une liste d’instructions se trouve à en.wikipedia.org/wiki/X86_instruction_ listings TP Architecture des ordinateurs, M2 CCI, Université d’Angers – 2009-2010 Daniel Porumbel Le programme suivant compare deux nombres a et b et affiche leur relation d’ordre. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 g l o b a l main extern p r i n t f SECTION .data a dd 10 b dd 9 b o n j o u r : db ”Bonjour ! ” , 1 0 , 0 msgInf : db ”a<b ” , 1 0 , 0 msgSup : db ”a>=b ” , 1 0 , 0 SECTION . t e x t g l o b a l main main : push mov pushad mov mov cmp jl pushad push call popad add jmp ; c e c i e s t un commentaire ; a e s t un e n t i e r s u r 32 b i t s , sa v a l e u r e s t 10 ; b e s t un e n t i e r s u r 32 b i t s , sa v a l e u r e s t 9 ebp ebp , esp eax , [ a ] ebx , [ b ] eax , ebx inf dword msgSup printf ; on mets l ’ a d r e s s e de l a c h aı̂ n e dans l a p i l e esp , 4 fin ; pop s t a c k ( d é p i l e r ) une f o i s ; on ne v e u t pas c o n t i n u e r à a f f i c h e r dword msgInf printf ; on mets l ’ a d r e s s e de l a c h aı̂ n e dans l a p i l e esp , 4 ; pop s t a c k ( d é p i l e r ) une f o i s eax , eax esp , ebp ebp ; v a l e u r de r e t o u r du programme = 0 msgInf inf : pushad push call popad add fin : popad xor mov pop ret Pour faire tourner ce programme, il est convenable d’écrire ce code dans le fichier bonjour.nasm et de le compiler avec la commande make. Ensuite, pour résoudre d’autre exercices, il est conseiller de travailler que avec le fichier bonjour.nasm que vous pouvez le modifier. Informations utiles : – Observez que ce programme a plusieurs variables dans la section .data, e.g. a, b, msgInf, msgSup. Les types de donnés qu’on utilise sont : db (data byte), dw (data word) et dd (data double). Un variable déclarée db est codé sur un octet (ou une série de plusieurs octets comme pour les variables msgIng, msgSup). Pour stocker les nombres a et b, on utilise des variables à 4 octets (dd) car les registres eax et ebx ont 4 octets (32 bits). Observez que la valeur d’une variable est lue/écrite en utilisant les crochets. Un exemple de déclaration de tableau de 100 entiers de valeur 7 est monTableau : times 100 dd 7 – Les registres qu’on va utiliser le plus souvent sont : eax, ebx, ecx, edx (registres génériques) ; ebp, esp (registres utilisés exclusivement pour traiter la pile d’exécution du programme) ; il faut aussi connaı̂tre le registre EIP (Instruction Pointer) qui représente l’adresse mémoire de l’instruction courante. La pile est importante quand on écrit des sous-programmes ou des procédures. TP Architecture des ordinateurs, M2 CCI, Université d’Angers – 2009-2010 Daniel Porumbel – Les principales instructions utilisés dans le TP d’assembleur sont : – mov dest,src copie le contenu de src en dest. Par exemple : mov eax,[a] ; copie la valeur de a dans le registre eax – jmp étiquette fait un saut à une adresse étiquette, voir lignes 27 et 34 pour la déclaration des étiquettes de saut – cmp op1, op2 fait une comparaison entre op1 et op2 (voir ligne 19). Le résultat de cette comparaison est stocké dans un autre registre (FLAGS) et la prochaine instruction (de saut) est capable de lire ce résultat. – jl étiquette fait un saut à l’adresse étiquette si la dernière comparaison à eu comme résultat op1<op2. Il y a en fait une série d’instruction de ce type : jl(Jump if Lower), jle (Jump if Lower of Equal), jg (Jump if Greater), etc. – push et pop instructions pour empiler et dépiler. Par exemple : 1 2 3 4 5 6 7 8 9 mov eax , push eax mov ebx , mov ecx , push ebx push ecx pop edx pop eax pop ebx 7 ; l a v a l e u r 7 s e r a dans l e r e g i s t r e eax ; l a v a l e u r de eax ( 7 ) e s t mise au sommets de l a p i l e 9 ; 5 ; ; la p i l e sera : 7 9 ; edx s e r a 5 e t l a ; eax s e r a 9 e t l a ; ebx sera 7 e t l a 5 pile : 7 9 pile : 7 p i l e vide Notons que l’instruction add esp,4 enlève pratiquement la valeur du sommet de la pile, e.g. si on ajoute add esp, 4 avant pop edx, alors edx sera 9. – call maProcedure appelle la procédure maProcedure, e.g. voir ligne 24 où on appelle printf – ret cette instruction termine la procédure courante et renvoie la valeur de eax – Add, Sub, Mul, Div, Inc, Dec, Shl, Sar ce sont des instructions pour des opérations mathématiques. Par exemple : 1 2 3 4 5 mov mov add mov sub eax , ebx , eax , ecx , eax , 7 5 ebx 10 ecx ; ; ; ; ; eax=7 e b x=5 eax s e r a 12 eax s e r a 2 D’autres exemples d’instructions arithmétiques sont disponibles à en.wikibooks.org/wiki/X86_ Assembly/Arithmetic. TP Architecture des ordinateurs, M2 CCI, Université d’Angers – 2009-2010 Daniel Porumbel