• Aucun résultat trouvé

Structure d’un programme assembleur 8086

N/A
N/A
Protected

Academic year: 2022

Partager "Structure d’un programme assembleur 8086"

Copied!
169
0
0

Texte intégral

(1)

Assembleur

(2)

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

(3)

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

(4)

Exemple

TITLE prog2.asm: Exemple sur ROL,

; pour mettre un commentaire, on écrit ;

Pile segment stack ; segemnt de pile dw 100 dup(?)

Pile ends

DATA segment ; segement de donnée

DATA1 DW 5F97H

COMPTE DB ?

DATA ends

CODE segment ; segment de code 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

(5)

Pourquoi les segments?

À l'origine

- Pour pouvoir adresser plus de 64 Ko de mémoire dans un programme car les registres sont sur 16 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 ...

(6)

Suite

Adressage sur 20 bits avec 2 registres

2 registres 16 bits : peut coder adresses sur 32 bits Pour uniquement 20 bits (car les bus d’adresse sur les

processeurs 8086 sont sur 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

(7)

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

(8)

• Vos programme sources, écrits en

assembleur, doivent avoir l’extension

.asm pour ASseMbler

(9)

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) non initialisé

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 chacun à 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 premier chiffre du nombre en hexadécimal commence par une lettre)

- binaire : 1b,0b,1010b,111101b

(10)

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 ; donne la main au DOS

Saisie d’un caratère: mov AH, 1; fonction no. 1

(avec écho) int 21h ; résultat est mis dans AL

(11)

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

(12)

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: ...

(13)

Instruction i Si condition alors

Instructions j Sinon

Instruction m Fin si

Instructions k

Instruction i

Condition ?

Instructions j

Instructions k FAUX VRAI

Instructions m

(14)

• 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:

(15)

• WHILE Assembleur

• bx = 5 MOV BX,5

• while (bx >0) while: CMP BX,0 bx = bx -1; JLE Endwhile DEC BX

JMP while Endwhile:

(16)

En règle générale

while (a > b) while: cmp a,b

{ jle endwhile … …

} jmp while …

endwhile: …

(17)

• 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: ...

(18)

É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++) { {

} }

(19)

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.

(20)

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.

(21)

La plupart des opérations de calculs donnent des informations sur le résultat dans le registre spécial flags. Les informations possibles sont : CF : 1 si le résultat a donné lieu à une retenue

PF : 1 si l'octet de poids faible du résultat à un nombre pair de 1 AF : 1 si le résultat a donné lieu à une retenue sur le 3eme bit ZF : 1 si le résultat est zéro

SF : 1 si le résultat est négatif

IF : 1 si les interruptions peuvent arriver

DF : 0 si la direction est incrémentée, 1 si elle est décrémentée OF : 1 si le résultat ne tient pas dans la destination

(22)

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.

(23)

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.

(24)

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

(25)

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

(26)

Quelques instructions de base-3

Logique

; AND bit à bit

MOV AH, 0101b ; AH <- 5 MOV BH, 1001b ; BH <- 9

AND AH, BH ; AH <- AH AND BH; AH vaut 0001b, soit 1

; OR bit à bit

MOV AH, 0101b ; AH <- 5 MOV BH, 1001b ; BH <- 9

Or AH, BH ; AH <- AH OR BH; AH vaut 1101b, soit 13 (8+4+1)

; XOR bit à bit

MOV AH, 0101b ; AH <- 5 MOV BH, 1001b ; BH <- 9

XOR Ah, BH ; AH <- AH XOR BH; AH vaut 1100b, soit 12 (8+4)

; NOT bit à bit

MOV AH, 0101b ; AH <- 5 Not AH ; AH <- NOT AH; AH vaut 1010b, soit 10 (8+2)

(27)

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

(28)

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.

(29)
(30)

Djamal Rebaïne 30

JZ  Saut si zéro. 

 ZF = 1

JNZ 

JE Saut si égal. JNE

JC  Saut si Retenue (inférieur). 

 CF = 1

JNC 

JB  Saut si inférieur.  JNB 

