Maxime CHAMBREUIL - Samy FOUILLEUX - ASI3 - Année 2001 / 2002
SE : TP5 - TP6 |
Programme invmess
Ce programme copie l'inverse d'une chaîne de caractères dans une
autre chaîne.
Assume CS : Code, DS : Data, SS : Pile Pile SEGMENT STACK dw 1024 dup(0) Pile ENDS Data SEGMENT |
Code SEGMENT main:MOV AX, Data MOV DS,AX MOV SI,0 MOV CX,long-1 boucle1 : MOV BL,msg[SI] PUSH BX INC SI LOOP boucle1 MOV SI,0 |
MOV CX,long-1 |
Pour réaliser l'inversion, on envoie tout les éléments de msg dans la pile grâce à une boucle. Pour cela, on crée une constante long, qui ne sera pas stockée en memoire, et qui est égale à la différence entre l'adresse du premier élément de msg et de celle du premier élément de inverse. une fois que l'on a réalisé ce stockage dans la pile, on dépile les éléments de la pile dans long. Mais comme on met le dernier élément qui a été stocké dans la pile dans long, on met en fait le dernier élément de msg à la premiére place dans long. On réalise donc bien une inversion. Enfin on rajoute un $ à la fin de long pour marquer la fin de la chaîne de caratére.
Registres en entrée : AX=0000 BX=0000 CX=083A DX=0000 SP=0800 BP=0000 SI=0000 DI=0000 DS=20BB ES=20BB SS=20CB CS=214C IP=0000
Registres en sortie : AX=4C4B BX=0063 CX=0000 DX=0000 SP=0800 BP=0000 SI=0006
DI=0000 DS=214B ES=20BB SS=20CB CS=214C IP=0028
On voit que les registres AX et BX qui ont servit dans le programme sont modifiés. On voit aussi que le registre CX est à 0, ce qui est normal car à la fin d'une boucle CX est obligatoirement à 0.
Nous voulons écrire un programme qui affiche (en hexadécimal) la valeur d'un mot (2 octets). Pour cela, nous décomposons l'opération de façon à écrire le mot 4 bits par 4 bits. En fait on a le nombre sous la forme :
X | Y | Z | W |
Assume CS:Code,DS: Data, SS:Pile Data SEGMENT Code SEGMENT affdigit PROC
|
affoctet PROC affnombre PROC |
main:MOV AX, Data Code ENDS |
Pour expliquer le programme, nous allons détailler chaque procédure. Tout d'abord, le nombre est mis dans un registre BX (passage par registre), on fait ensuite appel à la procédure affnombre. On sauvgarde le nombre dans la pile, puis on copie sa seconde moitié pour la mettre dans sa première (MOV BL,BH) et on met la premiére moitié à 0 en faisant un ou exclusif. BX contient alors 0-0-X-Y On passe ensuite à la procédure affoctet. Celle ci effectue d'abord un décalage de 4 bits pour afficher X grâce à la procédure affdigit qui transforme BX de façon à pouvoir afficher le nombre qui se trouve dans la dernière casse. La procédure affoctet reprend BX pour avoir 0-0-X-Y. On transforme BX pour avoir 0-0-0-X et on réutilise affdigit. La procédure affnombre reprend BX pour avoir X-Y-W-Z et le transforme en 0-0-W-Z et on relance affoctet. Au final on va afficher X puis Y puis Z et enfin W, on va donc afficher le nombre contenu dans BX.
E:\SE\lasm>affnom
8752
Registres en entrée : AX=0000 BX=0000 CX=0856 DX=0000 SP=0800 BP=0000
SI=0000 DI=0000 DS=20BA ES=20BA SS=20CA CS=214B IP=0037
Registres en sortie : AX=4C4A BX=8752 CX=0856 DX=0804 SP=0800 BP=0000
SI=0000 DI=0000 DS=214A ES=20BA SS=20CA CS=214B IP=0044
On voit que AX a été modifié, c'est normal on s'en sert. On voit surtout que BX a la valeur qui s'est affichée. C'est aussi normal car c'est dans BX que nous avons mis la valeur à afficher. Le programme marche.
Assume CS : Code,DS : Data, SS : Pile Pile SEGMENT STACK dw 1024 dup(0) Pile ENDS Data SEGMENT
affoctpi PROC |
affnbepi PROC affnbepi ENDP
|
La différence ne se passe qu'au niveau des passage de paramétre aux procédures, le programme faisant la même chose. Les résultats sont donc les mêmes.
E:\SE\lasm>affnbepi
3456
Registres en entrée : AX=0000 BX=0000 CX=0878 DX=0000 SP=0800 BP=0000 SI=0000 DI=0000 DS=20BB ES=20BB SS=20CB CS=214C IP=0056
Registres en sortie : AX=4C4B BX=0000 CX=0878 DX=0000 SP=0800 BP=0000 SI=0000 DI=0000 DS=214B ES=20BB SS=20CB CS=214C IP=0066
On voit encore que AX change car il est utilisé sans être sauvgardé
au début. On voit aussi que BX a la valeur de départ, car nous
l'avons sauvgardée dans la pile au début du programme.
Assume CS : Code,DS : Data, SS : Pile Pile SEGMENT STACK Data SEGMENT |
Code SEGMENT |
main : MOV AX, Data MOV AH,4Ch |
Tout d'abord nous mettons l'adresse du premier élément de chaine dans SI, nous mettons le caratére à rechercher dans AL. Nous allons ensuite réaliser la procédure premOcc. Celle ci va rélaiser une boucle, à chaque fois on regarde si le caratére de chaine choisit et identique à celui dans AL. Si c'est le cas alors on réalise une opération pour mettre ZF à 0. Si ce n'est pas le cas on regarde si le code du caractére est égal à 0, dans ce cas on met ZF à 1. Sinon on incrémente SI pour passer au caractére suivant de chaine.
Registres en entrée : AX=20CB BX=0000 CX=0040 DX=0000 SP=0000 BP=0000
SI=0000 DI=0000 DS=20BB ES=20BB SS=20CB CS=20CC IP=0022
Registres en sortie : AX=4C31 BX=0000 CX=0040 DX=0000 SP=0000 BP=0000 SI=0004
DI=0000 DS=20CB ES=20BB SS=20CB CS=20CC IP=002E
Le seul registre utilisé dans le programme est AX, et c'est bien le seul des 6 premiers registres a être modifié. En outre, on s'aperçoit que SI est à 4, et comme le caractére n'apparait pas, il est normal que SI soit égal à la taille de chaine.
Pour le drapeaux ZF, voyons ce que nous donne symdeb :
AX=0077 BX=0000 CX=0040 DX=0000 SP=FFFE BP=0000 SI=0004 DI=0000 DS=20CB ES=20BB
SS=20CB CS=20CC IP=0018 NV UP EI PL ZR NA PE NC
20CC:0018 B031 MOV AL,31 ;'1'
-t
AX=0031 BX=0000 CX=0040 DX=0000 SP=FFFE BP=0000 SI=0004 DI=0000 DS=20CB ES=20BB
SS=20CB CS=20CC IP=001A NV UP EI PL ZR NA PE NC
20CC:001A B430 MOV AH,30 ;'0'
-t
AX=3031 BX=0000 CX=0040 DX=0000 SP=FFFE BP=0000 SI=0004 DI=0000 DS=20CB ES=20BB
SS=20CB CS=20CC IP=001C NV UP EI PL ZR NA PE NC
20CC:001C 3AC4 CMP AL,AH
-t
AX=3031 BX=0000 CX=0040 DX=0000 SP=FFFE BP=0000 SI=0004 DI=0000 DS=20CB ES=20BB
SS=20CB CS=20CC IP=001E NV UP EI PL NZ NA PO NC
20CC:001E C3 RET
On voit que le drapeau est égal à 1, avant qu'on ne réalise
l'opération qui doit le mettre à 0. Lorsque que celle ci est réalisé,
le drapeau est égal 0. Ceci montre que le caractére n'est pas
dans la chaine, ce qui est bien le cas. Si on réalise le programme avec
le caractére dans AL apparaisant dans la chaine, on obtient ZF=1, ce
que nous montre les extraits suivants (on remplace w par i dans le programme)
:
AX=6969 BX=0000 CX=0040 DX=0000 SP=FFFE BP=0000 SI=0001 DI=0000 DS=20CB ES=20BB
SS=20CB CS=20CC IP=000F NV UP EI PL ZR NA PE NC
20CC:000F B031 MOV AL,31 ;'1'
-t
AX=6931 BX=0000 CX=0040 DX=0000 SP=FFFE BP=0000 SI=0001 DI=0000 DS=20CB ES=20BB
SS=20CB CS=20CC IP=0011 NV UP EI PL ZR NA PE NC
20CC:0011 B431 MOV AH,31 ;'1'
-t
AX=3131 BX=0000 CX=0040 DX=0000 SP=FFFE BP=0000 SI=0001 DI=0000 DS=20CB ES=20BB
SS=20CB CS=20CC IP=0013 NV UP EI PL ZR NA PE NC
20CC:0013 3AC4 CMP AL,AH
-t
AX=3131 BX=0000 CX=0040 DX=0000 SP=FFFE BP=0000 SI=0001 DI=0000 DS=20CB ES=20BB
SS=20CB CS=20CC IP=0015 NV UP EI PL ZR NA PE NC
20CC:0015 E90600 JMP 001E
Assume CS : Code,DS : Data, SS : Pile
Pile SEGMENT STACK Data SEGMENT |
Code SEGMENT |
main: MOV AX,Data MOV DS,AX MOV SI,offset chaine MOV DI,offset chaine2 CALL sousChaine MOV AH,4Ch INT 21h Code ENDS END main |
Tout d'abord, nous mettons les adresses du premier element de chaque chaine dans SI et DI. Nous réalisons ensuite une boucle dans la procédure sousChaine. On met le caratére de chaine désigné par SI et le caractére de chaine2 désigné par DI dans AH et AL. On compare ensuite les deux caratéres. Si ils sont égaux on regarde si le code n'est pas égal à 0 pour le caratére de chaine. Si oui, on refait la même chose pour le caractére de chaine2. Si son code est aussi égal à 0, les deux chaines sont égales, on réalise une opération qui met ZF à 1, et on met SI dans BX. Si les caratéres sont égaux, et qu'aucun n'a son code égal à 0, on incrémente SI et DI, et on refait le test. Sinon on met SI dans BX. Si les caratéres sont différents, on met SI dans BX. Il faut mettre SI dans BX et non DI car au début de la procédure SI=0 alors que DI=5. Ceci est du au fait que, comme chaine est le premier élément déclaré, on le place au début, c'est à dire en 0.
Registres en entrée : AX=0000 BX=0000 CX=0041 DX=0000 SP=0000 BP=0000
SI=0000 DI=0000 DS=20BA ES=20BA SS=20CA CS=20CB IP=001F
Registres en sortie : AX=4CCA BX=0004 CX=0041 DX=0000 SP=0000 BP=0000 SI=0004
DI=0009 DS=20CA ES=20BA SS=20CA CS=20CB IP=002F
On voit que AX a changé, c'est le registre qu'on utilise pour les calculs. On voit que SI et BX on la même valeur, et que celle ci est égale à 4. Or la plus longue sous-chaine initiale de l'exemple utilisé est justement 4. Le programme semble donc bien marcher. Vérifions maintenant que Zf est bien lis à 1 quand les listes sont égales. On relance le programme avec chaine=chaine2="Vite" :
AX=0000 BX=0000 CX=0049 DX=0000 SP=FFFC BP=0000 SI=0004 DI=0009 DS=20CA ES=20BA
SS=20CA CS=20CB IP=001D NV UP EI PL ZR NA PE NC
20CB:001D B031 MOV AL,31 ;'1'
-t
AX=0031 BX=0000 CX=0049 DX=0000 SP=FFFC BP=0000 SI=0004 DI=0009 DS=20CA ES=20BA
SS=20CA CS=20CB IP=001F NV UP EI PL ZR NA PE NC
20CB:001F B431 MOV AH,31 ;'1'
-t
AX=3131 BX=0000 CX=0049 DX=0000 SP=FFFC BP=0000 SI=0004 DI=0009 DS=20CA ES=20BA
SS=20CA CS=20CB IP=0021 NV UP EI PL ZR NA PE NC
20CB:0021 3AC4 CMP AL,AH
-t
AX=3131 BX=0000 CX=0049 DX=0000 SP=FFFC BP=0000 SI=0004 DI=0009 DS=20CA ES=20BA
SS=20CA CS=20CB IP=0023 NV UP EI PL ZR NA PE NC
20CB:0023 8BDE MOV BX,SI
Zf est bien mis à 1. Le programme semble donc marcher correctement.
On veut tester une procédure de type FAR. Pour cela on réalise une procédure qui met en majuscule les minuscules d'une chaîne de caractère.
Data SEGMENT message1 db "uv d'ArcHitEcture et de SySteme",10,13,0 message2 db "oN chaNGE de CHainE avEc des 012 %% §.",10,13,0 Data ENDS Pile SEGMENT STACK PUSH BP MOV BP,SP |
MOV [SI],AH faux : INC SI JMP boucle fin : POP CX,AX,SI,BP ret 2 Majuscule ENDP Code2 ENDS Code SEGMENT |
Nous envoyons l'adresse du premier carctére de SI dans la pile. Puis, nous mettons l'adresse du premier caractére de la chaine dans SI. Ensuite nous mettons le caractére correspondant dans AH. Nous vérifions que le code de ce caratére est différent de 0, sinon la procédure est finie. Nous regardons ensuite si le code ASCII de ce caratére est inférieur à 61h (code de a) et si oui si il est supérieur à 7Ah (celui de z). Si oui alors le caractére est une minuscule. On incrémente alors AH de 20h (pour arriver entre A et Z) de façon à obtenir la majuscule. Ensuite on incrémente SI et on recommence. A la fin de chaque boucle on met AH dans [SI] de façon à remplacer les minuscules de la chaine par des majuscules. La procédure affichage permet de vérifier que le programme donne le résultat escompté.
Registres en entrée : AX=0000 BX=0000 CX=016B DX=0000 SP=00C8 BP=0000
SI=0000 DI=0000 DS=20BA ES=20BA SS=20CF CS=20DF IP=0000
Registres en sortie : AX=4C22 BX=0000 CX=016B DX=0000 SP=00C8 BP=0000 SI=0000
DI=0000 DS=20CA ES=20BA SS=20CF CS=20DF IP=0019
On voit que seul AX a changé dans les premiers registres, ce qui est normal comme on ne sert que de lui. On remarque aussi que CF est le même en entrée et en sortie. Mais comment cela se passe pendant l'éxecution du programme.
AX=0000 BX=0000 CX=016B DX=0000 SP=00C6 BP=0000 SI=0000 DI=0000 DS=20CA ES=20BA
SS=20CF CS=20DF IP=0009 NV UP EI PL NZ NA PO NC
20DF:0009 9A0000DC20 CALL 20DC:0000
-t
AX=0000 BX=0000 CX=016B DX=0000 SP=00C2 BP=0000 SI=0000 DI=0000 DS=20CA ES=20BA
SS=20CF CS=20DC IP=0000 NV UP EI PL NZ NA PO NC
20DC:0000 55 PUSH BP
On remarque que lorsque la procédure est appelée, IP change comme à chaque fois, mais CS change aussi. Ceci siginifie que le programme principal et la procédure ne sont pas dans le même segement de code.
Voici l'architecture de mon ordinateur.
On tape le programme donné.
Ce programme assez complexe part de plusieurs éléments qui ne semblent rien dire. Ensuite, grâce à de nombreux décalages au niveau des registres, on affiche au fur et à mesure un caractére correspondant au code obtenu à chaque boucle. Au final on obtient :
E:\SE\lasm>fin
BoNNes VacancEs
Maxime CHAMBREUIL - Samy FOUILLEUX - ASI3
- Année 2001 / 2002