Transcript Résumé du cours précédent
Assembleur
Niveaux de programmation
• Niveaux de programmation circuit logiques 0/1 -------------------------------------------------------------------------------- unité de traitement micro-instructions (UAL, chemins de données) = suite de 0/1 (Unité de commande) micro-pgme = suite de micro-instructions ----------------------------------------------------------------------------------- Codop 111111 000011101010101 langage machine = suite de 0/1 ----------------------------------------------------------------------------------- ADD A,20 assembleur = remplacer les codop JZ 13 par des mnémoniques Djamal Rebaïne 2
Structure d’un programme assembleur 8086
TITLE
nom ; donner un nom au programme PILE
SEGMENT STACK
; déclaration d’un segment de pile ; dont le nom est pile ..........
..........
PILE
ENDS
DONNEE ; fin de la déclaration de la pile
SEGMENT
; déclaration d’un segment de données qui va ; contenir les variables ...........
DONNEE
ENDS
LECODE
SEGMENT
; fin de la déclaration de données ; déclaration du segment de code qui va contenir ; le code Debut: ; étiquette d’indication du point d’entrée du code .................................
LECODE
END ENDS
; fin de la déclaration du code Debut ; fin du point d’entrée du code Djamal Rebaïne 3
Exemple
TITLE prog2.asm: dw 100 dup(?) Pile ends Exemple sur ROL, Pile segment stack ; DATA segment DATA1DW COMPTE DATA ends 5F97H DB ?
CODE segment MAIN: ASSUME CS:CODE, DS:DATA MOV AX,DATA MOV DS, AX XOR MOV BL, BL DL, 16 MOV AX, DATA1 ENCORE : ROL AX, 1 JNC PROCHAIN INC BL PROCHAIN: DEC DL JNZ ENCORE MOV COMPTE, BL ; Mettre BL à 0 (ou bien SUB) ; rotation 16 fois ; Rotation a gauche (a droite aussi si on préfère) ; Test si CF=0 ; Si CF = 1, incrémenter le compteur du nombre de ‘1’ ; répéter 16 fois ; encore une fois si ce n’est pas fini ; sauvegarder le résultat dans la case mémoire COMPTE MOV AH, 4Ch INT 21h MAIN ENDS END MAIN
Djamal Rebaïne 4
Pourquoi les segments?
À l'origine Pour pouvoir adresser plus de 64 Ko de mémoire dans un programme car les registres sont sur16 bits En pratique aujourd'hui Permet de séparer clairement des zones mémoires selon leur rôle Exemple : la pile ne peut pas être écrasée par des données ou déborder sur des données / code Mais cela est contraignant ...
Djamal Rebaïne 5
Suite
Adressage sur 20 bits avec 2 registres 2 registres 16 bits : peut coder adresses sur 32 bits Pour uniquement 20 bits Décale le premier registre de 4 bits et l'additionne au second Adresse notée A:B Adresse réelle : A * 16 + B Exemple (les nombres sont en hexa) • 3100:27EE correspond à l'adresse 31000 + 27EE = 337EE • Décaler de 4 bits en binaire revient à décaler d'un chiffre en hexa Djamal Rebaïne 6
Suite 2
Nous avons 4 segments d'adresses : CS, DS, SS, ES • utiliser 2 registres pour adresser des mots mémoires - Le premier est le registre de segment Le second un registre général On l'appelle l'offset (décalage) Addresse :
segment:offset
• Exemples CS:IP : adresse de la prochaine instruction à exécuter DS:SI : adresse d'une donnée - SS:SP : adresse du haut de la pile Djamal Rebaïne 7
• Vos programme sources, écrits en assembleur, doivent avoir l’extension
.asm
pour
AS
se
M
bler
Djamal Rebaïne 8
Déclaration de variables
Les variables se déclarent de la manière suivante: datas1 db ? ; datas1 est un byte non initialisé datas2 db 0FFh ; datas2 est un byte initialisé à FF (255 en hexadécimal) datas3 dw ? ; datas3 est un word (16 bits) datas4 db 5 dup (?) ; datas4 est un tableau de 5 bytes non initialisés datas5 dw 10 dup (15) ; datas5 est un tableau de 10 byte initialisés à 15 De manière générale:
DB
: 1 byte (8 bits) (
D
eclare
B
yte)
DW
: 1 word (16 bits) (
D
eclare
W
ord)
DD
: 2 words (32 bits) (
D
eclare
D
ouble)
DF,DP DQ
: 6 bytes : 8 bytes (64 bits)
DT
: 10 bytes Les constantes peuvent être écrites en: décimal:
1, 2, 3, 123, 45
hexadécimal :
1h,2h,3h,12h,0Fh,0AD4h
(noter la présence du 0 quand le le premier chiffre du nombre en hexadécimal commence par une lettre) - binaire :
1b,0b,1010b,111101b
Djamal Rebaïne 9
Les entrées Sorties en assembleur
• Pour réaliser les opérations standards (affichage, saisie), le système d’exploitation (ici DOS) fournit les fonctions pré-écrites suivantes: • Affichage d’un caratère: mov DL, “A”; caractère A est transfére dans DL mov AH, 2; fonction no. 2 int 21h ; appel au DOS • • Affichage d’une chaine de caractères: mov DX, offset chaine; pointe vers l’adresse du premier caractère de la chaîne de caractères chaine mov AH, 09h; fonction no. 9 int 21h; Saisie d’un caratère: mov AH, 1; fonction no. 1 (avec écho) int 21h ; résultat est mis dans AL Djamal Rebaïne 10
•
Saisie d’un caractère mov AH, 7; fonction no. 7 (sans écho) int 21h ; résultat dans AL
•
Arrêt de programme
: mov AX, 4C00h; int 21h; À mettre à la fin de chaque fin programme; c’est l’équivalent du return (0) en C. Ces instructions ont pour effet de retourner au DOS Djamal Rebaïne 11
L’équivalent de quelques instructions du langage C en assembleur
• if then else Assembleur
If ax =1 if: CMP AX, 1 bx = 10; JNZ Else else { bx = 0; Then: MOV BX,10 cx = 10; JMP endif } Else: MOV BX,0 MOV CX,10 endif: ..............
Djamal Rebaïne 12
… Instruction i
Si
condition
alors
Instructions j
Sinon
Instruction m
Fin si
Instructions k FAUX Instructions m Instruction i Condition ?
Instructions k Djamal Rebaïne VRAI Instructions j 13
• La boucle FOR Assembleur
• • For (k=0; k<=10; k++) MOV BX,0 bx = bx + k; MOV CX,0 For: CMP CX,10 JA Endfor ADD BX,CX INC CX JMP For Endfor: Djamal Rebaïne 14
• WHILE Assembleur
• bx = 5 MOV BX,5 • while (bx >0) while: CMP BX,0 bx = bx -1; JLE Endwhile DEC BX JMP while Endwhile: Djamal Rebaïne 15
• SWITCH Assembleur
• switch (n) { CMP n,1 case 1: ....; break; JNE case2 case 2: .....; break; ............ default: .....; JMP endswitch } case2: CMP n,2 JNE default ..........
JMP endswitch default: ...........
endswitch: ........... Djamal Rebaïne 16
Écrire le code de l’instruction En assembleur
if (a>b) && (c <= d) if: cmp a, b { jng endif ................
} cmp c, d jnle endif ..............
endif:
Exercice:
coder en assembleur les instructions suivantes: 1. if (a >b) || (c > d)) 2. for (i=1; i < 10; i++) { { } } Djamal Rebaïne 17
Liste des registres les plus utilisés
• • • • • • •
A. Registres généraux AX (A pour accumulateur):
joue le rôle d’opérande implicite dans plusieurs opérations: MUL, DIV, INC, etc
. CX (C pour compteur):
est utilisé pour les boucles (instruction LOOP).
DX
: utilisé dans les multiplications et divisions comme registre d’extension.
SI (Source Index):
souvent utilisé comme pointeur sur une adresse mémoire (exemple: MOV AL, [SI]). Il est très utilisée avec les instructions de traitement de chaînes de caractères (LODS).
DI (Destination Index): BP
pareil que SI (instruction STOS) (base pointeur): sert de pointeur sur la base de la pile, et permet d’atteindre n’importe quel élément de la pile (exemple: MOV AX,[BP+2]).
SP (Stack pointer):
pointe sur le sommet de la pile; son contenu est automatiquement changé par les instructions PUSH et POP. Djamal Rebaïne 18
• • • • •
B. Registres spéciaux IP (Instruction pointeur
): contient l’adresse de l’instruction qui suit celle qui est en cours d’exécution.
DS (Data Segment)
: Pointe sur le début du segment qui contient les données
CS (Code Segment):
programme. Pointe sur le segment qui contient le code du
ES (Extended Segment) :
permet de pointer sur un segment supplémentaire défini par le programmeur. Il se charge par l’intermédiaire de AX, comme pour DS.
SS (Stack Segment):
segment contenant la pile.
C. Registre indicateur
: utilisé pour sauvegarder des états particuliers du microprocesseur en référence à la dernière instruction exécutée. Quelques bits seulement de ce registre ont une signification sont nommés: CF (retenue), OF (débordement), etc.
Djamal Rebaïne 19
Djamal Rebaïne 20
Format standard d’une instruction
Label: Mnémonique Opérandes ;commentaire Label:
est un identificateur permettant de désigner un endroit dans le code source, soit une instruction, soit une donnée. Si le label est placé avant une instruction, on fait référence à l’adresse de cette instruction. Si c’est avant une donnée, on fait référence à l’adresse de cette instruction. Le label de code doit se terminer par deux points (:). Il sert général comme destinations des instructions ou des retour de début des boucles de répétition. Le label de donnée ne contient pas les deux points(:) à la fin. Il sert dans ce cas là comme identificateur. Djamal Rebaïne 21
• • •
Mnémonique
(des instructions): il sert à identifier une instruction donnée. Quelques instructions de base sont résumées dans la prochaine section.
Opérandes:
une instruction assembleur peut avoir de 0 à 3 opérandes. Chaque opérande peut être le nom d’un registre, un opérande mémoire, une expression constante ou le nom d’un périphérique entrée/sortie.
Commentaire:
précédé du point-virgule (;). Il sert à à ajouter des informations explicatives au sujet du fonctionnement du programme ou de l’instruction correspondante. Djamal Rebaïne 22
Quelques instructions de base-1
•
Affectations
; Registres <-- Valeurs MOV
AX
, 65535 MOV
Cl
, 01101b MOV
DH
, 0FAh ; Entre registres MOV
AX
,
BX
MOV
CL
,
DH
; (décimal) ; (binaire) ; (hexa) ; Entre Registres et Variables MOV
CX
, variable_de_deux_octets MOV
variable_de_un_octet
, DL ;Registres <- Adresses Mémoire Mov
AX
, Offset variable ; AX <- adresse de variable Mov
CX
, [ 5Ah ] ; CX < valeur à l'adresse 5A en hexa Djamal Rebaïne 23
Quelques instructions de base- 2
•
Arithmétique
; Incrémentation INC
AX
; AX <- AX + 1 Inc
ma_variable
; Décrémentation DEC
AX
Dec
ma_variable
; Addition ADD
AX
, 5 ADD
BH
, toto Add ; Soustraction SUB
AX
, 5 SUB SUB
toto BH
, toto
toto
, Cx , CX ; AX <- AX + 5 ; BH <- BH + toto ; toto <- toto + Cx ; AX <- AX – 5 ; BH <- BH – toto ; toto <- toto - CX Djamal Rebaïne 24
Quelques instructions de base-3
•
Logique
; AND bit à bit MOV
AH
, 0101b ; AH <- 5 MOV
BH
, 1001b ; BH <- 9 AND
AH
, BH ; OR bit à bit ; AH <- AH AND BH; AH vaut 0001b, soit 1 MOV
AH
, 0101b ; AH <- 5 MOV
BH
, 1001b ; BH <- 9 Or
AH
, BH ; XOR bit à bit ; AH <- AH OR BH; AH vaut 1101b, soit 13 (8+4+1) MOV
AH
, 0101b ; AH <- 5 MOV
BH
, 1001b ; BH <- 9 XOR
Ah
, BH ; NOT bit à bit ; AH <- AH XOR BH; AH vaut 1100b, soit 12 (8+4) MOV
AH
, 0101b ; AH <- 5 Not
AH
soit 10 (8+2) ; AH <- NOT AH; AH vaut 1010b, Djamal Rebaïne 25
Quelques instructions de base-4
•
Comparaisons :
Toutes les comparaisons se font à l'aide de l'instruction
CMP
. On utilise ensuite les instructions de saut conditionnel:
Jump if Equal
,
JMP if Greater
, ... Il faut définir des labels (étiquettes): les endroits dans le programme où va sauter si le test est vérifié (comme les GOTO en Fortran). ; Egalité (Jump if Equal) CMP
AX
, 5 JE label_1 ; Différence (Jump if Not Equal) CMP
AX
, ma_variable JNE label_2 ;Inférieur, Supérieur, Inf. ou égal, Sup. ou égal ; (Jump if Lower, Greater, Lower or Equal, Greater or Equal) CMP
CH
, 0 JL label_1 CMP
DH
, Ah JG label_2 CMP
AL
, 01001b JLE label_3 Djamal Rebaïne 26
CMP
variable
, 65 JGE label_4 Label_1: instructions...
Label_2: instructions...
Label_3: instructions...
Label_4: instructions...
; Saut non conditionnel : JMP label_1
Remarque: CMP
résultat. Il positionne cependant les flags. Il permet de sauter à un label qui est à une adresse de 16 bits. Les sauts à un label sont toujours courts (à peu prés de est identique à l’instruction
127octets SUB
, mais ne produit pas de ). Il faut donc prendre garde que ce label puisse être atteint.
Djamal Rebaïne 27
Djamal Rebaïne 28
JZ JE JC JB JNAE JS JO JPE JP JNZ JNE JNC JNB JAE JNS JNO JPO JNP Saut si zéro.
Saut si égal.
Saut si Retenue (inférieur).
Saut si inférieur.
Saut si ni supérieur ni égal.
Saut si signe négatif.
Saut si débordement.
Saut si parité paire.
Saut si parité.
Saut si pas zéro.
Saut si différent.
Saut si pas de retenue.
Saut si pas inférieur.
Saut si supérieur ou égal.
Saut si aucun signe (positif).
Saut si pas de débordement.
Saut si parité impaire.
Djamal Rebaïne Saut si pas de parité.
ZF = 1 CF = 1 SF = 1 OF = 1 PF = 1 ZF = 0 CF = 0 SF = 0 OF = 0 PF = 0 JNZ JNE JNC JNB JAE JNS JNO JPO JZ JE JC JB JNAE JS JO JPE JP 29
Modes d’adressage
Un mode d'adressage est un moyen qui permet au microprocesseur d'avoir accès à une donnée. Cette donnée peut être un nombre quelconque dont on aura besoin dans le programme, un nombre qui se trouve déjà dans un registre, ou encore un nombre qui se trouve écrit quelque part en mémoire.
• La connaissance des principaux modes d'adressage est nécessaire car elle permet d'écrire les programmes de la façon la plus courte, la plus simple et la plus lisible possible. Djamal Rebaïne 30
Modes d’adressage
•
Mode immédiat
L’opérande est codée avec l’instruction mov AX, 568 •
Mode registre
L’opérande est un registre de donnée ou d’adresse mov AX,BX •
Mode mémoire direct
L’opérande est désigné par l’adresse donnée dans l’instruction mov mov [0hC040],AL DS :[0hC040],AL mov
mais pas
mov CS:var2,AX 0hFE15 :var2,AX Djamal Rebaïne 31
Modes d’adressage pour accéder aux données
•
Mode mémoire indirect
L’opérande est désignée par une adresse placée dans les registres d’adresses donnée dans l’instruction mov AX,[SI] BX,BP,SI,DI peuvent servir de registre pointeur 1.
Indirect avec déplacement
L’adresse = contenu du registre d’adresse + déplacement (
le registre d’adresse n’est pas modifié
) mov AX, [DI] mov BX,[DI+6] Djamal Rebaïne 32
Modes d’adressage pour accéder aux données
2.
Indirect avec index
L’adresse = contenu du registre d’adresse + contenu du registre d’index (
le registre d’adresse n’est pas modifié
) mov [BP][DI],AX les couples possibles sont BP-DI, BP-SI, BX-DI, BX-SI
Djamal Rebaïne 33
Quelques notes utiles
• La déclaration d’une chaîne de caractères est mise en '' '' ou ' ' .
• Le caractère '$' indique la fin d’une chaîne de caractères. Son omission implique que les octets en mémoire qui viennent après cette chaîne sont aussi affichés comme des caractères.
• L’assembleur ne fait pas de différence entre une majuscule et une minuscule dans l’écriture de ses instructions et la notation des registres. • La directive ASSUME permet d'indiquer à l'assembleur où se situe le segment de données et le segment de code. Puis il s'agit d'initialiser le segment de données à l’intérieur du segment de code: MOV AX, nom_du_segment_de_donnees MOV DS, AX Djamal Rebaïne 34
Un petit mot sur l’instruction de transfert
MOV reg, reg (registre à registre) reg, mem (registre à mémoire) mem, reg (mémoire à registre) reg, imed (registre à valeur) mem, imed (mémoire à valeur) NOTE: Pas de transfert de mémoire à mémoire Djamal Rebaïne 35
Applications de quelques instructions sur des exemples
Djamal Rebaïne 36
Instruction CMP (Comparer)
L’instruction CMP affecte les indicateurs AF, OF, SF, PF, CF et ZF mais seuls CF et ZF sont utilisés.
L’opérande destination peut être dans un registre ou dans une mémoire. L’opérande source peut être dans un registre, dans une mémoire, ou en mode immédiat.
Les opérandes (destination et source) ne changent pas.
DATA1 … PASSE : DW 235FH MOV MOV CMP J NC ADD ADD BX, 7888H CX, 9FFFH BX, CX PASSE BX, 4000H CX, DATA1
CMP destination, source
Compar e Opérand es Dest. > Src.
Dest. = Src.
Dest. < Src.
; 7888Hh
BX ; BX < CX
CF=1
JNC est exécutée
PASSE ; Note : les contenus de (BX, et CX) ne changent pas après CMP ; mais CF est toujours vérifié pour ( < ou > ). Pour ( = ) on utilise ZF.
C F 0 0 1 ZF 0 1 0 TEMP … DB MOV CMP J Z INC PROCHAIN : HLT ?
AL, TEMP AL, 99 PROCHAIN BX ; TEMP
AL ; TEMP = 99?. Avec ( SUB AL, 99), la même chose mais 0
; Si ZF=1 (TEMP=99), Saute a PROCHAIN: ; Sinon incrémente BX ; Arrêt du programme AL
Djamal Rebaïne 37
TITLE prog1.asm: Exemple sur CMP, PILE segment stack dw 100 dup(?) NOTES PLUS_G D B D B Trouver l’octet le plus grand parmi 5 notes d’élèves PILE ends ;------------------------------------------------------------------------------------------------------------------------------------------------------------ DATA segment 18, 06, 19, 11, 08 ? DATA ends ;----------------------------------------------------------------------------------------------------------------------------------------------------------- CODE segment main: assume CS:CODE, DS:data ; génération de l’adresse du segment de code et de données MOV AX, DATA ; Initialiser le registre DS pour récupérer l’adresse du segment de donnée MOV DS, AX MOV XOR ENCORE : CX , 5 MOV BX, OFFSET NOTES AL, AL CMP AL, [BX] ; compteur de boucle ; BX pointe vers les données NOTES ; Initialise AL à 0; va héberger la plus grande note ; compare la note prochaine a la note la plus élevée J A PROCHAIN ; Sauter si AL est encore la note la plus élevée MOV AL, [BX] ; sinon AL retient la plus élevée PROCHAIN : INC LOOP BX ; pointe vers la prochaine note ENCORE ; CX décrémente jusqu’à 0 pour sortir de la LOOP MOV PLUS_G, AL ; sauvegarde de la note la plus élevée dans PLUS_G ;------------------------------------------------------------------------------------------------------------------------------------------------------------ MOV INT MAIN END AH, 4Ch 21h ENDS MAIN
Djamal Rebaïne 38
TITLE prog2.asm: Pile ends Exemple sur ROL, Pile segment stack ; déclaration d’un segment de pile – pas nécessaire dans notre cas dw 100 dup(?) Trouver le nombre de ‘1’ dans un mot ;----------------------------------------------------------------------------------------------------------------------------------------------------------- DATA segment DATA1DW 5F97H COMPTE DB ?
DATA ends ;------------------------------------------------------------------------------------------------------------------------------------------------------------ CODE segment MAIN: ASSUME CS:CODE, DS:DATA MOV AX,DATA MOV DS, AX XOR MOV BL, BL DL, 16 MOV AX, DATA1 ENCORE : ROL AX, 1 JNC PROCHAIN INC BL PROCHAIN: DEC DL JNZ ENCORE MOV COMPTE, BL ; Mettre BL à 0 (ou bien SUB) ; rotation 16 fois ; Rotation a gauche (a droite aussi si on préfère) ; Test si CF=0 ; Si CF = 1, incrémenter le compteur du nombre de ‘1’ ; répéter 16 fois ; encore une fois si ce n’est pas fini ; sauvegarder le résultat dans la case mémoire COMPTE ;----------------------------------------------------------------------------------------------------------------------------------------------------------- MOV AH, 4Ch INT 21h MAIN ENDS END MAIN
Djamal Rebaïne 39
Quelques explications
L’itération:
On peut également transcrire une boucle à l’aide de l’instruction LOOP nécessitant l’utilisation implicite du registre CX. MOV CX, unevaleur Boucle: …… ; le corps de la boucle LOOP Boucle Cela signifie que le corps de la boucle est exécuté tant que la valeur de CX n’est pas nulle. A chaque itération, CX est décrémenté d’une unité.
Attention:
si CX est nul au premier tour, alors il décrémenté et sa valeur devient 65535, et on va attendre un bon bout de temps pour arriver à la valeur nulle et sortir de la boucle Djamal Rebaïne 40
for (cx=5; cx>0; cx--) ax = ax + cx MOV AX,0 MOV CX,5 ; CX est le compteur de boucle for: ADD AX,CX ; fait le calcul LOOP for ; décrémente d’une unité CX. ; si CX > 0 fait le saut à for
Djamal Rebaïne 41
On peut aussi utiliser LOOPE/LOOPZ/LOOPNE/LOOPNZ pour signifier : a.LOOPE («
Loop while Equal
») Monlabel Décrémente CX, puis, si CX <> 0 et ZF = 1, fait un saut à
MonLabel
. Mnémonique équivalent : LOOPZ • b. LOOPNE («
Loop while not Equal
») Monlabel Décrémente CX, puis, si CX <> 0 et ZF = 0, fait un saut à
MonLabel
. Djamal Rebaïne 42
Buffer DB 8 DUP(0) ……..
Boucle: MOV AH,1 ;lecture INT 21h MOV [BX], AL; rangement de qu’on vient de lire INC BX CMP AL, 0Dh; a-t-on lu le retour chariot?
LOOPNE Boucle; sinon on continue jusqu’à CX = 0 ????
Djamal Rebaïne 43
•
Décalage et rotation
SHL (Shift Left; SHR: shift right): effectue un décalage à gauche des bits. Si le deuxième opérande est une valeur, alors seule la valeur 1 est acceptée. Le bit de poids fort se retrouve dans CF; un 0 est introduit dans le bit de poids faible.
SHL AL, 1
Une façon plus élégante consiste à utiliser CL dans son rôle de compteur:
MOV CL, 4 SHL AX,CX
Pareil pour les instructions SAR, ROR, RCR et leurs équivalents à gauche. Djamal Rebaïne 44
Manipulation de données 1.
Operateur offset
: renvoie l’adresse à laquelle est située un label de donnée
Exemple:
…… Bval Wval1 db ?
dw ?
Wval2 dd ?
… … Si Bval se trouve à l’adresse offset 00404000 (hexa), l’opérateur offset renvoie les valeurs suivantes: MOV AX, offset bval ; AX = 00404000 MOV AX, offset Wval1 ; AX = 00404001 MOV AX, offset Wval2 ; AX = 00404002
2. Operateur PTR:
… Permet de passer outre la taille déclarée au départ pour un opérande. Par exemple, double dd 12345678h … MOV AX, double; erreur Mais si on insère la directive WORD PTR, on peut copier le mot de poids faible (5678h) dans AX; c’est-à-dire MOV AX WORD PTR double Djamal Rebaïne 45
Un mot sur les macros
Étant donné que certaines instructions se répètent constamment dans un programme, l’écriture de macro-fonctions (ou
macros
) est un moyen pratique de rendre votre code source plus lisible. Il est possible de choisir pour certaines suites d’instructions un nom qui les représente. Lorsque l’assembleur rencontrera ce nom dans votre code source, il le remplacera par les lignes de code qu’il désigne. Ces lignes forment une «
macro
». Djamal Rebaïne 46
Les macros, à la différence des procédures, n’ont aucune signification pour la machine. Seul l’assembleur comprend leur signification. Elles ne sont qu’un artifice mis à la disposition du programmeur pour clarifier son programme. Lorsque l’assembleur rencontre le nom d’une macro dans votre code, il le remplace par le code de la macro.
macro.
Tout se passe exactement comme si vous aviez tapé vous-même ce code à la place du nom de la
Ainsi, si vous appelez quinze fois une macro dans votre programme, le compilateur écrira quinze fois le code de cette macro. C’est toute la différence avec les fonctions qui ne sont écrites qu’une seule fois mais peuvent être appelées aussi souvent qu’on veut à l’aide d’un CALL (qu’on verra plus tard dans ce cours). Djamal Rebaïne 47
Voici comment écrire une macro : l’exemple suivant sert à écrire un message à l’écran.
Djamal Rebaïne 48
affiche macro chaine ; sauvegarder le contenu de DX, par ; exemple, en utilisant la pile push dx ; sauvegarde de dx dans la pile mov dx,offset chaine mov ah, 09h int 21h pop dx ; restauration de dx endm ;fin de la macro
Djamal Rebaïne 49
• • L’assembleur se chargera alors de la remplacer par les instructions comprises entre la première et la dernière ligne de cet exemple, en prenant le soin de remplacer le mot chaine par le message fourni en paramètre. • Supposons à présent que l’on veuille écrire à l’écran le message «
Coucou ! Ceci est un essai
» et revenir à la ligne à l’aide de notre macro
affiche
La syntaxe suivante
: •
affiche ‘Coucou ! Ceci est un essai !’, 10, 13, ‘$’
• 10, 13 est l’équivalent de endln en C-C++ Djamal Rebaïne 50
Présentation d’autres exemples
Djamal Rebaïne 51
TITLE ex3_somme; somme de deux nombres PILE SEGMENT STACK; déclaration de pile. ; Pour cet exemple, la pile n’est pas nécessaire.
DW 100 DUP (?) PILE ENDS affiche macro chaine ; macro pour afficher une chaîne de ; caractères MOV DX,offset chaine ; offset renvoie l’adresse de début de chaine MOV AH, 09h ; fonction qui affiche une chaîne de caractères INT 21h ENDM; fin de la macro DATA SEGMENT; déclaration de variables val1 db 0 val2 db 0 recup_val1 db 10,13,'veuillez taper la valeur1',10,13,'$' ; 10 et 13=endl du C++ recup_val2 db 10,13,'veuillez taper la valeur2',10,13,'$‘ aff_resu db 10,13,'la valeur saisie est:',32,'$' ; $ caractère de fin de chaine DATA ENDS Djamal Rebaïne 52
SCODE SEGMENT ; zone de code ASSUME CS:SCODE, DS:DATA ; génération de l’adresse du segment de code et de données DEBUT: ; entrée du code MOV AX, DATA ; Initialiser le registre DS pour récupérer l’adresse du MOV DS, AX ; segment de donnée ; à partir d’ici on peut placer nos lignes de code affiche recup_val1; appel de macro pour afficher un message contenu dans recup_val1 MOV AH,1 ; faire une lecture au clavier grâce à la fonction 1 le caractère tapé sera placé dans AL INT 21h MOV val1,AL affiche recup_val2; appel de la macro pour afficher un message sur écran MOV AH,1 ;faire une lecture au clavier INT 21h ADD AL,val1 ; AL = AL + val1 MOV val2,AL Djamal Rebaïne 53
affiche aff_resu; appel de la macro pour afficher un message sur écran SUB val2,30h ; les valeurs lues tantôt sont en ascii; exemple : ; si on tape les valeurs 1 et 2, ; le programme récupère 31 et 32, valeurs ; hexadécimales des caractères 1 et 2.
; Donc 31 + 32 = 63. et 63 n’est pas la valeur hexa ; du caractère 3. Sa valeur est 33 ; autrement dit, on doit retirer 30 en hexa ou 48 en ; décimal.
MOV AH,2 ; afficher la valeur saisie grâce à la fonction 2 INT 21h ; qui affiche le contenu de DL MOV DL,val2 MOV AH, 4Ch ; on termine le programme avec la fonction MOV AL, 0 ; 4c en hexa. On place une valeur >=0 pour dire INT 21h ; que l’exécution s’est déroulée correctement. ; Équivalent en c de return 0 SCODE ENDS; fin du segment de code END DEBUT Djamal Rebaïne 54
TITLE ex4_max ; détermine et affiche le maximum de deux nombres ; introduits à travers le clavier PILE SEGMENT STACK DW 100 DUP (?) ; déclaration d’une pile de 100 éléments PILE ENDS affiche macro chaine ; à la compilation, l’assembleur recopie l’ensemble mov dx,offset chaine mov ah, 09h ; de instructions de cette macro ; pointe vers le début de la chaîne chaine ; pour afficher une chaîne de caractères à partir de ; l’adres de début de chaine Endm int 21h DATA SEGMENT temp db 0 ; initialisation de temp à 0 val1 db 0 val2 db 0 recup_val1 db 10,13,'veuillez taper la valeur1',10,13,'$' ; 10 et 13=endl du c++ recup_val2 db 10,13,'veuillez taper la valeur2',10,13,'$' aff_resu db 10,13,'le maximun est :',32,'$' ; $ caractère de fin de chaîne DATA ENDS Djamal Rebaïne 55
SCODE SEGMENT ASSUME CS:SCODE, DS:DATA ; génération d,adresses pour les segments de code et de données DEBUT: ; entrée du code ; Initialiser le registre DS par l’adresse du segment de donnée générée par ; la directive ASSUME MOV AX, DATA MOV DS, AX affiche recup_val1 ; permet d’afficher le message contenu dans recup_val1 MOV val1,AL MOV AH,1 ;faire une lecture au clavier d’un caractère INT 21h affiche recup_val2 ; afficher un message MOV AH,1 ; faire une lecture au clavier int 21h MOV val2,AL CMP AL,val1 JG grand Djamal Rebaïne 56
MOV DL,val1 JMP sortie grand: MOV DL,val2 sortie: MOV temp,DL affiche aff_resu ; afficher un message MOV DL temp; ces trois instructions servent à ; afficher le contenu du registre dl MOV AH,2 INT 21h ; Terminer le programme en retournant vers le DOS MOV AH, 4Ch MOV AL, 0 INT 21h SCODE ENDS ; fin du segment de code END DEBUT ; fin de l’entrée du code Djamal Rebaïne 57
Exemple 5: que fait cette portion de code?
MOV BX, offset Alphabet ;alphabet étant une chaîne de caractères MOV CL, 26 MOV [BX], CL ; 26 caractères MOV AL, 65h ; 65 = 'A' dans AL MaBoucle: INC BX MOV [BX], AL ; écrit dans le tableau INC AL ; AL = caractère suivant DEC CL ; affecte l’inicateur ZF JNZ MaBoucle ; test l’indicateur ZF = 0 XOR BX, BX ; permet de mettre BX à 0 MOV BX,offset alphabet MOV CL,26 Boucle: INC BX MOV DL, alphabet[bx] MOV AH,2 INT 21h MOV DL, ‘ ‘ ; permet d’afficher un blanc MOV AH, 2 INT 21h DEC CL JNZ Boucle Djamal Rebaïne 58
Exemple 6
: que fait la portion de code ci-dessous ? MOV BX, offset Chose ; Met l‘adresse de début du tableau chose dans BX MOV DI, 0 ; Index nul MOV AX, 1 MOV CX, 11 ; 11 éléments dans le tableau MaBoucle: MOV [BX+DI], AX ; écrit dans le tableau SHL AX, 1 ; AX = AX * 2 ADD DI, 2 ; Chose est un tableau de Words -> 2 octets DEC CX JNZ MaBoucle
Remarque 1
: Lors de la saisie d’une chaîne de caractères au clavier, les deux premiers termes sont réservés: le premier étant la dimension et le deuxième est le nombre effectif de caractères.
Remarque 2 :
Les registres SI, DI, BX peuvent être utilisés pour les indices de tableaux indifféremment. Djamal Rebaïne 59
TITLE sommedetroixnombres ; ce programme fait la somme des trois premiers nombres entiers i.e : 1+2+3 PILE SEGMENT STACK DW 100 DUP (?) PILE ENDS affiche macro chaine; déclaration de macro mov dx,offset chaine mov ah, 09h int 21h endm; fin de la macro DATA SEGMENT temp db 0 val1 db 3 val db 0 aff_resu db 10,13,'la somme des termes jusqu a 3 est:',32,'$' ; $ caractère de fin de chaîne DATA ENDS Djamal Rebaïne 60
SCODE SEGMENT ASSUME CS:SCODE, DS:DATA DEBUT: ; Initialiser le registre DS MOV AX, DATA MOV DS, AX MOV AX,0 so: CMP AH,val1 JGE psorte INC AH ADD AL,AH JMP so psorte: ADD AL,30h MOV temp,AL affiche aff_resu; affichage à l’aide de la macro MOV AL,temp MOV DL, AL MOV AH,2 ; afficher la valeur saisie INT 21h ; Terminer le programme MOV AH, 4Ch MOV AL, 0 INT 21h SCODE ENDS END DEBUT Djamal Rebaïne 61
• Exemple 7: Exemple sur ROL, Trouver le nombre de ‘0’ dans un double-mot
Djamal Rebaïne 62
TITLE programme.asm: Exemple sur ROL, Trouver le nombre de ‘0’ dans un double-mot PILESEGMENT STACK DW 100 DUP (?) PILEENDS DATA DATA1 SEGMENT DD COMPTE DB DATA ENDS 0ABCD5F97H ?
CODE SEGMENT ASSUME CS:SCODE, DS:DATA ; Initialiser le registre DS MOV AX, DATA MOV DS, AX XOR CX, CX MOV AH, 4Ch INT 21h ; Mettre CX à 0 (ou bien SUB) MOV DX, 1010h ; mettre 16 dans DH et DL; 00010000 000010000 en binaire MOV MOV AX, WORD PTR DATA1 BX, WORD PTR DATA1 + 2 ENCORE1: ROL AX, 1 ; pointer vers le premier mot ; pointe vers le deuxième mot ; Rotation à gauche (à droite aussi si on préfère) JC INC PROCHAIN1: DEC DL JNZ ENCORE1 MOV AL, CL ENCORE2: ROL BX, 1 PROCHAIN1 CL Test si CF=1 ; Si CF = 0, incrémenter le compteur du nombre de ‘0’ ; répéter 16 fois ; encore une fois si ce n’est pas fini ; sauvegarder le résultat dans AL, en sortant de la boucle, le contenu de AX ; nous importe peu, donc en écrasant le premier mot n’est pas grave ; Rotation à gauche PROCHAIN2: DEC DH MOV AH, CH ADD AH, AL JC PROCHAIN2 INC CH JNZ ENCORE2 MOV COMPTE, AH ; Test si CF=1 ; Si CF = 0, incrémenter le compteur du nombre de ‘0’ ; répéter 16 fois ; encore une fois si ce n’est pas fini ; sauvegarder le résultat dans AH. Même remarque qu’en haut ; Additionner les nombres de ‘0’ trouvés séparément dans les 2 mots ; et sauvegarder le résultat dans COMPTE ; retour au DOS Code ENDS END MAIN Djamal Rebaïne 63
L .
.
A B Y Z Hex 41 42 59 5A
Conversion Minuscule en Majuscule
Binaire 01 0 00001 01 0 00010 ………… ………… 01 0 11001 01 0 11010 .
y z L a .
b Hex 61 62 79 7A Binaire 01 1 00001 01 1 00010 ………… ………… 01 1 11001 01 1 11010
Djamal Rebaïne 64
TITLE prog8.asm ; Conversion MINUSCULE PILE SEGMENT STACK MAJUSCULE d’un texte DW 100 DUP (?) PILE ENDS DATA SEGMENT TEXTE1 DB ‘mOn Nom eST REBainE’, 13,10, ‘$’ TEXTE2 DB 21 DUP(?) ;----------------------------------------------------------------------------------------------------------------------------------------------------------- CODE SEGMENT ASSUME CS:SCODE, DS:DATA ; Initialiser le registre DS MOV AX, DATA MOV DS, AX MAIN : MOV SI, OFFSET TEXTE1 ARRIERE: MOV MOV MOV BX, OFFSET TEXTE2 CX, 21 AL, byte ptr t[SI] CMP JB CMP JA AND MOV INC INC LOOP AL, 61H PASSE AL, 7AH PASSE AL, 11011111B [BX], AL SI BX ARRIERE ; SI pointe sur le texte original ; BX pointe sur le texte en MAJUSCULE ; compteur de boucle ; prochain caractère ; Si < ‘a’ (61H est le code ASCII de ‘a’) ; donc pas besoin de convertir ; Si > ‘z’ (7AH est le code ASCII de ‘z’) ; donc pas besoin de convertir Djamal Rebaïne 65
Exemple 9: lit une chaîne de caractères et l’affiche à l’envers • Programme palin
Djamal Rebaïne 66
title palin pile segment stack dw 100 dup(?) pile ends data segment reponse db 255 dup('$') enter db 10,13,'$‘ ; endln en C++ temp db 0 data ends scode segment assume cs:scode, ds:data entree: mov ax,data mov ds,ax ; on écrit le code à partir de là mov dx,offset reponse mov ah,0ah ; lecture à partir du clavier d’une chaîne de caractères ;qui se termine dès qu’on tape le retour chariot (touche entrée) int 21h mov si,dx mov cx,si Djamal Rebaïne 67
Deb: cmp BL,0dh; comparer à la touche entrée 13 en ascii car la fin de reponse contient ce caractère je finsearch inc SI mov BL,byte ptr[si] jmp deb finsearch: dec SI inc CX mov DX,offset enter mov AH,09h int 21h fs: cmp SI,CX je fin_s mov DL,byte ptr[si] mov AH,02h int 21h dec SI jmp fs fin_s: mov ax,4c00h int 21h scode ends end Deb Djamal Rebaïne 68
• • • • • • • • • • • • • • • • • • • • • • • • • Une autre manière de le faire ;debut: xor dx,dx mov DL,[si+1] ; récupération du nombre de caractères lus ; la taille à récupérer est obtenue par l’objet de destination ; car [si+1] n’a pas de taille spécifique donc obligation de la ; récupérer avec la destination ; ici DL donc récupération de 8bits ; si DX récupération de 16bits ; la destination décide de la taille à récupérer mov si,dx inc si mov cx,1 f_s: cmp si,cx jle fin_s mov dl,reponse[si] mov ah,02h int 21h dec si jmp f_s fin_s: mov ax,4c00h int 21h scode ends end Djamal Rebaïne 69
Une troisième manière de le faire
• • • • • • • • • • • • • • • • • • • • • • • debut: xor DX,DX mov DX,reponse[si] ; récuperation du nombre de caractères lus ; la taille à récupérer est obtenue par l’objet de destination ; ici DL donc récupération de 8bits si DX récupération de 16bits ; la destination décide de la taille à récupérer mov SI,DX inc SI mov CX,1 fs: cmp SI,CX jle fins mov DL,reponse[si] mov AH,02h int 21h fins: dec SI jmp fs mov AX,4c00h int 21h scode ends end Djamal Rebaïne 70
• • • •
MULTIPLICATION ET DIVISION SIGNÉE (IMUL / IDIV) reg. (ou mém.)
Note
: Dans les manuels d’Intel IMUL et IDIV pour Integer MULtiplication et DIVision (X et / des nombres entiers) mais au fait il s’agit de Multiplication et Division des nombres signées.
DIVISION SIGNEE NUM. (> ou <) DENOM. (> ou <) QUOTIENT RESTE Octet/Octet Mot/Mot Mot/Octet DoubleMot/Mot
AL = Octet CBW AX = Mot CWD AX = Mot DXAX = DoubleMot Reg. ou mem.
Reg. ou mem.
Reg. ou mem.
Reg. ou mem.
AL AX AL (Erreur si –128>AL>+127) AX (Erreur si –32768>AX>+32767) AH DX AH DX
MULTIPLICATION SIGNEE Octet/Octet
AL
OPERANDE 1 (> ou <) Mot/Mot Mot/Octet DoubleMot/Mot
AX AL = Octet CBW
OPERANDE 2 (> ou <)
Reg. ou mem.
Reg. ou mem.
Reg. ou mem.
RESULTAT
AX (CF=OF=1 si AH possède une partie du résultat, mais si celui ci n’est pas large pas besoin de AH, le bit de signe est copié aux bits non utilisés de AH et la CPU force CF=OF=0 pour l’indiquer) DXAX(CF=OF=1 si DX possède une partie du résultat, mais si celui-ci n’est pas large pas besoin de DX, le bit de signe est copié aux bits non utilisés de DX et la CPU force CF=OF=0 pour l’indiquer) DXAX (même remarque que précédemment) Djamal Rebaïne 71
Title exemple pour trouver la moyenne d’un ensemble de nombres PILE segment stack dw 100 dup (?) PILE ends DATA segment SIGN_DAT DB +13,-10,+19,+14,-18,-9,+12,-9,+16 MOYENNE DW ?
RESTE DW ?
DATA ends CODE segment ASSUME CS:CODE, DS:DATA MOV AX,DATA MOV DS,AX MAIN: ARRIERE: MOV XOR MOV MOV INC LOOP MOV MOV MOV CX,9 BX,BX SI,OFFSET SIGN_DAT AL,[SI] CBW ADD BX,AX SI ARRIERE AL,9 CBW CX,AX AX,BX ; Charger le compteur ; Mettre a 0 le registre BX, utilisé comme accumulateur ; SI
SIGN_DAT ; Un octet de donnée
AL ; Extension du signe
; BX+AX
BX ; SI+1
SI AX ; Boucler tant que CX > 0 ; Le nombre totales des températures
; Extension du signe
AX AL ; Sauvegarder le DENOMINATEUR dans CX ; LA somme des températures
AX
• • • • • •
; EXEMPLE D’UTILISATION DE IDIV
•
CWD IDIV MOV CX MOYENNE,AX MOV MOV MAIN ENDP END REMAINDER,DX MAIN TROUVER LA TEMPERATURE MOYENNE ; Extension du signe AH,4CH INT 21H ;Retourner au DOS
; Sauvegarder le reste AX ; Trouver la moyenne des températures (AX/CX) ; Sauvegarder la moyenne (QUOTIENT)
Djamal Rebaïne 72
Expression arithmétique X = (A*2 + B*C)/(D-3) .......
Data segment X dw ?
A dw ?
B dw ?
C dw ?
D dw ?
Data ends Arithmetique proc near MOV AX, 2 IMUL A MOV BX,DX MOV CX,AX MOV AX,B ; ;établir la constante ;DX:AX = A*2 ;BX:AX = A *2 IMUL C ADD AX,CX ;AX = AX + CX ! faites attention, il peut y avoir une retenue ici ADC DX,BX ;DX:AX = A*2+B*C + la retenue s’il y a lieu avec ADC MOV CX, D SUB CX,3 ;DX:AX = B*C ; cx = D -3 IDIV CX ; AX =(A*2 + B*C)/(D-3) MOV X,AX ; X = ax (A*2 +B*C)/(D 3) stocker le résultat RET Arithmetique endp ; fin de la procedure ............ Djamal Rebaïne 73
Conversion d’une chaine de caractères en une valeur décimale Toute information introduite via le clavier est considérée comme une chaîne de caractères. Ainsi, si on introduit le nombre 827, il sera considéré par l’assembleur comme la chaîne de caractères ‘827’. Pour avoir sa valeur numérique, il y a lieu de la convertir suivant l’algorithme suivant:
Djamal Rebaïne 74
Algorithme de conversion
• nbre = nombre de caractère lus • Nombre = 0 • • • Repeter chiffre = caractère lu nombre = nombre *10+chiffre • • nbre = nbre -1 • Si nbre > 0 aller à repeter
Djamal Rebaïne 75
Exemple
• ‘827’ • nombre = 0 • Chiffre = 8 • nombre = nombre * 10 +chiffre =0*10+8 = 8 • Chiffre = 2 • nombre = nombre * 10 + 2 = 8*10 + 2 = 82 • • Chiffre = 7 • Nombre = nombre * 10 + 7 = 82*10+7 = 827 Djamal Rebaïne 76
En assembleur, on aura quelque chose comme ci-dessous TITLE caracteresversnombre SPILE SEGMENT STACK DW 100 DUP(?) SPILE ENDS SDATA SEGMENT chaine db 255 dup('$') SDATA ENDS SCODE SEGMENT ASSUME CS:SCODE,DS:SDATA DEBUT: mov AX,sdata mov DS,AX mov DX,offset chaine mov AH,0ah int 21h mov SI,1 mov AX,0 xor CX,CX mov CL,chaine[si] inc SI repeter: mov DX,10 mul DX mov DL,chaine[si] sub DL,48; ou bien 30h, c’est pareil. C’est pour rendre le caractère lu comme une valeur numérique mov DH,0 add AX,DX inc SI loop repeter MOV AX,4C00H INT 21H SCODE ENDS END DEBUT Djamal Rebaïne 77
Pour lire une chaine de caractères, appeler 21h fonction 0Ah qui installe les caractères tapés dans une zone repérée par DS:DX (buffer déclarée dans le segment de données). La fonction se termine quand un return (touche entréée) est détecté. Le buffer contient alors les informations suivantes:
byte contenu
0 nombre maximum de caractères à lire 1 nombre de caractères lus (sans compter le retour chariot).
cette valeur est installée par la fonction.
2 À partir de cette position, on trouve les caractères lus Djamal Rebaïne 78
Conversion d’une valeur décimale en une chaîne de caractères
Toute information affichée sur écran est considérée comme un caractère. Ainsi, pour afficher la valeur 827, il faut dans un premier temps avoir tous le chiffres qui la composent; ensuite convertir chacun de ces chiffres en leur équivalent ascii et ensuite passer à l’affichage proprement dit.
Ainsi, si on veut afficher le 827, on doit d’abord récupérer les chiffres 8, 2 et 7 par une succesion de divisions par dix (ces chiffres seront récupérés dans l’ordre inverse). Ensuite, les convertir en ASCII en ajoutant la valeur 30h, et enfin passer à l’affichage proprement dit dans l’odre inverse pour avoir le bon ordre.
L’algorithme, récupérant les chiffres dans l’ordre inverse, peut être comme suit: Djamal Rebaïne 79
Algorithme
k = 0 do quotient = nombre / 10; reste = nombre % 10; tab[k] = reste; nombre = quotient; k++ while (quotient != 0) Djamal Rebaïne 80
Dans ce programme, les chiffres composant le nombre contenu dans AX est affiché dans le bon ordre
; on suppose que le registre AX contient le nombre mov result,AX ; déclarer result dans le segment de données mov dx,offset enter ; retour chariot 10, 13 dans le segment de données mov ah,09h int 21h mov ax,result mov SI, offset tabconv ; tabconv est à déclarer dans le segment de données mov start, offset tabconv ; start sert à garder le début du tableau mov BX,0 mov BL,10 division: ; on suppose que la division se fait sur des nombres de 16 bits div BL cmp AL,0 je fin_div add AH,48 mov byte ptr[si],AH mov AH,0 inc SI jmp division Djamal Rebaïne 81
fin_div: add AH,48 mov byte ptr[si],AH ;tabconv contient le nombre converti à l’envers xor BX,BX mov BX, offset tabsortie le segment de données xor AX,AX st_bcl: ; à declarer dans cmp SI,start jb fin_bcl mov AH , byte ptr[si] mov byte ptr[bx] , AH dec si inc bx jmp st_bcl Djamal Rebaïne 82
fin_bcl: mov byte ptr[bx],10 inc BX mov byte ptr[bx],13 inc BX mov byte ptr[bx],'$' mov dx,offset tabsortie mov ah,09h int 21h MOV AX,4C00H INT 21H SCODE ENDS END DEBUT Djamal Rebaïne 83
La directive EQU
La directive EQU a un rôle voisin de celui des macros. Elle permet de remplacer un simple mot par d’autres plus complexes. Son intérêt est qu’elle peut être invoquée en plein milieu d’une ligne.
Djamal Rebaïne 84
Quelques exemples
Longueur
EQU (
fin
–
debut
)
Message
EQU “
Bonjour messieurs ! Comment allez-vous ?
”, ‘
$
’
Version
EQU
2 Quitter Quitter2
EQU ret EQU int 20h
Mettre_dans_AH Interruption_21h
EQU mov ah, EQU int 21h Djamal Rebaïne 85
Les piles
Djamal Rebaïne 86
•
Utilité d'une pile
Une pile est une zone de mémoire dans laquelle on peut stocker temporairement des registres. Il s'agit d'un moyen d'accéder à des données en les empilant, telle une pile de livre, puis en les dépilant pour les utiliser. Ainsi il est nécessaire de dépiler les valeurs stocker au sommet (les dernières à avoir été stockées) pour pouvoir accéder aux valeurs situées à la base de la pile. En réalité il s'agit d'une zone de mémoire et d'un pointeur qui permet de repérer le sommet de la pile. La pile est de type LIFO (Last In First Out), c'est à-dire que la première valeur empilée sera la dernière sortie (Si vous empilez des livres, il vous faudra les dépiler en commençant par enlever les livres du dessus. Le premier livre empilé sera donc le dernier sorti!). •
Les instructions PUSH et POP
Les instructions PUSH et POP sont les instructions qui servent à empiler et dépiler les données. - PUSH
registre
- POP
registre
(dépilage met le contenu du registre dans la pile (empilement) récupère le contenu de la pile et le stocke dans le registre Djamal Rebaïne 87
Ainsi, l'instruction
PUSH BX
empile le contenu du registre BX, et l'instruction
POP AX
récupère le contenu du sommet de la pile et le transfère dans AX. Djamal Rebaïne 88
Utilisation de la pile sur un exemple
• Dans l'exemple suivant, que l'on imaginera au milieu d'un programme, on stocke les valeurs contenues dans AX et BX pour pouvoir utiliser ces deux registres, puis une fois l'opération accomplie on remet les valeurs qu'ils contenaient précédemment...
Djamal Rebaïne 89
• PUSH AX • PUSH BX • MOV AX, [0140] • ADD BX, AX • MOV [0140], BX • POP BX • POP AX
Djamal Rebaïne 90
•
Les registres SS et SP
Les registres SS et SP sont deux registres servant à gérer la pile: • SS (
Stack Segment
, dont la traduction est
segment de pile
) est un registre 16 bits contenant l'adresse du segment de pile courant. • Il doit être initialisé au début du programme • SP (
Stack Pointer
, littéralement la pile (16 bits de poids faible).
pointeur de pile
) est le déplacement pour atteindre le sommet de Djamal Rebaïne 91
• SP pointe vers le sommet, c'est-à-dire sur le dernier bloc occupé de la pile. Lorsque l'on ajoute un élément à la pile, l'adresse contenue dans SP est décrémentée de 2 octets (car un emplacement de la pile fait 16 bits de longueur). • En effet, lorsque l'on parcourt la pile de la base vers le sommet, les adresse décroissent. Par contre l'instruction POP incrémente de 2 octets (16 bits) la valeur de SP. Djamal Rebaïne 92
• •
PUSH
: SP <- SP - 2
POP
: SP <- SP + 2 • Ainsi, lorsque la pile est vide SP pointe sous la pile (la case mémoire en-dessous de la base de la pile) car il n'y a pas de case occupée. Un POP provoquera alors une erreur...
Djamal Rebaïne 93
Déclarer une pile
• Pour pouvoir utiliser une pile, il faut la déclarer, c'est à-dire réserver un espace mémoire pour son utilisation, puis initialiser les registres avec les valeurs correspondant à la base de la pile, ainsi que son sommet (rappel: situé sous la pile lorsque celle-ci est vide). • Ainsi pour définir une pile, il s'agit tout d'abord de la déclarer grâce à la directive SEGMENT stack. Djamal Rebaïne 94
Déclaration d'une pile
Pour utiliser une pile en assembleur, il faut déclarer un segment de pile, et y réserver un espace suffisant. Ensuite, il est nécessaire d'initialiser les registres SS et SP pour pointer sous le sommet de la pile. Voici la déclaration d'une pile de 200 octets : segment_pile SEGMENT stack ; mot clef stack pour pile DW 100 dup (?) ; réserve espace base_pile EQU this word ; etiquette base de la pile segment_pile ENDS Noter le mot clef ``stack '' après la directive SEGMENT, qui indique à l'assembleur qu'il s'agit d'un segment de pile. Afin d'initialiser SP, il faut repérer l'adresse du bas de la pile; c'est le rôle de la ligne base_pile EQU this word (voir figure suivante). Djamal Rebaïne 95
Djamal Rebaïne 96
• Suite aux déclarations, il faut écrire une séquence d'initialisations: • • • • ASSUME SS:segment_pile ; génère une adresse pour l’emplacement de la ; pile MOV AX, segment_pile MOV SS, AX ; initialise le segment de pile MOV SP, base_pile ; copier l'adresse de la base de la pile dans SP • Remarquez qu’il n'est pas possible de faire directement
MOV SS, segment_pile
instruction n'existe pas! car cette Djamal Rebaïne 97
Les procédures-fonctions
La notion de procédure - fonctions
En langage assembleur, on appelle
procédure
un sous programme qui permet d'effectuer un ensemble d'instructions par simple appel de la procédure. Cette notion de sous programme est généralement appelée fonction dans d'autres langages. Les fonctions et les procédure permettent d'exécuter dans plusieurs parties du programme une série d'instruction, cela permet une simplicité du code et donc une taille de programme minimale. D'autre part, une procédure peut faire appel à elle même, on parle alors de procédure récursive (il ne faut pas oublier de mettre une condition de sortie au risque sinon de ne pas pouvoir arrêter le programme...). Djamal Rebaïne 98
Djamal Rebaïne 99
La déclaration d'une procédure
Etant donnée qu'une procédure est une suite d'instructions, il s'agit de regrouper les instructions composant la procédure entre des mots clés. L'ensemble de cette manipulation est appelée
déclaration de procédure
. Ces mots clés permettant la déclaration de la procédure sont le
une étiquette PROC
(qui représente le nom de la fonction) précédant le mot clef marquant le début de la procédure, suivi de
near
(qui signale que la procédure est située dans le même segment que le programme appelant) et
RET
désignant la dernière instruction, et enfin le mot clé
ENDP
qui annonce la fin de la procédure. Ainsi une déclaration de procédure ressemble à ceci: Djamal Rebaïne 100
Etiquette
PROC near instruction1 instruction2 ...
RET
Etiquette
ENDP Djamal Rebaïne 101
Appel d'une procédure
C'est l'instruction
CALL
qui permet l'appel d'une procédure. Elle est suivie soit d'une adresse 16 bits, désignant la position du début de la procédure, ou bien du nom de la procédure (celui de l'étiquette qui précède le mot clé
PROC
). Djamal Rebaïne 102
Comment l'appel et la fin de la procédure fonctionnent?
mot clé
RET
stocké avant l'appel par
PROC
. Lorsque l'on appelle une procédure, la première adresse de la procédure est stocké dans le registre IP (pointeur d’instruction), le processeur traite ensuite toutes les lignes d'instructions jusqu'à tomber sur le , qui va remettre dans le registre IP l'adresse qui y était Cela paraît simple mais le problème provient du fait que les procédures peuvent être imbriqués, c'est-à-dire que de saut en saut, le processeur doit être capable de revenir successivement aux adresses de retour. En fait, à chaque appel de fonction via l'instruction
CALL
, le processeur empile l'adresse contenue dans le registre IP (il pointe alors sur l'instruction suivant l'instruction CALL) avant de la modifier, à l'appel de l'instruction registre IP.
RET
(qui ne prend pas d'arguments) le contenu de la pile est dépilé puis stocké dans le Djamal Rebaïne 103
Djamal Rebaïne 104
Voici un exemple d’utilisation des procédures aussi simple que possible : ce programme appelle 12 fois une procédure qui écrit un message à l’écran et rend la main au DOS. Remarque : Les codes ASCII 10 et 13 représentent respectivement la fin de ligne et le retour chariot. Grâce à eux, on revient à la ligne chaque fois qu’on a écrit le message. Djamal Rebaïne 105
Title les procédures Pile segment stack dw 100 dup (?) Basedepile equ thisword Pile ends data segement message db ’bonjour, monde!’, 10,13, ‘$’ data ends code segment assume cs:code, ds:code, ss:pile debut: MOV AX, data MOV DS, AX MOV AX, Pile MOV SS, AX ; initialise le segment de pile MOV SP, basedepile MOV CX,12 boucle: call ecritmessage LOOP boucle ; appel de procédure ; décrementer CX de une unité et aller à ; boucle si CX est différent de 0 ; terminer le programme ici par le retour au DOS mov AX, 4C00h INT 21H Djamal Rebaïne 106
ecritmessage proc near ;notre fonction mov ah, 09h move dx,offset message int 21h ret ecritmessage endp ; fin de la procédure/fonction code ends ; fin du segment de code end debut ; fin de la porte d’entrée Djamal Rebaïne 107
Le passage de paramètres
Une procédure effectue généralement des actions sur des données qu'on lui fournit, toutefois dans la déclaration de la procédure il n'y a pas de paramètres (dans des langages évolués on place généralement les noms des variables comme paramètres entre des parenthèses, séparés par des virgules). Il existe toutefois deux façons de passer des paramètres à une procédure:
Le passage des paramètres par registre
: on stocke les valeurs dans les registres utilisés dans la procédure
Le passage des paramètres par pile:
dans la procédure.
on stocke les valeurs dans la pile avant d'appeler la procédure, puis on lit le contenu de la pile
Le passage de paramètres par registres
l’appel de la fonction... C'est une méthode simple pour passer des paramètres: Elle consiste à écrire une procédure en faisant référence à des registres dans les instructions, et de mettre les valeurs que l'on désire dans les registres juste avant Djamal Rebaïne 108
Le passage des paramètres par registre
Cette manière de procéder est très simple à mettre en oeuvre mais elle est très limité, car on ne peut pas passer autant de paramètres que l'on désire, à cause du nombre limité de registres. On lui préfèrera le passage des paramètres par pile.
Le passage de paramètres par pile
Cette méthode de passage de paramètres consiste à stocker les valeurs des paramètres dans la pile avant l'appel de procédure (grâce à l'instruction
PUSH
), puis de lire le contenu de la pile grâce à un registre spécial ( sommet de pile (SP).
BP
: Base pointer) qui permet de lire des valeurs dans la pile sans les dépiler, ni modifier le pointeur de Djamal Rebaïne 109
L'appel de la procédure se fera comme suit: PUSH parametre1 ; où parametre1 correspond à une valeur ou une adresse PUSH parametre2 ; où parametre1 correspond à une valeur ou une adresse CALL procedure La procédure commencera par l'instruction suivante: MOV BP, SP ;permet de faire pointer BP sur le sommet de la pile Puis pourra contenir des instructions du type: MOV AX, [BP] ;Stocke la valeur contenue dans le sommet de ;la pile dans AX, sans dépiler MOV BX, [BP+2] ;Stocke la valeur contenue dans le mot suivant de la ;pile dans BX (un mot fait 2 octets), sans dépiler
Djamal Rebaïne 110
Exemple avec passage par registre
• On va écrire une procédure ``SOMME'' qui calcule la somme de 2 nombres naturels de 16 bits. • Convenons que les entiers sont passés par les registres AX et BX, et que le résultat sera placé dans le registre AX. • La procédure s'écrit alors très simplement :
Djamal Rebaïne 111
SOMME PROC near ; AX <- AX + BX ADD AX, BX RET SOMME ENDP et son appel, par exemple pour ajouter 6 à la variable Truc : MOV AX, 6 MOV BX, Truc CALL SOMME MOV Truc, AX Djamal Rebaïne 112
Exemple avec passage par la pile
Cette technique met en oeuvre un nouveau registre, BP (
Base Pointer
), qui permet de lire des valeurs sur la pile sans les dépiler ni modifier SP. Le registre BP permet un mode d'adressage indirect spécial, de la forme : MOV AX, [BP+6]; cette instruction charge le contenu du mot mémoire d'adresse BP+6 dans AX. • Ainsi, on lira le sommet de la pile avec : MOV BP, SP MOV AX, [BP] MOV AX, [BP+2] ;BP pointe sur le sommet ;lit sans dépiler et le mot suivant avec : ;2 car 2 octets par mot de pile. L'appel de la procédure ``SOMME2'' avec passage par la pile est : PUSH 6 PUSH Truc CALL SOMME2 Djamal Rebaïne 113
; passage de paramètres push AX push BX push CX push DX call soubroutine ; branchement vers la procédure ; ......... Contineur traitement soubroutine proc near mov BP,SP ; pointe vers le sommet de pile move AX, [BP+2] ; acquérir dernier paramètre (DX) sans dépiler; pourquoi?
move AX, [BP+4] ; acquérir 3ème paramètre (CX) sans dépiler move AX, [BP+6] ; acquérir 2ème paramètre (BX) sans dépiler move AX, [BP+8] ; acquérir premeir paramètre (AX) sans dépiler ...........
ret soubroutine ends Djamal Rebaïne 114
Emplacement de sous-programmes
En général, les sous-programmes sont mis à la fin du programme principal. Mais, on peut aussi les mettre dans la partie du segment de code. Seulement,il faudra s’assurer que la première instruction de code exécutée soit celle du programme principal. Pour cela, il suffit juste de mettre un JMP juste avant la déclaration du sous-programme. Djamal Rebaïne 115
Exemple: le calcul de PGCD de plusieurs nombres TITLE PGCDdeplusieursnombres SPILE SEGMENT STACK DW 100 DUP(?) SPILE ENDS SDATA SEGMENT valeurs DB 10,30,40,76,32,52 resultat DB 3 dup(?) tab_sortie db 7 dup('$') tab_conv db 7 dup('$') start dw 0 SDATA ENDS SCODE SEGMENT ASSUME CS:SCODE,DS:SDATA JMP debut PGCD proc near ; déclaration de la fonction repet: MOV AL,CL MOV AH,0 IDIV CH; CMP AH,0 JE dfin MOV CL, CH MOV CH, AH JMP repet dfin: RET ;le PGCD est dans CH PGCD ENDP ;fin de la procédure PGCD Djamal Rebaïne 116
• • • • • • • • • • • • • • • • DEBUT: mov ax,sdata mov ds,ax mov SI,0; sert d’indice tableau MOV BX, 5; compteur de nombre à manipuler mov CH, valeurs[SI] INC SI repeter: CMP BX,0 JE fin mov CL, valeurs[SI] Call PGCD INC SI DEC BX JMP repeter Fin: ; le PGCD de tous les nombres est dans CH Djamal Rebaïne 117
xor ax,ax ; tout ce qui suit sert à afficher les chiffres contenus dans le PGCD qui est dans CH mov al,ch mov si, offset tab_conv mov start, offset tab_conv ;start sert à garder le début du tableau mov bx,0 mov bl,10 division: ; on suppose que la division se fait sur des nombre de 16 bits div bl cmp al,0 je fin_div add ah,48 mov byte ptr[si],ah mov ah,0 inc si jmp division fin_div: add ah,48 mov byte ptr[si],ah ; tab_conv contient le nombre converti à l’envers xor bx,bx mov bx, offset tab_sortie xor ax,ax Djamal Rebaïne 118
st_bcl: cmp si,start jb fin_bcl mov ah , byte ptr[si] mov byte ptr[bx] , ah dec si inc bx jmp st_bcl fin_bcl: mov byte ptr[bx],10 inc bx mov byte ptr[bx],13 inc bx mov byte ptr[bx],'$' mov dx,offset tab_sortie mov ah,09h int 21h Sortie: MOV AX, 4c00h; Int 21h SCODE ENDS END DEBUT Djamal Rebaïne 119
• Le compilateur se chargera alors de la remplacer par les instructions comprises entre la première et la dernière ligne de cet exemple, en prenant le soin de remplacer le mot chaine par le message fourni en paramètre. • Supposons à présent que l’on veuille écrire à l’écran le message « Je suis bien content » et revenir à la ligne à l’aide de notre macro
affiche
• • La syntaxe suivante :
affiche ‘Coucou ! Ceci est un essai !’, 10, 13, ‘$’
Djamal Rebaïne 120
Traitement des tableaux et chaînes de caractères
Une chaîne de caractères ASCII est constiuée d’une suite de caractères terminée par le ‘$’. Ce type de caractères est utilisé par le MS DOS. Une chaîne de caratères ASCII se déclare à l’aide de la directive DB • Exemple: mesg DB ‘bonjour$’ Message DB 'Bonjour$' est la même chose que Message DB 'B', 'o', 'n', 'j', 'o', 'u', 'r', '$' ou que Message DB 66, 111, 110, 106, 111, 119, 114, 36 La seule obligation est le caractère '$' qui indique la fin de la chaîne (sinon les octets situés à la suite du message en mémoire sont aussi affichés comme caractères). Zone DB 30 DUP(?), ‘$’; chaîne de 30 caratères de valeur non définie Tamp DB 25 DUP (‘ ‘); chaîne de 25 espaces blancs Ligne DB 10 dupl(‘ ‘); ‘*’, 20 dup (?), ‘$’ Djamal Rebaïne 121
• En assembleur, il n’existe pas de distinction entre une chaîne de caractères et un tableau de caractères. Ainsi, il est posible d’accéder à un élément quelconque de la chaîne.
• • ;AL zone[i]; i >= 0 mov SI, i mov AL, zon[SI] ;Zone[i] AL; i >= 0 mov DI, i mov zone[DI], AL
Remarque:
Les registres SI, DI, BX peuvent être utilisés indifférement pour accéder aux éléments d’une chaîne. Djamal Rebaïne 122
• Exemple de parcours séquentiel d’une chaîne ;AX nombre de lettres ‘L’ ; SI registre d’index mov SI,0 MOV AX, 0 While1: CMP zone[SI], ‘$’; tester la fin de la chaîne le $ JA enwhile1 If1: CMP zone[SI], ‘L’ JNE endif1 INC AX Endif1: INC SI JMP while1 Endwhile1: Djamal Rebaïne 123
Autre possibilité: utiliser SI comme pointeur lea SI,zone; SI contient l’adresse de début de zone MOV AX, 0 While1: CMP byte PTR [SI], ‘$’; tester si la fin de la chaîne est atteint JA enwhile1 If1: CMP byte PTR [SI], ‘L’ JNE endif1 INC AX Endif1: INC SI JMP while1 Endwhile1: Djamal Rebaïne 124
Les vecteurs
Vecteur d’entiers
Le principe est le même pour un vecteur d’entiers où chaque élément est stocké sur un entier. Pour un vecteur d’entiers stockés sur deux octets nous devons tenir compte de la longueur d’un élément du vecteur.
Exemple: T dw 1, 4, 7, 1; vecteur de 4 entiers initialisés respectivement ; aux valeurs 1, 4, 7 et -1 T1 dw 100 dup (?); vecteur de 100 éléments non initialisés.
Djamal Rebaïne 125
Implémentation en mémoire (un élément est sur 2 octets) Indice 1 2 3 4 Déplacement 0 1 2 3 4 5 6 7 |--------------------------------------------| t | x x | x x | x x | x x | -------------------------------------------- Fonction d’indicage: adresse de début de t + i * longueur d’un élément de t ---------------------------------------------- adresse du i ème élément de t Djamal Rebaïne 126
• Exemple: ; AX t[i] mov SI,i ADD SI,SI; SI = SI * 2 (longeur d’un élément) MOV AX, t[SI] ; t[i] AX MOV SI, i ADD SI, SI MOV t[SI], AX Djamal Rebaïne 127
Tableau à deux dimensions
La fonction d’indicage des tableaux à deux dimensions est plus complexe. Généralement, ces derniers sont rangés en mémoire ligne par ligne.
Exemple:
Ligne 1 x x x x x x x x Ligne 2 x x x x x x x x Ligne 3 x x x x x x x x Implémentation em mémoire Ligne 1 ligne 2 ligne 3 x x x x x x x x x x x x x x x x x x x x x x x x 0 1 2 3 4 5 6 7 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 Djamal Rebaïne 128
Soit n et m le nombre de lignes et de colonnes, respectivement; et i et j les indices de ligne et de colonne: Adresse de début du tableau t + i * m longueur d’un élément de t (sélection de la ligne) + j * longueur d’un élément de t (sélection de la colonne) ------------------------------------------------------------- = addresse de l’élément t[i][j] Djamal Rebaïne 129
Exemple 8 : parcours d'un tableau
Ce programme passe une chaîne de caractères en majuscules. La fin de la chaîne est repérée par un caractère $. On utilise un ET logique pour masquer le bit 5 du caractère et le passer en majuscule (voir le code ASCII). Title parcours pile segment stack 100 dup (?) pile ends data SEGMENT tab DB 'Un boeuf Bourguignon', '$' data ENDS code SEGMENT ASSUME DS:data, CS:code debut: MOV AX, data MOV DS, AX MOV BX, offset tab repet: MOV AL, [BX] AND AL, 11011111b MOV [BX], AL ; adresse debut tableau ; lit 1 caractère ; force bit 5 à zero ; range le caractère INC BX CMP AL, '$' JNE repet MOV AH, 4CH INT 21H ; Retour au DOS ; passe au suivant ; arrive au $ final ?
; sinon recommencer code ENDS END debut Djamal Rebaïne 130
Les instructions de traitement de chaînes de caractères
Les instructions disponibles pour effectuer des traitement de chaines sont comme ci desous. Ce jeu d’instructions permet de considérer des chaînes de caractères (1 octet) et de mots (2 octets).
MOVS recopier des chaînes SCAS chercher un élément (octet, mot) dans une chaîne CMPS comparer deux chaînes LODS charger un élément dans le registre accumulateur STOS ranger le registre accumulateur dans une chaîne Les instructions de chaînes fonctionnent toutes selon le même principe: Djamal Rebaïne 131
1.
2.
3.
4.
Le flag de direction du registre des codes-conditions indique le sens de traitement de chaines: s’il vaut zéro, les chaînes sont traitées par adresse croissante, sinon les chaînes sont traitées par adresse décroissante. Rappelons que l’instruction CLD initialise le flag de direction à 0 que l’instruction STD le positionne à 1 Le nombre d’itérations à effectuer doit être rangé dans le registre CX L’adresse de départ de la chaîne donnée est dans l’ensemble des registres DS et SI. L’adresse de départ de la chaîne résultat (ou deuxième chaîne opérande) est dans le registre ES et DI Choisir le prefixe et l’instruction.
Djamal Rebaïne 132
Les préfixes disponibles sont: • REP ou REPZ répète l’opération du nombre de fois contenu dans CX • REPE ou REPZ répète l’opération tant que l’on a l’égalité et que CX est différent de 0 • REPNE ou REPNZ répète l’opération tant que l’on a différence et que CX est différent de 0 Djamal Rebaïne 133
Résumé des instructions sur des chaînes de caractères pour effectuer des opérations avec des opérandes se trouvant dans des locations mémoire.
Instruction Dep. Ch. Oct.
Dep. Ch. Mot Sav. Ch. Oct.
Sav. Ch. Mot Chg. Ch. Oct.
Chg. Ch. Mot Cmp. Ch. Oct.
Cmp. Ch. Mot Scn. Ch. Oct.
Scn. Ch. Oct.
Mnémonique MOVSB MOVSW STOSB STOSW LODSB LODSW CMPSB CMPSW SCASB SCASW Destination ES:DI ES:DI ES:SI ES:SI AL AX ES:DI ES:DI ES:DI ES:DI Source DS:SI DS:SI AL AX DS:SI DS:SI DS:SI DS:SI AL AX Préfixe REP REP / / REP REP REPE/REPNE REPE/REPNE REPE/REPNE REPE/REPNE DF
(registre flag)
CLD
DF=0 Incrémentation ( DF=0 ) Décrémentation ( DF=1 ) du pointeur utilisé pour les opérations
STD
DF=1 Djamal Rebaïne 134
• Les instructions de gestion des chaînes d’octets • a) l’instruction MOVSB («
Move String Byte
») • Syntaxe : MOVSB • Description : Copie l’octet adressé par DS:SI à l’adresse ES:DI. Si DF = 0, alors DI et SI sont ensuite incrémentés, sinon ils sont décrémentés. • Remarque : Pour copier plusieurs octets, faire REP MOVSB (« • Exemple :
Repeat Move String Byte
CX de même que pour un LOOP. »). Le nombre d’octets à copier doit être transmis dans Djamal Rebaïne 135
Djamal Rebaïne 136
• b)
l’instruction SCASB
(«
Scan String Byte
») • Syntaxe : SCASB • Description : Compare l’octet adressé par ES:DI avec AL. Les résultats sont placés dans le registre des indicateurs. Si DF = 0, alors DI est ensuite incrémenté, sinon il est décrémenté. • Remarques : Pour comparer plusieurs octets, faire “REP SCASB” ou “REPE SCASB” («
Repeat until Egal
»), ou encore “REPZ SCASB” («
diffèrent Repeat until Zero
»). Ces trois préfixes sont équivalents. Le nombre d’octets à comparer doit être transmis dans CX. La boucle ainsi créée s’arrête si CX = 0 ou si le caractère pointé par ES:DI est le même que celui contenu dans AL (i.e. si ZF = 1). On peut ainsi rechercher un caractère dans une chaîne. Pour répéter au contraire la comparaison c’est-à-dire jusqu’à ce que AL et le caractère adressé par ES:DI , utiliser REPNE ou REPNZ. • Exemple :
jusqu’à ce que
ZF = 0, Djamal Rebaïne 137
Djamal Rebaïne 138
• • • c)
l’instruction LODSB
Syntaxe : LODSB Description Remarque MOVSB. («
Load String Byte
») : Charge dans AL l’octet adressé par DS:SI. Si DF = 0, alors SI est ensuite incrémenté, sinon il est décrémenté. : Possibilité d’utiliser les préfixes de répétition, de même que pour • • • d)
l’instruction STOSB
Syntaxe : STOSB Description Remarque LODSB. («
Store String Byte
») : Stocke le contenu de AL dans l’octet adressé par ES:DI. Si DF = 0, alors DI est ensuite incrémenté, sinon il est décrémenté. : Possibilité d’utiliser les préfixes de répétition, de même que pour • • • e)
l’instruction CMPSB
Syntaxe : CMPSB Description = Remarque SCASB. («
Compare String Byte
») : Compare l’octet adressé par DS:SI et celui adressé par ES:DI. Si DF 0, alors SI et DI sont ensuite incrémentés, sinon ils sont décrémentés. : Possibilité d’utiliser les préfixes de répétition, de même que pour Djamal Rebaïne 139
Exemple: REP MOVSB et CLD
• • • • • • • • • • • • • • •
TITLE PROG3_12.asm
pile segment stack dw 100 dup (?) pile ends data segment DATA_S DATA_D data ends DB DB ;Transfert un bloc de 20 octets dans la mémoire ‘AQWERTTYUIOPLJKHGFDS’ 20 DUP(?) Code segment assume CS:Code, ES:data, DS:data MAIN MOV AX,DATA MOV DS,AX MOV ES,AX CLD MOV SI,OFFSET DATA_S MOV DI,OFFSET DATA_D END MAIN ; Initialiser le segment de données ; Initialiser le segment Extra ; DF=0
Auto incrémentation des pointeurs SI et DI ; Charger le pointeur source ; Charger le pointeur destination MOV CX, 20 ; Charger le compteur REP MOVSB; Déplacer les octets pointés par SI vers des locations pointés par DI ; et répète jusqu’à CX
0, sachant qu’a chaque itération SI et DI sont ; automatiquement incrémentés MOV AH,4CH INT 21H Code ENDS ;
DOS
Djamal Rebaïne 140
TITLE Exemple:LODSB , REP STOSW et CLD pile segment stack dw 100 dup (?) pile ends data segment DATA_S DB ‘AQWERTTYUIOPLJKHGFDS’ DATA_D DB 20 DUP(?) MESSAGE DB ‘ Mémoire défectueuse’ ESP_MEM DB 100 DUP(?) data ends CODE segment Assume CS:CODE, DS:data, ES: data MAIN: MOV AX,DATA MOV DS,AX MOV ES,AX CLD MOV CX, 50 ; Initialiser le segment de données ; Initialiser le segment Extra ; DF=0 ; Charger le compteur avec 50 (50 mots = 100 octets) MOV DI,OFFSET ESP_MEM
Auto incrémentation des pointeurs SI et DI ; Charger le pointeur destination MOV AX, 0CCCCH REP STOSW ; le pattern qui servira de test ; Placer AAAAH dans 50 locations mémoires pointées par DI (jusqu’à CX
0) ; sachant qu’a chaque itération DI est automatiquement incrémenté MOV SI,OFFSET ESP_MEM MOV CX, 100 ; Charger le pointeur source ; Charger le compteur avec 100 (100 octets) ENCORE: LODSB XOR AL, AH JNZ PASSE LOOP ENCORE ; Charger de DS:SI vers AL (pas de REP) ; Est ce que le pattern est est le même, sachant que dans AL et AH se trouve CCh ; Sortir du programme si c’est différent ; continue jusqu’a CX
0
mémoire défectueuse JMP SORTI PASSE: MOV DX, OFFSET MESSAGE MOV AH,09H INT 21H ; Afficher un message sur écran ; le message est ‘Mémoire défectueuse’ ;
DOS SORTIR:MOV AH,4CH INT 21H CODE ENDS END MAIN ;
DOS
Djamal Rebaïne 141
Exemple:
TITLE
REPE CMPSB et CLD
PROG11 .asm; Vérifier l’orthographe d’un mot et afficher un message PILE SEGMENT stack DW 100 DUP (?) PILE ENDS Data SEGMENT MOT_EXACT DB ‘CHICOUTIMI’ MOT_TAPEE DB ‘CIHCOUTIMI’ MESSAGE1 DB ‘L’orthographe est juste’ , ‘$’ MESSAGE2 DB ‘L’orthographe est fausse’ , ‘$’ DATA ENDS CODE SEGMENT ASSUME CS:code, DS:data, ES: data MAIN: MOV AX,DATA MOV DS,AX MOV ES,AX CLD ; Initialiser le segment de données ; Initialiser le segment Extra ; DF=0 Auto incrémentation des pointeurs SI et DI MOV SI,OFFSET MOT_EXACT ; Charger le pointeur source MOV DI,OFFSET MOT_TAPEE ; Charger le pointeur destination MOV CX, 10 REPE CMPSB ; Charger le compteur avec 10 (10 lettres ou octets) ; Répéter tant que les deux lettres soient égales ou C= 0. ; Si c’est différent le programme sort de cette instruction. A noter ; qu’à chaque itération SI et DI sont automatiquement incrémentés.
JE PASSE ; Si ZF=1 afficher le message 1 (égalité) MOV DX,OFFSET MESSAGE2 ; Si ZF=0 afficher le message 2 (différence) JMP AFFICHAGE PASSE: MOV DX, OFFSET MESSAGE1 AFFICHAGE: MOV AH,09H ; le message est ‘Mémoire défectueuse’ INT 21H ; DOS CODE ENDS END MAIN Djamal Rebaïne 142
Exemple: REPNE SCASB et CLD TITLE PROG12.asm Pile segment stack dw 100 dup(?) Pile ends ; Balayer une chaîne de caractère et Remplacer une lettre particulière par une autre Data segment CHAINE DB ‘Mr. Gones’ , ‘$’ Data ends Code segment MAIN: assume CS:code, DS:Data, ES:Data MOV AX,DATA MOV DS,AX ;MOV ES,AX CLD ; DF=0
; Initialiser le segment de données ; Initialiser le segment Extra Auto incrémentation des pointeurs SI et DI MOV DI, OFFSET CHAINE MOV CX, 9 MOV AL, ‘G’ ; Charger le pointeur destination ES:DI ; Charger le compteur avec 9 (la taille de la chaîne de caractères) ; le caractère a scanner (balayer) REPNE SCASB JNE PASSE DEC DI ; Répéter le balayage tant que les deux lettres ne sont pas égales ou jusqu’a C= 0. ; Saut si ZF=0 afficher le message 1 (égalité) MOV BYTE PTR[DI], ‘J’ ; Décrémenter DI (a la lettre G) car entre autre DI s’est automatiquement incrémenté ; Remplacer ‘G’ par ‘J’ PASSE : MOV DX, OFFSET CHAINE AFFICHAGE : MOV AH,09H INT 21H ; le message correcte est affiche: ‘Mr. Jones’ ;
DOS Code ENDS END MAIN
Djamal Rebaïne 143
Donnee SEGMENT chaine1 db 2000 dup(?) chaine2 db 100 dup(?) Donnee ENDS CODE SEGMENT ASSUME CS:CODE, DS:Donnee, ES:Donnee MOV AX, Donnee MOV DS,AX MOV ES,AX ENTREE: ; initialiser sens de transfert CLD ; adresse croissante ;initialiser chaine1 avec 200 caractères ‘A’ MOV AL, ‘A’ ; caractères de remplissage MOV CX,2000 ; longueur de la chaîne LEA DI,chaine1 ; DI recoit l’adresse de chaine1 REP STOSB Djamal Rebaïne 144
; afficher chaine1 MOV CX,2000 LEA SI,chaine1 MOV AH,2 ;fonction DOS affichage d’un caractère Boucle: LODSB MOV DL,AL INT 21H LOOP Boucle ; recopier dans chaine2 les 100 premiers caractères de chaine1 MOV CX,100 LEA SI,chaine1 LEA DI,chaine2 REP MOVSB Djamal Rebaïne 145
; rechercher un caractère dans une chaîne MOV CX,100 LEA DI,chaine1 MOV AL,’B’ ;caractère à rechercher REPNE SCASB JNE non_trouve MOV DL,’O’ JMP aff1 non_trouve: MOV DL,’N’ aff1: MOV AH,2 INT 21H Djamal Rebaïne 146
; comparer deux chaînes MOV CX,100 LEA SI,chaine1 LEA DI,chaine2 REPE CMPSB JNE non_identique MOV DL,’O’ JMP aff2 non_identique: MOV DL,’N’ aff2: MOV AH,2 INT 21H MOV AX,4C00H INT 21H CODE ENDS END ENTREE Djamal Rebaïne 147
La récursivité
• Définition: Une procédure est dite récursive si, et seulement si, elle fait appel à elle-même, soit directement soit indirectement
Djamal Rebaïne 148
Fonctionnement d’une fonction récursive
• Création d’une pile pour la sauvegarde
entre autres
des paramètres d’appels de la procédure et la l’adresse de retour.
Djamal Rebaïne 149
Calculer le factoriel de n, noté n!
•
Le problème est:
Calculer le factoriel d'un nombre entier donné en entrée.
•
En entrée:
Nous avons n nombre entiers qui sont plus grands ou égaux à 0.
•
Sortie:
Nous avons un nombre entier qui représente le factoriel de n.
Djamal Rebaïne 150
•
Fonction principale
• entier n nfact • lire n • si (n < 0) alors écrire “entrée négative: ” n • • • sinon nfact factoriel(n) écrire “la factorielle de ” n “est” nfact • • où
factoriel
satisfait le prototype
entier factoriel(entier)
Djamal Rebaïne 151
Fonction factoriel }
int factoriel(entier n)
{
si (n < 1) retourner 1 retourner n * factoriel(n-1
)
Djamal Rebaïne 152
Comment le faire en assembleur?
On a besoin d’une pile!
• En effet, à chaque appel récursif, la valeur du paramètre n est sauvegardée dans la pile de travail. • Ce processus d’empilement est répété jusqu’à ce que le paramètre actuel (de l’appel) n atteigne la valeur un. Cela correspond à la fin de l’exécution de la fonction appelante.
• Ensuite, commence le dépilement, et l’exécution de la prochaine instruction de la fonction appelante est entamée. Ce processus de dépilement est répété jusqu’à ce qu’on atteigne la valeur de départ du paramètre n.
Djamal Rebaïne 153
Cela se traduit par le programme assembleur suivant TITLE factoriel PILE segment stack dw 100 dup(?) Basdepile equ this word PILE ends Data segment N dw 4 fact dw ?
Data ends Code segment assume CS:code, DS:Data, SS:Pile Debut: MOV AX,Data MOV DS,AX MOV AX,Pile MOV SS, AX ; initialise le segment de pile MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP mov BX,n; sauvegarde la valeur de n mov ax,bx call factoriel Fin: pop AX; le résultat calculé par la fonction factoriel est dans AX mov fact, AX mov AX,4c00h int 21h Djamal Rebaïne 154
factoriel proc near push ax Continuer: CMP AX,1 JLE dépiler; déplier jusqu’à ce n = 1 dec AX push AX JMP continuer Depiler: POP AX POP CX mul CX Push AX CMP BX,CX Ja depiler ret factoriel endp ; fin de la procédure code ends end debut ; fin du programme code Djamal Rebaïne 155