Résumé du cours précédent

publicité
Assembleur
Niveaux de programmation
• Niveaux de programmation
circuit logiques
0/1
--------------------------------------------------------------------------------unité de traitement
micro-instructions
(UAL, chemins de données)
(Unité de commande)
= suite de 0/1
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 ; fin de la déclaration de la pile
DONNEE SEGMENT ; déclaration d’un segment de données qui va
; contenir les variables
...........
DONNEE ENDS
; fin de la déclaration de données
LECODE SEGMENT ; déclaration du segment de code qui va contenir
; le code
Debut:
; étiquette d’indication du point d’entrée du code
.................................
LECODE ENDS
; fin de la déclaration du code
END Debut
; fin du point d’entrée du code
Djamal Rebaïne
3
Exemple
TITLE prog2.asm: Exemple sur ROL,
Pile segment stack ;
dw 100 dup(?)
Pile ends
DATA segment
DATA1DW
COMPTE
DATA ends
5F97H
DB
?
CODE segment
MAIN:
ASSUME CS:CODE, DS:DATA
MOV AX,DATA
MOV DS, AX
XOR
MOV
MOV
ENCORE: ROL
JNC
INC
PROCHAIN: DEC
JNZ
MOV
MAIN
BL, BL
DL, 16
AX, DATA1
AX, 1
PROCHAIN
BL
DL
ENCORE
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
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 ASseMbler
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) (Declare Byte)
DW
: 1 word (16 bits) (Declare Word)
DD
: 2 words (32 bits) (Declare Double)
DF,DP
: 6 bytes
DQ
: 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:
•
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
•
mov DL, “A”; caractère A est transfére dans DL
mov AH, 2; fonction no. 2
int 21h
; appel au DOS
Djamal Rebaïne
10
•
Saisie d’un caractère
(sans écho)
mov AH, 7; fonction no. 7
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
bx = 10;
else {
bx = 0;
cx = 10;
}
if:
CMP AX, 1
JNZ Else
Then: MOV BX,10
JMP endif
Else: MOV BX,0
MOV CX,10
endif: ..............
Djamal Rebaïne
12
Instruction i
…
Instruction i
Si condition alors
Instructions j
Sinon
Instruction m
Fin si
Instructions k
VRAI
FAUX
Condition ?
Instructions m
Instructions j
Instructions k
Djamal Rebaïne
13
• La boucle FOR
Assembleur
• For (k=0; k<=10; k++)
•
bx = bx + k;
For:
MOV BX,0
MOV CX,0
CMP CX,10
JA Endfor
ADD BX,CX
INC CX
JMP For
Endfor:
Djamal Rebaïne
14
• WHILE
• bx = 5
• while (bx >0)
bx = bx -1;
Assembleur
while:
MOV BX,5
CMP BX,0
JLE Endwhile
DEC BX
JMP while
Endwhile:
Djamal Rebaïne
15
• SWITCH
• switch (n) {
case 1: ....; break;
case 2: .....; break;
default: .....;
}
Assembleur
CMP n,1
JNE case2
............
JMP endswitch
case2: CMP n,2
JNE default
..........
JMP endswitch
default: ...........
endswitch: ...........
Djamal Rebaïne
16
Écrire le code de l’instruction
if (a>b) && (c <= d)
{
................
}
En assembleur
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): pareil que SI (instruction STOS)
• BP (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): Pointe sur le segment qui contient le code du
programme.
• 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
; (décimal)
MOV Cl, 01101b
; (binaire)
MOV DH, 0FAh
; (hexa)
; Entre registres
MOV AX, BX
MOV CL, DH
; 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
; AX <- AX + 5
ADD BH, toto
; BH <- BH + toto
Add toto, Cx
; toto <- toto + Cx
; Soustraction
SUB AX, 5
; AX <- AX – 5
SUB BH, toto
; BH <- BH – toto
SUB toto, CX
; toto <- toto - CX
Djamal Rebaïne
24
Quelques instructions de base-3
• Logique
; AND bit à bit
MOV AH, 0101b
MOV BH, 1001b
AND AH, BH
; OR bit à bit
MOV AH, 0101b
MOV BH, 1001b
Or AH, BH
; XOR bit à bit
MOV AH, 0101b
MOV BH, 1001b
XOR Ah, BH
; NOT bit à bit
MOV AH, 0101b
soit 10 (8+2)
; AH <- 5
; BH <- 9
; AH <- AH AND BH; AH vaut 0001b, soit 1
; AH <- 5
; BH <- 9
; AH <- AH OR BH; AH vaut 1101b, soit 13 (8+4+1)
; AH <- 5
; BH <- 9
; AH <- AH XOR BH; AH vaut 1100b, soit 12 (8+4)
; AH <- 5 Not AH
; 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 est identique à l’instruction SUB, mais ne produit pas de
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 127octets). Il faut donc prendre garde que ce label puisse être
atteint.
Djamal Rebaïne
27
Djamal Rebaïne
28
JZ
Saut si zéro.
JE
Saut si égal.
JC
Saut si Retenue (inférieur).
JNC
JB
Saut si inférieur.
JNB
JNAE
Saut si ni supérieur ni égal.
CF = 1
JAE
JS
Saut si signe négatif.
SF = 1
JNS
JO
Saut si débordement.
OF = 1
JNO
JPE
Saut si parité paire.
JP
Saut si parité.
PF = 1
JPO
JNZ
Saut si pas zéro.
JNE
Saut si différent.
JNC
Saut si pas de retenue.
JC
JNB
Saut si pas inférieur.
JB
JAE
Saut si supérieur ou égal.
CF = 0
JNAE
JNS
Saut si aucun signe (positif).
SF = 0
JS
JNO
Saut si pas de débordement.
OF = 0
JO
JPO
Saut si parité impaire.
JNP
Saut si pas de parité.
Djamal Rebaïne
JNZ
ZF = 1
JNE
JZ
ZF = 0
JE
JPE
PF = 0
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
[0hC040],AL
mov
DS :[0hC040],AL
mov
CS:var2,AX
mais pas
mov
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)
CMP destination, source
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:
TEMP
…
DW
C
F
ZF
Dest. >
Src.
0
0
Dest. =
Src.
0
1
Dest. <
Src.
1
0
235FH
MOV
MOV
CMP
JNC
ADD
ADD
BX, 7888H
CX, 9FFFH
BX, CX
PASSE
BX, 4000H
CX, DATA1
DB
?
MOV
CMP
JZ
INC
PROCHAIN: HLT
Compar
e
Opérand
es
AL, TEMP
AL, 99
PROCHAIN
BX
; 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.
; TEMP  AL
; TEMP = 99?. Avec (SUB AL, 99), la même chose mais 0  AL
; Si ZF=1 (TEMP=99), Saute a PROCHAIN:
; Sinon incrémente BX
; Arrêt du programme
Djamal Rebaïne
37
TITLE prog1.asm: Exemple sur CMP, Trouver l’octet le plus grand parmi 5 notes d’élèves
PILE segment stack
dw 100 dup(?)
PILE ends
;------------------------------------------------------------------------------------------------------------------------------------------------------------DATA segment
NOTES
DB
18, 06, 19, 11, 08
PLUS_G
DB
?
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 CX, 5
; compteur de boucle
MOV BX, OFFSET NOTES
; BX pointe vers les données NOTES
XOR
AL, AL
; Initialise AL à 0; va héberger la plus grande note
ENCORE: CMP AL, [BX] ; compare la note prochaine a la note la plus élevée
JA
PROCHAIN
; Sauter si AL est encore la note la plus élevée
MOV AL, [BX]
; sinon AL retient la plus élevée
PROCHAIN: INC BX
; pointe vers la prochaine note
LOOP 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 AH, 4Ch
INT
21h
MAIN ENDS
END
MAIN
Djamal Rebaïne
38
TITLE prog2.asm: Exemple sur ROL, Trouver le nombre de ‘1’ dans un mot
Pile segment stack ; déclaration d’un segment de pile – pas nécessaire dans notre cas
dw 100 dup(?)
Pile ends
;-----------------------------------------------------------------------------------------------------------------------------------------------------------DATA segment
DATA1DW
5F97H
COMPTE
DB
?
DATA ends
;------------------------------------------------------------------------------------------------------------------------------------------------------------CODE segment
MAIN:
ASSUME CS:CODE, DS:DATA
MOV AX,DATA
MOV DS, AX
XOR
BL, BL
; Mettre BL à 0 (ou bien SUB)
MOV
DL, 16
; rotation 16 fois
MOV
AX, DATA1
ENCORE: ROL
AX, 1
; Rotation a gauche (a droite aussi si on préfère)
JNC
PROCHAIN
; Test si CF=0
INC BL
; Si CF = 1, incrémenter le compteur du nombre de ‘1’
PROCHAIN: DEC DL
; répéter 16 fois
JNZ ENCORE
; encore une fois si ce n’est pas fini
MOV COMPTE, BL
; 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
db ?
Wval1
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. Tout se passe exactement comme si vous
aviez tapé vous-même ce code à la place du nom de la
macro.
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
; de instructions de cette macro
mov dx,offset chaine ; pointe vers le début de la chaîne chaine
mov ah, 09h
; pour afficher une chaîne de caractères à partir de
; l’adres de début de chaine
int 21h
Endm
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
SEGMENT
DATA1
DD
0ABCD5F97H
COMPTE DB
?
DATA
ENDS
CODE
SEGMENT
ASSUME CS:SCODE, DS:DATA ; Initialiser le registre DS
MOV AX, DATA
MOV DS, AX
XOR
CX, CX
; Mettre CX à 0 (ou bien SUB)
MOV
DX, 1010h
; mettre 16 dans DH et DL; 00010000 000010000 en binaire
MOV
AX, WORD PTR DATA1 ; pointer vers le premier mot
MOV
BX, WORD PTR DATA1 + 2
; pointe vers le deuxième mot
ENCORE1: ROL
AX, 1
; Rotation à gauche (à droite aussi si on préfère)
JC
PROCHAIN1
Test si CF=1
INC
CL
; Si CF = 0, incrémenter le compteur du nombre de ‘0’
PROCHAIN1: DEC DL
; répéter 16 fois
JNZ ENCORE1
; encore une fois si ce n’est pas fini
MOV AL, CL
; 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
ENCORE2: ROL BX, 1
; Rotation à gauche
JC PROCHAIN2
; Test si CF=1
INC CH
; Si CF = 0, incrémenter le compteur du nombre de ‘0’
PROCHAIN2: DEC DH
; répéter 16 fois
JNZ ENCORE2
; encore une fois si ce n’est pas fini
MOV AH, CH
; sauvegarder le résultat dans AH. Même remarque qu’en haut
ADD AH, AL
; Additionner les nombres de ‘0’ trouvés séparément dans les 2 mots
MOV COMPTE, AH
; et sauvegarder le résultat dans COMPTE
MOV AH, 4Ch
; retour au DOS
INT 21h
Code ENDS
Djamal Rebaïne
63
END MAIN
Conversion Minuscule en
Majuscule
L
Hex
Binaire
L
Hex
Binaire
A
41
01000001
a
61
01100001
B
42
01000010
b
62
01100010
.
…………
.
…………
.
…………
.
…………
Y
59
01011001
y
79
01111001
Z
5A
01011010
z
7A
01111010
Djamal Rebaïne
64
TITLE prog8.asm ; Conversion MINUSCULE  MAJUSCULE d’un texte
PILE
SEGMENT STACK
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
; SI pointe sur le texte original
MOV
BX, OFFSET TEXTE2
; BX pointe sur le texte en MAJUSCULE
MOV
CX, 21
; compteur de boucle
ARRIERE: MOV
AL, byte ptr t[SI]
; prochain caractère
CMP
AL, 61H
; Si < ‘a’
(61H est le code ASCII de ‘a’)
JB
PASSE
; donc pas besoin de convertir
CMP
AL, 7AH
; Si > ‘z’
(7AH est le code ASCII de ‘z’)
JA
PASSE
; donc pas besoin de convertir
AND
AL, 11011111B
; masque le bit 5 pour convertir en MAJUSCULE
PASSE:
MOV
[BX], AL
; sauvegarde le caractère MAJUSCULE
INC
SI
; incrémente le “pointeur vers le texte original”
INC
BX
; incrémente le “pointeur vers le texte en MAJUSCULE”
LOOP
ARRIERE
; Continuer à boucler tant que CX > 0
;-----------------------------------------------------------------------------------------------------------------------------------------------------------MOV AX, 4C00h
INT 21h
CODE
ENDS
END
MAIN
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
dec SI
jmp fs
fins:
mov AX,4c00h
int 21h
scode ends
end
Djamal Rebaïne
70
• MULTIPLICATION ET DIVISION SIGNÉE
(ou mém.)
(IMUL / IDIV) reg.
• 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
AL = Octet CBW
Reg. ou mem.
AL
AH
Mot/Mot
AX = Mot CWD
Reg. ou mem.
AX
DX
AX = Mot
Reg. ou mem.
AL (Erreur si –128>AL>+127)
AH
DXAX = DoubleMot
Reg. ou mem.
AX (Erreur si –32768>AX>+32767)
DX
Mot/Octet
DoubleMot/Mot
MULTIPLICATION
SIGNEE
OPERANDE 1
(> ou <)
OPERANDE 2
(> ou <)
RESULTAT
Octet/Octet
AL
Reg. ou mem.
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)
Mot/Mot
AX
Reg. ou mem.
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)
AL = Octet CBW
Reg. ou mem.
DXAX (même remarque que précédemment)
Mot/Octet
DoubleMot/Mot
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:
;
•
•
•
•
•
•
•
MAIN
MOV
XOR
MOV
MOV
CBW
ADD
INC
LOOP
MOV
CBW
MOV
MOV
CX,9
BX,BX
SI,OFFSET SIGN_DAT
AL,[SI]
BX,AX
SI
ARRIERE
AL,9
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  AX
; BX+AXBX
; SI+1  SI
; Boucler tant que CX > 0
; Le nombre totales des températures  AL
; Extension du signe  AX
; Sauvegarder le DENOMINATEUR dans CX
; LA somme des températures  AX
EXEMPLE D’UTILISATION DE IDIV  TROUVER LA TEMPERATURE MOYENNE
CWD
; Extension du signe  AX
IDIV
CX
; Trouver la moyenne des températures (AX/CX)
MOV
MOYENNE,AX
; Sauvegarder la moyenne (QUOTIENT)
MOV
REMAINDER,DX
; Sauvegarder le reste
MOV
AH,4CH INT 21H
;Retourner au DOS
ENDP
END
MAIN
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
IMUL C
ADD AX,CX
ADC DX,BX
MOV CX, D
SUB CX,3
IDIV CX
MOV X,AX
RET
Arithmetique endp
............
;établir la constante
;DX:AX = A*2
;
;BX:AX = A *2
;DX:AX = B*C
;AX = AX + CX ! faites attention, il peut y avoir une retenue ici
;DX:AX = A*2+B*C + la retenue s’il y a lieu avec ADC
; cx = D -3
; AX =(A*2 + B*C)/(D-3)
; X = ax (A*2 +B*C)/(D-3) stocker le résultat
; 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
Djamal Rebaïne
END DEBUT
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
0
contenu
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
; à declarer dans
le segment de données
xor AX,AX
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
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 EQU ret
Quitter2 EQU int 20h
Mettre_dans_AH EQU mov ah,
Interruption_21h 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 met le contenu du registre dans la pile (empilement)
- POP registre récupère le contenu de la pile et le stocke dans le registre
(dépilage
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 pointeur de pile)
est le déplacement pour atteindre le sommet de
la pile (16 bits de poids faible).
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 car cette
instruction n'existe pas!
Djamal Rebaïne
97
Les procédures-fonctions
La notion de procédure - fonctions
En langage assembleur, on appelle procédure un sousprogramme 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 (qui représente le nom de la fonction) précédant le mot clef
PROC 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? 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
mot clé RET, qui va remettre dans le registre IP l'adresse qui y était
stocké avant l'appel par PROC.
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 RET (qui ne prend pas
d'arguments) le contenu de la pile est dépilé puis stocké dans le
registre IP.
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: on stocke les valeurs dans la
pile avant d'appeler la procédure, puis on lit le contenu de la pile
dans la procédure.
Le passage de paramètres par registres 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
l’appel de la fonction...
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 (BP: Base pointer) qui permet de lire des
valeurs dans la pile sans les dépiler, ni modifier le pointeur de
sommet de pile (SP).
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
;BP pointe sur le sommet
MOV AX, [BP]
;lit sans dépiler et le mot suivant avec :
MOV AX, [BP+2]
;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
T1
dw 1, 4, 7,-1; vecteur de 4 entiers initialisés respectivement
; aux valeurs 1, 4, 7 et -1
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
Déplacement
t
1
2
3
4
0 1
2 3
4 5
67
|--------------------------------------------|
|x x | x x | x x |
xx |
---------------------------------------------
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
xx xx xx xx xx xx xx xx xx xx xx xx
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 ; adresse debut tableau
repet:
MOV AL, [BX]
; lit 1 caractère
AND AL, 11011111b ; force bit 5 à zero
MOV [BX], AL
; range le caractère
INC BX
; passe au suivant
CMP AL, '$'
; arrive au $ final ?
JNE repet
; sinon recommencer
MOV AH, 4CH
INT 21H
; Retour au DOS
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
SCAS
CMPS
LODS
STOS
recopier des chaînes
chercher un élément (octet, mot) dans une chaîne
comparer deux chaînes
charger un élément dans le registre accumulateur
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
Mnémonique
Destination
Source
Préfixe
Dep. Ch. Oct.
MOVSB
ES:DI
DS:SI
REP
Dep. Ch. Mot
MOVSW
ES:DI
DS:SI
REP
Sav. Ch. Oct.
STOSB
ES:SI
AL
REP
Sav. Ch. Mot
STOSW
ES:SI
AX
REP
Chg. Ch. Oct.
LODSB
AL
DS:SI
/
Chg. Ch. Mot
LODSW
AX
DS:SI
/
Cmp. Ch. Oct.
CMPSB
ES:DI
DS:SI
REPE/REPNE
Cmp. Ch. Mot
CMPSW
ES:DI
DS:SI
REPE/REPNE
Scn. Ch. Oct.
SCASB
ES:DI
AL
REPE/REPNE
Scn. Ch. Oct.
SCASW
ES:DI
AX
REPE/REPNE
DF (registre flag)  Incrémentation (DF=0) Décrémentation (DF=1) du pointeur utilisé pour les opérations
CLD
 DF=0
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 (« Repeat Move String Byte »). Le
nombre d’octets à copier doit être transmis dans
CX de même que pour un LOOP.
• Exemple :
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” (« 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 jusqu’à ce que ZF = 0,
c’est-à-dire jusqu’à ce que AL et le caractère adressé par ES:DI
diffèrent, utiliser REPNE ou REPNZ.
• Exemple :
Djamal Rebaïne
137
Djamal Rebaïne
138
c) l’instruction LODSB (« Load String Byte »)
• Syntaxe : LODSB
• Description : Charge dans AL l’octet adressé par DS:SI. Si DF = 0, alors SI est
ensuite incrémenté, sinon il est décrémenté.
• Remarque : Possibilité d’utiliser les préfixes de répétition, de même que pour
MOVSB.
d) l’instruction STOSB (« Store String Byte »)
• Syntaxe : STOSB
• Description : 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é.
• Remarque : Possibilité d’utiliser les préfixes de répétition, de même que pour
LODSB.
e) l’instruction CMPSB (« Compare String Byte »)
• Syntaxe : CMPSB
• Description : 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.
• Remarque : Possibilité d’utiliser les préfixes de répétition, de même que pour
SCASB.
Djamal Rebaïne
139
Exemple: REP
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
MOVSB et CLD
TITLE
PROG3_12.asm
;Transfert un bloc de 20 octets dans la mémoire
pile segment stack
dw 100 dup (?)
pile ends
data segment
DATA_S
DB
‘AQWERTTYUIOPLJKHGFDS’
DATA_D
DB
20 DUP(?)
data ends
Code segment
assume CS:Code, ES:data, DS:data
MAIN
MOV AX,DATA
MOV DS,AX
; Initialiser le segment de données
MOV ES,AX
; Initialiser le segment Extra
CLD
; DF=0  Auto-incrémentation des pointeurs SI et DI
MOV SI,OFFSET DATA_S
; Charger le pointeur source
MOV DI,OFFSET DATA_D
; 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
; DOS
Code ENDS
END MAIN
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
; Initialiser le segment de données
MOV ES,AX
; Initialiser le segment Extra
CLD
; DF=0  Auto-incrémentation des pointeurs SI et DI
MOV CX, 50
; Charger le compteur avec 50 (50 mots = 100 octets)
MOV DI,OFFSET ESP_MEM
; Charger le pointeur destination
MOV AX, 0CCCCH
; le pattern qui servira de test
REP
STOSW
; 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
; Charger le pointeur source
MOV CX, 100
; Charger le compteur avec 100 (100 octets)
ENCORE: LODSB
; Charger de DS:SI vers AL (pas de REP)
XOR
AL, AH
; Est ce que le pattern est est le même, sachant que dans AL et AH se trouve CCh
JNZ
PASSE
; Sortir du programme si c’est différent  mémoire défectueuse
LOOP ENCORE
; continue jusqu’a CX0
JMP
SORTI
PASSE: MOV DX, OFFSET MESSAGE
; Afficher un message sur écran
MOV AH,09H
; le message est ‘Mémoire défectueuse’
INT
21H
; DOS
SORTIR:MOV AH,4CH
INT
21H
; DOS
CODE ENDS
END MAIN
Djamal Rebaïne
141
Exemple:
REPE CMPSB et CLD
TITLE
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
; Initialiser le segment de données
MOV ES,AX
; Initialiser le segment Extra
CLD
; 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
; Charger le compteur avec 10 (10 lettres ou octets)
REPE CMPSB
; 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
; Balayer une chaîne de caractère et Remplacer une lettre particulière par une autre
Pile segment stack
dw 100 dup(?)
Pile ends
Data segment
CHAINE DB ‘Mr. Gones’ , ‘$’
Data ends
Code segment
MAIN: assume CS:code, DS:Data, ES:Data
MOV AX,DATA
MOV DS,AX
; Initialiser le segment de données
;MOV ES,AX
; Initialiser le segment Extra
CLD
; DF=0  Auto-incrémentation des pointeurs SI et DI
MOV DI, OFFSET CHAINE
; Charger le pointeur destination ES:DI
MOV CX, 9
; Charger le compteur avec 9 (la taille de la chaîne de caractères)
MOV AL, ‘G’
; le caractère a scanner (balayer)
REPNE SCASB
; Répéter le balayage tant que les deux lettres ne sont pas égales ou jusqu’a C= 0.
JNE
PASSE
; Saut si ZF=0 afficher le message 1 (égalité)
DEC DI
; Décrémenter DI (a la lettre G) car entre autre DI s’est automatiquement incrémenté
MOV BYTE PTR[DI], ‘J’
; Remplacer ‘G’ par ‘J’
PASSE: MOV DX, OFFSET CHAINE
AFFICHAGE: MOV AH,09H
; le message correcte est affiche: ‘Mr. Jones’
INT
21H
; 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
Téléchargement