Première séance machine Notions de base en langage d’assemblage Ensimag 2009 1 Accès à votre environnement Les expérimentations se feront sur la machine telesun, votre machine habituelle. 2 2.1 Le travail à effectuer PGCD La séance a pour objectif de vous faire faire une première expérience d’exécution de programme assembleur et de se familiariser avec l’utilisation de l’outil de mise au point gdb sur des fichiers assembleur. Cette expérience se fera en exécutant un programme élémentaire calculant le pgcd de deux nombres. Commencez par télécharger l’archive LdB-pgcd-seance-5.tgz depuis EnsiWiki, puis décompressezlà : telesun> tar xzvf LdB-pgcd-seance-5.tgz telesun> cd LdB-pgcd-seance-5 Vous trouverez un fichier pgcd.s. Ouvrez-le dans une nouvelle fenêtre (utilisez un l’éditeur de texte de votre choix si vous le préférez à Emacs) : telesun> emacs & En conservant la fenêtre emacs dans un coin de l’écran, vous produirez ensuite un listing d’assemblage et un fichier exécutable en utilisant la commande (attention pas d’espace avant le -a) : gcc -Wa,-a pgcd.s -o pgcd > pgcd.l (si on n’a pas besoin du listing d’assemblage, on peut aussi faire simplement gcc pgcd.s -o pgcd) Ouvrez le listing d’assemblage dans un éditeur de texte. Ce listing vous détaille le travail qu’a fait l’assembleur, il affiche le contenu binaire généré (en hexa) pour chaque ligne de code, et termine par un récapitulatif des symboles définis. Vous chargerez ensuite le programme dans gdb au moyen de la commande : gdb pgcd La première chose à faire consiste à poser un point d’arrêt au début du programme par la commande br main. Il est possible de lancer l’exécution du programme (run), qui s’arrêtera à main, puis d’exécuter l’ensemble du programme pas à pas au moyen des commandes si ou ni (équivalentes pour ce programme). 1 Au cours de cette exécution on surveillera l’évolution des registres eax et ecx dans lesquels se font les calculs (commandes : display $eax et display $ecx ou commande : i reg eax ecx). Pour l’instant, nous avons compilé notre programme sans l’option -g, donc gdb n’a pas toutes les informations de retour aux sources. Mais nous pouvons tout de même suivre la progression dans le programme toujours visible dans la fenêtre emacs - « à la main » en traçant la (les) prochaine(s) instruction(s) à exécuter au moyen de la commande : display /xi $eip, avec x=1 pour une instruction par exemple. Les deux dernières instructions (leave, ret) redonnent le contrôle à l’environnement et provoquent l’exécution d’instructions qui ne font pas partie du programme et sont donc incompréhensibles pour nous. Il n’y a plus lieu de continuer en “pas à pas” et il vaut mieux relancer l’exécution (cont). Cependant après exécution d’une itération de la boucle pas à pas, il est possible d’accélérer le déroulement du programme tout en suivant son évolution en insérant deux nouveaux points d’arrêt (br iter et br fin). Une fois ces points d’arrêts posés on relance l’exécution par la commande gdb cont. Il est ainsi possible de connaître le résultat du calcul lors du passage sur le second d’entre eux. Il est aussi possible de calculer d’autres valeurs de pgcd en modifiant les registres concernés à l’emplacement approprié ou encore de modifier le programme source pgcd.s afin d’effectuer, de façon analogue, d’autres calculs de pgcd. On pourra en outre, lors du passage sur le point d’arrêt fin, modifier les registres eax, ecx ainsi que le registre pointeur d’instructions eip avant de relancer l’exécution. PGCD de 256 et de 1024 code machine .text # Sera expliqué ultérieurement .global main # Sera expliqué ultérieurement main : pushl %ebp # Sera expliqué ultérieurement movl %esp,%ebp # Sera expliqué ultérieurement movl $256, %eax # Chargement de la valeur 256 dans le registre eax movl $1024, %ecx # Chargement de la valeur 1024 dans le registre eax iter : cmpl %eax, %ecx # Comparaison de eax et ecx je fin # Saut à fin en cas d’égalite jl suite # Saut à suite si ecx est plus petit que eax subl %eax, %ecx # Calcul de ecx - eax, resultat dans ecx jmp iter # Saut inconditionnel à iter suite : subl %ecx, %eax # Calcul de eax - ecx, resultat dans eax jmp iter fin : leave # Sera expliqué ultérieurement ret # Sera expliqué ultérieurement 2.2 Mieux utiliser gdb Ce que vous avez déjà vu sur gdb lors des séances sur le langage C s’applique aussi ici. En compilant avec -g, vous pourrez utiliser l’interface de votre choix. Un récapitulatif des commandes utiles, et quelques commandes plus utiles en assembleur est disponible sur EnsiWiki (gdb.pdf), et plus d’informations sont données à la fin du sujet. 2 2.3 Multiplication On trouve bien évidemment dans le langage assembleur x86 des instructions pour multiplier deux nombres. L’exercice consiste ici à écrire sa propre multiplication en utilisant l’instruction d’addition. En d’autres termes, pour multiplier un entier A par un entier B, il suffit de faire “A fois” la somme de B. Vous conserverez le même début de programme jusqu’au chargement des registres contenant les nombres à multiplier et vous utiliserez l’instruction d’addition que l’on trouve dans le programme du pgcd. D’autres registres peuvent être utilisés si besoin est : les registres edx, edi et esi. Le registre ebx qui est aussi utilisable est déconseillé à ce stade de vos connaissances car son utilisation « naïve » provoque des erreurs lors du rappel du système à la fin d’exécution du programme. Quelques instructions peuvent vous être utiles comme : inc %reg # ajoute 1 à la valeur du registre reg dec %reg # diminue de 1 la valeur du registre reg 2.4 2.4.1 Interfaces plus conviviales pour gdb Informations de debug : option -g pour gcc Savoir utiliser un debugger sur un programme exécutable quelconque est parfois utile. Mais quand on sait qu’on va utiliser un debugger sur un programme, on peut dire au compilateur de générer des informations de retour aux sources en plus (fichier et numéro de ligne correspondant à chaque instruction entre autres). Pour gcc, c’est l’option -g. Essayez de recompiler pgcd en ajoutant -g sur la ligne de commande de compilation, puis recommencez quelques unes des manipulations précédentes. Quand on s’arrête sur un point d’arrêt ou quand on fait du pas à pas, gdb donne directement le nom du fichier source, et le numéro de la ligne que l’on est en train d’exécuter. La commande list de gdb permet d’afficher une portion du code source autour de l’instruction courante. L’option -g est quasi indispensable pour utiliser ddd et Emacs dans les sections suivantes. 2.4.2 ddd : DataDisplay Debugger ddd est une interface graphique (« front-end ») qui utilise gdb comme back-end. Pour le lancer, taper ddd pgcd dans un terminal. ddd ouvre alors deux fenêtres. L’une affiche le code source, l’autre quelques boutons correspondant à des commandes gdb. On peut poser un point d’arrêt en double-cliquant sur une ligne. A noter que cette interface ne vous empêche pas d’utiliser directement les commandes gdb, puisque vous avez une console gdb en dessous de l’affichage du code source. 2.4.3 Emacs Utiliser gdb depuis Emacs est également très pratique, mais un peu plus compliqué (donc, vraiment intéressant pour vous seulement si vous connaissez déjà un peu Emacs. Cela permet en particulier de rester dans le même environnement pour éditer et débuger des programmes). Pour lancer gdb, depuis Emacs, faites M-x gdb RET, c’est à dire « Alt-x, puis gdb, puis Entrée ». Emacs vous demande la commande à exécuter pour lancer gdb. Pour vous, ça sera gdb --anotate=3 pgcd (qui est le défaut en principe). 3 Ensuite, on a une ligne de commande gdb comme celle que l’on aurait obtenue depuis le terminal, avec deux choses en plus : – Un curseur suit l’exécution du programme dans les sources, – Depuis un fichier source, C-x SPC (« Control-x, puis Espace ») place un point d’arrêt sur cette ligne du programme. 4