JNAE Saut si ni supérieur ni

égal. JAE

JS Saut si signe négatif.  SF = 1 JNS JO Saut si débordement.  OF = 1 JNO JPE  Saut si parité paire. 

 PF = 1 JPO JP Saut si parité.

JNZ  Saut si pas zéro. 

 ZF = 0

JZ 

JNE Saut si différent. JE

JNC  Saut si pas de retenue. 

 CF = 0

JC 

JNB  Saut si pas inférieur.  JB 

JAE Saut si supérieur ou égal. JNAE JNS Saut si aucun signe

(positif).  SF = 0 JS

JNO Saut si pas de

débordement.  OF = 0 JO

(31)

Un Warm-up

Quelques exemples de

programmes en assembleur

(32)

Impression d’une chaine de caractères

TITLE Mon_premier_programme_assembleur

PILE SEGMENT STACK;

DW 100 DUP (?) PILE ENDS;

DATA SEGMENT;

chaine db 'Bienvenue au monde de l',39,'assembleur!','$‘

; remarquez le $ pour marquer la fin de la chaîne de caractères DATA ENDS

(33)

MAIN SEGMENT

ASSUME DS:DATA, CS:MAIN; pour l’instant on fait comme ça sans ; trop se poser de question.

DEBUT:

MOV AX, DATA ; Initialiser le registre DS pour récupérer ; l’adresse du segment de donnée

MOV DS, AX

MOV DX, offset chaine ; Afficher une chaine de caractères

MOV AH, 09h ; fonction 9 pour imprimer sur écran une

;chaine de caratères à partir d’une adresse; un $ doit terminer cette

;chaine pour marquer l,arrêt de l’impression.

INT 21h

MOV AX, 4C00h ; l’équivalent de return(0) en C-C++

INT 21h;

MAIN ENDS

(34)

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

(35)

• Les données sont regroupées dans une zone de la mémoire appelée segment de données, tandis que les instructions se situent dans un autre segment qui est le segment d'instructions.

• Le registre DS (Data Segment) contient le segment de données, tandis que le registre CS (Code Segment) contient le segment d'instructions.

• C'est la directive ASSUME qui 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:

MOV AX, nom_du_segment_de_donnees MOV DS, AX

• La même procédure est faite quand viendra le moment d’utiliser

le segment de pile

(36)

Maximum entre deux nombres

TITLE Exercice 3 ; Écrire un programme en assembleur 8086 qui calcule le maximum ; de deux nombres A et B.

PILE SEGMENT STACK;

DW 100 DUP (?) PILE ENDS;

DATA SEGMENT;

n1 db (?) n2 db (?) DATA ENDS

MAIN SEGMENT

ASSUME DS:DATA, CS:MAIN

DEBUT: MOV AX, DATA ; Initialise le registre DS pour récupérer l’adresse du segment de MOV DS,AX ; donnée

MOV AH, 1h ; Lire un nombre à partir du clavier INT 21h

MOV n1, AL

MOV AH, 1h ; Lire un deuxième nombre à partir du clavier INT 21h

MOV n2, AL

(37)

CMP AL, n1

JG AFFICHER_N2 JL AFFICHER_N1

JMP AFFICHER_EGAL AFFICHER_N1 :

MOV DL, N1 ; afficher n1 mov AH, 02h

int 21h

JMP RETURN AFFICHER_N2 :

MOV DL, N2 ; afficher n2 mov AH, 02h

int 21h

JMP RETURN

(38)

AFFICHER_EGAL :

MOV DL, '=' ; afficher "="

mov AH, 02h int 21h

JMP RETURN RETURN:

MOV AX, 4C00h ; return 0 INT 21h;

MAIN ENDS

END debut

(39)

Modes d’adressage pour accéder aux données

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.

(40)

1. Adressage immédiat : l'opérande est une constante mov ah,10h ;

2. Adressage direct : l'opérande est une case mémoire (registre ds est par défaut)

mov al,[10h] ; [ds:10h]

mov ax,[es:10h] ; [ici le segment est ES

3. Adressage basé : l'opérande est une case mémoire dont l'adresse est donnée par BX (Si ou Di, avec ds par défaut) ou bp (avec ss par défaut)

mov AH,[BX] ; <=> mov AH,[DS:BX]

mov AL,[bp] ; <=> mov AL,[ss:bp]

BX,BP,SI,DI peuvent servir de registre pointeur

Modes d’adressage pour accéder aux

données

(41)

4. Adressage indexé : l'opérande est une case mémoire dont l'adresse est donnée par si ou di (avec ds par défaut, sauf mnemonic spécique)

mov ah,[si] ; <=> mov ah,[ds:si]

5. Adressage basé et indexé

mov ah,[bx+di] ; <=> mov ah,[ds:bx+di]

mov [bp+si],ah ; <=> mov [ss:bp+si],ah

Les couples possibles sont BP-DI,BP-SI, BX-DI, BX-SI

6. Adressage basé avec déplacement

(42)

7. Adressage indexé avec déplacement mov ah,[di+123h] ; <=>

mov ah,[ds:di+123h]

8. Adressage basé et indexé avec déplacement

mov ah,[bx+si+123h] ; <=>

mov ah,[ds:bx+si+123h]

(43)

Remarques

1. Si aucun registre de segment n'est précisé, c'est le segment par défaut qui est utilisé : CS pour IP; DS pour BX et SI; ES pour DI, SS pour BP et SP.

2. Ce n’est pas toutes les combinaisons registres de segment / registres d'index qui sont

possibles; les combinaisons les plus communément utilisées sont:

DS:BX, DS:SI, ES:DI, SS:BP, CS:BX

(44)

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

(45)

Applications de quelques

instructions sur des exemples

(46)

Compar e Opérand

es

C

F ZF

Dest. >

Src. 0 0

Dest. =

Src. 0 1

Dest. <

Src. 1 0

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 DW 235FH

MOV BX, 7888H ; 7888Hh  BX MOV CX, 9FFFH

CMP BX, CX ; BX < CX  CF=1  JNC est exécutée  PASSE

JNC PASSE ; Note: les contenus de (BX, et CX) ne changent pas après CMP

ADD BX, 4000H

PASSE: ADD CX, DATA1 ; mais CF est toujours vérifié pour (< ou >). Pour (=) on utilise ZF.

TEMP DB ?

MOV AL, TEMP ; TEMP  AL

CMP AL, 99 ; TEMP = 99?. Avec (SUB AL, 99), la même chose mais 0  AL JZ PROCHAIN ; Si ZF=1 (TEMP=99), Saute a PROCHAIN:

INC BX ; Sinon incrémente BX

PROCHAIN: MOV AH, 4Ch

(47)

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 à 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

(48)

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 Noter que l’opérateur offset utilise un registre de 16

bits.

(49)

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

DATA1 DW 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

(50)

; Segment de données data SEGMENT

chaine DB 'Hello world*'

data ENDS

; Segment de code code SEGMENT

ASSUME DS:data, CS:code

main: ; Initialisation du registre de segment de données MOV AX,data

MOV DS,AX

; Chargement de l'adresse de la chaîne dans BX

; Il s'agit de l'adresse relative au début du segment MOV BX,offset chaine

; Initialisation compteur MOV CX,0

Repeter: MOV AL,[BX]

CMP AL,’*’ ; Test de fin de chaîne JZ finito

INC BX ; va de l’avant dans la chaine INC CX ; Incrémentation compteur

JMP repeter

finito: ; Retour au DOS MOV AH,4CH

INT 21H code ENDS

END main ; Adresse de lancement

(51)

Quelques explications sur l’itération

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

(52)

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

(53)

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.

(54)

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 ????

(55)

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.

(56)

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

(57)

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 ».

(58)

Les macros, à la différence des procédures et des

fonctions, 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).

(59)

L’instruction pour définir une macro est:

nom MACRO [paramètres,...]

<instructions>

ENDM ; pour End Macro

(60)

Exemple de macro

Toto MACRO p1, p2, p3 – MOV AX, p1

– MOV BX, p2 – MOV CX, p3 ENDM

; et dans dans le segment de code, on peut faire ceci Toto 1, 2, 3

Toto 4, 5, DX

À l’aide de la macro Toto, le programme ci-dessous met d’abord 1, 2 et 3 dans AX,BX et CX, respectivement. Ensuite, il met 4, 5 et DX dans AX,BX et CX, respectivement.

(61)

affiche macro chaine

; sauvegarder le contenu de DX, par ; exemple, en utilisant le registre AX

Mov Ax, dx ; sauvegarde de dx dans AX mov dx,offset chaine

mov ah, 09h int 21h

Mov dx,Ax; restauration de dx endm ;fin de la macro

L’exemple suivant sert à écrire un message à

l’écran.

(62)

• 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++

(63)

Présentation d’autres exemples

(64)

TITLE ex3_somme; somme de deux nombres dont la somme est < 10 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

(65)

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

(66)

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

(67)

TITLE ex4_max ; détermine et affiche le maximum de deux nombres < 10 ; 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

(68)

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

(69)

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

(70)

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 ; 65h = 'A' dans AL MaBoucle: INC BX

MOV [BX], AL ; écrit dans le tableau

INC AL ; AL = caractère suivant DEC CL ; affecte l’indicateur 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

(71)

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

(72)

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

(73)

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

(74)

• Exemple 7: Exemple sur ROL, Trouver le

nombre de ‘0’ dans un double-mot

(75)

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 END MAIN

(76)

Conversion Minuscule en Majuscule

L Hex Binaire

A 41 01000001

B 42 01000010

. …………

. …………

Y 59 01011001

Z 5A 01011010

L Hex Binaire

a 61 01100001

b 62 01100010

. …………

. …………

y 79 01111001

z 7A 01111010

(77)

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

(78)

Exemple 9: lit une chaîne de caractères et l’affiche à l’envers

• Programme palin

(79)

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

(80)

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

(81)

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

(82)

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

(83)

MUL, IMUL, DIV, IDIV

1 seul opérande = REG ou mémoire

REG : AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.

Les instructions MUL et IMUL affectent uniquement les flags CF et OF : lorsque le résultat est plus grand que la taille de l'opérande ces flags sont placés à 1, lorsque la taille de l'opérante est ajustée ces flags sont placés à 0.

Pour DIV et IDIV les flags ne sont pas définis.

MUL - Multiplication non signée :

byte : AX = AL * opérande.

word : (DX AX) = AX * opérande.

IMUL - Multiplication signée :

byte : AX = AL * opérande.

word: (DX AX) = AX * opérande.

DIV - Division non signée :

byte : AL = AX / opérande; AH = reste (modulo)…

word : AX = (DX AX) / opérande; DX = reste (modulo)…

IDIV - Division signée :

Références

Documents relatifs

Les descriptions de cas sélectionnés pour leur intérêt pour l’évaluation de la dose interne ont été rassemblées dans une autre base de données appelée base de données

On a trois zones dans la mémoire: la zone des termes (où sont écrits les λ -termes à exécuter), la zone des environnements et la pile.. Dans la zone des environnements, on a des

Les données biologiques sont regroupées dans un grand nombre de bases de données (généralistes ou spécialisées ), utilisables via Internet et le Web.. Les récents progrès

Les données utiles ne sont pas apportées au fil de l'énoncé comme dans un exercice classique, mais elles peuvent être regroupées au début ou à la fin du document présentant

Le BIOS est stocké dans une ROM (mémoire morte, c'est-à-dire une mémoire en lecture seule), ainsi il utilise les données contenues dans le CMOS pour connaître

Les données sont regroupées dans le tableau 5.3 et sur la figure 5.12 en marge, nous avons reporté l’évolution de la compressibilité en fonction de la concentration pour une

La localisation des données peut être différente selon qu’elles sont stockées loca- lement (sur le disque ou dans la mémoire du client) ou bien sur un serveur distant.. Dans

Ce menu est utile pour copier les données de la plaque vers la mémoire amovible. Cette mémoire pourra ensuite être restaurée sur une autre plaque pour dupliquer